TUTORIAL


John Bryan 2004

Purpose

The purpose of this tutorial is introduce you to the IEEE standard hardware description language, VHDL (VHSIC (Very High Speed Integrated Circuit) Hardware Description Language), to the ModelSim simulation tool, to FPGA synthesis, to FPGA placement and routing, and to design verification using backannotated gate-level simulation.

Summary

A simulator accepts inputs that you specify and displays what the design's anticipated outputs will be.  In the tutorial beginning, we will be doing rtl simulation, in which the input to the simulator is the compiled VHDL source code. VHDL is a programming language for defining the structural and behavioral description of digital circuits.  In rtl simulation, since no delay information is present, the simulation has no delays in it.   Later in the tutorial, after FPGA synthesis and placement and routing, we will be doing gate-level simulation, which will include delay information.

The Tutorial

The tutorial is comprised of the following sections:
  1. Preparation: Unix paths
  2. VHDL Source Code
  3. Simulation: Modelsim vsim
  4. Four-bit adder using the + operator
  5. Four-bit adder using a process
  6. Delta cycles and processes
  7. Built-in functions
  8. FSMs
  9. A counter example
  10. A register file example
  11. Functional rtl
  12. A few notes
  13. Synthesis Preparation and Startup
  14. Specification and Loading of the Technology Library
  15. Reading in Your VHDL Source Files
  16. Optimization
  17. Writing an EDIF File
  18. The Resource Report
  19. The Delay Report
  20. Synthesis Script Method
  21. Xilinx placement and routing
  22. Backannotated gate-level simulation

1.  Preparation: Unix paths

For the instructions given below, we will assume that you are working in your home directory.  Setup the following recommended directory structure in your home directory:

2.  VHDL Source Code

In order to enter HDL source code, you will need to use a text editor.  Popular choices are:

VHDL source code is plain text contained in a single file or a group of files.  VHDL text files use the file extension, .vhd .

3.  Simulation: Modelsim vsim

To initialize ModelSim vsim: To compile your design into the work library (this needs to be done whenever you make a change to your source code):
  1. vcom full.adder.vhd  -explicit
    The -explicit option is not needed here, but some students may prefer to use it each time they compile.
  2. vcom h.4.bit.adder.vhd
  3. vcom tb.h4ba.vhd
An option that is available to you in compiling files for ModelSim vsim is to write a makefile.  A script to compile the three files listed above is h4ba.makefile

Since the full_adder entity is used as a component in the h_4_bit_adder entity, the full_adder entity is compiled before the h_4_bit_adder entity.  Likewise, since the h_4_bit_adder entity is used as a component in tb_h4ba entity, the h_4_bit_adder entity is compiled before tb_h4ba entity.

When you make a change in a HDL source code file, you must recompile not only that file, but any file that instantiates the entity in that file as a component.  For example, if we made a change to h.4.bit.adder.vhd, we would then have to recompile tb.h4ba.vhd after we recompiled h.4.bit.adder.vhd, since the h_bit_adder entity is used as a component in the tb_h4ba entity.  We would not have to recompile full.adder.vhd since the h_4_bit_adder entity is not instantiated as a component in the full_adder entity.

To list the compiled entities in the work directory: To invoke the simulator with the name of the top-level design unit, which in this case is the entity tb_h4ba:

