Part 7 · Environment & Tests · Intermediate
Env-Owned Virtual Sequencer: Lifecycle and Reuse Discipline
Own virtual sequencer lifecycle in env for repeatable build/connect behavior and easy reuse across test classes.
Why Env Ownership
Env ownership ensures one canonical construction path. Tests remain policy-focused and cannot accidentally diverge infrastructure setup.
[TEST][UVM][ENV] ownership tradeoff
test-owned v_sqr:
many construction variants
repeated boilerplate
inconsistent diagnostics
env-owned v_sqr:
one lifecycle contract
one mapping location
one health-report pathclass soc_env extends uvm_env;
`uvm_component_utils(soc_env)
soc_virtual_sequencer v_sqr;
apb_agent apb_agt;
axi_agent axi_agt;
irq_agent irq_agt;
function void build_phase(uvm_phase phase);
super.build_phase(phase);
v_sqr = soc_virtual_sequencer::type_id::create("v_sqr", this);
apb_agt = apb_agent::type_id::create("apb_agt", this);
axi_agt = axi_agent::type_id::create("axi_agt", this);
irq_agt = irq_agent::type_id::create("irq_agt", this);
endfunction
endclassKey takeaways
Centralized ownership produces consistent startup behavior.
Tests stay thin and focus on scenario-level intent.
Reuse improves when infrastructure setup is not duplicated in tests.
Common pitfalls
Constructing v_sqr in individual tests.
Conditionally creating v_sqr based on scenario name.
Spreading sequencer mapping across multiple components.
Lifecycle Contract
[TEST][UVM] phase contract
build_phase:
create v_sqr and child agents
connect_phase:
map child sequencer handles
null inactive handles explicitly
end_of_elaboration:
enforce required-handle contract
run_phase:
tests start vseq on env.v_sqrfunction void connect_phase(uvm_phase phase);
super.connect_phase(phase);
v_sqr.apb_sqr_h = cfg.apb_active ? apb_agt.sqr : null;
v_sqr.axi_sqr_h = cfg.axi_active ? axi_agt.sqr : null;
v_sqr.irq_sqr_h = cfg.irq_active ? irq_agt.sqr : null;
endfunctionfunction void end_of_elaboration_phase(uvm_phase phase);
super.end_of_elaboration_phase(phase);
if (cfg.require_apb && v_sqr.apb_sqr_h == null)
`uvm_fatal("ENV_VSQR", "APB required but unmapped")
if (cfg.require_axi && v_sqr.axi_sqr_h == null)
`uvm_fatal("ENV_VSQR", "AXI required but unmapped")
endfunctionKeep lifecycle rules explicit and documented near env code.
Fail fast on required-handle mismatch.
Avoid runtime remapping unless deliberately designed and tested.
Applied Patterns
[TEST][UVM][ENV] env-owned v_sqr checklist
construction:
create once in env.build_phase
keep factory override-friendly
mapping:
connect_phase only
active/passive aware
clear null assignment for inactive handles
validation:
end_of_elaboration fatal checks
scenario-level optional checks in vseq.pre_start
observability:
startup handle map log
report_phase health summaryfunction void report_phase(uvm_phase phase);
`uvm_info("ENV_VSQR_MAP",
$sformatf("apb=%0d axi=%0d irq=%0d",
v_sqr.apb_sqr_h != null,
v_sqr.axi_sqr_h != null,
v_sqr.irq_sqr_h != null),
UVM_LOW)
endfunctionOne owner and one lifecycle avoid ambiguous startup behavior.
Explicit mapping logs cut triage time for null-handle failures.
Env ownership scales better as agents are added.