Part 2 · Phases & Lifecycle · Intermediate
Super-Call Discipline: super.phase(phase) Every Time
Why super.build_phase(phase) and friends are mandatory, what base-class work they perform, and ordering conventions for super-first vs super-last.
What super calls do
Calling super.<phase>_phase(phase) executes base-class implementation — field automation hooks, registered callbacks, and internal UVM bookkeeping. Skipping it is a silent correctness bug.
super.build_phase triggers config and child phase registration logic.
super.connect_phase may complete automated connections.
super.run_phase participates in objection and phase state machinery.
super.report_phase contributes to global report summary.
[UVM][PHASE] super call impact
without super.build:
- factory automation may not run
- callback registration missed
without super.run:
- library run scaffolding skipped
without super.report:
- aggregated report incompleteKey takeaways
super is not ceremonial — it is functional base-class behavior.
Missing super is silent until something subtle breaks later.
Default convention: super first in function phases unless documented otherwise.
Common pitfalls
Removing super to 'avoid double create' — fix duplicate logic instead.
Never calling super in intermediate abstract base classes.
Calling super twice — usually indicates copy/paste error.
Ordering conventions
Function phases: super first (default)
function void build_phase(uvm_phase phase);
super.build_phase(phase);
// now safe to create children and get config
mon = my_monitor::type_id::create("mon", this);
endfunction
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
mon.ap.connect(scb.imp);
endfunctionWhen super-last is intentional
Rarely, a child wants parent cleanup after child work — e.g. super.report_phase after local detail prints. Document super-last explicitly in class comments.
function void report_phase(uvm_phase phase);
`uvm_info("RPT", $sformatf("local_errors=%0d", local_errs), UVM_LOW)
super.report_phase(phase); // parent aggregates after local detail
endfunctionInheritance chains
[PHASE] three-level chain
base_agent.build -> mid_agent.build -> axi_agent.build
each level:
super.build_phase(phase); // calls immediate parent
// then level-specific work
omitting super in mid_agent breaks chain for axi_agent subtreeclass mid_agent extends base_agent;
function void build_phase(uvm_phase phase);
super.build_phase(phase);
cfg = agent_cfg::type_id::create("cfg");
endfunction
endclass
class axi_agent extends mid_agent;
function void build_phase(uvm_phase phase);
super.build_phase(phase); // must include mid_agent + base_agent work
drv = axi_driver::type_id::create("drv", this);
endfunction
endclassKey takeaways
super propagates up the inheritance chain one level per call.
Every class in the hierarchy must call super unless it is uvm_component itself.
super-last is exceptional — comment why when used.
Common pitfalls
Abstract base with pure virtual build and no super — breaks children.
Mixin-style multiple inheritance workarounds that skip super.
Assuming macro utils replaces super — it does not.