SYSTEMVERILOG SERIES · SV-14

SystemVerilog Series — SV-14: Scheduling Semantics — VLSI Trainers
SystemVerilog Series · SV-14

Scheduling Semantics

How SystemVerilog simulation time is structured — the discrete event model, the eleven ordered time-slot regions, the reference simulation algorithm, and how PLI callbacks map to those regions.

Hardware Model Execution (§14.1)

A SystemVerilog description is a set of concurrent processes. Each process has state and responds to changes in its inputs to produce outputs. Processes include:

  • initial, always, always_comb, always_latch, always_ff blocks
  • Continuous assignments (assign)
  • Gate primitives
  • Tasks called asynchronously
  • Program blocks and their threads

Every change in state of a net or variable is an update event. Processes sensitive to that event are triggered to evaluate — this evaluation is itself an evaluation event. Evaluation events may produce further update events, forming a chain that runs until the time slot is quiescent.

Why semantics matter for testbench writers. The ordering of evaluation and update events within a single time step determines whether your testbench samples “before” or “after” a clock edge, and whether your assertions see clean or glitching values. Understanding the scheduler turns vague “race condition” bugs into predictable, fixable problems.

🕐 Event Simulation (§14.2)

SystemVerilog uses a discrete event simulation model. Simulation time advances in steps — a time slot is the collection of all events scheduled at a specific simulation time. The simulator never goes backward in time.

  • All events at time T form the time slot for T.
  • The simulator processes the current time slot completely before advancing to the next non-empty time slot.
  • Within a time slot, events are processed in region order (described below), not in an arbitrary global order.
  • Processes within the same region can execute in any order — determinism is guaranteed only between regions.
Intra-region ordering is non-deterministic. Two blocking assignments in the same Active region may execute in either order — the simulator is free to choose. This is why race-condition-free RTL requires non-blocking assignments for registered signals and careful placement of testbench code in the correct region.

📋 The Stratified Event Scheduler (§14.3)

To provide predictable design-testbench interaction, each time slot is divided into eleven ordered regions. Events can only be scheduled forward — either into a later region in the same time slot (moving right in the diagram) or into a future time slot.

The scheduler works through the regions in order. When it finds a non-empty region, it executes all events there. Some executions may produce new events in the same or a later region of the same time slot, requiring another pass through the active regions. This is the iterative loop.

🔄 The Eleven Time-Slot Regions

1
Preponed
PLI read-only access before any value changes. Conceptually where #1step sampling occurs — signals have their values from the previous time step.
PLI
2
Pre-active
PLI callback point. User code can read/write values and create events before the Active region begins. New in SV 3.1.
PLI
3
Active
Blocking assignments, evaluation of continuous assignments, gate primitives, module-level code. Can execute in any order — the main RTL evaluation region.
ITERATIVE
4
Inactive
Events from explicit #0 delays in the current time step. Processed after all Active events complete.
ITERATIVE
5
Pre-NBA
PLI callback before NBA updates. User code can read/write before NBA assignments commit. New in SV 3.1.
PLI
6
NBA
Non-blocking assignment updates commit here. All RHS values sampled in Active; LHS written here ensuring all processes see consistent values.
ITERATIVE
7
Post-NBA
PLI callback after NBA updates. User code can read/write/create events after NBA region completes. New in SV 3.1.
PLI
8
Observed
Property expressions (assertions) are evaluated here. Design is stable — no more RTL changes will happen in this pass. New in SV 3.1.
SV NEW
9
Post-observed
PLI read-only callback after property evaluation. New in SV 3.1 for PLI support of assertion results.
PLI
10
Reactive
Program block code and assertion pass/fail actions execute here. Testbench reacts to the stable, post-assertion design state. New in SV 3.1.
SV NEW
11
Postponed
Monitoring only. $monitor, $strobe, and read-only PLI. No new value changes allowed — time slot ends here.
PLI

SV NEW = new regions added in SystemVerilog 3.1 • PLI = primary purpose is PLI callback support • ITERATIVE = part of the iterative loop

📌 Region Details

Active region — where RTL lives

Most simulation activity happens here: blocking assignments, gate evaluation, continuous assignment updates. The order of execution within the Active region is non-deterministic — the simulator may process events in any order. New Active events can be created during Active processing, requiring re-entry into the Active region.

Inactive region — explicit #0

When code contains #0, the process is suspended and an event is placed in the Inactive region. It will resume after all currently-Active events finish. This is a way to explicitly “yield” to let other Active events run first.

// #0 schedules into Inactive — runs after all current Active events
always @(posedge clk) begin
  #0;         // yield: run after all posedge-clk Active events complete
  do_check();
end

NBA region — where <= commits

All non-blocking assignment right-hand sides are sampled in the Active region when the statement executes. The actual update to the left-hand side variable is deferred to the NBA region. This guarantees that a block of non-blocking assignments all read the old values and all write the new values simultaneously — the cornerstone of correct flip-flop modelling.

// Both sampled in Active (old values), both written in NBA (simultaneously)
always_ff @(posedge clk) begin
  a <= b;    // RHS sampled: current b. Update deferred to NBA.
  b <= a;    // RHS sampled: current a. Update deferred to NBA.
             // Effect: a and b swap — correct pipeline behaviour.
end

Observed region — where assertions evaluate

After all RTL has settled (Active, Inactive, and NBA have all completed for this pass), property expressions are evaluated in the Observed region. Because the design is stable at this point, assertions always see clean, non-glitching values. This is the key reason assertions use the clocking block’s #1step sampling — it samples from the Preponed region (before any Active events) to capture the steady state before the clock edge.

