Skip to content

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:

reading-the-settled-value.v
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
   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. $strobe and $monitor sample 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

the-full-order
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
   ACTIVE     →   INACTIVE   →   NBA      →   POSTPONED
   (most work)    (#0)           (<= upd)     ($strobe, $monitor)  ← settled

By 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.

strobe.v
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
   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.

monitor.v
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
   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 $monitor is active at a time (a second call replaces the first — the 8.1 rule).
  • Because it samples in Postponed, a $monitor of a flop shows the new value after each clock edge, like $strobe — not the pre-NBA value $display would 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 flow
Same signal, different region, different value$display (Active)pre-NBA → OLD value#0 (Inactive)still pre-NBA → OLD valueNBA updates applyvalues change here$strobe / $monitor (Postponed)$strobe /$monitor…post-NBA → SETTLED value
$display (Active) and #0 (Inactive) both read BEFORE the NBA updates, so they see the old value. $strobe and $monitor read in the Postponed region, AFTER NBA, so they see the settled new value. To observe a flop's output after its update, sample in Postponed.

6. 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:

ApproachRegionSees the NBA update?
$display in a same-edge blockActiveNo — pre-NBA
#0 then readInactiveNo — still before NBA
$strobe / $monitorPostponedYes — 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

  1. Using $display to observe a flop's post-edge value. Active runs pre-NBA, so it shows the old value; use $strobe (§4, DebugLab).
  2. Using #0 to "wait for" an update. Inactive is before NBA — #0 still misses non-blocking updates; Postponed is the fix (§7, 19.1).
  3. Comparing DUT outputs in a same-edge always block. The body runs in Active, before the DUT's NBA update — a systematic stale compare (§9).
  4. Expecting $monitor to print intermediate values. It prints once per timestep, after settling — Postponed, not mid-instant (§5).
  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.
  • $strobe reads here → post-NBA (new) values; contrast $display (Active → old). $strobe evaluates all its arguments in Postponed.
  • $monitor also 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#0 targets 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.