Difficulty: Hard · Puzzle 5 of 6 · Topic: UVM Phases and Objections
UVM 1.2. The DUT answers up to 200 ns after the last request. The scoreboard tries to keep the run phase open until its pending queue is empty by using phase_ready_to_end, but the run still ends with 'pending at end' errors. Find the defect.
class my_sb extends uvm_scoreboard;
`uvm_component_utils(my_sb)
txn pending[$];
function new(string name, uvm_component parent); super.new(name, parent); endfunction
function void phase_ready_to_end(uvm_phase phase);
if (phase.get_name() != "run_phase") return;
if (pending.size() > 0) begin
phase.raise_objection(this, "draining scoreboard");
fork begin
wait (pending.size() == 0);
phase.drop_objection(this);
end join_none
end
endfunction
function void check_phase(uvm_phase phase);
if (pending.size() > 0) `uvm_error("SB", "pending at end")
endfunction
endclassThe mechanism (raise inside the callback, drop later from a forked process) is fine. Look at the very first line of the callback.
1) UVM calls phase_ready_to_end on every component when a phase's objection count reaches zero (after the drain time), for run and for each runtime sub-phase that uses objections.
2) Built-in phase names do not carry the `_phase` suffix: the run phase's `get_name()` is "run".
3) The guard compares with "run_phase", is always true, and the callback returns immediately, so the objection is never raised and the phase ends with items still pending.
4) Fix: compare with "run" (or compare `phase.get_imp()` with `uvm_run_phase::get()`). The fork/join_none is required because the callback is a function and cannot block.Answer: The guard `phase.get_name() != "run_phase"` is always true because the phase name is "run"; the callback returns early, never raises the objection.
Not run here: The UVM library is not installed here, so this cannot be executed; phase_ready_to_end, phase names and the objection machinery are UVM library internals; no plain-SV stand-in could show the name-mismatch honestly.. The answer follows the language rules and the solution steps above.
Phase names drop the suffix ("run", "build", "main"), so a name test written with `_phase` silently never matches and you get no warning, just a callback that does nothing.
Why is the guard needed at all, and what extra problem does an unguarded callback cause? Model answer: the callback is invoked for every objection-using phase of every component, not just run; unguarded, the scoreboard would also raise objections in the runtime sub-phases (main, shutdown, ...) when pending is non-empty at those boundaries, holding phases open for a condition that only means something at the end of the run.