Verilog · Chapter 19.3 · Timing Regions
The Postponed Region in Verilog — $strobe, $monitor & Race-Free Sampling
If the non-blocking assignment region is where values update, the Postponed region is where they have finished updating. It is the last region the simulator processes in a timestep, after Active, after Inactive, and after the non-blocking region, at the point where every signal has reached its final settled value for that instant. That makes it the one place you can read a value and be certain you are seeing the result of the timestep, not an intermediate. The strobe and monitor system tasks sample here, which is exactly why strobe shows a flop's new value after a non-blocking update while display shows the old one, and why the Postponed region, not the zero-delay trick, is the correct way to sample settled values in a self-checking testbench. This lesson drills the region, how strobe and monitor use it, why it gives race-free sampling, and the practical pattern for reading settled values in a checker.
Advanced13 min readVerilogEvent RegionsPostponed$strobe$monitor
Chapter 19 · Section 19.3 · Timing Regions
1. The Engineering Problem
You want to observe a flop's value after the clock edge has updated it — to log it, or to compare it in a self-checking testbench. But the obvious tools give the wrong answer:
always @(posedge clk) q <= d; // q updates in the NBA region
always @(posedge clk) $display("q=%b", q); // ACTIVE region → prints OLD q
always @(posedge clk) #0 $display("q=%b", q);// INACTIVE (before NBA) → OLD q
always @(posedge clk) $strobe ("q=%b", q); // POSTPONED (after NBA) → NEW q$display runs in the Active region — before the NBA update — so it prints the old q. The #0 trick (19.1) defers to the Inactive region, which is also before NBA, so it still prints the old q. Only the third line is correct, because it reads in the Postponed region — the last region of the timestep, after every update has settled.
The Postponed region is the final region of a timestep, processed after all updates (Active, Inactive, NBA) have settled.
$strobeand$monitorsample here, so they read the settled, post-update value of every signal — which is why they are the correct tools for observing a flop's new output, and why#0(before NBA) is not.
2. Mental Model — The Last Region: Everything Has Settled
3. The Postponed Region
ACTIVE → INACTIVE → NBA → POSTPONED
(most work) (#0) (<= upd) ($strobe, $monitor) ← settledBy the time the simulator reaches Postponed, the instant's work is finished: blocking assignments applied (Active), #0 events run (Inactive), and non-blocking updates applied (NBA). Nothing further will change a value at this time. The Postponed region exists precisely so that monitoring code can read these final values without racing the updates that produce them. After Postponed drains, simulation time advances.
4. $strobe — Sample After Everything Settles
$strobe formats and prints in the Postponed region, so it reads post-NBA values.
always @(posedge clk) begin
q <= d; // NBA update
$display("display q=%b", q); // Active → OLD q (pre-NBA)
$strobe ("strobe q=%b", q); // Postponed → NEW q (post-NBA)
end
// At one posedge with d=1, q was 0:
// display q=0 (the value BEFORE this edge's update)
// strobe q=1 (the value AFTER this edge's update)The difference is purely the region each runs in. $display (Active) captures q before the NBA update lands; $strobe (Postponed) captures it after. Use $strobe whenever you need the value a register holds after its clock-edge update — the settled result, not the value going into the edge. A subtle, useful detail: $strobe evaluates all of its arguments in the Postponed region — including any expressions — so a comparison written inside a $strobe argument is computed against settled values (§9 uses this).
5. $monitor — Continuous Settled Observation
$monitor watches a list of signals and prints whenever any of them changes — and it, too, samples in the Postponed region.
initial $monitor("t=%0t q=%b state=%b", $time, q, state);
// Prints ONCE per timestep, at the END (Postponed), whenever q or state
// changes — always showing the SETTLED values for that instant.- It prints once per timestep, after settling, so you never see an intermediate value mid-instant.
- Only one
$monitoris active at a time (a second call replaces the first — the 8.1 rule). - Because it samples in Postponed, a
$monitorof a flop shows the new value after each clock edge, like$strobe— not the pre-NBA value$displaywould show.
It is the low-effort way to get a settled, post-update trace of a small set of signals across a whole simulation.
Visual A — where each observer reads, and what it sees
Same signal, different region, different value
data flow6. Why Postponed Is Race-Free Sampling
The reading guarantee follows directly from the order. In the Active region, a read can race an update — whether you see the old or new value depends on the undefined within-region order (19.1). In the Postponed region, there is nothing left to race: every update of the instant has already been applied, so a Postponed read sees the one, final, settled value, independent of how the Active and NBA events were interleaved.
That is what makes Postponed the correct sampling point for a checker or scoreboard: it observes the result of the timestep, deterministically, on every simulator. Reading the same signals in the Active region (in a same-edge always block, say) instead samples a value that may be pre-update and order-dependent — the systematic bug in §9.
7. Postponed vs #0 — The Right Tool and the Wrong One
This page resolves the temptation 19.1 warned about. To sample a settled, post-update value:
| Approach | Region | Sees the NBA update? |
|---|---|---|
$display in a same-edge block | Active | No — pre-NBA |
#0 then read | Inactive | No — still before NBA |
$strobe / $monitor | Postponed | Yes — post-NBA, settled |
#0 fails not because it is "too early in time" — it is at the same simulation time — but because the Inactive region it targets is processed before NBA. The Postponed region is the only one after NBA, so it is the only place a read is guaranteed to see non-blocking updates. When you need settled values, reach for Postponed ($strobe/$monitor), never #0.
8. Common Mistakes
- Using
$displayto observe a flop's post-edge value. Active runs pre-NBA, so it shows the old value; use$strobe(§4, DebugLab). - Using
#0to "wait for" an update. Inactive is before NBA —#0still misses non-blocking updates; Postponed is the fix (§7, 19.1). - Comparing DUT outputs in a same-edge
alwaysblock. The body runs in Active, before the DUT's NBA update — a systematic stale compare (§9). - Expecting
$monitorto print intermediate values. It prints once per timestep, after settling — Postponed, not mid-instant (§5). - Trying to drive logic from the Postponed region. It is for observation; updates belong in Active/NBA.
9. Debugging Lab
The scoreboard that compared against stale data
10. Interview Q&A
11. Exercises
Exercise 1 — Old or new?
After q <= d; with d = 1 and old q = 0, state what each prints: $display(q), #0 $display(q), $strobe(q). Explain by region.
Exercise 2 — Why race-free?
Explain why a Postponed read of a signal does not depend on the order of Active/NBA events, while an Active read can.
Exercise 3 — Fix the checker
A scoreboard compares dut_out !== expected in an always @(posedge clk) block and reports false failures. Explain the region cause and give a Postponed-based fix.
Exercise 4 — #0 vs Postponed
Why does #0 fail to sample a non-blocking-updated value, even though it does not advance time? Which region does it target, and which region is correct?
12. Summary
The Postponed region is where a timestep's values have settled:
- Last region — after Active, Inactive, and NBA; every update has been applied; observation only.
$strobereads here → post-NBA (new) values; contrast$display(Active → old).$strobeevaluates all its arguments in Postponed.$monitoralso samples in Postponed — once per timestep, after settling, showing settled values (one active monitor at a time).- Race-free — after all updates, a Postponed read sees the final value regardless of Active/NBA order; the correct place to sample a flop's output or a scoreboard's values.
- vs
#0—#0targets the Inactive region, before NBA, so it misses non-blocking updates; Postponed is the only region after NBA.
The crux to keep: to read settled, post-update values, sample in the Postponed region ($strobe/$monitor) — never in a same-edge Active block, and never via #0.
The final sub-topic ties the whole chapter together: Chapter 19.4 Race Conditions & Simulation Determinism — how undefined event order produces simulator-dependent results, the #0 trap, and the coding discipline that guarantees determinism.
Related Tutorials
- The NBA Region — Why Non-Blocking Updates Last — Chapter 19.2; the updates Postponed reads after.
- The Active Region & Evaluation Order — Chapter 19.1; where
$displayand#0read (pre-NBA). - $display vs $monitor vs $strobe vs $write — Chapter 8.1; the display family this page explains by region.
- Timing Regions — Chapter 19 overview; the full stratified event queue.