Part 7 · Environment & Tests · Intermediate

phase_ready_to_end: Gate Closure on True Quiescence

Use phase readiness checks to hold phase closure until scoreboards and analysis pipelines are empty, then release deterministically.

Why readiness hooks matter

Objections signal intent, but intent is not always equivalent to completed checking. phase_ready_to_end hooks let components delay phase ending briefly until internal pipelines are quiescent.

diagram
[UVM][ENV] intent vs completion

objection dropped:
  "I am done generating"

ready_to_end true:
  "all required observation/checking work is done"

both are needed for robust closure
diagram
[CHECK] typical readiness conditions

- expected queue empty
- actual queue empty
- no in-flight predictor transaction
- no deferred compare task pending
  • Use readiness for bounded tail completion, not indefinite waits.

  • Keep conditions objective and measurable via counters/queues.

  • Document which component owns each readiness condition.


Scoreboard readiness implementation

systemverilog
class my_scoreboard extends uvm_scoreboard;
  `uvm_component_utils(my_scoreboard)
  my_txn exp_q[$];
  my_txn act_q[$];
  int unsigned inflight_pairs;

  function bit is_quiescent();
    return (exp_q.size() == 0) &&
           (act_q.size() == 0) &&
           (inflight_pairs == 0);
  endfunction

  task wait_quiescent_or_timeout(time limit);
    time start_t = $time;
    while (!is_quiescent()) begin
      if (($time - start_t) >= limit) begin
        `uvm_error("READY_END",
          $sformatf("not quiescent in %0t exp=%0d act=%0d in_flight=%0d",
            limit, exp_q.size(), act_q.size(), inflight_pairs))
        return;
      end
      #10ns;
    end
  endtask

  task phase_ready_to_end(uvm_phase phase);
    if (phase.get_name() == "run")
      wait_quiescent_or_timeout(500ns);
  endtask
endclass
systemverilog
task phase_ready_to_end(uvm_phase phase);
  if (phase.get_name() != "run")
    return;
  if (!env.sb.is_quiescent())
    env.sb.wait_quiescent_or_timeout(500ns);
endtask
diagram
[UVM][ENV] bounded readiness contract

ready_to_end may delay
but must not hang forever

always include local timeout and counters in error message
  • Bound readiness waits with component-local timeout.

  • Emit queue/counter state on readiness failure.

  • Keep readiness logic deterministic and side-effect free.


Coordination with objections and drain

Interaction model

  1. Test drops objection when stimulus generation is complete.

  2. Drain time permits passive tail activity window.

  3. ready_to_end verifies tail activity actually converged.

  4. Global timeout remains ultimate protection for non-converging runs.

diagram
[UVM] layered closure stack

Layer 1: objection lifecycle (ownership)
Layer 2: drain_time window (latency allowance)
Layer 3: ready_to_end (quiescence proof)
Layer 4: global timeout (safety net)
diagram
[ENV] when to avoid ready_to_end

- if component has no tail work and no queues
- if condition depends on unbounded external behavior
- if used to hide design deadlock rather than detect it

Key takeaways

  • phase_ready_to_end turns end-of-test intent into measurable completion.

  • Use bounded waits with precise diagnostics to avoid silent hangs.

  • Readiness complements objections and drain, it does not replace them.

  • Layered closure architecture is robust under stress regressions.

Common pitfalls

  • Unbounded ready_to_end wait that becomes another hang source.

  • Readiness checks that mutate state and create heisenbugs.

  • Assuming empty one queue implies full-system quiescence.

  • Using ready_to_end to hide structural checker backlog bugs.