Question

I was learning about the verilog stratified event queue. I had a minor doubt about the inactive events. I understood that they are carried out after all the active events are done with at the current simulation time. But I wrote a simple code to understand the concept better but the result I got is what confuses me. Here is the code I wrote:

module main;

    int x; 

    initial begin 

       $monitor("x is %0d",x); 

       #0 x = 5; // inactive event 
       x = 3; // active event 
     end 

endmodule

RESULT : x is 3.

According to my knowledge the #0 delay creates an inactive event and therefore the result should have been x is 5. But my understanding of the concept might be wrong somewhere. Any help will be appreciated. Thanks.

Was it helpful?

Solution

Definitions of the regions from IEEE Std 1800-2012:

4.4.2.2 Active events region
The Active region holds the current active region set events being evaluated and can be processed in any order.

4.4.2.3 Inactive events region
The Inactive region holds the events to be evaluated after all the Active events are processed.

If events are being executed in the active region set, an explicit #0 delay control requires the process to be suspended and an event to be scheduled into the Inactive region of the current time slot so that the process can be resumed in the next Inactive to Active iteration.

...

4.4.2.9 Postponed events region
$monitor, $strobe, and other similar events are scheduled in the Postponed region. No new value changes are allowed to happen in the current time slot once the Postponed region is reached.

Within this region, it is illegal to write values to any net or variable or to schedule an event in any previous region within the current time slot.

Diagram see a diagram of scheduler on Figure 4-1—Event regions

You are correct in your understanding that the #0 puts the x = 5; into the inactive region. However, this #0 also blocks the x = 3; from executing in the first time entering in the active region. It is executed in the second pass to the active region rigged by the Inactive region. This is because blocking statements are always always sequential. $monitor() is always displayed at the end to the time step, after all other regions have completed, hence you will only get the final value if x.

By placing the statements inside of a fork-join, then the two statements will execute in parallel. This will allow the x = 3; to execute the first time the active region is entered.

module main;
    int x; 
    initial begin 
       $monitor("From    $monitor: x is %0d",x); 
       #0 x = 5; // inactive event 
       x = 3; // active event (after inactive event)
       #1; // go to next time stamp
       fork
         #0 x = 7; // inactive event 
         x = 11; // active event 
       join
    end 
    // reactive event, x value from the observed region
    always @* $display("From @* $display: x is %0d",x); 
endmodule

Outputs:

From @* $display: x is 3
From    $monitor: x is 3
From @* $display: x is 11
From @* $display: x is 7
From    $monitor: x is 7

OTHER TIPS

In your code, x is being overwritten in the same time step. According to IEEE std 1800-2012:

when a $monitor task is invoked with one or more arguments, the simulator sets up a mechanism whereby each time a variable or an expression in the argument list changes value the entire argument list is displayed at the end of the time step.

If you use $display after each statement, you will see each value change:

module main;

    int x; 

    initial begin 

       $monitor("x in $monitor is %0d",x); 

       #0 x = 5; // inactive event 
       $display ("x in $display=%0d", x);
       x = 3; // active event 
       $display ("x in $display=%0d", x);
     end 

endmodule

Output:

x in $display=5

x in $display=3

x in $monitor is 3

exit

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top