Can I describe a pipelined design in behavioral VHDL?
A pipelined design is usually best explained using a structural diagram consisting of computational stages separated by register banks. As a result, a pipelined design is often best described using structural VHDL. Note however that it is possible to describe a pipelined design with behavioral VHDL.
The key to writing a correct behavioral description of a pipelined design is to understand how to implement a register in behavioral VHDL. You must then carefully divide your computations in pipeline stages and store the results of computations in pipeline registers. Signals used in subsequent stages must also be saved in the stage's register bank. Remember that a pipeline stage must only use signals coming from the previous register bank.
Here is an example of a simple pipelined design described with behavioral VHDL.
How do I use MAX+PLUS II VHDL Library Components
Add the following lines at the beginning of your VHDL file:
LIBRARY altera; USE altera.maxplus2.ALL;
The library "altera" is declared as the resource library and the USE clause specifies the "maxplus2" package. A library may contain several packages.
From MAX+PLUS II's Help menu, select "Old-style Macrofunctions" to see a list of available components. Click on the component to see its I/O and functional specification.
To see the component declaration (i.e. port definitions) for the selected component, search through the components package file. (Note: This VHDL file is part of the installation of MAX+PLUS II version 10.1. To find the file installed with your version of MAX+PLUS II, look for maxplus2/vhdl93/altera/maxplus2.vhd.)
Here are three examples on how to use VHDL components from the Altera library:
How do I use MAX+PLUS II LPM Components
LIBRARY lpm; USE lpm.lpm_components.ALL;The library "lpm" is declared as the resource library and the USE clause specifies the "lpm_components" package.
The description for each LPM component can be displayed in MAX+PLUS II by choosing the "Megafunctions/LPM" option from the "Help" menu. Click on the component to see its parameters, I/O and functional specifications. More information is also available on the Altera web site and in the LPM Quick Reference Guide.
Alternatively, you can browse the LPM components package file. (Note: This VHDL file is part of the installation of MAX+PLUS II version 10.1. To find the file installed with your version of MAX+PLUS II, look for maxplus2/vhdl93/lpm/lpm_pack.vhd.)
In the component declaration, the parameters appear within the GENERIC statement and their types are explicitly declared. Some parameters may have default values. A "required parameter" must be assigned a value and must appear in a GENERIC MAP statement (see below). A "required I/O" must be used and must appear in a PORT MAP statement.
To assign a value to a parameter, the GENERIC MAP statement is used when the component is instantiated, in a similar way as a PORT MAP statement. The types of the value and the parameter must match.
Here are two examples on how to use LPM components: a 5-bit multiplier and a 24-bit register.
As an alternative, you can also use the MegaWizard Plug-In Manager which is accessible from the 'file' menu of Max+Plus II. The wizard helps you select an LPM component and choose the appropriate parameters. It then creates a VHDL file that contains an entity encapsulating an instance of the LPM module with the requested parameters. (Make sure that you select VHDL as the output type.)
The use of the MegaWizard Plug-In Manager should be avoided whenever possible. The wizard generates a new VHDL entity for each particular configuration of a LPM component that you require. The bloat of your VHDL code caused by the wizard is inelegant and reduces the readability of your code.
The wizard is very useful when debugging a LPM component instanciation. Setting the parameters of a LPM component incorrectly often causes compiler errors or an incorrect behavior of your device. When faced with this problem, it is often convenient to use the wizard and read the VHDL code that it outputs. You can then compare the wizard's instanciation of the component with your own instanciation and often solve your problem.
Where can I find VHDL language references?
There are many books on generic VHDL including the following:
You can also find free VHDL tutorials and documents on the web. You should keep in mind that not all features of VHDL (rev. 1993) are supported in MAX+PLUS II.
Does MAX+PLUS II support all features of VHDL?
Altera MAX+PLUS II supports many but not all features of VHDL. For a complete list of supported and unsupported features, select "VHDL" from the help menu and consult the "MAX+PLUS II VHDL Support" section.
Keep in mind that using an unsupported feature will not necessarily result in a compilation error. MAX+PLUS II often ignores valid but unsupported VHDL code.
How do I initialize signals and variables?
It is not possible to initialize signals with Altera MAX+PLUS II. The VHDL specifications indicate that it is possible to initialize a signal with a default value in its declaration. For example, a signal could be declared with an initial value of "101" as follows:
SIGNAL my_vec : STD_LOGIC_VECTOR(2 downto 0) := "101";
MAX+PLUS II compiles this code without complaining but ignores the default value. See the help files under the heading 'Declarations' for a list of supported and unsupported features related to declations.
A reset mechanism can be used as an alternative to signal initialization. Add a process to your VHDL code that sets your signals to an initial state when the reset line is high. Leave your reset line high for the first clock cycle of your simulations to set the system to its initial state.
The same is true of variables. VHDL allows the specification of initial values for variables but these are ignored by the MAX+PLUS II compiler.
Is the AFTER keyword supported?
According to the VHDL specifications, it is possible to delay a signal assignment with the following construct:
my_signal <= '0' AFTER 10ns;
In theory, the signal assignment should occur only 10ns later. MAX+PLUS II compiles this code without complaining but ignores the 'after' clause. As a result the signal assignment is immediate.
This behavior makes perfect sense. The 'after' keyword is part of VHDL mainly to specify timing constraints when simulating VHDL components. It is not meant to be used for synthesis. The MaxPlus II compiler has no way to generate a specified delay. The actual delay of the assignment is due to the delays on the chip after synthesis.
The best way to implement a delay is generally to use a clock.
How do I access bits with a STD_LOGIC_VECTOR?
To access a single bit, simply specify the bit number, which must be within the declared range. For example, if we declare:
my_signal : STD_LOGIC_VECTOR(2 downto 0);
then,
my_signal(0) means bit 0, the LSB. my_signal(1) means bit 1, the middle bit. my_signal(2) means bit 2, the MSB.
To extract a group of contiguous bits, specify the range of bit numbers using the DOWNTO keyword:
my_signal(1 downto 0) means the 2-bit vector containing bits 1 and 0.
Note that the following are not equivalent:
my_signal(0 downto 0) is a 1-bit vector containing bit 0. my_signal(0) is of STD_LOGIC type.
How do I concatenate STD_LOGIC_VECTORs?
Two or more STD_LOGIC_VECTORs can be concatenated using the & operator. For example, signals declared as
sig_a : STD_LOGIC_VECTOR(3 downto 0); sig_b : STD_LOGIC_VECTOR(3 downto 0); sig_c : STD_LOGIC_VECTOR(3 downto 0); concat : STD_LOGIC_VECTOR(11 downto 0);can be concatenated as follows:
concat <= sig_a & sig_b & sig_c;
How do I shift bits in a STD_LOGIC_VECTOR?
The following statements performs a left shift with a zero shifted into the LSB:
y(2 downto 1) <= x(1 downto 0); y(0) <= '0';
How do I perform arithmetic on a STD_LOGIC_VECTOR?
There are two methods to perform arithmetic on a STD_LOGIC_VECTOR. You can perform arithmetic directly on STD_LOGIC_VECTORs or by first converting them to the INTEGER type. The direct method is preferred.
You can perform arithmetic directly on a STD_LOGIC_VECTOR. Include the following libraries and packages at the top of your VHDL code:
LIBRARY ieee; USE ieee.std_logic_1164.all; USE ieee.std_logic_arith.all; -- arithmetic operators USE ieee.std_logic_unsigned.all; -- Treat vectors as unsignedThese packages allow you to do operations on STD_LOGIC_VECTOR signals as if they were unsigned numbers. The supported arithmetic operators are +,-,*. The supported comparison operators are <,<=,>,>=,=,=. You can use constructs such as the following:
c <= a + b; c <= a - b; c <= a * b;where a, b, c are defined as STD_LOGIC_VECTOR. Don't forget to take care of carry-in, carry-out, over-flow or under-flow.
Note that STD_LOGIC_VECTOR signals are not treated as signals of the INTEGER type. You may notice, for example, that the '/' operator is defined for integers but not for STD_LOGIC_VECTORS. To get more information about the ieee libraries and the supported operators, look for "ieee libraries" in the index of the help files.
As an alternative you may also convert a STD_LOGIC_VECTOR into an integer, perform arithmetic operations on the integer and convert the resulting integer back into a STD_LOGIC_VECTOR. A STD_LOGIC_VECTOR can be converted into an integer using the CONV_INTEGER conversion function. An integer can be converted into a STD_LOGIC_VECTOR using CONV_STD_LOGIC_VECTOR. Consider the following example:
int1 <= CONV_INTEGER(vec1); int2 <= CONV_INTEGER(vec2); sum_vec <= CONV_STD_LOGIC_VECTOR(int1 + int2, 8);
where vec1, vec2 and sum_vec are defined as STD_LOGIC_VECTOR(7 downto 0) and int1 and int2 as INTEGER RANGE 0 TO 255.
The division ('/') operator is defined for integers but the right-hand operator must be a power of two. The '/' operator is thus not very useful.
Signals are accessible within the entire architecture body of the entity they are declared in. Variables can only be declared and used within a process. Their content are lost between successive activation of a process. Declaring variables is similar to declaring signals with the keyword SIGNAL replaced by VARIABLE.
PROCESS(reset_queue) VARIABLE i : integer; VARIABLE addr16 : STD_LOGIC_VECTOR(15 downto 0); BEGIN : : END PROCESS;
Note that for variable assignment, you must use the ":=" instead of the signal assignment operator "<=". Unlike for signals, the value of a variable changes instaneously following an assignment. For example:
vtemp := vb; vb := va; va := vtemp;swaps variables va and vb. On the other hand, the following code:
stemp <= sb; sb <= sa; sa <= stemp;
does not swap signals sa and sb correctly. Signal assignments are executed concurrently which means that the third assignment uses the current value of stemp (before sb is assigned to it). The correct way to swap signals is:
sb <= sa; sa <= sb;
How do I create VHDL packages?
Packages are a collection of commonly used VHDL constructs that can be shared by more than one design unit, i.e., by multiple Entity Declarations, Architecture Declarations, Configuration Declarations, and Package Declarations.
A VHDL package consists of a Package Declaration and an optional Package Body of the following form:
<Specify necessary libraries here> -- Package declaration PACKAGE <package_name> IS : : END; -- Package body PACKAGE BODY <package_name> IS : : END <package_name> ;In the package declaration section, you may define common types, constants and signals, as well as the parameter specification of functions and procedures (i.e. the interface). In the package body declaration section, you specify the behavior of the functions or procedures defined in the package declaration.
Each package should be entered in a separate file, preferably with the same name as <package_name>. Make sure your packages are placed in the same directory as your design files.
In order to access the package you have created, insert the following lines at the beginning of your VHDL file:
LIBRARY work; USE work.<package_name>.ALL;
The library "work" is a special keyword to indicate a user library and the USE clause specifies the user-defined package <package_name>.
(See also How do I create VHDL functions and procedures?)
How do I create VHDL functions and procedures?
MAX+PLUS II supports the use of VHDL functions and procedures, with some limitations. The main distinction between procedures and functions is that a function must return a single value to its caller. You may declare your function/procedure in a separate package, which can be shared by other designs or in the architecture body of the entity calling it.
A procedure has the following form:
PROCEDURE <proc_name> ( in_param1 : in <param_type> ; ... out_param2 : out <param_type> ; ... ) IS BEGIN : : END;The procedure parameter list is similar to an ENTITY PORT declaration, where each parameter is specified as an input or an output (if any). In MAX+PLUS II, when you call the procedure, you can only assign variables (and not signals) into the parameters (see example below).
A function has the following form:
FUNCTION <func_name> ( param : <param_type> ; ... ) RETURN <return_type> IS BEGIN : : RETURN ... ; END;The function parameter list is similar to a SIGNAL declaration. The type of the return value is explicitly stated after the parameter list. The function should terminate by returning a value using the
RETURN keyword.
Here is an example of declaring a procedure (my_and2) and a function (my_or2) in a package (my_gates.vhd) and calling them from a design entity (test_my_gates.vhd).
(See also How do I create VHDL packages?)
How do I use VHDL revision 1993?
VHDL is an acronym which stands for "VHSIC Hardware Description Language". VHSIC is yet another achronym which stands for "Very High Speed Integrated Circuits". The acronym is supposed to capture the entire theme of the language, that is to describe hardware much the same way we use schematics.
VHDL is a standard (VHDL-1076) developed by IEEE (Institute of Electrical and Electronics Engineers). It was standardized in 1987 and hence the designation std 1076-1987 or VHDL-87. The standard was revised in 1993 to produce std 1076-1993 or VHDL-93.
By default, MAX+PLUS II will use VHDL-87. To enable VHDL-93, perform these simple steps:
Call up the Compiler.
Select VHDL Netlist Reader Settings option from the Interfaces menu.
Select the VHDL-1993 button and click OK.
Now, you should recompile your code. Note that all your files in the same project must be compiled in the same VHDL revision (either 1987 or 1993).
How do I use hexadecimal notation in VHDL?
Normally, if you have a STD_LOGIC_VECTOR, you can assign a value to it using a long string of bits. There is an easy method using hexadecimal but this only works in VHDL-93. Here's what to do:
To enable VHDL-1993, refer to How do I use VHDL revision 1993.
To assign in hex, do the following:
sig <= x"FFCC"; -- sig is STD_LOGIC_VECTOR(15 downto 0);
Many LPM component inputs are specified as type STD_LOGIC_2D. This type is defined as a 2-dimensional array of STD_LOGIC (see package LPM_COMPONENTS of the LPM library).
Therefore, you would have to manipulate each STD_LOGIC bit individually when reading or writing to such a type. If you try to map a STD_LOGIC_VECTOR directly to a STD_LOGIC_2D, you will receive a type incompatibility error.
It is possible to convert a set of STD_LOGIC_VECTOR signals into a STD_LOGIC_2D signal. To do so, use the CONV_2D entity defined in conv_2d.vhd. This entity takes as input a set of vectors concatenated into a single vector and outputs the corresponding STD_LOGIC_2D signal. Note that vector must be concatenated in reverse order. Do not try to compile this vhdl file by itself: no default values are defined for the generic parameters and thus Max+Plus II cannot compile the entity by itself. Simply put the file in your working directory and instantiate the conv_2d component in your own module, specifying the generic parameters required by your application. The CONV_2D component will be compiled by Max+Plus II as it compiles your module. This entity was written by Altera (see http://www.altera.com/support/solutions/735.html).
The CONV_2D entity can be used to simplify interfacing with LPM modules requiring the use of STD_LOGIC_2D signals. mux28.vhd is an example of a 2x8 multiplexer built using LPM_MUX and CONV_2D. Note that it is often easier to implement a simple component such as that 2x8 multiplexer using a short behavioral description.
How do I implement a state machine?
The easiest way to write a state machine with MAX+PLUS II is to start with a template. Select "VHDL Template..." from the "Templates" menu. Pick either the "State Machine with Asynch. Reset" or the "State Machine without Asynch. Reset". The generated code can be modified to fit your needs.
It is important to know that MAX+PLUS II recognizes properly written state machines. A state machine is reported as such in the report file. The simulator also enhances the state variable by displaying the state name instead of its corresponding index.
For more information about state machines refer to the following MAX+PLUS II help document:
Help -> VHDL -> How to Use MAX+PLUS II VHDL -> Implementing State Machines
How do I check for a signal's rising or falling edge?
The functionrising_edge(x), returns TRUE if a rising edge is detected on signal x. This function is equivalent to the condition x'EVENT and x = '1', which means there is a change in the value of x (attribute EVENT) and the value of x is 1.
Similarly, the function falling_edge(x) returns TRUE if a falling edge is detected on signal x. This is equivalent to this condition: x'EVENT and x = '0'.
What VHDL libraries are available in MAX+PLUS II?
For a list of all the VHDL libraries available in MAX+PLUS II, refer to the following help document:
Help -> VHDL -> How to Use MAX+PLUS II VHDL -> MAX+PLUS II Packages
The order in which the libraries used are listed in your VHDL files is important. If more than one library is used, they must be listed in the same order as in the above help page.
How do I find MAX+PLUS II's VHDL examples?
Some VHDL examples are installed with MAX+PLUS II in the max2work/vhdl directory.
How do I read test vectors and save output vectors in MAX+PLUS II?
Entering simulation inputs through the Waveform Editor is cumbersome when the number of inputs is large. To get around this problem, it is possible to define a list of input value changes in a text file called a Vector file (.vec). The Vector file can then be used to generate a Waveform Editor file (.scf):
This approach is particularly useful when the input data is generated by software. You can, for example, write software in your favourite language (Java, C, Perl, etc.) to read in a bitmap image and generate a corresponding set of inputs in the .vec format. Here is an example of a vector file.
Similarly, a Waveform Editor file (.scf) can be saved as a Table file (.tbl) which is exactly the same format as a Vector file. The outputs of a simulation can thus be saved in a text file and parsed by custom-made software. This could be used, for example, to generate a bitmap image from simulation outputs. Select "File -> Create Table File" from the Waveform Editor menu to generate the text file.
Software-oriented students often miss a very subtle difference between signals and variables in VHDL. Signal assignments are concurrent whereas variable assignments are sequential. The concept of variables is thus very close to that used in software. The concept of signals, on the other hand, is not typically seen in software. One error that beginners often make is illustrated in the following process:
PROCESS(clk) BEGIN IF RISING_EDGE(clk) THEN b <= a * 2; -- b is a register c <= b + 10; -- c is a register END IF; END PROCESS;
The goal here is to compute 'c <= (a * 2) + 10' and change 'c' only on the rising edge of the clock. Because of the concurrency of signal assignments however, the computation is effectively pipelined. Signals b and c act as registers. Thus the entire computation will take two clock cycles instead of the single clock cycle that was intended. The solution here is either to use variables instead of intermediate signals or to do the following:
PROCESS(clk) BEGIN b <= a * 2; -- b is NOT a register IF RISING_EDGE(clk) THEN c <= b + 10; -- c is a register END IF; END PROCESS;
This concept is very important. Please consult the Teaching Assistants if you do not understand it.
See this section for an example of an intentional pipeline in behavioral VHDL.
This section list a few error messages frequently observed in Altera MaxPlus II and attempts to describe the most plausible causes for the error. The lists of possible causes are not exhaustive, other causes should be investigated if the following suggestions do not solve the problem.
This error message usually means that an output node of your component is not assigned a value inside the architecture body. Here are some suggestions:
I didn't find the answer to my question. What can I do?
Browse through these archives of messages that were posted on webct in previous semesters:
If you don't find your answer there contact your Teaching Assistants.