Difficulty: Easy · Puzzle 3 of 6 · Topic: Race Condition Puzzles
The monitor reports a mismatch although the RTL is correct. Is this a race? Give the time of every mismatch and the real cause.
`timescale 1ns/1ns
module tb;
bit clk = 0;
bit d = 1;
bit q = 0;
always #5 clk = ~clk;
always @(posedge clk) q <= d;
always @(posedge clk) begin
if (q !== d)
$display("[%0t] mismatch q=%0b d=%0b", $time, q, d);
end
initial begin
repeat (2) @(posedge clk);
$finish;
end
endmoduleBoth always blocks run in Active; the q update is deferred to the NBA region.
1) At t=5 both always blocks run in Active. q<=d only queues an update, so the monitor reads the old q=0 and d=1 and prints a mismatch.
2) The NBA region then sets q=1. This ordering is guaranteed by the LRM, so every simulator prints the same line: nothing here is a race.
3) At t=15 q is already 1 and d is still 1, so no mismatch is printed.
4) The bug is in the testbench: it compares q with the current d, but q holds d from the previous edge.Answer: One mismatch only, at t=5 (q=0 d=1). It is deterministic, not a race; the monitor compares the wrong pair (q against the current d instead of the previous d).
Checked by running the code in Verilator 5 and Icarus Verilog 13; the printed output supports the answer above. One mismatch, at t=5: the monitor reads q before the NBA commits, which is guaranteed ordering, not a race. Icarus prints the identical single line, showing the behaviour is deterministic.
Calling this a race teaches the wrong model: the NBA update after all Active reads is guaranteed. The mismatch disappears at t=15 only because d never changes; with a toggling d it would persist every edge.
Would using a clocking block input #0 or a $strobe-based check remove this false failure? Model answer: input #0 yes (it samples after the NBAs, so the monitor sees q=1, d=1). $strobe alone no: it only delays the print, but the if condition is still evaluated in Active with the old q. Comparing q with the previous d (or $past(d)) also fixes it.
This is not a race. The NBA update comes after every Active read, which the LRM guarantees, so the monitor reads the old q of 0 and d of 1 at five and reports one mismatch, and every tool agrees. The trap is calling it a race, which teaches the wrong model. The bug is in the testbench, which compares q with the current d instead of the previous d; I would compare against a registered copy of d, or sample through a clocking block.