Tracking down some weird simulation results, I found that the use of blocking assignments at clock edges was the culprit. More specifically, different simulators seem to treat them differently.
Take the following example:
module test;
reg clk, foo, bar;
initial
begin
clk = 0;
foo = 0;
bar = 0;
#10 $finish;
end
always
#1 clk = ~clk;
always @(posedge clk)
foo = ~foo;
always @(posedge clk)
bar <= foo;
endmodule
Running this in Xilinx' ISim gives the following waveform:
This seems reasonable although I do find it a bit strange that a change in foo
at a clock edge gets picked up by bar at the same clock edge.
The following waveform is produced by running the same example using Icarus Verilog:
This seems completely wrong to me. A change in foo
from 0
to 1
is not picked up by bar
at the same clock edge. However, a change in foo
from 1
to 0
does get picked up by bar
at the same clock edge (otherwise bar
would change to 1
at the second positive clock edge I suppose).
So, I have two questions:
- Which, if any, of these simulators is correct? In other words, how should the above code behave?
- Are differences between simulators something we should always be aware of? If so, are there any guidelines on writing code that is deterministic across different simulators?
Note: I'm aware of the fact that using blocking assignments in always @
blocks is not a good idea and that using a non-blocking assignment in my example gives logical and consistent results. I'm asking this question because I'm currently debugging some third-party simulation code.