Skip to content

Testbenches in Verilog

Writing Testbench Basics in Verilog

Testbenches are simulation-only modules (Non-synthesizable) used to verify the functionality of RTL designs. They do not synthesize into hardware however used for validation.

Testbench Structure

A typical testbench includes:

  1. DUT (Device Under Test) instantiation
  2. Signal declarations (reg for inputs, wire for outputs)
  3. Stimulus generation (initial block or procedural blocks)
  4. Monitoring and debugging ($display, $monitor)

Example Skeleton

`timescale 1ns / 1ps

module tb_example;
  // Signals
  reg a, b;
  wire y;

  // DUT instance
  and_gate uut (.a(a), .b(b), .y(y));

  // Stimulus
  initial begin
    a = 0; b = 0;
    #10 a = 1;
    #10 b = 1;
    #10 a = 0;
    #10 $finish;
  end

  // Monitoring
  initial begin
    $monitor("Time=%0t a=%b b=%b y=%b", $time, a, b, y);
  end
endmodule

Using $display and $monitor

  • `timescale 1ns / 1ps sets the simulation time unit to 1 nanosecond and the time precision (smallest time step) to 1 picosecond. Learn more about timescale directive : Timescale directive
  • $display prints once when called
  • $monitor prints whenever a specified signal changes

Examples

initial begin
  $display("Simulation starts at time %0t", $time);
end

initial begin
  $monitor("a=%b, b=%b, y=%b", a, b, y);
end
  • $time returns the current simulation time
  • Formats: %b (binary), %d (decimal), %h (hex), %t (time)

Initial Blocks for Stimuli

  • Use initial blocks to provide input patterns or clock/reset sequences
  • Multiple initial blocks can run concurrently

Example: Clock Generation

reg clk;
initial clk = 0;
always #5 clk = ~clk; // Toggle every 5 time units

Example: Reset and Input Stimuli

reg reset, enable;
initial begin
  reset = 1;
  enable = 0;
  #10 reset = 0;
  #20 enable = 1;
  #50 $finish;
end

Why Testbench Modules Don’t Have Parentheses in Definition ?

In Verilog, parentheses in a module definition are used to define ports — that is, signals that connect to the outside world of that module.

Example of a design module:

module and_gate (
    input  wire a,
    input  wire b,
    output wire y
);
  assign y = a & b;
endmodule

Here:

  • The parentheses list the ports (a, b, and y).
  • These ports connect the AND gate module to other modules or the testbench.

Example of a test bench

A testbench is not part of the synthesized hardware — it’s only used in simulation to test your design. It doesn’t need to connect to any external module. So, it does not have ports (no inputs or outputs), and therefore, no parentheses are needed.

module tb_and_gate;
  reg a, b;
  wire y;

  and_gate uut (
    .a(a),
    .b(b),
    .y(y)
  );
endmodule

Here:

  • tb_and_gate is a top-level module.
  • It instantiates (uut) the design module and_gate.
  • The testbench internally drives and observes all signals — nothing connects from outside.
  • Since there are no ports, you don’t write parentheses after the module name.

Best Practices

  • Keep DUT separate from testbench
  • Use reg for inputs, wire for outputs
  • Use $monitor for continuous signal observation
  • Use $display for logging specific events
  • Avoid synthesizable constructs like # delays in real hardware modules; testbenches allow them

Summary

Concept Description Example
DUT Device under test and_gate uut (.a(a), .b(b), .y(y));
Stimuli Apply input patterns initial begin a=0; #10 a=1; end
Clock generation Periodic toggle always #5 clk = ~clk;
Reset sequence Initialize and release reset reset=1; #10 reset=0;
Monitoring Observe signal changes $monitor("a=%b b=%b y=%b", a,b,y);
Logging Print messages at specific times $display("Time=%0t", $time);