We will then look at the language in more detail, studying the constructs used within the language to create models. These include constants, signals, processes.
Next we will learn how VHDL code is synthesized and look at to construct some commonly used functions.
Finally we will discuss designing hierarchically with in VHDL.
VHDL is an IEEE standard hardware description language. It is used for both simulation and Synthesis.
In 1980 the U.S. department of defense started a program that eventually produced VHDL. The language was ratified as IEEE standard 1076 in 1987. In 1993 the IEEE VHDL standard was revised.
HDL stands for hardware description language.
Behavior Modeling describes a component by its input/output response. This is also sometimes referred to as black boxing.
Structural Modeling describes a component in terms of its lower level components and primitives.
Synthesis is the process by which HDL code is translated into a circuit. After the code is translated the circuit is optimized. The precise method of optimization depends on the synthesis tool and options that you set with in that tool.
A process is the basic unit of execution in VHDL. Within a process, statements execute sequentially, however processes themselves execute concurrently.
perform2 steps, translation and optimization. During translation, the synthesis tool directly translates the HDL code in a gate implementation. During optimization, the synthesis tools improves the logic, by making it smaller or faster. It may make the logic smaller by removing redundant logic or make it faster by adding some parallel structures in it.
Other languages like ABEL, PALASM and AHDL are more structural. With those languages, I specifically instantiate the component I want in my design, such as a d-flip flop and the tool goes into a library and drops that into my design. Very similar to low level schematic entry of the old days.
VHDL supports both methods of designing, both by inference and by instantiation which is what makes it so powerful. By simply describing the functionality of a circuit and letting the synthesis tool build it for me, you can produce very powerful functions in just a few lines of code. Doing this using a structural language is much more like programming in low level assembly with the circuit having a very specific implementation, so changes to that implementation do not scale easily and require much more effort.
On the left, the synthesis compiler takes the same VHDL design and libraries to produce a synthesized netlist. This netlist is your design translated into the primitives that make up the target hardware architecture. Notice that in the synthesis flow a technology library was used. Every FPGA family has a different library that a synthesis tool uses to map a design to its specific architecture. Using the generated synthesized netlist, the design can be placed and routed in the actual target device. If post synthsis simulation is desired, the synthesis tool can produce a VHDL output file that represents the synthesized results. This can be taken back to the simulation tool and re-simulated. This provides a check to ensure that the synthesis did not produce any errors.
An entity defines the external view of your design. All designs are expressed in terms of entities. The top-level is always an entity. If you are designing hierarchically, there will be lower level entities. An entity can be thought of as similar to a symbol. It defines port information
An architecture defines the functionality of an entity. It is used to fill in the details of a model. Every design that you can simulate has an architecture.
A configuration associates an entity and an architecture. Using configurations, you can have more than one architecture per entity. This allows you to create one entity, but have it function in different ways.
A package is a collection of commonly used code. It can be referenced by other parts of your design. A package can be thought of as a toolbox or a library that contains information needed by the rest of your design.
Here is the basic structure for an entity declaration. The keyword entity begins the entity statement. The name of the entity follows the keyword. The line ends with the keyword IS.
An entity consists of two sections, the generic declarations and the port declarations. Generic declarations are used to pass information into the model. The port declarations section describes the inputs and outputs to the entity.
There are several ways to close the entity depending on what your preference is and what version of VHDL you are trying to support.
The structure for a port declaration goes, class, object name: mode and type. The class is most always signal, though it doesn’t have to be, so you almost never see the word signal appear. The object name is the name of the I/O port. In this example, the object names are clk, clr and q. Since clk and clr are of the same type, they are declared together, separated by a comma.
The mode is the direction of the port. In VHDL, the keywords for directions are in for input, out for output, inout for a bidirectional and buffer for an output with internal feedback. Typically input signals and only be read from not written to. Outputs can only be written to, not read from. Inouts must be used as inputs and outputs. With buffers, physically in the design you will have an output pin, but you will be allowed to read from it as well. Use care when using buffers as there are restrictions on them when connecting them to other design blocks hierarchically. Personally, I typically stick with in, out and inout.
And lastly, the type is the data type defines the type of values that can be held by your I/O.
Like the generic declaration, the semicolon is used as a separator and the last port declared is not followed by a semicolon.l
The generic declaration is contained inside of the entity declaration. We use the keyword generic and within parenthesis list the generics.
The format for a generic declaration goes class, object name type and initial value. The class signifies what can be done to the generic. Generics are almost always constants and the keyword constant is usually left out. The object name is the name of the generic that will be used within your model. The type is the data type, which specifies the values that your generic can hold. Finally, the initial value is optional.
As you can see in the example, the generic declaration itself is considered a statement and ends with a semicolon. Within the parenthesis, the generics are listed with semicolons separating each one. Since the semicolon is used to separate the list, there is no semicolon after the last generic, as you can see after the word up. Also notice you can declare multiple generics in one line if they are of the same time and initial value, by using the comma. Thus tplh and tphl are both generics of type time initialized to 5 ns. And tphz and tplz are both generics of time initialized to 3 ns.
Architectures must be associated with an entity, but an entity can have multiple architectures associated with it. This is done sometimes in simulation when a designer wants to use two different sets of test vectors to test the design. He or she may have two architectures and will select one at compile time. Multiple architectures may also be used by designers when they have one architecture that contains a a synthesizable model and another architecture that contains a simulatable model. Depending on what action they are performing, be it in synthesis or simulation, they will select the appropriate architecture.
Within an architecture are implied and explicit processes that execute concurrently. We’ll be discussing processes in a bit.
When coding an architecture, there are two methods that can be used.
Behavioral: with the design described with an RTL and functional coding style,
Structural: which interconnects gates and components together like a netlist,
or a mixture of both.
Similar to the ENTITY block, the architecture can be terminated with several different methods depending on which version of VHDL you are supporting.
After the architecture name, you have the the keyword OF and then the name of the entity that this archiecture belongs to, followed by IS.
Then yo have the architecture declaration section. Local identifier that you use insde the architecture that are not ports or generics must be declared in the architecture declaration section before that can be used. In this example, that could be a signal, a constant or an enumerated data type. All of these we will take more about later.
After the declaration section, you have the keyword BEGIN followed by the architecture body. The arch body contains the executable lines of code within your design, made up of various processes.
End your architecture with the line end architecture and then the architecture name.
The format for a configuration starts with the keyword configuration. Then the configuration name followed by OF the entity name IS FOR the architecture named and END FOR.
End your configuration with the keywords END configuration and the configuration name.
The entity defines the ports.
In this example a, b, and sel are inputs, x, y, and z are outputs.
The architecture defines three muxes.
You can see that the three muxes are coded using three different styles, a simple signal assignment, a conditional signal assignment, and a selected signal assignment. We will look at these assignments in detail later in the presentation.
Finally the configuration ties the architecture and the entity together. Once again configurations are typically used in a simulation environment.
The package consists of a package declaration and a package body. The package declaration is required and is used to declare identifiers that you will be using, such as type declarations and subprogram declarations. The package body is an optional section. Though you can declare items in the body, it is typically use to define the functionality of the subprograms that were declared in the package declaration section.
VHDL has 2 built-in packages called the standard and textio packages. The standard package defines built-in VHDL data types that can be used for designing and associated operations that go along with them. The textio package provides support for file operations, for example reading and writing to external data files.
The PACKAGE BODY section contains the function itself. You can see that this example implements a basic compare function.
Libaries can come from various places. VHDL has a standard library that contains the standard packages I referred to in the last slide. IEEE came along and created additional libaries that are supported by almost all VHDL compilers. Specific silicon vendors like Altera created further libraries from which you can call vendor-specific information. And you can also create your own libraries, in which you store your own units for reuse.
The current project library in which you are design is called the working library. If you don’t indicate that you want something compiled into a specific library, then it will automatically be compiled in your working library or directory.
To use a package, you must first call out its library using the library clause. Again, the library name is a symbolic name that refers to a directory containing your compiled packages. Each VHDL compiler you use will have a specified way to associate a name to a particular directory path.
To call out a library, You type the keyword library followed by the library name. After that, you use the USE clause to call out the package within the library.
Both the library WORK and standard STD are considered implicit libraries and do not need to be explicitly called out.
For the use clause, I type the library name (dot) the package name (dot) the object in the package I want to reference. If I want the entire package available to the model, then I can use the keyword ALL, which you will find most designers do since it is easier and memory impact on your system is neglibile.
The libray and use clauses are placed at the very beginning of your model so that they can be accessed by all of the design units in your model.
The BIT_VECTOR type is an array of bits. Here you can see examples of defining both a bit and a bit_vector.
The BOOLEAN type simply takes on the values true and false, while the integer value can store up to a 32 bit number. You can use both positive and negative numbers with the integer type.
The std_ulogic is similar to the std_logic type, but it does not support multiple signal drives. If a std_ulogic signal has multiple signal drives, an error will be generated.
First we talked about some basic terminology. Synthesis, the step in which HDL code is translated to a circuit, is a very important concept. Behavior modeling allows you to specify the functionality of a circuit, while structural modeling allows you to specify both the functionality of the circuit and its implementation.
Next we covered the basic design units in VHDL. Remember that an entity is similar to a symbol and an architecture is similar to a schematic. A configuration associates an entity with an architecture.
Then we looked at packages. A package allow you to reuse code throughout a model.
Finally we talked about libraries. A library contains one or more compiled packages. The work library is automatically created and contains your current model. The ieee library contains a number of useful packages, such as std_logic_1164.
Generics are essentially constants whose values can be passed in from other modules and changed at compile time. Local constants, invisible outside the model are declared in the arch declaration. To declare a constant, you use the keyword constant followed by a identifier name, the data type := and the value you are assigning to the constant. The value must be valid for the constant’s data type. So in this example you can see the identifier bus_width is being assigned an integer value of 16.
Constants cannot be changed during design execution.
When declaring a signal, you specifiy SIGNAL, give it a name and then the type of signal such as a STD_LOGIC or in this case a STD_LOGIC VECTOR which is used to define a bus. In this example we are defining an 8 bit bus from 7 down to 0, with 7 being the MSB and 0 being the LSB.
The first example shows all eight bits being assigned at once. In this case we are assigning the signal with a binary value, which is the default and since we are defining multiple bits at the same time, they are separated by quotes. In the second example a hex value is being assigned to the signal temp.
The next case is known as “Single bit.” In this example a 1 is being assigned to bit seven of the signal temp. For single bit assignments, single quotes are used.
Now, it is possible to assign explicit widths that are either sign or unsigned and can even contain meta values, such as undefined or high impedance as shown in these examples
In the first example, we are assigning a 6 bit hex value for temp that is a 0F, which means the 0 only represents 2 of the 4, 0’s we would have had previously.
In another example, we can see that we are assigning a 6 bit signed value of F to the signal. Since F is a 1111, it automatically sign extends the 1 to fill the full 6 bit field. We can also see that when we specify an Octal 7 to the 6 bit signal, the upper bits are filled with 0s automatically.
It is important to note that we are using double quotes for all of these assignments and they are not case sensitive either.
So in the example we show here we see that we are assigning the signal qa to get the output of r OR’d with t. This is also how we define a signal that is used as an interconnect between logical blocks. And qb will get the output of qa and the inverted output of g XOR’d with h. These signal assignments have the function of implying the logic shown in the diagram above.
You can see that this code synthesizes to two MUXes. If sela=’1’ q becomes ‘a’ regardless of the selb signal.
Operator overloading allows the same operator to be used with multiple data types. This done by declaring a function whose namem is the same name as the operator itself. This is done by enclosing the character in double quotes. To make this easier, IEEE-defined data types have already been overloaded for us to to use the same operators as standard data types in VHDL.
The format to do this is to provide an optional, but suggested, descriptive label for the process followed by the keyword PROCESS and then an optional sensitivity list. The sensitivity list is optional because it is only really needed for simulation. Since the code we are writing is synthesized into actual pieces of hardware, it will operate exactly as the implied process works, when an input to the process changes it will cause the output signals to be updated. If we do not specify the sensitivity list we will have simulation mismatches, so it is strongly suggested. To make your life easier, in VHDL 2008 we have the option of using the keyword all to represent all of the input signals rather than specifying them individually.
After the process declaration is a local objects section that allows the definition of constants, custom types and variables. The actual functional contents of the process is defined between a begin and end process set of statements.
In the second example, process2, this example does not have a sensitivity list, so this process begins executing immediately at the start of simulation. Again, the statements inside are executed sequentially. This time when the process reaches the end, a wait on statement is seen. This wait on statement forces the process the process to wait until a or b transition before the process loops around and begins executing again.
While the behavior of two processes may seem different, they are actually identical. This is because all processes begin executing at the start of simulation in order to define the initial output values. Thus, it’s during the second iteration of process1 when the sensitivity list starts controlling its execution. Thus, as I mentioned in the previous slide, having a sensitivity list is said to “imply” having a wait on statement at the end of the process since their behavior is the same.
Having a sensitivity list and wait statements inside the same process is not legal in VHDL.
We have talked about how to make signal assignments and how to control the flow of your code using if-then and case statements. Next we will look at loops in VHDL.
An infinite loop does not exit until an EXIT command is reached. The EXIT command can be embedded in an If statement so that the loop is only exited if some condition that is evaluated by the If statement is true.
A While loop exits when some condition defined at the start of the loop evaluates to false.
A for loop executes some specified number of times. In some programming languages the identifier can be modified with in the loop, but VHDL does not allow this.
The basic structure of a process is the keyword PROCESS followed by a sensitivity list. Anytime a signal in the sensitivity list changes, the statements following the PROCESS statement, but before the END PROCESS statement are executed. We will look at an example process on the next slide.
A combinatorial process is sensitive to all inputs. If any signal changes, the process will execute again.
A sequential process is sensitive to a clock and or a control signals. If a process is sensitive to just a clock signal, a flip-flop is synthesized. In this way, only when the value of the clock signal changes, will the output change. We will see an example of this on the next slide
Though they would synthesize to the same logic, they are different in simulation.
Designing hierarchically in VHDL requires that you use components to connect your VHDL design units. In this example you can see that the top level top.vhd, references mid_a and mid_b. By referencing mid_a, top.vhd now has access to that entity.
After a component has been declared, you need to instantiate the component. The syntax is instance name colon lower level design name followed by the keyword PORT MAP. Within the port map section the lower level port names are mapped to current level port names.
Thank you