Electronic – Simulation of blocking assignments in always @ blocks

simulationverilog

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:

Waveform produced by ISim

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:

Waveform produced by 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:

  1. Which, if any, of these simulators is correct? In other words, how should the above code behave?
  2. 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.

Best Answer

I'm no Verilog guru, but as I understand it (from here http://www.sigasi.com/content/verilogs-major-flaw amongst other places), using blocking assignments to communicate between clocked processes is asking for non-determinism.

Regarding part 2 - As I understand it... if you only use non-blocking assignments when you communicate between processes, you'll get deterministic behaviour across all simulators. The non-determinism of blocking assignments is not a "simulator thing" - it's inherent in the way Verilog works. Changing the order of the processes in the source files (for example) may change the order of the updates and hence the behaviour of the code, even within the same simulator.