I am still a bit confused about how SystemVerilog's 2012 rule 4.7 is implemented. The rule states that in a situation like this:
module test;
logic a;
integer cnt;
initial begin
cnt = 0;
#100;
a <= 0;
a <= 1;
a <= 0;
a <= 1;
a <= 0;
end
always @(posedge a)
begin
cnt <= cnt + 1;
end
endmodule
all assignments would be scheduled on the Non Blocking Assignment queue, and must then be executed in order. The last value wins. Up to here, it's all clear.
What happens next though is not the same for all simulators. iverilog and Modelsim (at least the Vivado 2016/3 edition) create one event on 'a', which causes cnt to increment. This seems to also match the behaviour as illustrated by Mr Cummings at SNUG 2000
VCS however filters out the intermediate values and applies only the last one, which by the way is also the way that real flip flops work.
In this case it is not a purely hypothetical discussion, the simulation results are different, and the iverilog/modelsim behaviour could cause bugs that are very difficult to catch, because the flop toggles but no value change is seen in the waveforms.
The other point is this: if iverilog/modelsim are correct, why then are they creating one event and not two?
EDIT: Additional note.
The example above is indeed not very meaningful. A more realistic case would be
always @(posedge clk)
begin
clk2 <= 1'b1;
if (somecondition)
clk2 <= 1'b0;
end
always @(posedge clk2, negedge rst_n)
begin
if (!rst_n)
q <= 1'b0;
else
q <= ~q;
end
this is perfectly legal and in real hardware would never glitch. the first always is actually logically identical to
always @(posedge clk)
begin
if (somecondition)
clk2 <= 1'b0;
else
clk2 <= 1'b1;
end
However, if you simulate the first version with ModelSim, you'll see your q happily toggling away, with clk2 constant 0. This would be a debugging nightmare.