1
1 Simulation with ModelSim
figure 1
ModelSim is a handy VHDL/Verilog simulator. In this document you can find a short
introduction how to use ModelSim.
ModelSim starts with the window shown in figure 1. The left windows shows the libraries and
the right window is used for entering commands and for reporting information to the user.
An analysed VHDL file is stored in a library. Library work is used to store your analysed
VHDL designs.
The first step is to create a library work:
FileΔChange directory” and browse to the directory that contains your design files. Next
you enter the command:
vlib work <return>
Note: Due to a bug in the software the library “work” is not always shown in workspace
after this command is entered. Workaround: quit ModelSim, start ModelSim and
browse to the directory.
The library is created but is still empty. A correctly analysed design unit (entity, architecture,
package, package body or configuration) is placed in library work.
As an example a circuit that counts the number of ones in the input pattern is used in this
tutorial (N.B. the line numbers are not part of VHDL).
1. LIBRARY ieee;
2. USE ieee.std_logic_1164.ALL;
3. ENTITY count IS
4. GENERIC (w : positive := 8);
5. PORT (a : IN std_logic_vector(w-1 DOWNTO 0);
6. q : OUT integer RANGE 0 TO w);
7. END count;
8.
9. ARCHITECTURE behaviour OF count IS
10. FUNCTION cnt (a:std_logic_vector) RETURN integer IS
11. VARIABLE nmb : INTEGER RANGE 0 TO a'LENGTH;
12. BEGIN
13. nmb := 0;
14. FOR i IN a'RANGE LOOP
15. IF a(i)='1' THEN nmb:=nmb+1; END IF;
16. END LOOP;
17. RETURN nmb;
18. END cnt;
19. BEGIN
20. q <= cnt(a);
21. END behaviour;
Figure 2: behavioural description of count
2
The generic w, on line 4, is a global constant with value 8.
The input a of this design is w bits wide. The output q is an integer value. The width of the
input is w therefore the number of ones must be between 0 and w (inclusive). A range
constraint is added to the integer type. The range constraint is not necessary but it can be used
for documentation and will help synthesis.
There are many ways to count the number of ones in an array. In the architecture (figure 2) a
function is declared that takes care of this. This function has as input of type std_logic_vector.
A std_logic_vector is an unconstrained array; the length of this type is not (yet) known! The
reason to use an unconstrained array as input is to make the design generic with respect to the
width of the input. At the location of the function call, line 20, it is clear what the range of the
input is.
The algorithm used in the function is straightforward. With a loop all elements of the inputs
are examined. The only problem is: how do I know what the vector indices are? The attribute
‘range is used for this. If the function is called with an object that is declared as
std_logic_vector(5 to 36) then within the function the attribute ‘range is replaced with “5 to
36”.
1.1 Analyse/Compile
Place (a copy) of the file count_loop.vhd in the design directory. Via the menu compile you
can compile this description. Compile the design via compileÎcompile.
If there are no errors then your ModelSim environment should look like shown in figure 3.
In library work the entity and architecture of the design is located. In case of an error you can
double click the error message and an editor is opened with your design on the line where the
error was found (the error is often just before this line).
3
1.1.1 Simulate
Click with the right mouse button on the architecture name ‘behaviour’ and you can load your
design in the simulator (or you can use menu button “simulate”).
During simulation you probably like to see some waveforms therefore enter:
add wave * <return>
(In stead of * you may enter a list with the signal names separated with a comma).
With the run command you perform a simulation with length 100 ns (default) or you can
explicitly add a time length:
run 200ns <enter>
The inputs are all ‘U’ why?
Note 1: In a synchronous design a clock signal is needed. Assume signal clk is the clock line.
A repetitive pattern is generated with the command:
force clk 0, 1 50 ns –repeat 100ns
Note 2: The ModelSim command “run –all” performs a simulation and will stop simulation
when nothing ‘happens’ anymore. Do not use this command when a clock signal is
generated with the method of Note 1.
4
1.1.3 Stimuli generation with VHDL
Applying stimuli as presented in the previous section is tool dependent. You can also use
VHDL to generate stimuli. Finding test data for a design is not an easy task. In this chapter we
only want to illustrate that stimuli can be generated.
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;
ENTITY testset IS
GENERIC (w : positive := 8);
PORT (data : OUT std_logic_vector(w-1 DOWNTO 0));
END testset;
Figure 4 gives a simple test set. It contains one process statement. It first generates all zeros,
waits for 10 ns, then generates all ones and it waits again,… Of course an exhaustive test is
possible. In the for-statement the loop variable i (which is implicitly declared!) goes from 0 to
2w-1. This integer value should then be converted to a bit pattern (using a binary coding; also
called unsigned). For this the function to_unsigned is used. This function converts the integer
value i to a binary vector with length w. This function is located in a package numeric_std (in
library ieee).
5
In case the operands are of type std_logic_vector you cannot perform an addition because no
decimal interpretation is associated with this type. (There are packages that can handle this,
but these packages are not IEEE standard and some of can be frustrating in use.)
However in case the generic (~ constant) w is large this is a time consuming task. Therefore in
this example the loop is ended in case i is equal to 20. The process ends with wait. This means
the process will not resume execution.
If the simulator is still active end the current simulation via the simulation menu.
6
1.1.3.1 Connect the test set with the design under test
Figure 6 shows the structural VHDL description that connects the test set with count. Compile
file testbench.vhd and simulate entity testbench.
Check that the length of the pattern is changed to 10 in the design!
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;
ENTITY testbench IS
GENERIC (width : positive := 10);
END testbench;
-- local connections
SIGNAL stimuli : std_logic_vector(width-1 DOWNTO 0);
SIGNAL output : integer;
BEGIN
ts : testset
GENERIC MAP (w => width)
PORT MAP ( data => stimuli);
dut : count
GENERIC MAP (w => width)
PORT MAP ( a => stimuli,
q => output);
END structure;
Figure 6: test bench
7
Via the menu SimulateÎRunÎ------- A new window is opened:
With this window you can step through your design (maybe to locate errors). The ‘step’
button is often used. Then only one statement (concurrent or sequential) is executed. Also a
source window is opened so you can see (the arrow) what the next statement to execute will
be. “Step -Over” is similar to the execution of a function/procedure in one step.
Often during debugging you like to run your program to a certain point and perform a low
level debug from that point. Double click on the left of the line number of an executable line
and a breakpoint appears.
8
1.2 Simulation model
VHDL has concurrent statements. In a VHDL model there is an order in which the statements
are written however the simulation is order independent!
Processes can only communicate with each other using signals (I forget here the ‘shared
variable’; don’t use ‘shared variables’). If you assign a value to a signal that signal value is
not updated immediately. This means that all processes will use the same signal value;
consequently the simulation is order independent. If you assign a value to a variable that
variable is updated immediately.
Sometimes you are surprised by the update mechanism of signals.
If you write:
y <= a after 10 ns;
The output y follows the input a with a delay of 10 ns. (More precise; the input should be
stable for 10 ns too.)
y <= a;
The output is updated after a delta delay. Delta delays are not shown in the wave window.
There can be infinite delta delays before simulation time advances. You will experience this if
you don’t see any progress during simulation but your simulation is still going on (for hours
…). ModelSim will report a warning when it performs 1000 delta steps.
ModelSim also makes is possible to show the simulation results after every delta steps.
Repeat the previous simulation but (also) use the following command:
add list * <return>
Check that you really understand what is going on.
9
2 Synthesis with LeonardoSpectrum
Part of VHDL is synthesizable. There is a separate IEEE standard that describes a
synthesizable subset of VHDL (IEEE std. 1076.6-2004).
It is almost clear that a synthesis tool has problems with timing aspects and dynamic types
(access types). Also the initial values of signals, and variables in a process, are synthesizable.
Therefore almost all designs have an explicit reset input. Furthermore recursion is supported
when the recursion depth can be determined statically.
For this tutorial the synthesis details are not important:
- LeonardoSpectrum is a high level synthesis tool. It is technology (Actel, Xilinx,..)
independent. It supports a quite large subset of VHDL and will generate an
intermediate format (mostly EDIF; electronic design interchange format; also an IEEE
standard).
- The generated intermediate file is used as input by the FPGA specific synthesis tool
(Quartus, ISE,..) to map it on the specific device.
We will not focus on the second step. In this course we will only perform the high-level
synthesis step. The RTL (register transfer level) output gives us enough information about the
quality of the design (including a nice schematic). If we had installed the specific synthesis
tool the second step is rather easy; however it often is a time consuming task.
10
FileΔChange working directory” and choose a directory.
Note: if the size of the schematic is large the tool will automatically use more sheets.
11
3 Alternative descriptions
The previous solution was a straightforward and readable description. This description can be
handed over to someone and probably (s)he will recognize the intention quite fast. A synthesis
tool supports more and more these kinds of descriptions, and sometimes finds smart
implementations. (It is expected that the tools will be better in the future with respect to this;
similar to the software compilers that are in use nowadays).
You can speed up the design by dividing the problem into two smaller problems that both take
the half of the input vectorÎrecursion!
Figure 11 shows a VHDL description with a recursive solution.
Do you understand all the details in this description? Maybe the two constant declarations in
the function are not quite clear.
CONSTANT n: natural := vec'LENGTH;
Vec’LENGTH is the length of the vector Vec (‘Length is an attribute).
CONSTANT v: std_logic_vector(1 TO n) := vec;
This looks funny. Why not use vec in stead of v? Remember the function has as input type
std_logic_vector. This is an unconstrained array. Not only the length but also the left and right
index is not known when the function is written. Only when the function is called it is known.
The function should operate properly with s1 and s2 if they are declared as:
signal s1 : std_logic_vector (4 to 20) ;
signal s2 : std_logic_vector (30 downto 3);
BEGIN
q <= count_bits(a);
END recursive;
Figure 11: recursion (file count_recursive_funct2.vhd)
1
The division operator, based on integer, will always give an integer result. Hence 8/3 is 2.66666 and the
integer result is 2.
12