Part 2 · Phases & Lifecycle · Intermediate

Phase Method Debug: Finding Silent Override and Type Bugs

Systematic workflow for phase method bugs — signature verification, super audit, function-vs-task placement, and trace-driven triage.

Triage order for 'my phase code did not run'

  1. Verify exact method name ends with _phase.

  2. Verify return kind: function void vs task.

  3. Verify uvm_phase phase argument present.

  4. Verify super.<phase>_phase(phase) called.

  5. Verify +UVM_PHASE_TRACE shows entry.

  6. Only then debug functional logic inside the callback.

diagram
[UVM][PHASE] method debug flowchart

symptom: expected code never runs
  -> signature match? NO -> fix name/type/arg
  -> super called? NO -> add super
  -> trace shows phase? NO -> override not registered / wrong type
  -> YES -> logic bug inside callback

symptom: hang in run
  -> objection trace
  -> fork join completeness

symptom: compile error on override
  -> function vs task mismatch
systemverilog
function void build_phase(uvm_phase phase);
  `uvm_info("PH_DBG", $sformatf("%s::build_phase", get_type_name()), UVM_NONE)
  super.build_phase(phase);
endfunction

Key takeaways

  • Method bugs cluster at signature and super — check those first.

  • PH_DBG entry print is the cheapest override verification.

  • Phase trace confirms scheduler actually invoked your callback.

Common pitfalls

  • Rewriting functional logic while override never ran.

  • Enabling full UVM_FULL verbosity before signature proof.

  • Fixing waves while build_phase override is misspelled.


Function-vs-task placement audit

Illegal time control scan

Search function phases for #, @, wait, and

blocking TLM. Any hit is a methodology violation to relocate to run_phase.

systemverilog
// WRONG — time in function phase
function void start_of_simulation_phase(uvm_phase phase);
  super.start_of_simulation_phase(phase);
  @(posedge vif.rst_n); // MOVE to run_phase
endfunction

// RIGHT
task run_phase(uvm_phase phase);
  super.run_phase(phase);
  @(posedge vif.rst_n);
  phase.raise_objection(this, "post-reset");
  seq.start(sqr);
  phase.drop_objection(this, "done");
endtask

Lint-style review checklist

  • Every function phase: super first, no time statements.

  • run_phase: super, raise, work, drop on all paths.

  • No objections outside task phases.

  • Sequence start only in task phases.

diagram
[PHASE] CI-friendly static checks (manual or scripted)

grep function phases for "@(posedge" -> must be empty
grep build_phase for "#" -> must be empty
grep run_phase for "raise_objection" without "drop_objection" -> review
grep for "function void run_phase" -> must be empty

Regression artifact

systemverilog
function void report_phase(uvm_phase phase);
  super.report_phase(phase);
  `uvm_info("PHASE_AUDIT",
    $sformatf("type=%s super_ok=1 sig_ok=1", get_type_name()), UVM_NONE)
endfunction

Key takeaways

  • Placement audit catches #delay-in-build before it reaches silicon TB bring-up.

  • Simple greps are high leverage for large VIP repos.

  • PHASE_AUDIT report lines document override health per regression.

Common pitfalls

  • Disabling audit logs in CI to reduce noise — keep UVM_NONE one-liners.

  • Moving time control to run_phase without objections — early end risk.

  • Fixing signature but leaving illegal time control in another phase.