0

Consider the below example:

module test;
 reg a;
 initial begin
  a = 1'b0;
  a <= 1'b1;
  $display(a);
 end
endmodule

The above example displays 0. My reason is because the non-blocking assignment will be assigned at step 3 of the "Stratified Event Queue" while the blocking assignment and $display are done at step 1. If I modify the example as:

module test;
 reg a;
 initial begin
  a = 1'b0;
  a <= 1'b1;
  $display(a);
  $monitor(a);
 end
endmodule

Then 0 and 1 are printed because, I assume $monitor is executed at step 4 of the Event Queue(?). But if I modify the example further:

module test;
 reg a;
 initial begin
  a = 1'b0;
  a <= 1'b1;
  $monitor(a);
  $display(a);
 end
endmodule

Again the output is: 0 and 1 -- which I did not expect. I expected 1 and 1 to be printed because $monitor will be evaluated at step 4 of the Event Queue, by which time, "a" is already 1. After that we have $display, which should print 1.

References I could find talk about "current simulation time" and the "stratified event queue" but I'm not sure how it works.

I appreciate your explanation! Thanks

cmutex
  • 1,478
  • 11
  • 24

2 Answers2

1

The verilog simulation cycle is more complex than your current explanation describes. The short answer to your question is that $monitor does not wait for the end of the current cycle, shows its message then continues executing the process (and thus triggering the $display afterwards) but instead simply schedules the message to be displayed at the end of any simulation cycle in which any of the dependent variables (in this case just a) change; it's a very special (and rather outdated) way of monitoring the changes in signals over the simulation. $display however executes immediately, thus printing whatever a is at the time. So, another way to think of it is like nonblocking assignment (<=), $monitor just sets up something to happen later, and execution continues to the next statement rather than happening inline.

You should consider learning about systemverilogs simulation model, taking note of the active, nba and postpone regions as these are when blocking-assignments (=), nonblocking assignments (<=) and $monitor are run respectively.

Unn
  • 4,775
  • 18
  • 30
1

Verilog simulation is event driven. Event is a change of the value of a verilog variable (or a named event). Simulation is done in steps.

A step starts with input events put on an event queue. Every new change in values because of the evaluation creates new events which are added to the queue. Simulation ends when the queue is empty (there are no more active events). Every such a step advances simulation time.

The step itself is divided in multiple zones which are executed using algorithm defined in the standard.

For verilog 2K, there are roughly 3 main zones:

  1. blocking assignment zone. Verilog executes all the procedural blocks scheduled by the event queue and reacts to new blocking assignment events. It just schedules nbas events to be executed later. When all blocking events are done, it gets to the next zone.

  2. non-blocking assignment zone. Here it executes all blocks which react to the schedules nba events. It will put both ba, and nba event on the queue. When all nba is done, it might get back to the zone '1' if there are ba event and do all over.

  3. monitor/strobe zone -- this is the zone when $monitor (and $strob) work. It gets execute after both ba and nba zones are done (no more events).

In your case a = 1 is executed in the blocking assignment zone. this value is persistent till the end of this zone. $display will also be executed in this zone. So, it will see the value of the 'a == 0`.

a <= 1 will be schedule for execution in the non-blocking zone, after $dislpay is done. $monitor will pick events in the monitor zone, after the non-blocking is done. So, it will show you the value of 1.

Your statements are executed in the initial block. As a result, there is no event propagation. Events only are picked by always and assign statements. If you put your $display in an always block, you will see more interesting results. always @* $display(a);

You should read about standard simulation semantics in verilog to get more information.

Serge
  • 11,616
  • 3
  • 18
  • 28