Search code examples
verilogsystem-verilogtest-bench

Determinism in Verilog: event controls


Consider the below example:

module test;
  reg a;
  initial begin
    a = 1'b1;
  end
  initial begin
    wait(a) $display("wait(a): %b", a);
    $display("wait(a)");
  end
  initial begin
    @a $display("@a: %b", a);
    $display("@a");
  end
endmodule

When I run it, I always get this output:

wait(a): 1
wait(a)

Which confuses me. My understanding of the code is like this:

  1. the default value for a is x.
  2. all initial blocks start in parallel at time 0.
  3. the first initial block does a block assignment while at the same time the wait and @a event controls read a.
  4. since there is no determinism in the sequencing among the three, the blocking assignment a=1'b1, may be executed before or after the wait(a) or @a.
  5. if the blocking assignment is executed before wait(a) and @a, no output should be displayed since wait(a) and @a will not detect any change in a.
  6. if, however, the blocking assignment a=1'b1 is executed after the read of a in wait(a) and @a, which both will read as x, then the output from both should be displayed after the blocking assignment completes.

But, as I pointed out above, the output I see is always the output from wait(a). Can someone please explain to me:

  1. What is going on and the defect in my understanding?

And more generally, and outside of the example above:

  1. What exactly happens when the simulator encounters a wait(a) and @a?
  2. wait(a) and @a detect level and edge changes (in the example, level and edge change are identical). When we say "change" in this case, does it mean a change after the last read of the variables involved in the event controls (in this example a)?

Solution

  • You are correct up until point 5.

    If a=1'b1 gets executed before the wait(a), then it has no effect—it does not suspend the process. If the reverse order, the wait(a) suspends the process and resumes after the assignment a=1'b1. In your example, you always see the output from the second initial block regardless of the order.

    But the ordering is very important for the third initial block. The @a must execute before any change to a, otherwise it suspends until it sees another change. Although you should not rely on it, most tools executed initial blocks in source code order. But optimizations and ordering between initial blocks in different modules can never guarantee ordering.