In Modelsim,

  1. To set the environment workspace to the instantiation of the h_4_bit_adder entity named uut, from the ModelSim Main (transcript) window menu, select View | Structure.  The stucture window will open.  In the structure window, select uut.

  2. To view the signals window, from the ModelSim Main (transcript) window menu, choose View | Signals.

  3. To view the wave window, from the ModelSim Main window menu, choose View | Wave.

  4. From the signals window menu, choose Add | Wave | Signals in Region. 
    The h_4_bit_adder entity signals will be placed in the wave window. 
    Use the left mouse button to move the vertical divider lines in the wave window so that you can read the names of all the signals.

  5. To run the simulation for 60 ns, enter
    run 60
    at the ModelSim prompt in the Modelsim Main window.

  6. In the wave window, to zoom in, from the wave window menu, select View | Zoom | Zoom In.

  7. In the wave window, to change the radix to unsigned, from the wave window menu, first select Edit | Select All
    Then, from the wave window menu, select Format | Radix | Unsigned.
    Then, from the wave window menu, select Edit | Unselect All.

  8. On a waveform in the wave window, click the left mouse button to obtain a marker.

  9. To restart the run, from the ModelSim Main window menu, choose Simulate | Run | Restart..., and when the Restart window appears, select the Restart button.

  10. To run the simulation for 100 ns, enter  run 100  at the ModelSim prompt in the Modelsim Main window.

  11. To delete the signals presently listed in the wave window, from the wave menu choose Edit | Select All.  Then from the wave menu choose Edit | Cut.

  12. When you want to quit ModelSim vsim, from the ModelSim Main window menu, choose File | Quit
