Skip to content

Latest commit

 

History

History
executable file
·
257 lines (202 loc) · 8.93 KB

content.asc

File metadata and controls

executable file
·
257 lines (202 loc) · 8.93 KB

Using the ISIM simulator

Now that we have a design that changes millions of times a second, testing becomes hard. In this module we will use the ISIM simulator - a tool that allows you to \'run' the logical design and see how it behaves as it is poked and prodded with external signals.

What is simulation?

When you debug software you are actually running the code on the processor, with all the access to the system resources such as the OS, memory, communications and file systems. Unlike debugging software, simulating an FPGA project doesn’t run it on the actual hardware - the closest equivalent you may have experience with is the simulation of a microcontroller in MPLAB or WinAVR.

Although no FPGA hardware is involved, simulation is very powerful - it is very much like having the most powerful logic analyser at your fingertips. The downside is that if your idea of how an external device works isn’t accurate you will not be able to spot the problems.

The initially confusing bit about simulation is that it requires another VHDL module to drive the input signals and receives the outputs from your design - a module that is called a "test bench". They are pretty easy to spot - the ENTITY declaration has no "IN" or "OUT" signals, just something like this:

ENTITY TestBench IS
END TestBench;

In effect, the test bench is a module that ties up all the loose ends of your design so that the simulator can run it.

Creating a test bench module

Here is how to create a test bench using the wizard in WebPack.

Right-click on the top level of the hierarchy and select to add a new source module into the project:

m8s1

Select the "VHDL Test Bench" and assign it a name (I just add 'tb_' to the name of the component being tested), then click \'Next':

m8s2

You will then need to select which component of the design you wish to test and then click \'Next':

m8s3

A summary screen will be presented - review the details and then click \'Finish'.

Breakdown of a Test Bench module

Here is the resulting VHDL with most of the comments removed, to reduce its size:

 LIBRARY ieee;
 USE ieee.std_logic_1164.ALL;

 ENTITY tb_Switches_LEDs IS
 END tb_Switches_LEDs;

 ARCHITECTURE behavior OF tb_Switches_LEDs IS
    COMPONENT Switches_LEDs
    PORT(
         switches : IN  std_logic_vector(7 downto 0);
         LEDs : OUT  std_logic_vector(7 downto 0);
         clk : IN  std_logic
        );
    END COMPONENT;

   --Inputs
   signal switches     : std_logic_vector(7 downto 0) := (others => '0');
   signal clk          : std_logic := '0';

    --Outputs
   signal LEDs         : std_logic_vector(7 downto 0);

   -- Clock period definitions
   constant clk_period : time := 20 ns;

 BEGIN
   -- Instantiate the Unit Under Test (UUT)
   uut: Switches_LEDs PORT MAP (
          switches => switches,
          LEDs => LEDs,
          clk => clk
        );

   -- Clock process definitions
   clk_process :process
   begin
      clk <= '0';
      wait for clk_period/2;
      clk <= '1';
      wait for clk_period/2;
   end process;

   -- Stimulus process
   stim_proc: process
   begin
      wait for 100 ns;
      wait for clk_period*10;
      wait;
   end process;
 END;

This has a few more language structures that have not been seen so far. First is a component declaration, which defines the project that is being tested - much like a C function prototype:

    COMPONENT Switches_LEDs
    PORT(
         switches : IN  std_logic_vector(7 downto 0);
         LEDs : OUT  std_logic_vector(7 downto 0);
         clk : IN  std_logic
        );
    END COMPONENT;

There is a "constant" declaration, which is of a "time" data type - this data type is exclusively used in simulation. If your design has a timing constraint, the value here is usually set correctly, but it pays to check:

   constant clk_period : time := 20 ns;

The next stanza is creating an instance of the Switches_LEDs component, and attaching its signals to the signals within the test bench:

   uut: Switches_LEDs PORT MAP (
          switches => switches,
          LEDs => LEDs,
          clk => clk
        );

And finally, two processes that contain "wait" statements. These two processes control the timing of signals within the simulation:

   clk_process :process
   begin
      clk <= '0';
      wait for clk_period/2;
      clk <= '1';
      wait for clk_period/2;
   end process;

   -- Stimulus process
   stim_proc: process
   begin
      wait for 100 ns;
      wait for clk_period*10;
      wait;
   end process;

The first process ('clk_process') defines the clock signal - which will stay '0' for ten (simulated) nanoseconds, then flip to '1' for ten nanoseconds - giving a 20ns (50MHz) clock. The second process ('stim_proc') is where you add statements to change the inputs of the unit under test - for example, you could use "switches ⇐ "11111111" to simulate the switches being turned on. When initially created, all inputs (other than the clock signal) are set to '0'.

Warning

The "wait for [time period]" cannot be realized inside an FPGA, so it is only useful inside simulations. If you use this statement outside of a testbench your design will simulate perfectly but you will not be able to implement your design in the FPGA.

Starting the simulation

From top to bottom, switch to "Simulation" view, select the desired test bench (you can have more than one), expand the "Processes" tree, and then double-click on "Simulate Behavioral Model" - as a quirk, if you have just finished a simulation, you may need to right-click on this and choose "Run all".

m8s4

The simulation will be compiled, and then the simulator tool is launched. On start-up the simulator will simulate the first microsecond:

m8s4a

Using the simulator

From left to right you have the following panes:

  • Instances and processes - the design hierarchy being simulated

  • Objects - what signals are in the selected instance

  • Waveform window - a list of signals being recorded, and a graphical display of their values over time

Expand the tb_switches_leds instance in the \'Instances and processes' pane, and click on the "uut". In the "Objects" pane you will then see all the signals in your design:

m8s6

The default timescale is very small - 10 or so picoseconds; You can click "zoom out" on the toolbar until you can see the clock signal ticking away:

m8s5

As desired, you can drag a signal from the "Objects" pane into the waveform window, but as the signal has not been recorded you will need to click the "Reset" and then "Run for specified time" to get values displayed in the window. In this screenshot, I have dragged "counter[29:0]" from \'uut' into the waveform window and reran the simulation:

m8s7

When you drag and click on the Waveform pane, the value of that signal at that time is shown - unlike when debugging code, in ISIM you can trace backwards in time!

Project

  • Make some part of the design dependent on the state of one of the switches. Simulate the design after adding assignments to change the switch signal in the stimulus process

  • Right-click on some of the signals in the waveform window and explore the "radix" and cursor options

  • Click and drag over the waveform window to measure the duration of a signal from transition to transition

  • Click on the triangle to the left of a bus’s name. What happens?

Points to ponder

  • Does the simulation take into account the propagation delays inside the internal logic of the FPGA?

  • If a signal changes at exactly the same time as the clock signal’s rising edge, what happens?