However large it gets, a self-checking testbench does four jobs. It makes stimulus, computes the expected answer, compares the DUT with it, and reports one verdict.
The bench below does all four jobs for a 4-bit adder. Each job is marked with a comment.
// The design under test (DUT): a 4-bit adder with a carry-out bit.
module add4 (
input wire [3:0] a,
input wire [3:0] b,
output wire [4:0] sum
);
assign sum = a + b;
endmodule
PASS: add4 matched the reference model on all 256 input pairs256: 16 values of a times 16 values of b. Printing the count proves the checks really ran. A PASS that says 0 checks would be a bench that checked nothing.
PASS: add4 matched the reference model on all 256 input pairsTrying every input works for a 4-bit adder. It does not work for a bus with 32-bit addresses, so the course builds each job into something that scales.
Job | In this small bench | Built properly in |
|---|---|---|
Stimulus | Two loops | Part 3 (random values with rules) and Part 7 (generator and driver) |
Reference model | One function | Part 7 (reference models and scoreboards) |
Checking | One if and a counter | Part 4 (assertions on every cycle) and Part 7 (scoreboard) |
Knowing you tested enough | Every input, so nothing is missed | Part 5 (functional coverage) |
PASS. Both agree, so the checker sees no difference. This is why a reference model should come from the spec and, ideally, from a different person or a different method.
Run with Icarus Verilog 13 (iverilog -g2012) and Verilator 5.048 (--binary --timing) on 2026-10-18; both printed the PASS line shown, with no warnings.
Exhaustive here means all 256 input pairs of a 4-bit adder; the same method does not scale to wide inputs, which is why Parts 3 to 5 exist.