Verilog Testbenches
A testbench is a Verilog module written to simulate and verify a design. Unlike RTL modules, a testbench is not intended for synthesis — it exists purely in the simulation domain and provides the stimulus needed to validate the Design Under Test (DUT).
Testbenches are the primary tool for catching functional bugs before committing to costly FPGA bitstreams or silicon tape-outs.
What is a Testbench?
A testbench wraps the DUT and drives its inputs with controlled sequences of values while observing the outputs. The basic structure is:
Instantiate the DUT.
Declare
regsignals for the DUT’s inputs (so the testbench can drive them).Declare
wiresignals for the DUT’s outputs (so the testbench can observe them).Drive inputs using an
initialoralwaysblock.Check outputs with
$display,$monitor, or assertion-like conditionals.
module tb_and_gate;
// Testbench signals
reg a;
reg b;
wire y;
// Instantiate the Design Under Test
and_gate dut (
.a(a),
.b(b),
.y(y)
);
// Apply stimulus
initial begin
$dumpfile("and_gate.vcd");
$dumpvars(0, tb_and_gate);
a = 0; b = 0; #10;
a = 0; b = 1; #10;
a = 1; b = 0; #10;
a = 1; b = 1; #10;
$finish;
end
endmodule
Clock Generation
Sequential designs require a clock signal. A common technique is to toggle a
reg every half-period in an always block:
module tb_counter;
reg clk;
reg reset;
wire [3:0] count;
// Instantiate DUT
counter dut (
.clk(clk),
.reset(reset),
.count(count)
);
// Generate a 10ns-period clock
initial clk = 0;
always #5 clk = ~clk;
// Apply reset and run
initial begin
reset = 1;
#20;
reset = 0;
#100;
$finish;
end
endmodule
The #5 delay means the clock toggles every 5 time units, giving a full
period of 10 time units. Adjust the delay to match the DUT’s timing
requirements.
Reset Initialization
Always initialize critical signals, especially reset, before releasing them.
Failure to reset can leave flip-flops in unknown (X) state, causing
simulations to produce meaningless results.
initial begin
reset = 1;
#20; // Hold reset for 2 clock cycles (at 10ns period)
reset = 0;
end
Checking Output Behavior
Use Verilog system tasks to observe and verify signals during simulation.
$display
Prints a message once when the line executes:
initial begin
#30;
$display("Time=%0t count=%b", $time, count);
end
$monitor
Automatically prints whenever any of its arguments change. Useful for continuous monitoring:
initial begin
$monitor("Time=%0t a=%b b=%b y=%b", $time, a, b, y);
end
Assertion-style checking
Use if statements to assert expected values and report failures:
initial begin
a = 1; b = 1; #10;
if (y !== 1'b1)
$display("FAIL: expected y=1 at time %0t", $time);
else
$display("PASS: y=1 correct");
end
Waveform Dumping
Most simulators can output a VCD (Value Change Dump) file that records signal transitions over time. This file can be loaded into a waveform viewer such as GTKWave to visualize the simulation:
initial begin
$dumpfile("simulation.vcd"); // Output file name
$dumpvars(0, tb_top); // Dump all variables in tb_top hierarchy
end
The first argument to $dumpvars is the scope depth (0 means all
levels). The second argument is the top-level module scope.
Complete Testbench Example
The following testbench tests a 4-bit counter with synchronous reset:
module tb_counter_full;
reg clk;
reg reset;
wire [3:0] count;
// Instantiate DUT
counter dut (
.clk(clk),
.reset(reset),
.count(count)
);
// Clock generation (10ns period)
initial clk = 0;
always #5 clk = ~clk;
// Waveform dump
initial begin
$dumpfile("counter.vcd");
$dumpvars(0, tb_counter_full);
end
// Monitor output
initial $monitor("Time=%0t reset=%b count=%d", $time, reset, count);
// Stimulus and checks
initial begin
// Apply reset
reset = 1;
@(posedge clk); #1;
@(posedge clk); #1;
reset = 0;
// Count for several cycles
repeat (20) @(posedge clk);
// Apply reset again
reset = 1;
@(posedge clk); #1;
if (count !== 4'd0)
$display("FAIL: counter did not reset");
else
$display("PASS: counter reset correctly");
reset = 0;
repeat (5) @(posedge clk);
$finish;
end
endmodule
Running the Simulation
With Icarus Verilog (iverilog), compile and run your testbench as follows:
iverilog -o sim counter.v tb_counter_full.v
vvp sim
This produces console output from $display and $monitor, and generates
a counter.vcd file if the dump commands are present. Open the VCD file in
GTKWave to view waveforms:
gtkwave counter.vcd
See also
Procedural Blocks in Verilog —
initialandalwaysblocks used in testbenches.Common Verilog Design Examples — Design modules to test.
Finite State Machines in Verilog — Testing FSM transitions through testbenches.