Part 2 · Phases & Lifecycle · Intermediate
Objection Hierarchy Propagation: Up the Component Tree
How a raise at a leaf component propagates to the phase root, what total vs source count means, and propagation implications for debug.
Raises propagate upward
When a component calls phase.raise_objection(this, desc), UVM increments the objection count not only for that component but propagates the raise up through its parent chain — agent → env → test — until it reaches the phase root objection.
[PHASE][UVM] propagation chain
driver.raise(this, "driving")
│
▼
agent (agent's total count now includes driver's objection)
│
▼
env (env's total count includes agent's)
│
▼
test (test's total count includes env's)
│
▼
phase root (global count for this phase)
phase ends ONLY when phase root count = 0Every raise at any hierarchy level contributes to the same phase root count.
The caller argument (this) identifies the source component for tracing.
Parents don't need to raise separately — child raises propagate automatically.
Source count vs total count
UVM tracks two counts per component: source count (raises made directly by this component) and total count (includes all descendants' propagated raises).
// driver raises directly
driver.raise_objection(this, "driving"); // driver source=1, total=1
// agent source=0, total=1
// env source=0, total=1
// agent ALSO raises directly
agent.raise_objection(this, "agent active"); // driver source=1, total=1
// agent source=1, total=2
// env source=0, total=2
// driver drops
driver.drop_objection(this, "driving"); // driver source=0, total=0
// agent source=1, total=1 ← still alive!
// env source=0, total=1[PHASE][UVM] source vs total
source count: raises/drops made BY this component directly
total count: source + all children's propagated counts
phase root total count = sum of all source counts in tree
phase ends when root total = 0A child drop does NOT end the phase if parent or sibling still objects.
convert2string() shows source components with outstanding objections.
set() can set source count directly — advanced, use with caution.
Propagation and the component tree
// Typical testbench hierarchy
// test
// └── env
// ├── axi_agent
// │ ├── driver
// │ └── monitor
// ├── apb_agent
// │ ├── driver
// │ └── monitor
// └── scoreboard
// Only test and sequences typically raise top-level objections
class my_test extends uvm_test;
task run_phase(uvm_phase phase);
fork super.run_phase(phase); join_none
phase.raise_objection(this, "test duration"); // propagates: test→root
main_seq.start(env.v_sqr);
phase.drop_objection(this, "test done");
endtask
endclass
// Driver does NOT raise — it's a forever loop killed at phase end
class my_driver extends uvm_driver #(item_t);
task run_phase(uvm_phase phase);
forever begin
seq_item_port.get_next_item(req);
drive(req);
seq_item_port.item_done();
end
endtask
endclass[PHASE][RUN] who should raise?
SHOULD raise: test, sequences (pre_body/post_body), phase-specific tasks
should NOT: driver forever loop, monitor forever loop, passive scoreboard
MAY raise: env (for config sequences), agent (for sub-phase activity)
rule: the component that owns DURATION raisesTest/sequence owns duration — clearest propagation path.
Drivers/monitors as forever loops don't need objections.
Env/agent raises only when they own a bounded task (config, reset).
Debug implications of propagation
When reading +UVM_OBJECTION_TRACE, the count shown is the phase root total. convert2string() walks the tree and shows which source components still have non-zero source counts.
[PHASE][UVM] trace interpretation
OBJTN RAISE my_test "main seq" count=1
→ source: my_test (source=1)
→ root total=1
OBJTN RAISE bg_seq "bg traffic" count=2
→ source: bg_seq (source=1), my_test (source=1)
→ root total=2
OBJTN DROP my_test "main done" count=1
→ source: bg_seq (source=1) only
→ root total=1 ← phase STILL alive
look for source components with count > 0 in convert2string()// Dump full objection tree
`uvm_info("OBJ", phase.phase_done.convert2string(), UVM_LOW)
// Output shows hierarchy:
// my_test: source=0 total=0
// env: source=0 total=0
// bg_agent.sqr.bg_seq: source=1 total=1 ← culpritKey takeaways
Raises propagate up the parent chain to the phase root objection.
Phase ends when root total count reaches zero — not when any single component drops.
Source count = direct raises; total count = source + descendants.
convert2string() reveals the exact source component blocking phase end.
Common pitfalls
Dropping at child level expecting phase to end — parent/sibling may still object.
Raising in driver 'just to keep sim alive' — unclear ownership, messy traces.
Misreading trace count as per-component instead of global root total.
Deep hierarchy without clear duration owner — multiple unrelated raisers.