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

  1. Objection Propagation Tree — how raises and drops flow from leaf components to the phase root.

  2. Raise/Drop Discipline — matched patterns for tests, sequences, and asynchronous work.

  3. set_drain_time — handling trailing monitor/checker activity after the last drop.

  4. phase_ready_to_end — conditional extension when scoreboards or FIFOs are still draining.

  5. Debugging Hung Phases — +UVM_OBJECTION_TRACE and a deterministic triage playbook.

  6. Objections Best Practices — phase-type matrix and team conventions for scalable regressions.

End-of-phase control flow

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

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

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

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