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.