Verilog & SystemVerilog DISCUSSION

Verilog testbench race: why does my design capture inputs a cycle early in one simulator?

Started by muhammet Verilog testbenchsimulation race conditionclock generationcase inequality operator$finish
4 replies 248 views 5 participants
Latest activity · 30 Sep 2026

Verilog testbench race: why does my design capture inputs a cycle early in one simulator?

muhammet Verilog & SystemVerilog Forum
#1

My testbench generates a clock with always #5 clk = ~clk; and applies stimulus with @(posedge clk) din = 8'h3C;. The registered design samples din on the rising edge. In one simulator the new value is captured on the very edge where I apply it; in another it is captured one cycle later. My result check, if (dout != 8'h3C) $display("FAIL");, also stays silent while dout is still X.

Which simulator is right, how should a testbench drive and check a synchronous design, and how do I end the run cleanly?

Community replies 4

Re: Verilog testbench race: why does my design capture inputs a cycle early in one simulator?

#2

Both simulators are right, because the code has a race. At the rising edge two things are ready to run: the design's always @(posedge clk), which reads din, and your testbench statement, which writes din with a blocking assignment. The standard does not define their order. If the testbench happens to run first, the design sees 8'h3C at once; otherwise it sees the old value.

Real hardware has no such ambiguity, so the testbench must not create one.

Re: Verilog testbench race: why does my design capture inputs a cycle early in one simulator?

#3

There are two standard cures. Drive with a non-blocking assignment: @(posedge clk) din <= 8'h3C;. The update is deferred until all blocks triggered by the edge have run, so the design always samples the old value at this edge and the new one at the next, exactly as if din came from another flip-flop. Or change inputs away from the active edge, for example @(negedge clk) din = 8'h3C;, which gives half a period of setup and looks clearer in the waveform.

Pick one convention and use it for every input. SystemVerilog clocking blocks formalise the same idea with explicit input and output skews.

Re: Verilog testbench race: why does my design capture inputs a cycle early in one simulator?

#4

Your check is silent because of X propagation. If any bit of dout is X, dout != 8'h3C evaluates to X, and if treats X as false, so the failure branch is skipped. Use the case inequality operator, which compares X and Z literally and always returns 0 or 1: if (dout !== 8'h3C) $display("FAIL: dout=%h at %0t", dout, $time);. In testbench checks, === and !== should be the default.

Sample outputs at a well-defined moment too, typically just before the next active edge or on the opposite edge, not at the instant they are changing.

Re: Verilog testbench race: why does my design capture inputs a cycle early in one simulator?

#5

For the clock, initialise it, otherwise ~clk stays X forever: initial clk = 0; with always #5 clk = ~clk; gives a period of 10 time units, which is 100 MHz with `timescale 1ns/1ps. Hold reset for a few cycles and release it using the same driving convention as the other inputs.

Because the clock block never stops, the simulation must be ended explicitly: call $finish; at the end of the stimulus block ($stop only pauses for interactive use). Add a watchdog as well, such as initial begin #100000; $display("TIMEOUT"); $finish; end, so that a design that hangs does not run forever, and count errors so the last line of the log states pass or fail.

TEP COMMUNITY