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
run-phase-parallel — how every component's run_phase executes concurrently.
raise-drop-basics — the objection reference count and API semantics.
simulation-end-trigger — what happens when the count reaches zero.
run-objections-pattern — canonical test, sequence, and background-traffic patterns.
run-vs-runtime-schedule — choosing plain run_phase vs the 12 runtime sub-phases.
run-phase-debug — tracing, watchdogs, and triage for stuck or premature end.
Architecture map
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[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.