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
1 is not picked up by
bar at the same clock edge. However, a change in
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.