Verilog · Chapter 19 · Timing Regions
Timing Regions in Verilog — Chapter 19 Overview
Two procedural blocks that read and write the same signal on one clock edge can give different answers on different simulators. This chapter explains why. Within a single simulation instant, Verilog does not evaluate everything at once. It sorts events into ordered regions named Active, Inactive, NBA, and Postponed, and drains them in a defined sequence. That ordering is the machinery beneath the non-blocking assignment rule you follow for sequential logic and the reason strobe shows a flop's new value while display shows the old one. It is also why two blocks racing on the same signal produce simulator-dependent results. This overview frames why event ordering matters, surveys the four regions, and sets up the sub-pages that drill each one.
Advanced14 min readVerilogEvent RegionsSchedulingRace ConditionsDeterminism
Chapter 19 · Timing Regions (Overview)
1. The Engineering Problem
Two always blocks trigger on the same clock edge. One writes a signal; the other reads it. The design simulates perfectly on your simulator — and produces a different answer on your colleague's.
// Both blocks run on the SAME posedge clk:
always @(posedge clk) a = b; // block 1: write a (blocking)
always @(posedge clk) c = a; // block 2: read a (blocking)
// Does block 2 see a's OLD value or its NEW value?
// - If the simulator runs block 1 first: c gets the NEW a.
// - If it runs block 2 first: c gets the OLD a.
// The Verilog standard does NOT define which runs first. The result is
// SIMULATOR-DEPENDENT — a race.Nothing here is syntactically wrong. The problem is ordering: within the single instant of the clock edge, the order in which the two blocks execute changes the result, and the language deliberately leaves that order unspecified. To understand — and avoid — this, you need to know how a simulator processes the events inside one moment of time.
Within a single simulation instant, Verilog processes events in ordered regions — Active, Inactive, NBA, Postponed. That ordering is the machinery behind the blocking/non-blocking rule, the
$display/$strobedifference, and the race conditions that make some code simulator-dependent.
2. What Is the Stratified Event Queue?
A simulation instant is not atomic. When the simulator reaches a given time, it has a queue of things to do — and it sorts them into regions that are processed in a fixed order. The simplified Verilog-1364 set:
┌─ ACTIVE blocking assigns, continuous assigns, $display,
│ evaluate the RHS of non-blocking assigns, gate I/O
├─ INACTIVE events explicitly deferred with #0
├─ NBA apply the non-blocking assignment UPDATES (LHS)
└─ POSTPONED $strobe, $monitor (read settled, end-of-step values)The simulator drains Active fully, then Inactive, then NBA, then Postponed — and because processing one region can schedule new events in another (an NBA update can wake an Active event), it loops until every region is empty, at which point simulation time finally advances. The whole of Chapters 14 and 8's "surprising" behaviour falls out of this single ordering.
3. Mental Model — One Instant, Drained Region by Region
4. The Four Regions
| Region | Holds | Consequence |
|---|---|---|
| Active | blocking =, continuous assigns, $display/$write, evaluation of <= right-hand sides, primitive I/O | most work happens here; same-region order is undefined |
| Inactive | events deferred with #0 | runs after Active, before NBA — a way (often a hack) to reorder within an instant |
| NBA | the update (left-hand side) of non-blocking <= | applied after Active drains → <= "updates last" |
| Postponed | $strobe, $monitor | read settled end-of-step values → see post-NBA results |
The two regions that explain the most are NBA (why <= defers its update) and Postponed (why $strobe sees the new value). The Active region is where races live, because everything in it is unordered. Inactive (#0) is the smallest and the most abused.
5. Visual Explanation
5.1 Visual A — the region order within one instant
One simulation instant, drained in region order
data flow5.2 Visual B — how the regions explain rules you already follow
Regions explain the blocking/NBA and $display/$strobe rules
data flow6. Why This Explains Rules You Already Follow
This chapter is unusual: it does not teach a new feature, it reveals the reason behind features you already use.
- Blocking vs non-blocking (14.3). A blocking
=updates in Active, immediately; a non-blocking<=evaluates its RHS in Active but applies its LHS update in NBA, after all Active work. That deferral — pure event ordering — is whya <= b; b <= a;swaps correctly and why<=is the rule for sequential logic. The blocking/non-blocking "rule" is a consequence of the regions. $displayvs$strobe(8.1).$displayruns in Active and reads values before NBA updates apply (the old flop value);$stroberuns in Postponed and reads after (the new value). Same regions, different read time.#0(the Inactive region). A#0defers an event from Active to Inactive — a way to "run after everything else in this instant." It is almost always a hack to paper over a race, and a fragile one (19.1, 19.4).- Races. Because same-region events are unordered, code that reads and writes a shared signal in the same region produces a simulator-dependent result.
Once you see the regions, none of these is a rule to memorise — each is just where the event runs.
7. Races and Determinism — A Preview
A race exists whenever the result depends on the order of events that the standard leaves undefined — which is the order of events within the same region. The classic is two always blocks, both using blocking =, that read and write a shared signal on the same edge (§1): both updates are Active events, their order is unspecified, and the answer flips between simulators.
The discipline that removes the race is exactly the rule you were taught early: use non-blocking <= for sequential logic. With <=, every flop's update is deferred to the NBA region, so all blocks read the old values consistently in Active and update together in NBA — order within Active no longer affects the result. The blocking/non-blocking rule is, at bottom, a determinism rule, and the regions are why. Chapter 19.4 drills this.
8. Chapter 19 Roadmap
Four sub-pages take you through the regions in the order they matter.
- 19.1 The Active Region & Evaluation Order — where most events live, why same-region order is undefined (the root of races), and the Inactive region and the
#0anti-pattern. - 19.2 The NBA Region — Why Non-Blocking Updates Last — the heart of the chapter: the mechanical explanation of the blocking/non-blocking rule, the swap, and the delta-cycle behaviour of
<=. - 19.3 The Postponed Region —
$strobe&$monitor— race-free sampling: why these read settled post-NBA values, deepening the 8.1 lesson. - 19.4 Race Conditions & Simulation Determinism — the capstone: read/write races, why results differ across simulators, the
#0"fix" trap, and the coding discipline that makes designs deterministic.
9. Industry Perspective
Event-region understanding is not academic — it is what keeps a design's simulation portable and deterministic across the multiple simulators a real project uses (one vendor for regressions, another for sign-off, a third for a specific IP). A design that relies on a particular simulator's resolution of an undefined event order will pass on one tool and fail on another, and such bugs are notoriously hard to find because they look like tool problems, not design problems. The industry's defence is a coding discipline rooted entirely in the regions: non-blocking <= for sequential logic, blocking = for combinational logic, never mix the two in one block, and never read-and-write a shared signal across blocks in the same region. Those rules are not style preferences — they guarantee that the result does not depend on the unspecified within-region order, which is what makes a simulation mean the same thing everywhere.
10. Common Misconceptions
"Everything in a single timestep happens at once." False. A timestep is drained in ordered regions — Active, Inactive, NBA, Postponed. The ordering is the whole point; "at once" would make <= and $strobe impossible to define.
"Non-blocking <= is just a slower blocking =." False. <= evaluates its RHS in Active but applies its update in a later region (NBA). That deferral is what makes it behave like a real register; it is a different scheduling, not a slower assignment.
"All simulators produce the same result for the same code." False. For code with a race — events whose order the standard leaves undefined — different simulators can legitimately produce different results. Determinism is something your coding discipline provides, not something the language guarantees for all code.
"#0 fixes a race." Misleading. #0 only defers an event to the Inactive region; it reorders within an instant but does not make the result well-defined in general. It is a fragile hack that often hides a race rather than fixing it.
11. DebugLab
The design that gave two answers
12. Interview Q&A
13. Exercises
Conceptual exercises — reason about event ordering; no coding required.
Exercise 1 — Place the construct
Name the region each runs in: (a) a blocking =; (b) the update of a non-blocking <=; (c) $display; (d) $strobe; (e) a #0-deferred event.
Exercise 2 — Old or new?
After q <= d; on a clock edge, does $display(q) in the same block show the old or new q? What about $strobe(q)? Explain via the regions.
Exercise 3 — Spot the race
Two always @(posedge clk) blocks: one does x = y;, the other does z = x;. Why is the result simulator-dependent, and what one change makes it deterministic?
Exercise 4 — Why not #0?
Explain why using #0 to force one block to run after another is considered a fragile fix rather than a real solution to a race.
14. Summary
Timing regions are the scheduling machinery beneath the whole language.
- The stratified event queue — within one instant, events are drained in order: Active → Inactive → NBA → Postponed, looping until empty, then time advances.
- The regions explain the rules — blocking
=updates in Active; non-blocking<=evaluates in Active but updates in NBA (so it "updates last");$displayreads in Active (old values),$strobein Postponed (new values);#0defers to Inactive. - Races — events in the same region have no defined order, so reading and writing a shared signal in the same region is simulator-dependent.
- Determinism — the non-blocking discipline moves updates to NBA, removing the dependence on within-region order; this is why
<=is the rule for sequential logic.
The four sub-pages:
- 19.1 The Active Region & Evaluation Order — where races are born; the
#0anti-pattern. - 19.2 The NBA Region — Why Non-Blocking Updates Last — the mechanism behind the blocking/non-blocking rule.
- 19.3 The Postponed Region —
$strobe&$monitor— race-free sampling. - 19.4 Race Conditions & Simulation Determinism — the capstone discipline.
With Chapter 19, the timing curriculum is complete: delays make signals late (17), checks judge whether late is too late (18), and regions decide the exact order in which every value is computed and observed (19) — the full account of how real hardware behaves in simulation.
Related Tutorials
- Blocking and Non-Blocking Assignments — Chapter 14.3; the rule whose mechanism this chapter reveals.
- $display vs $monitor vs $strobe vs $write — Chapter 8.1; the region-dependent sampling this chapter explains.
- Timing Checks — Chapter 18 overview; the checks whose observed values the regions determine.
- Delay Modeling — Chapter 17 overview; the first rung of the timing ladder this chapter completes.