Draft preview. Lessons are being written and reviewed.

Digital Design / Module 3: Verilog that means hardware

18. Your first self-checking testbench

Prove the design works rather than eyeballing it.

Lecture coming soon

See it move

The idea

A testbench is the code that exercises your design: it makes a clock, drives inputs and checks outputs. It isn't hardware, so it can use delays, files and printing. A self-checking testbench decides pass or fail by itself, so nobody needs to read a waveform to know the result.

module tb;
  reg  [3:0] a, b;
  wire [3:0] s;
  wire cout;
  integer errors = 0;

  add4 dut(.a(a), .b(b), .cin(1'b0), .s(s), .cout(cout));

  task check(input [3:0] x, y);
    begin
      a = x; b = y;
      #1;  // let the combinational logic settle
      if ({cout, s} !== x + y) begin
        $display("FAIL %0d+%0d: got %0d", x, y, {cout, s});
        errors = errors + 1;
      end
    end
  endtask

  integer i, j;
  initial begin
    $dumpfile("tb.vcd");
    $dumpvars(0, tb);
    for (i = 0; i < 16; i = i + 1)
      for (j = 0; j < 16; j = j + 1)
        check(i, j);
    if (errors == 0) $display("PASS");
    else $display("%0d errors", errors);
    $finish;
  end
endmodule

What makes it good

  • It uses !== so that x in the output counts as a failure.
  • It is exhaustive here, which is possible with only 256 cases. Larger designs use directed plus random stimulus.
  • It computes the expected value a different way, which is what makes the check meaningful.

Clocked designs

reg clk = 0;
always #5 clk = ~clk;

Change inputs away from the sampling edge, such as on the falling edge, or just after the rising edge. Driving inputs exactly on the active edge invites a race with the design.

Common mistake

A testbench that prints values for you to check by eye. It can't run in a regression, and a tired engineer will miss a wrong number. Try the injected bug in the animation: the checks catch it with no reading at all.

Key ideas

  • Generate a clock, drive stimulus, and check results.
  • Drive inputs away from the sampling edge to avoid races.
  • $dumpvars produces a waveform for debugging.

Your exercise

Write a self-checking testbench for your adder.

Find the bug

This code has one deliberate bug. Read the symptom, then click the line you think is wrong.

What goes wrong: This check is meant to catch a design whose output isn't 1. The design outputs x, and the check stays silent.

Interview questions

coreWhy be self-checking?

basicWhy does a testbench module usually have no ports, and what is it allowed to do that design RTL is not?

basicThe output y of your design is x because you forgot a reset. Which of these two checks reports the error, and why?

if (y != 1'b1)  errors = errors + 1;  // check A
if (y !== 1'b1) errors = errors + 1;  // check B

coreThis loop tests a correct 4-bit adder built from full-adder instances, yet in simulation it can report many failures. Why, and what is the fix?

for (i = 0; i < 16; i = i + 1)
  for (j = 0; j < 16; j = j + 1) begin
    a = i; b = j;
    if ({cout, s} !== i + j) errors = errors + 1;
  end

coreWhere should a self-checking testbench get its expected values from, and why not reuse a copy of the design's own RTL?

coreA 4-bit adder passes eight hand-picked sums, but it has a bug in which bit 2 of the sum ignores its carry-in. Why did the directed tests not settle the question, and what would you do instead?

coreAn adder has two 16-bit inputs and a carry-in. How many vectors does an exhaustive test need, and how long would it take at one million vectors per second?

advancedA testbench drives a flop's input with a blocking assignment inside always @(posedge clk). Moving that block to a different place in the file changes when the flop captures the new value. What is happening, and how do you fix it?

always @(posedge clk)
  if (n == 1) d = 1'b1;   // stimulus

always @(posedge clk)
  q <= d;                 // the flop

advancedThis clock generator is in a testbench, but every flop in the design stays x and nothing ever happens. Why?

reg clk;
always #5 clk = ~clk;

Practise these 9 questions with animations