Lesson 2 of 148 minBeginner

A Simple Testbench

Drive inputs, check outputs, and make it self-checking

Before any fancy methodology, you must understand the plain idea: a testbench wraps your design, feeds it inputs, and checks the outputs. Everything else in this path is just a better-organized version of this.

The testbench drives inputs into the DUT, then compares the output against the expected value (click to enlarge)

The DUT we will test

Say the design is a simple adder: out = a + b. The spec is one line, but it is enough to show the whole pattern.

verilog
module adder (
  input  [7:0] a,
  input  [7:0] b,
  output [8:0] out   // 9 bits so the carry fits
);
  assign out = a + b;
endmodule

A first testbench - just print

systemverilog
module adder_tb;
  logic [7:0] a, b;
  logic [8:0] out;

  adder dut (.a(a), .b(b), .out(out));

  initial begin
    a = 8'd10; b = 8'd20; #1;
    $display("10 + 20 = %0d", out);

    a = 8'd200; b = 8'd100; #1;
    $display("200 + 100 = %0d", out);

    $finish;
  end
endmodule

This works, but it makes you read the numbers and judge them yourself. That does not scale, and tired eyes miss bugs.

A self-checking testbench - the real upgrade

Instead of printing, compute what the answer should be and compare. Let the computer judge, and shout only when something is wrong.

systemverilog
initial begin
  for (int i = 0; i < 100; i++) begin
    a = $random;          // random value, truncated to 8 bits on assignment
    b = $random;
    #1;                    // let the result settle
    if (out !== a + b)     // the golden expected value
      $error("FAIL: %0d + %0d gave %0d", a, b, out);
  end
  $display("All checks done");
  $finish;
end
Pro tip

The line if (out !== a + b) $error(...) is the heart of all verification. You have a reference for the correct answer (here, a + b) and you compare automatically. Everything in UVM later is an elaborate, reusable way to do exactly this: generate stimulus, predict the answer, compare.

Watch out

Use !== and === (the case-equality operators) when checking, not != and ==. The triple version also catches x and z values, so an uninitialized output cannot silently pass your check. This single habit catches a surprising number of real bugs.

Finished reading?

Mark it complete to track your progress through the path.

Get new lessons by email

New lessons, interview prep and real EDA tool workflows. No spam.

PrevNext