Loading header...

Simulation and Testbenches

Simulation is where you ask the design questions before hardware makes them expensive. A testbench is not synthesized into the FPGA; it is a verification environment that drives inputs, checks outputs, and helps you debug.

Learning Objectives

You will be able to:

  • explain the difference between design RTL and testbench code;
  • write a clock/reset testbench structure;
  • create self-checking tests;
  • use waveforms as a debugging tool instead of a substitute for checks.

Design Code vs Testbench Code

Design RTL Testbench
Synthesizes to FPGA hardware Runs only in simulator
Must use synthesizable constructs Can use delays, loops, file I/O, tasks
Describes actual registers and logic Drives stimulus and checks behavior
Must meet timing Must expose bugs clearly

Minimal Clocked Testbench

`timescale 1ns/1ps

module tb_counter8;
    reg clk = 0;
    reg rst = 1;
    reg en  = 0;
    wire [7:0] count;

    counter8 dut (.clk(clk), .rst(rst), .en(en), .count(count));

    always #5 clk = ~clk;  // 100 MHz illustrative clock

    initial begin
        repeat (2) @(posedge clk);
        rst <= 0;
        en <= 1;
        repeat (4) @(posedge clk);
        if (count !== 8'd4) begin
            $display("FAIL count=%0d", count);
            $finish;
        end
        $display("PASS counter8");
        $finish;
    end
endmodule

What to Check

Good testbenches check behavior, not just that the simulator ran.

  • Reset state.
  • First valid output after enable.
  • Boundary conditions.
  • Overflow or wrap behavior.
  • Illegal or unused states.
  • Back-to-back transactions.
  • Stalls, pauses, and recovery.

Waveforms Help You See Timing

title "Illustrative simulation sequence"
time start=0 end=80 unit=ns divisions=8

CLK: square label="clk" low=0 high=1 duty=50 cycles=8 unit=logic color=#2563eb
RST: pulse label="rst" low=0 high=1 at=0 width=20 unit=logic color=#dc2626
EN: step label="en" low=0 high=1 at=25 unit=logic color=#7c3aed
COUNT: sawtooth label="count rises after reset" min=0 max=4 cycles=1 unit=count color=#16a34a

marker RELEASE at=20 label="reset released"
marker CHECK at=70 label="check expected count"

This is an explanatory waveform. Your simulator waveform will reflect the actual RTL and testbench.

Self-Checking Beats Manual Inspection

Manual waveform inspection is useful while debugging. It is not enough for regression testing. A self-checking testbench should print PASS only when expected behavior is proven.

Worked Example: Counter Reset Check

Requirement: when rst is high at a clock edge, count becomes zero.

Test idea:

  1. Let the counter run to a nonzero value.
  2. Assert reset.
  3. Wait for a clock edge.
  4. Check count == 0.

This catches designs where reset is missing, inverted, asynchronous in the wrong way, or connected to the wrong register.

Common Mistakes

  • Treating “no simulator crash” as success.
  • Looking at waveforms once and never automating checks.
  • Forgetting reset behavior in tests.
  • Driving inputs exactly on the active clock edge, creating artificial races.
  • Testing only the happy path.

Summary

Simulation gives fast feedback. A useful testbench creates a realistic clock/reset sequence, drives meaningful stimulus, checks expected behavior automatically, and uses waveforms to debug failures. Hardware testing comes later; it should not be the first time your design is exercised.

Next: Verilog Simulation: Verilator, Icarus Verilog, and GTKWave.

Further Reading

  • Verilator user guide
  • GHDL quick start and VCD wave output
  • cocotb documentation
  • Vendor simulator tutorials

Mind Map

mindmap root((Simulation)) Core concept Testbench drives DUT Assertions check behavior Waveforms explain timing Applications Applications RTL verification Regression tests Checks Design checks Expected output Corner cases Common mistakes Only eyeballing waves Common mistakes No self check