How to Write Testbench in Verilog: Syntax and Example
To write a testbench in Verilog, create a separate module without ports that instantiates the design under test (DUT), applies stimulus signals, and monitors outputs. Use
initial blocks to set inputs and $monitor or $display to observe results during simulation.Syntax
A Verilog testbench is a module without input or output ports. It includes:
- Instantiation of the design under test (DUT).
- Signal declarations to connect to DUT inputs and outputs.
- Initial blocks to apply stimulus and control simulation time.
- Monitoring statements like
$monitoror$displayto print output values.
verilog
module testbench(); // Declare signals to connect to DUT reg clk, reset; wire out_signal; // Instantiate DUT design_module dut(.clk(clk), .reset(reset), .out(out_signal)); // Apply stimulus initial begin clk = 0; reset = 1; #10 reset = 0; // further stimulus end // Clock generation always #5 clk = ~clk; // Monitor outputs initial begin $monitor("At time %t, out = %b", $time, out_signal); end endmodule
Example
This example shows a simple testbench for a 1-bit D flip-flop module. It applies clock and data signals and prints the output Q.
verilog
module dff(input clk, input d, output reg q);
always @(posedge clk) begin
q <= d;
end
endmodule
module testbench();
reg clk = 0;
reg d = 0;
wire q;
// Instantiate the D flip-flop
dff dut(.clk(clk), .d(d), .q(q));
// Clock generation: toggle every 5 time units
always #5 clk = ~clk;
initial begin
// Apply stimulus
$display("Time\tclk\td\tq");
$monitor("%0t\t%b\t%b\t%b", $time, clk, d, q);
d = 0; #10;
d = 1; #10;
d = 0; #10;
d = 1; #10;
$finish;
end
endmoduleOutput
Time clk d q
5 1 0 0
10 0 0 0
15 1 1 0
20 0 1 1
25 1 0 1
30 0 0 0
35 1 1 0
40 0 1 1
Common Pitfalls
Common mistakes when writing Verilog testbenches include:
- Not toggling the clock signal, so the DUT never sees clock edges.
- Forgetting to initialize inputs, causing unknown (X) states.
- Not using
$finishto end simulation, which can run forever. - Using blocking assignments (
=) incorrectly insidealwaysblocks for sequential logic.
verilog
/* Wrong: Clock not toggled, simulation never ends */ module testbench_wrong(); reg clk = 0; initial begin // No clock toggling #100 $finish; end endmodule /* Right: Clock toggled and simulation ends */ module testbench_right(); reg clk = 0; always #5 clk = ~clk; initial begin #100 $finish; end endmodule
Quick Reference
Tips for writing effective Verilog testbenches:
- Use
initialblocks to set inputs and control simulation flow. - Generate clocks with
alwaysblocks toggling signals. - Instantiate the DUT inside the testbench module.
- Use
$monitoror$displayto observe signals. - End simulation with
$finishto avoid infinite runs.
Key Takeaways
Write a testbench as a separate module without ports that instantiates your design.
Use initial blocks to apply input signals and always blocks to generate clocks.
Monitor outputs with $monitor or $display to see simulation results.
Always initialize inputs and toggle clocks to avoid unknown states.
End simulation explicitly with $finish to stop the run.