The following are a few examples of command-line interface commands that can be entered at the ModelSim prompt in the ModelSim Main window.

 radix bin   Set the radix to binary.  
 radix unsigned   Set the radix to unsigned. 
 radix hex   Set the radix to hexadecimal. 
 radix decimal   Set the radix to decimal. 
 vdir    List the compiled entities in the work directory. 
 vdel reg    Delete the reg entity in the work directory. 
 vcom reg.vhd    Compile the file, reg.vhd.  
 vsim reg    Load the reg entity. 
 do  macrofile.do  Execute the macro file, macrofile.do. 
 vsim  tb_h4ba  -do  macrofile.do    Load the entity tb_h4ba and execute the macro file, macrofile.do. 
 run 80    Run the simulation for 80 ns.  
 run -all    Run the simulation until a wait statement or breakpoint is executed. 
 restart -f    Restart the simulation. 
 view source   View the source window. 
 view *   View all the ModelSim windows. 
 add  wave  uut/*  Add all the signals in the uut component to the wave window. 
 add  wave  uut/sum  Add the sum signal in the uut component to the wave window. 
 pwd   List the name of the directory that you are in. 
 ls   List the contents of the directory. 
 quit    Quit vsim. 

The keyboard arrow keys can be used to execute previous commands. A few common vsim questions:

  1. How can I display signals from an entity instantiated as a component in my design on the wave diagram when running vsim?

  2. How can I set a breakpoint when running vsim?

  3. How can I obtain code coverage information in ModelSim?

  4. How can I view a variable in a process in the ModelSim wave or list window?

  5. How can I run ModelSim in command-line mode?
Note:If you ever have a simulation that does not halt, you can stop it by selecting, Simulate | Break, from the ModelSim main window menu.   You may need to use this if you ever choose Run | Run - All from the Modelsim menu or the run - all icon in the Modelsim window.  If you use either of these and the simulation time increases to a large value before you click the Break icon, you should type the command  ls -l vsim.wlf  in a xterm window in the directory in which you are running the simulator to check the memory usage of the file vsim.wlf.  The file vsim.wlf is a file generated by vsim during the simulation, if you have the wave window up, to hold the data displayed in the wave window.  The file size can reach your alloted memory usage quota if you use run - all and don't use the Break icon soon enough.  To view your memory usage and quota, type  quota -v  in a xterm window.  To remove the vsim.wlf file, use,  rm vsim.wlf  in a xterm window.  The vsim.wlf file is overwritten each time you run a simulation, so as long as you don't use run - all and run a long simulation or set the run simulation time to a very large number, you should not have to worry about it.

You may want to occasionally print out the simulation results that appear in the wave window.  You can use the zoom feature from the wave menu to obtain the proper zoom.  To print the wave, from the wave menu, select File | Print Postscript...  When the Write Postscript window opens, click File name: and type in a name for the file name, i.e., wave1.ps, and click ok.   Only the portion of the wave that is presently viewable will be printed out.  If the waveform is long, you will have to use more than one page.  To set the laser printer destination, in a xterm window, use the command, setenv PRINTER printername  To view and print out a postscript file, you can use ghostview by typing the command, ghostview wave1.ps in a xterm window, where wave1.ps is the name of your postscript file.  To print out the postscript file in ghostview, choose File | Print..., type in the name of the printer in the popup window and click ok.

4.  Four-bit adder using the + operator

The VHDL arithmetic operators available include '+','-', and '*'.
  1. An example of a 4-bit adder using the '+' operator is, plus.sign.adder.vhd.  This source code contains an entity called easy_adder.  This adder has two 4-bit addend std_ulogic_vector inputs and a 4-bit sum std_ulogic_vector output.  The two addends are added using the + operator.  The numeric_std package is listed in the package declaration section at the top of the code as it is required for the + operator use.  To use the + operator an explicit conversion to type unsigned is done on the two addends and an explicit conversion to type std_ulogic_vector is done on the result of the addition. Additions using the + operator with two four-bit addends are modulo-16.  The msb carry-out is truncated.  A testbench to test the easy_adder entity is the tb_psa entity in the file, tb.psa.vhd   


  2. plus.sign.adder2.vhd: In this file, the entity easy_adder2 has two four-bit addends that are each concatenated with a '0' in the msb before they are added.  The result of the addition will be five bits, so the result can be assigned to the five-bit sum. A testbench to test the easy_adder2 entity is the tb_psa2 entity in the file, tb.psa2.vhd

5.  Four-bit adder using an unclocked process

The VHDL code of the 4-bit adder using an unclocked process with a sensitivity list is process.4.bit.adder.vhd.  A process always has either a wait statement or a sensitivity list, but never both.  In this process, we are using a sensitivity list. The sensitivity list of an unclocked process should include the primary inputs to the process, that is to say the signals that are read in the process that are from outside of the process and that not generated inside of the process.  Since the signals, addend_one, addend_two, and carry_in are read in the process and are from outside the process, they are included in the sensitivity list.  When the value of a signal in the sensitivity list changes, the process is executed.  In the process, carry is declared as a five-bit variable.  The variable assignment operator is :=.  A variable changes value instantaneously when written to, whereas a signal, when assigned a value, is scheduled to change a delta cycle later.  Delta cycles will be examined in section 7 of this tutorial.  A variable can only be declared inside a process , function, or a procedure.  When writing to a variable,that is to say that a variable is on the left-hand side of the assignment operator, you should use the variable assignment operator.  When writing to a signal, you should use signal assignment operator, <=. A variable can read either the value of a signal or a variable. Likewise, a signal can read either the value of a signal or a variable. You should use caution when using both signals and variables, since variables change value instantaneously when assigned to, while signals are scheduled to change value at the next delta cycle when assigned to. A signal can only be assigned a value once when a process is executed. If a signal is assigned twice in a process execution, it will always get the second value.

6.  Delta cycles and processes

This section of the tutorial will introduce the concept of delta cycles.  Delta cycles are used in VHDL to enable concurrency.  Compile  delta.vhd.   Note that the initialization of signals in the declaration portion of the entity is unsynthesizable (the initialization will be ignored by the synthesis tool) and should not be done in an entity that is to be synthesized (mapped to hardware by a synthesis tool), but it is done here as this entity will not be synthesized.  Load the delta_example entity in vsim.  In the vsim transcript window, type radix unsigned.  Also, in the vsim transcript window, from the menu, choose View => List, choose View => Signals, and choose View => Source.  From the Signals window menu, choose View => List => Signals in design.  In the List window, you will see the initial values of the signals at 0 ns and delta +0.  Click on the Step icon in the vsim window or click on the Step icon in the Source window.  The step icon is the second icon from the right in both the vsim window and the Source window.  This will single step through your souce code in the Source window.  Continue to slowly step through your code, checking the order in which the lines of your source code are executed and checking the delta cycle updates in the List window.  On the 12th step, you will obtain the message "Nothing left to do" in the vsim window, indicating the two processes have stopped firing and signal updating has stopped. The List window should look like:

  ns    delta    a    b    x    y    z 
  0    +0    2    3    7    8    9 
  0    +1    2    3    8    5    7 
  0    +2    2    3    5    5    8 
  0    +3    2    3    5    5    5 

a,b,x,y, and z received the initialization values in delta cycle 0.  This change fired processes p1 and p2 and at the end of delta +1, signals x,y, and z have changed from their value at the end of delta +0.  The change in y fired p1 and the change in x fired p2 in delta +2 and x and z changed their value in delta +2.  Since y did not change in delta +2 and y is the only signal in the sensitivity list of p1, p1 did not fire in delta +3.  However, since x did change value in delta +2 and it is in the sensitivity list of p2, p2 fired in delta +3.  The signal z is the only signal that changed in delta +3 and since z is not in any sensitivity list, neither process fired and we received the message "Nothing left to do".

To write your List data to a file , from the List menu, choose File | Write List (tabular).  When the Write List window opens, enlarge it so that you can view it properly, type in a name for the file, and choose Save.   To set the printer destination, in a xterm window, use the command,  setenv printername.  To print, since this is a text file, you can use the command, lp list.lst  in the xterm window assuming you named the file containing the list data, list.lst.

Another example of delta cycles can be seen by compiling infinite.vhd and stepping through the simulation of the infinite_loop entity.  Signals y and z are initialized in delta +0.  This fires processes p1 and p2, which assign new values to y and z at delta +1.  This fires processes p1 and p2, which assign new values to y and z at delta +2.  We have an infinite loop.  The signal updating queue and the process firing queue are never simultaneously empty.  After 5 deltas, your List window should look as below. 

  ns    delta    a    b    y    z 
  0    +0    0    1    1    0 
  0    +1    0    1    0    1 
  0    +2    0    1    1    0 
  0    +3    0    1    0    1 
  0    +4    0    1    1    0 
  0    +5    0    1    0    1 

7.  Built-in functions

The entity in the file, left.rotator.vhd uses a built-in function, rotate_left, that logically rotates left. There is also a built-in function, rotate_right, that logically rotates right.   The VHDL source for the testbench for this rotator is,  tb.left.rotator.vhd.   Other built-in functions are defined in the numeric_std package.

8.  FSMs

A sample VHDL testbench for the moore state machine is provided:  tb_moore.vhd.   Suppose that you want to view on the wave timing diagram the six signals: RESET, X, CLK, Z, NEXT_STATE, and CURRENT_STATE.

One method to do this is to use a .do macro file.  Another method is to use the window menus.

To generate a .do macro file, open vsim and use the sequence of menu choices and/or commands in the vsim windows that you wish to place in the macro file.  In the directory in which vsim was opened, there will be a file called transcript.  That file contains the vsim commands that correspond to the sequence of menu choices and/or commands that were used.  The file, transcript, can be copied to a .do file and used as a macro file.

9.  Counter example

10.  Register file example

A four 32-bit register file example is reg4.vhd.  To read a register, the nr_w bit is set to 0; to write to a register, the nr_w bit is set to 1.  The register to be read from or written to is determined by a 2-bit address.  The register file entity in reg4.vhd uses four instantiations of the 32-bit register entity in the VHDL source, reg.vhd.

11.  Functional rtl

By using the state machine design style 4 in moore4.vhd and defining the datapath operations in each state, as in the functional_rtl entity in, functional.rtl.vhd, is a popular style of design, functional rtl style.  Some designers prefer to keep synchronous elements in a separate process from the combinational elements.  The functional_rtl entity is rewritten using this style in frtl2.vhd.  The hardware synthesized by the synthesis tool was equal for the two files. 

12.  A few notes

  1. Unix note.
  2. Cpu limit note.
  3. Latch note.
  4. Combinational loop note.
  5. Explicit option note.
  6. Integer note.
  7. -93 compile option note.

13.  Synthesis preparation and startup

The two VHDL files used in the Leonardo FPGA synthesis are:
  1. full.adder.vhd

  2. h.4.bit.adder.vhd
To start Leonardo at the unix shell prompt:
  1. unlimit

  2. prep leonardo

  3. leonardo   &

  4. Select the default of Leonardo Spectrum 3 as the license to check out when that window appears and select ok.

  5. From the Leonardo menu, select Tools => Flowtabs.

14.  Specification and Loading of the technology library

  1. Select the Technology tab.

  2. Select the + next to FPGA/CPLD.

  3. Select the + next to Xilinx.

  4. Select X4000E.

  5. In the Device field scroll down to 4025ePG223.  The speed field should be set to -2 and the wire load should be set to 4025e-2_avg.

  6. Select the Load Library button.

15.  Reading In Your VHDL Source Files

  1. Select the Input tab.

  2. Then select the open file icon.  The Set Input File(s) window will open. 

  3. Browse to full.adder.vhd. 

  4. Select full.adder.vhd.

  5. Select "Open".  The Set Input File(s) window will close.

  6. Then select the open file icon.  The Set Input File(s) window will open. 

  7. Browse to h.4.bit.adder.vhd. 

  8. Select h.4.bit.adder.vhd.

  9. Select "Open".  The Set Input File(s) window will close.

  10. On the Input flowtab page, Select "Read".

  11. The act of reading in the file performs syntax checking of the file.   There should be no errors.  Errors in the transcript window are designated with a red circle.  Warnings are designated with a blue circle.  Information is designated with a green circle.  If you have an error, read the error message and try to correct the error.  By double clicking on the red circle, your source code will open with the red circle marking the problematic code.

16.  Optimization

  1. Select the "Constraints" tab. 

  2. Select "Specify Clock Period".  Specify 20 ns.  Select "Apply". 

  3. Select the Optimize tab.  Choose "Optimize For: Delay".  Select the "Optimize" button.  Your design will be mapped and optimized to the Xilinx X4000E FPGA technology library.

17.  Writing An EDIF Output File

  1. Select the "Output" tab.

  2. Select edif.

  3. Select write.

  4. An .edf file will be written to the file specified in the filename space.

18.  The Resource Report

To generate a resource report showing the FPGA resources that your design used:
  1. Select the "Report" tab. 

  2. Type h4ba.resources in the "Report File Name" box. 

  3. Select the "Report Area" button.  A resource report will be written to the file, h4ba.resources, in the directory in which you opened Leonardo.

19.  The Delay Report

To generate a delay report listing your design's critical path:
  1. Select the "Report" tab. 

  2. Select the "Delay Report" tab near the bottom of the Leonardo window. 

  3. Type h4ba.delay in the "Report File Name" box. 

  4. Select the "Report Delay" button.  A delay report will be written to the file, h4ba.delay, in the directory in which you opened Leonardo.
To clear the Leonardo workspace, you can use the command,
clear
at the Leonardo command-line.

20.  Synthesis Script Method

An alternate method to using the flowtab method in Leonardo to execute commands is to use a script.  The script, h4ba.synthesis.script is an example.  To run the script at the Leonardo gui command-line, copy the script to the directory that you are running Leonardo and enter the command,
source  h4ba.synthesis.script
To execute this file successfully, you should have the files, full.adder.vhd and h.4.bit.adder.vhd in the directory in which you are running Leonardo.

To run the script file from the unix shell prompt in batch-mode (no gui), a procedure is:
  1. At a unix shell prompt, type,
    unlimit

  2. At a unix shell prompt, type,
    prep  leonardo

  3. At the unix shell prompt, type,
    spectrum
    which will invoke Leonardo Spectrum in batch-mode.

  4. At the spectrum prompt, type,
    source  h4ba.synthesis.script
    To execute this file successfully, you should have the files, full.adder.vhd and h.4.bit.adder.vhd in the directory in which you are running the script.
Some VHDL code that compiles correctly with the vcom compiler for simulation will generate an error when read into Leonardo for synthesis.  This is because only a subset of VHDL is synthesizable. 

To exit Leonardo, from the menu, choose File => Exit. 

21.  Xilinx placement and routing

  1. Select one of the Windows computers.


  2. Log on.


  3. Select the Class Resources icon.  The Class Resources window will open.


  4. On the left side of the Class Resources window under "File and Folder Tasks", select "Make a new folder".  Make a new folder named xilinx.project to place your Xilinx files.


  5. In the Class Resources window, connect to your home directory.  Copy the h.4.bit.adder.edf file from your directory to the xilinx.project folder.


  6. At the lower left corner of the screen select Start => All Programs => Xilinx Foundation Series 2.1i => Design Manager.


  7. The Design Manager window will open.  From the menu, select File => New Project.


  8. The New Project window will open.  For the Input Design field browse to the xilinx.project directory and select h.4.bit.adder.edf.  Select OK.


  9. A New Version window will open.  Select Part.  The Part Selector Window will open. 
    Select:
    • Family: XC4000E
    • Device: XC4025E
    • Package: PG223
    • Speed Grade: -2
    Select OK in the Part Selector window.  The Part Selector window will close.  The Part field in the New Version Window should now contain XC4025E-2-PG223.  Select OK in the New Version window.  The New Version window will close. 


  10. From the Design Manager menu, select Tools => Flow Engine.  The Flow Engine window will open. 


  11. From the Flow Engine menu, select Setup => Options... . The Options window will open. 


  12. In the Options window, under Program Options : Simulations, select Modelsim VHDL.  Select OK.  The Options window will close.


  13. From the Flow Engine menu, select Flow => run.


  14. When the Configure phase is completed and the status is OK, the run is complete.


  15. In the class resources window, browse to the xilinx.project\xproj\ver1\rev1 directory. Three of the files generated by Xilinx in this directory are:

    1. map.mrp : This is a summary of the Xilinx 4000E resources used in your design.  Copy this file to your home directory.


    2. time_sim.vhd : This is one of the two files generated in the Xilinx run that will be used in the ModelSim gate-level simulation.  Copy this file to your home directory.


    3. time_sim.sdf : This is one of the two files generated in the Xilinx run that will be used in the Modelsim gate-level simulation. Copy this file to your home directory.


  16. To log out from the Windows pc, from the lower left of the screen, select Start => Log Off.

22.  Gate-level simulation

  1. Select a Unix workstation.


  2. Make a new unix directory, tutorial3.dir.


  3. Copy the modelsim.ini file to your new unix directory.


  4. Copy the time_sim.vhd file generated in the Xilinx run to your new unix directory.


  5. Copy the time_sim.sdf file generated in the Xilinx run to your new unix directory.


  6. Copy tb_h4ba.vhd to tutorial3.dir.  This file is a testbench from earlier in the tutorial, but with the std_ulogic and std_ulogic_vector changed to std_logic and std_logic_vector.  This is so there will be no type incompatability with the time_sim.vhd file produced by Xilinx which uses std_logic and std_logic_vector. 


  7. Copy tutorial3.makefile to tutorial3.dir.


  8. Copy tutorial3.do to tutorial3.dir.


  9. Type the command, 
    prep mentor


  10. Type the command, 
    chmod   u+x   tutorial3.makefile
    The last line of tutorial3.makefile enables annotation of maximum timing values from the SDF file time_sim.sdf to the instance UUT under the top-level entity tb_h4ba.  The line also executes the macro file tutorial3.do in the gate-level simulation.


  11. Type the command, 
    tutorial3.makefile


  12. The gate-level simulation of the 4-bit adder will be displayed in the wave timing window in vsim.


Top