2026-04-30
The asker has a short Verilog snippet that mixes blocking and non-blocking assignments to the same variable, then uses $monitor to observe the result. They expect the non-blocking assignment (a<=a+1) to take effect at time 1, so they anticipate the monitor printing at time 1. Instead, the monitor fires at time 0 with the final value of 2. The question is: why?
This is a deceptively deep question because the answer requires understanding three distinct aspects of the Verilog scheduling semantics simultaneously:
a=1 executes immediately in the Active region. The non-blocking a<=a+1 samples a (now 1) in the Active region but schedules the update (a=2) to the NBA (Non-Blocking Assignment) region of the same time step. There is no # delay on the NBA, so it resolves at time 0, not time 1.$monitor execution region. $monitor is defined by the IEEE 1800 standard to execute in the Postponed region, which runs after all Active, Inactive, and NBA updates have settled within that time step. By the time $monitor fires at time 0, the NBA update has already written 2 into a.$monitor triggers on value change. $monitor prints once per time step whenever any of its arguments change. Since a changed during time 0 (from x to 1 to 2), the monitor fires at time 0 and reports the final settled value: 2.The asker's mental model likely assumes that a<=a+1 defers its update until the #1 delay. That is not how non-blocking assignments work. An NBA without an explicit intra-assignment delay (a <= #1 a+1) schedules into the NBA region of the current time step. The #1 on the next line is a separate statement that simply suspends the initial block; it has no effect on the already-scheduled NBA.
To get the expected behavior, the asker would need to write a <= #1 a+1;, which explicitly delays the NBA update by one time unit. Alternatively, placing the NBA in a separate always block triggered at a later time would also defer it.
A useful diagnostic technique here is to replace $monitor with $strobe (which also prints in the Postponed region) or to add $display calls at strategic points in the Active region to see intermediate values. This makes the scheduling order visible.
$monitor's Postponed-region semantics within a single Verilog time step.
