Difficulty: Medium · Puzzle 6 of 6 · Topic: Race Condition Puzzles
Is this code legal? If a tool accepts it anyway, what can data become when load and clear are both 1, and is that result defined by the language?
module tb;
bit clk = 0;
bit load = 1;
bit clear = 1;
byte in = 8'hA5;
byte data = 8'h00;
always #5 clk = ~clk;
always_ff @(posedge clk) begin
if (load) data <= in;
end
always_ff @(posedge clk) begin
if (clear) data <= 8'h00;
end
initial begin
@(posedge clk);
$strobe("[%0t] data=%0h", $time, data);
$finish;
end
endmoduleCheck LRM 9.2.2.4 before you reason about NBA order.
1) LRM 9.2.2.4: a variable written in an always_ff shall not be written by any other process. This code writes data from two always_ff blocks, so it is illegal and a conforming tool must report an error.
2) Icarus and Verilator do not reject it (Verilator only warns), so both NBAs are queued at t=5.
3) The order of NBAs queued by different processes is not defined by the language, so data ends up as a5 or 00.
4) Observed: Icarus prints data=a5, Verilator prints data=0; neither is 'right'.
5) Fix: one always_ff with explicit priority.Answer: Illegal (LRM 9.2.2.4). If a tool simulates it anyway, data may be 8'hA5 or 8'h00 and the language does not say which; Icarus gave a5, Verilator 00.
Checked by running the code in Icarus Verilog 13 and Verilator 5; the printed output supports the answer above. Icarus applies the load NBA last and prints a5; the code is illegal for always_ff (LRM 9.2.2.4) and the result is undefined. Verilator applies the clear NBA last and prints 0: a different, equally undefined result.
Saying only 'it is a race, answer A5 or 00' misses that the code should not compile at all. always_ff does not make multiple writers legal; it forbids them.
Refactor this into one always_ff with explicit priority. Model answer: always_ff @(posedge clk) if (clear) data <= 8'h00; else if (load) data <= in; (clear wins, so data=00; swap the branches for load priority, data=a5).
First, this code is illegal. The LRM says a variable written in an always_ff cannot be written by any other process, so a conforming tool must error. If a tool simulates it anyway, then both NBAs are queued and the order between processes is not defined, so data is A5 or 00, and Icarus gave A5 while Verilator gave 0. The trap is answering only A5 or 00 and missing that it should not compile. I would merge them into one always_ff with an explicit priority, and turn the tool warning into an error.