Part 2 · Phases & Lifecycle · Intermediate

run_phase & Objections: How Simulation Ends

Hub — the single common task phase, parallel execution, raise/drop mechanics, simulation-end triggers, canonical patterns, run vs runtime schedule, and run_phase debugging.

Overview

run_phase is the single common task phase where every component forks off in parallel — drivers drive, monitors sample, scoreboards compare, sequences run. Objections are the global reference count that decides when this phase (and therefore the simulation run) ends.

Master run_phase and objections together and most 'simulation hung' or 'instant pass with no activity' failures become straightforward to diagnose.

Sub-lessons in this topic

  1. run-phase-parallel — how every component's run_phase executes concurrently.

  2. raise-drop-basics — the objection reference count and API semantics.

  3. simulation-end-trigger — what happens when the count reaches zero.

  4. run-objections-pattern — canonical test, sequence, and background-traffic patterns.

  5. run-vs-runtime-schedule — choosing plain run_phase vs the 12 runtime sub-phases.

  6. run-phase-debug — tracing, watchdogs, and triage for stuck or premature end.

Architecture map

diagram
Legend: [PHASE] [RUN] [UVM]

[UVM] start_of_simulation completes (time 0)
   │
   ▼
[PHASE] run_phase begins — all components fork in parallel
   │
   ├─► [RUN] test raises objection (count 0  1)
   ├─► [RUN] driver.run_phase — forever loop
   ├─► [RUN] monitor.run_phase — sample bus
   ├─► [RUN] scoreboard.run_phase — compare queue
   └─► [RUN] sequence.start() — consumes time
   │
   ▼
[PHASE] last objection dropped (count  0)
   │
   ▼
[PHASE] extract  check  report  final
diagram
[PHASE][RUN] objection lifecycle

  raise  ──► count++  ──► phase stays alive
  drop   ──► count--  ──► phase ends when count == 0

  owner: usually the test or sequence that owns test duration
  rule:  raise BEFORE time-consuming work, drop AFTER (every exit path)

Key takeaways

  • run_phase is the only common task phase — all time-consuming activity happens here.

  • Objections are a global reference count; run_phase lives while count > 0.

  • Raise before work, drop after — including error and timeout branches.

  • Plain run_phase vs runtime sub-phases is a per-component choice, not both.

Common pitfalls

  • Forgetting to raise — run_phase ends at time 0 with no stimulus.

  • Raise without matching drop on an error path — simulation hangs forever.

  • Mixing run_phase and runtime sub-phases for the same activity in one component.

  • Debugging hangs without +UVM_OBJECTION_TRACE.