Part 10 · Advanced Topics · Intermediate
Objection Hierarchy & Phase Completion
Hub — objection propagation tree, raise/drop discipline, drain time, phase_ready_to_end, hung-phase debug, and production best practices.
Overview
In UVM, objections are the liveness protocol for task-based phases. They answer a simple question: does any component still have meaningful work to do? If yes, keep the phase running. If no, end the phase and move on.
Engineers often memorize raise/drop as boilerplate and still lose days debugging hung runs, premature phase ends, or regressions slowed by oversized drain delays. This topic is about building a precise mental model: where counts live, how they propagate up the hierarchy, how delayed phase completion works, and how to debug failures quickly.
Treat the diagram below as the map for all six sub-lessons. Each lesson expands one branch of this lifecycle.
Lessons in this topic
Objection Propagation Tree — how raises and drops flow from leaf components to the phase root.
Raise/Drop Discipline — matched patterns for tests, sequences, and asynchronous work.
set_drain_time — handling trailing monitor/checker activity after the last drop.
phase_ready_to_end — conditional extension when scoreboards or FIFOs are still draining.
Debugging Hung Phases — +UVM_OBJECTION_TRACE and a deterministic triage playbook.
Objections Best Practices — phase-type matrix and team conventions for scalable regressions.
End-of-phase control flow
[UVM] objection lifecycle (run_phase shown)
leaf component / sequence starts work
│
├─► phase.raise_objection(this, "reason")
│ local_count[source]++
│ total_count++
│ propagate to parent ... up to phase root
│
├─► time passes while stimulus/checking run
│
└─► phase.drop_objection(this, "done")
local_count[source]--
total_count--
propagate drop to parent ... up to phase root
At root:
if total_count != 0 → phase remains active
if total_count == 0 → start drain window (optional)
then consult phase_ready_to_end hooks
then end phaseNotice that objections are counted by source and by aggregate count. A single forgotten drop from any source keeps the aggregate count non-zero and blocks phase completion for the entire environment.
[CHECK] common failure classes
HANG:
unmatched raise, blocked fork branch, or conditional drop never reached
EARLY END:
objection dropped before scoreboard/monitor sees final activity
SLOW REGRESSION:
drain_time too large, multiplied by every test in nightly farm
SILENT DATA LOSS:
run ends "cleanly" while pending expected items still in scoreboardKey takeaways
Objections are phase liveness control, not optional boilerplate.
Counts propagate up hierarchy; one missed drop at a leaf blocks the root.
drain_time and phase_ready_to_end are separate tools: fixed delay vs conditional hold.
A deterministic debug routine beats waveform guessing on hung tests.
Common pitfalls
Treating objections as 'raise at top, drop at bottom' without source-level reasoning.
Using drain_time to mask logic bugs instead of fixing root cause.
Dropping objection before passive checkers finish consuming traffic.