Skip to content

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.

same-edge-different-answer.v
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
   // 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/$strobe difference, 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:

one-timestep,-in-order
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
   ┌─ 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

RegionHoldsConsequence
Activeblocking =, continuous assigns, $display/$write, evaluation of <= right-hand sides, primitive I/Omost work happens here; same-region order is undefined
Inactiveevents deferred with #0runs after Active, before NBA — a way (often a hack) to reorder within an instant
NBAthe update (left-hand side) of non-blocking <=applied after Active drains → <= "updates last"
Postponed$strobe, $monitorread 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 flow
One simulation instant, drained in region orderActiveblocking =, assigns, $display, eval <= RHSInactive#0 deferred eventsNBAapply <= updates (LHS)Postponed$strobe, $monitor
Within one timestep the simulator drains Active, then Inactive, then NBA, then Postponed — looping back when a region schedules new work — before time advances. This fixed order, not the source-code order, decides what every read observes.

5.2 Visual B — how the regions explain rules you already follow

Regions explain the blocking/NBA and $display/$strobe rules

data flow
Regions explain the blocking/NBA and $display/$strobe rulesblocking =(Active)updates immediatelynon-blocking <=(NBA)updates AFTER Active → 'last'$display (Active)sees pre-NBA (old) values$strobe(Postponed)sees post-NBA (new) values
The region a construct runs in explains its behaviour: non-blocking updates land in NBA (after blocking), so they appear to 'update last'; $display runs in Active and sees old values, while $strobe runs in Postponed and sees the settled new ones. Chapter 14.3 and Chapter 8.1 were describing this machinery.

6. 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 why a <= b; b <= a; swaps correctly and why <= is the rule for sequential logic. The blocking/non-blocking "rule" is a consequence of the regions.
  • $display vs $strobe (8.1). $display runs in Active and reads values before NBA updates apply (the old flop value); $strobe runs in Postponed and reads after (the new value). Same regions, different read time.
  • #0 (the Inactive region). A #0 defers 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 #0 anti-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: ActiveInactiveNBAPostponed, 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"); $display reads in Active (old values), $strobe in Postponed (new values); #0 defers 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 #0 anti-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.