Reactive region — where testbench code runs

Program block code and pass/fail actions from assertions execute here. The testbench sees the design in its post-assertion stable state. This ensures testbench stimulus and checks do not interfere with ongoing RTL evaluation — they always run after the design has settled.

Postponed region — monitoring only

This is the final region of the time slot. After the Postponed region, no more events can be scheduled for the current time — the slot ends. $monitor and $strobe display values here. Writing to any net or variable in the Postponed region is illegal.

🔂 Iterative Regions and the Execution Loop

The iterative regions — Active, Inactive, Pre-NBA, NBA, Post-NBA, Observed, Post-observed, and Reactive — can all produce new events that require re-processing. The scheduler loops through them repeatedly until all iterative regions are empty.

The scan rule: After completing Active processing, the scheduler scans the iterative regions in order. It moves events from the first non-empty region into the Active region and restarts. This continues until no iterative region has any events remaining. Then Postponed executes and the time slot ends.

What each region produces

RegionWhat can create events hereWhat new events go into
ActiveBlocking assigns, gate/continuous assign, function callsActive (more blocking), Inactive (#0), NBA (<=)
Inactive#0 deferred eventsActive (on next scan)
NBANon-blocking assignment updatesActive (triggers sensitive processes)
ObservedProperty evaluation trigger (clocking block)Reactive (pass/fail code)
ReactiveProgram block code, assertion pass/fail actionsActive (if new events generated by testbench)
Why program blocks run in Reactive, not Active: If testbench code ran in the Active region alongside RTL, it could interfere with ongoing RTL evaluation in the same time step. By running in Reactive (after Observed), the testbench always sees a stable, post-assertion view of the design. It can then inject new stimulus into Active for the next pass, maintaining clean separation between design and verification code.

📄 Reference Simulation Algorithm (§14.3.1)

The specification defines this pseudocode algorithm. All compliant simulators must produce user-visible results consistent with it (though they may use different internal algorithms for efficiency).

execute_simulation {
  T = 0;
  initialize values of all nets and variables;
  schedule all initialization events into time 0 slot;
  while (some time slot is non-empty) {
    move to next future non-empty time slot, set T;
    execute_time_slot(T);
  }
}

execute_time_slot {
  execute_region(Preponed);
  while (some iterative region is non-empty) {
    execute_region(Active);
    scan iterative regions in order {
      if (region is non-empty) {
        move events to Active;
        break;               // restart the while loop
      }
    }
  }
  execute_region(Postponed);
}

execute_region {
  while (region is non-empty) {
    E = any event from region;
    remove E from region;
    if (E is an update event) {
      update the modified object;
      evaluate sensitive processes and schedule further events;
    } else {   // evaluation event
      evaluate the process and schedule further events;
    }
  }
}
Key insight from the algorithm: Preponed and Postponed are outside the iterative while-loop — they run exactly once per time slot, at the beginning and end respectively. All eleven iterative regions between them can cycle multiple times until the design settles. This structure guarantees that monitoring (Postponed) always sees the final, stable values for the time step.

🔗 PLI Callback Control Points (§14.4)

The Programming Language Interface (PLI) allows external C/C++ code to interact with the simulator. PLI callbacks are registered as events associated with a specific (time, region) tuple. SystemVerilog maps existing Verilog PLI callbacks to explicit regions and adds new callback points.

PLI CallbackRegionWhat it enables
cbAtStartOfSimTime
cbNextSimTime
cbAfterDelay
Pre-activeRead/write and create events before Active begins in the current time slot
tf_synchronize
tf_isynchronize
cbNBASynch
Pre-NBARead/write before non-blocking updates commit
cbReadWriteSynchPost-NBARead/write after NBA updates have committed
tf_rosynchronize
tf_irosynchronize
cbReadOnlySynch
cbAtEndOfSimTime
PostponedRead-only access to final stable values in the time slot
Two kinds of PLI callbacks: Immediate callbacks execute as soon as specific activity occurs (e.g. signal value change). Registered callbacks are one-shot events explicitly placed at a (time, region) point. Any region can receive an explicit PLI callback event.

📋 Quick Reference

Eleven regions at a glance

#RegionSV new?Key role
1PreponedPLI read-only; #1step sampling conceptually here
2Pre-activeNewPLI read/write before Active
3ActiveRTL evaluation — blocking assigns, gates, continuous
4Inactive#0 deferred events
5Pre-NBANewPLI read/write before NBA
6NBANon-blocking assignment updates commit
7Post-NBANewPLI read/write after NBA
8ObservedNewProperty/assertion evaluation on stable design
9Post-observedNewPLI read-only after assertions
10ReactiveNewProgram block + assertion pass/fail code
11Postponed$monitor/$strobe; read-only; no new value changes

Rules to remember

  • Preponed and Postponed run exactly once per time slot — outside the iterative loop.
  • Active, Inactive, Pre-NBA, NBA, Post-NBA, Observed, Post-observed, and Reactive are iterative — they repeat until all are empty.
  • Within any single region, event execution order is non-deterministic.
  • Non-blocking assignment RHS is sampled in Active; the LHS update fires in NBA.
  • Writing to any net or variable in the Postponed region is illegal.
  • Program block code runs in Reactive — always after RTL has settled and assertions have fired.
  • #1step sampling is conceptually equivalent to sampling in the Preponed region (the signal’s value just before the clock edge).
Coming next: SV-15 covers Section 15 — Clocking Blocks: clocking block declaration, input/output skew, #1step sampling, hierarchical expressions, signals in multiple clocking blocks, and the two-clocking-block example.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top