A synthesis tool ignores the event list and builds the block body as combinational logic. Simulation obeys the list and re-evaluates only when a listed signal changes.
That split is the whole bug class. Any signal that is read but not listed simulates stale and synthesizes live.
Consider always @(a) y = a & b. Toggling b alone leaves y frozen in simulation, while the gates follow b at once.
The Yosys script below proves the point: both lists build identical logic, so the simulation difference is the entire mismatch.
read_verilog <<EOV
module gold(a, b, y);
input a;
input b;
output y;
reg y;
always @* y = a & b;
endmodule
module gate(a, b, y);
input a;
input b;
output y;
reg y;
always @(a) y = a & b;
endmodule
EOV
hierarchy -check
proc
opt
miter -equiv -flatten -make_outputs gold gate m
hierarchy -top m
sat -prove trigger 0 -verify m
log PASS: incomplete list builds the same AND gatesZero-delay blocks scheduled in one timestep run in an order the standard leaves undefined. Two simulators may therefore evaluate the same step differently.
Pattern | Simulation risk | Safe form |
|---|---|---|
Two blocks driving one variable | Last write wins, order unknown | Exactly one driver per variable |
Reading another block's blocking update | Value depends on run order | Non-blocking updates sampled at the clock |
Stimulus racing the design at time zero | Unknown initial sample | Drive stimulus before the first clock |
Write combinational blocks with always_comb, which infers the full list. Reserve explicit event lists for clocked logic and testbench timing.
always @(a) y = a & b runs while b toggles and a stays still. What does RTL simulation show, and what do the gates do?Simulation holds the old y because a never moves. The gates track a & b continuously, since synthesis ignored the list.
Block order within a timestep is undefined. Each simulator picks a legal order, so opposite orders give opposite samples.