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.

diagram
[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

bash
# Full objection trace
simv +UVM_OBJECTION_TRACE +UVM_VERBOSITY=UVM_HIGH

# Filter in log
grep -E "OBJTN|objection" sim.log | tail -50
diagram
[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 DROP
  • Trace 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

systemverilog
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);
diagram
[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 path
  • convert2string 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

systemverilog
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
diagram
[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

  1. Note sim end time: 0ns (no raise), timeout (no drop), or expected (OK).

  2. Re-run with +UVM_OBJECTION_TRACE; find last unmatched RAISE.

  3. Inspect that component's run_phase/sequence for all exit paths.

  4. Check error/timeout branches — uvm_error does not auto-drop.

  5. Verify super.run_phase was called in test/env/agent hierarchy.

  6. For premature end: confirm raise_objection precedes any time-consuming call.

  7. For stuck sim: grep component source for raise without drop in each branch.

  8. 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.