What's event region of @ in System Verilog?

I am confused by the event region of @ in system verilog.

Here is the code:

module tb;
  bit a=0;

  //BA
  //initial
  //  a = 1;

  //NBA
  initial 
    a <= 1;

  initial
    @(posedge a) $display("Detect posedge edge of a!");

endmodule

By using BA and NBA to initialize bit variable a, I get different result.
BA → not trigger posedge a.
NBA → trigger posedge a.

Based on SystemVerilog_3.1a, the event region like this:
preponed → active → inactive → NBA → observed → reactive → postponed.

Where does @ sit in the event region? It looks come after NBA.

In reply to mlsxdx:
First, you should be using the latest freely available version of the IEEE 1800-2012 SystemVerilog LRM.

The delay control ‘@’ executes in the active region. In fact, if you put aside assertions and a few other miscellaneous constructs, everything executes in the active region. The way the scheduler works, you have nested loops of execution. i.e.

  1. All events in the active region execute until empty. Execution of active events can schedule more events in this or any other region.
  2. The events in the inactive region become active events and we go back to step 1.
  3. Once the active and inactive events queues are empty, the NBA events become active and we go back to step 1.
  4. Once the active, inactive, and NBA event queues are empty, its time to advance to the next time slot. (assuming no assertions).

Any time you have multiple processes synchronized to the same event where some processes are reading, and other processes are writing to the same variable, you have a race condition where the results are not predictable. You need to use an NBA to move the writing process to a later region.

In your example, you have two process(two initial blocks) synchronized to the same event(time 0 startup). The initial block that appears last in your source code is going suspend itself waiting for a @(posedge a). The initial block that does a BA to a will in a race with the process with the @(posedge a). They are both executing in the same active region. If the BA executes first, the posedge of a happens before the @ executes to wait for a posdege of a, and the @ statement suspends itself waiting for a posedge of a that never happens again. If the @ executes first, then it will see the posedge of a that comes afterwards, unspend itself and execute the $display all in the same active region.

In the NBA case, the NBA statement executes in the active region, but the update to a is scheduled in the NBA event queue. The @ sill executes in the active region suspending itself, but the update to a has not happened yet. So the active and inactive event queues empty with an update to a in the NBA event queue that moves become an active event. That update to a resumes the process waiting for the posedge of a, and executes the $display.

In reply to dave_59:

I have question about this eg. In process 2, what region does the $display statement in? It’s blocked by the @ statement, should it be in some region after NBA? Or it’s still in the active region? When is it put into the event queue?

Similar question about the always@ block. Is it still in active region? What about the statement inside the always block?

In reply to dave_59:

Hi Dave,

Thank you for explanation.

For @, you said it executes in active region. Then it suspends wait for @(posedge a).
If active region queue is not empty, how can it schedules inactive region?

In order to understand this, could you please explain how those events sit?

module tb;
  logic a;
  
  //state1
  initial a<=0;

  //state2
  initial begin
    @(a) begin
      a<=1;
      $display(a);
  end

  //state3
  initial $monitor("a:%0b",a)
endmodule

Based on your explanation,
state1 sits in NBA region
state2 sits in active region, @ suspend the thread. What region do a<=1 and $display sit? Still active region or NBA region?
state3 sits in postpone region.

Is this correct?

In reply to mlsxdx:

In reply to runxuanl:

I don’t think either of you are getting it, and it might be to difficult to explain in this forum. All the code mentioned here executes as part of the active event queue. All other “regions” are just queues waiting to become active.

In reply to dave_59:

HI Dave In LRM there are arrows that re-enter the active region after the Active,Inactive,NBA regions so I tried the code below:

reg A = 0;

//Method 1
always @ ( A )
#10 A = ~A;

// Method 2
always @ ( A )
#10 A <= ~A;

Why is it that method1 doesn’t give an infinite loop whereas method2 gives an infinite loop
Also could u explain what the re-entrant arrows actualy Indicate?

Thank You In Advance

In reply to Have_A_Doubt:
An always block is a loop that can be unrolled as follows

@(A)
#10
A = ~A;
@(A)
#10
A = ~A;
@(A)
...

and

@(A)
#10
A <= ~A;
@(A)
#10
A <= ~A;
@(A)
...

When using a blocking assignment, the update to A happens before the next statement ‘@(A)’ so it is stuck until some other process makes a change to A. When using a non-blocking assignment, the update is scheduled fro the NBA region, and the statement that immediately follows it executes. So the ‘@(A)’ statement executes before the update and will unblock when that happens,