skip to primary navigationskip to content
 

Course pages 2025–26 (working draft)

ECAD and Architecture Practical Classes

Verilog Tutorial Part 4 - Simulation and Test Benches

Test Benches

A test bench is used to intatiate a design and provide inputs. For example, the following test bench can be used to test the timer module from the previous page. This test bench will generate the clk and rst signals, and output the t signal generated.

The following test bench uses several simulation only System Verilog commands including:

  • initial used to initialise registers in a particular sequential order. Note the use of blocking assignment on registers that only makes sense in simulation.
  • $dumpfile and $dumpvars functions tell the simulator where to store a simulation trace and what variables to dump to the trace file.
  • #20 and #100 are examples of simulation delays in terms of simulation time steps.
  • Simulation functions: $finish to end the simulation, $display to print output similar to printf() in C, and $time which is a variable that returns the current simulation time step.
  • always @(posedge clk) is used to sequence output on the positive edge of the clock.
  • In simulation the always statement can have an arbitrarity long sensitivity list. For example, we could used always @(clock or t) $display(t) to display the value of t whenever clock (either edge) or tchange. This use of always is useful in simulation but cannot be synthesised (i.e. we cannot produce a circuit for it).
module tb_timer(
        output logic clk,  // generated clock
        output logic rst,  // generated reset
        output [63:0] t    // test output
        );

  initial begin
    $dumpfile("tb_timer_trace.vcd"); // dump signal changes
    $dumpvars();                     // dump all variables in this module
    clk = 1;                         // value of clk at simulation step 0
    rst = 1;                         // value of rst at simulation step 0
    #20 rst = 0;                     // wait 20 simulation steps and then lower rst
    #100 $finish();                  // wait 100 simulation steps, then call $finish() to stop
  end

  // invert the clock every 5 simulation steps
  always #5 clk = !clk;

  // initatiate the design under test (DUT)
  timer dut(.clk(clk), .rst(rst), .t(t));

  // every negative edge of the clock, output the status
  always @(posedge clk)
    $display("sim_time=%4d      t=%4d", $time, t);
   
endmodule
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

Installing a simulator

See the Setup page for access to tools.

Ensure that you have Verilator version 5 or higher by running: verilator --version

Run a simulation

Make a directory to store your simulation, and it in put two files called timer.sv (contents copied from the code on the Tutorial 3 page) and tb_timer.sv with the test bench code above.

Then execute: verilator --binary --trace tb_timer.sv

This will generate C++ based simulation models of the tb_timer and will also pull in the timer module since tb_timer instantiates it. Generated files can be found in the obj_dir/ directory including the executable simulation obj_dir/Vtb_timer.

Now run the simulation: ./obj_dir/Vtb_timer

The simulation output should be similar to:

sim_time=   0      t=   0
sim_time=  10      t=   0
sim_time=  20      t=   0
sim_time=  30      t=   1
sim_time=  40      t=   2
sim_time=  50      t=   3
sim_time=  60      t=   4
sim_time=  70      t=   5
sim_time=  80      t=   6
sim_time=  90      t=   7
sim_time= 100      t=   8
sim_time= 110      t=   9
- tb_timer.sv:11: Verilog $finish
sim_time= 120      t=  10
- S i m u l a t i o n   R e p o r t: Verilator 5.036 2025-04-27
- Verilator: $finish at 125ps; walltime 0.000 s; speed 163.399 ns/s
- Verilator: cpu 0.001 s on 1 threads; alloced 0 MB

Viewing Waveforms

The test bench also produced a trace file tb_timer_trace.vcd in Value Change Dump (VCD) format. We can now use a waveform viewer to display the information in the VCD file. See the Setup tab for waveform viewer installation and how to use them.

In the figure below you'll see the clock (clk) signal oscillating, the reset signal (rst) start high and then go low after two clock ticks. The t output then starts counting up every clock cycle after reset. Click on the image below if you need to see a larger version.