Part 2 · Phases & Lifecycle · Intermediate
run_phase Debug: Tracing, Watchdogs, and Hang Triage
Systematic debug for stuck simulations and premature ends — objection trace, convert2string, watchdog patterns, and a step-by-step triage runbook.
Two symptoms, one mechanism
Nearly all run_phase failures reduce to objection count problems — either too many raises (stuck) or too few raises (premature end). The debug toolkit targets the count directly.
[PHASE][RUN] triage decision tree
sim ends at ~0ns?
YES → nobody raised → add raise before stimulus
NO → sim hits timeout?
YES → count > 0 → find undropped objection
NO → sim ended correctly ✓Start with +UVM_OBJECTION_TRACE on every hang investigation.
Check sim time at end — 0ns vs timeout vs expected duration narrows cause.
Watchdog + convert2string pinpoints the stuck component.
Tool 1: +UVM_OBJECTION_TRACE
# Full objection trace
simv +UVM_OBJECTION_TRACE +UVM_VERBOSITY=UVM_HIGH
# Filter in log
grep -E "OBJTN|objection" sim.log | tail -50[PHASE] reading objection trace
RAISE base_test "main sequence" count=1
RAISE bg_seq "background traffic" count=2
DROP base_test "main sequence done" count=1
... sim hangs ...
last line shows count=1 → bg_seq never dropped
look for: last RAISE without matching DROPTrace shows component name, reason string, and running count.
The last few lines before timeout reveal the stuck objector.
Compare raise/drop pairs per component — mismatches are immediate suspects.
Tool 2: Watchdog with convert2string
class obj_watchdog extends uvm_component;
`uvm_component_utils(obj_watchdog)
time timeout_ns = 10_000_000;
task run_phase(uvm_phase phase);
#(timeout_ns * 1ns);
if (phase.phase_done.get_objection_count() > 0)
`uvm_error("WD", $sformatf(
"run_phase timeout — outstanding objections:\n%s",
phase.phase_done.convert2string()))
endtask
endclass
// Instantiate in test build_phase for debug runs
// obj_watchdog wd;
// wd = obj_watchdog::type_id::create("wd", this);[UVM][PHASE] watchdog output example
UVM_ERROR @ 10000000ns: WD
run_phase timeout — outstanding objections:
bg_traffic_seq @ bg_agent.sqr count=1 "background traffic"
→ inspect bg_traffic body() for missing post_body drop pathconvert2string lists every component still objecting with reason.
Watchdog does not fix the hang — it diagnoses before global timeout.
Disable watchdog in production regressions or set generous timeout.
Tool 3: Phase activity counters
class instrumented_test extends uvm_test;
int seq_items_sent, mon_samples, scb_compares;
task run_phase(uvm_phase phase);
fork super.run_phase(phase); join_none
phase.raise_objection(this, "instrumented run");
`uvm_info("RUN", "objection raised", UVM_LOW)
main_seq.start(env.v_sqr);
`uvm_info("RUN", $sformatf("sent=%0d mon=%0d scb=%0d",
seq_items_sent, mon_samples, scb_compares), UVM_LOW)
phase.drop_objection(this, "instrumented run done");
`uvm_info("RUN", "objection dropped", UVM_LOW)
endtask
endclass[PHASE][RUN] activity vs objection correlation
raised at 0ns, dropped at 0ns, sent=0 → sequence never ran (sqr issue?)
raised at 0ns, dropped at 500ns, sent=50, mon=0 → monitor not sampling
raised at 0ns, never dropped, sent=50 → drop path skipped (error branch?)Step-by-step triage runbook
Note sim end time: 0ns (no raise), timeout (no drop), or expected (OK).
Re-run with +UVM_OBJECTION_TRACE; find last unmatched RAISE.
Inspect that component's run_phase/sequence for all exit paths.
Check error/timeout branches — uvm_error does not auto-drop.
Verify super.run_phase was called in test/env/agent hierarchy.
For premature end: confirm raise_objection precedes any time-consuming call.
For stuck sim: grep component source for raise without drop in each branch.
Add watchdog + convert2string to pin exact stuck objector.
Key takeaways
Stuck sim = undropped objection; premature end = missing raise.
+UVM_OBJECTION_TRACE is the first tool for any run_phase hang.
convert2string in a watchdog identifies the exact stuck component.
Activity counters correlate objection timeline with actual stimulus flow.
Common pitfalls
Debugging with waveform alone — objection count is invisible in waves.
Removing watchdog after one fix — reintroduce on next hang.
Fixing by adding global timeout instead of finding the missing drop.
Assuming uvm_fatal auto-drops objections — it does not.