Self-Checking Testbenches
Reference models, directed and random tests, and a real bug caught automatically.
Reading printed values by eye does not scale past a few cases. A self-checking testbench computes the expected result itself, with a reference model written independently of the design, compares every output and reports PASS or FAIL. Then it can run thousands of tests in a second, and every change to the design can be re-checked automatically.
An ALU and its checker
Directed tests come first: the corner cases you know are risky (overflow, borrow, the most negative number).
Then 1000 random tests: $random(seed) with a fixed seed gives the same sequence every run, so failures are reproducible.
Only the first three failures are printed, followed by a summary line.
Toward professional verification
if (y != expected) errors = errors + 1;
if (y !== expected) errors = errors + 1;
If y is x, y != expected is x, which if() treats as false: the failure is silently skipped. !== compares x literally and catches it.
a = $random; // different seed handling between runs/tools integer seed = 2026; a = $random(seed);
A fixed, explicit seed makes the random sequence reproducible, so a failure can be re-run and debugged.
Why should the reference model not be copied from the design?
A copied model contains the same bugs, so the comparison always passes. It must be written independently, ideally from the specification, or at a higher level (e.g. using $signed comparison instead of the design's gate logic).
What is the difference between directed and random testing?
Directed tests are hand-picked inputs that target known risky cases. Random tests generate many inputs automatically to find unexpected bugs. Good test plans use both, and measure coverage to see what was missed.