Part 2 · Phases & Lifecycle · Intermediate
Runtime Sub-Phase Use Cases: SoC, RAL, VIP, and Shutdown
Production scenarios where runtime sub-phases shine — multi-clock SoC bring-up, RAL configuration flows, reusable VIP lifecycle, and coordinated shutdown.
Use case 1: Multi-clock SoC bring-up
A SoC with multiple clock domains and a power-sequencing controller needs all agents to wait for their respective clocks before reset, and all to finish reset before configuration:
// CPU agent: wait for CPU clock
task pre_reset_phase(uvm_phase phase);
phase.raise_objection(this, "wait CPU clock");
wait (cpu_clk_stable);
phase.drop_objection(this, "CPU clock ready");
endtask
// DDR agent: wait for DDR clock (different timing)
task pre_reset_phase(uvm_phase phase);
phase.raise_objection(this, "wait DDR clock");
wait (ddr_clk_stable);
phase.drop_objection(this, "DDR clock ready");
endtask
// Both agents: reset_phase waits for shared SoC reset release
task reset_phase(uvm_phase phase);
phase.raise_objection(this, "SoC reset");
drive_idle();
wait (soc_reset_n === 1'b1);
phase.drop_objection(this, "SoC reset released");
endtask[PHASE][RUN] SoC bring-up timeline
pre_reset: CPU clk ready ──┐
pre_reset: DDR clk ready ──┤ parallel, both must drop
pre_reset: IO clk ready ──┘
│
reset: all agents idle + wait soc_reset_n (parallel)
│
post_reset: all agents settle N cycles (parallel)
│
configure: RAL programming begins (ONLY after reset group done)pre_reset handles per-domain clock readiness in parallel.
reset_phase synchronizes on shared reset release.
Cross-domain coordination is automatic via group objections.
Use case 2: RAL configuration flow
class soc_env extends uvm_env;
ral_block_soc regmodel;
reg2bus_adapter adapter;
task configure_phase(uvm_phase phase);
soc_cfg_seq cfg;
fork super.configure_phase(phase); join_none
phase.raise_objection(this, "SOC register config");
// Reset mirror to hardware reset values
regmodel.reset();
// Frontdoor configure via adapter
cfg = soc_cfg_seq::type_id::create("cfg");
cfg.regmodel = regmodel;
cfg.start(reg_sequencer);
// Verify critical mode bits
regmodel.ctrl.mode.read(status, .path(UVM_FRONTDOOR));
if (regmodel.ctrl.mode.get() != EXPECTED_MODE)
`uvm_error("CFG", "mode register mismatch after config")
phase.drop_objection(this, "SOC register config done");
endtask
endclass[PHASE][RUN][UVM] RAL configure flow
configure_phase:
regmodel.reset()
frontdoor writes (mode, clock enables, interrupt masks)
readback verify critical registers
drop → main_phase can begin trafficconfigure_phase is the canonical home for RAL frontdoor sequences.
regmodel.reset() in configure_phase establishes known mirror state.
Readback verify before main_phase catches config errors early.
Use case 3: Reusable VIP lifecycle
A reusable AXI VIP packages its lifecycle into runtime sub-phases so integrators get correct behavior without manual coordination:
class axi_vip_agent extends uvm_agent;
// VIP documents: override nothing in run_phase — use sub-phases
task reset_phase(uvm_phase phase);
phase.raise_objection(this, "AXI VIP reset");
drv.drive_reset_state();
mon.wait_reset_done();
phase.drop_objection(this, "AXI VIP reset done");
endtask
task configure_phase(uvm_phase phase);
phase.raise_objection(this, "AXI VIP config");
apply_cfg_to_vip(); // burst length, ID width, etc.
phase.drop_objection(this, "AXI VIP config done");
endtask
task main_phase(uvm_phase phase);
// default_sequence auto-starts traffic if configured
super.main_phase(phase);
endtask
task shutdown_phase(uvm_phase phase);
phase.raise_objection(this, "AXI VIP shutdown");
drv.drain_and_idle();
phase.drop_objection(this, "AXI VIP shutdown done");
endtask
endclass[UVM][PHASE] VIP integration contract
integrator env:
build: create axi_vip_agent, pass cfg via config_db
connect: wire analysis ports
(no run_phase override needed)
VIP handles: reset → configure → main → shutdown internallyVIP runtime sub-phases are the integration contract — integrator stays thin.
Document which phases the VIP overrides and which it expects from the env.
shutdown_phase in VIP ensures clean bus state for next test or power-down.
Use case 4: Coordinated multi-interface shutdown
class soc_test extends uvm_test;
task post_main_phase(uvm_phase phase);
phase.raise_objection(this, "stop all traffic");
global_stop_ev.trigger();
#(cfg.post_main_drain_ns);
phase.drop_objection(this, "traffic stopped");
endtask
endclass
// Each agent drains in shutdown_phase
class generic_agent extends uvm_agent;
task shutdown_phase(uvm_phase phase);
phase.raise_objection(this, "drain");
wait (drv.inflight_count == 0);
wait (mon.pipeline_empty);
drv.drive_idle();
phase.drop_objection(this, "drained");
endtask
endclass[PHASE][RUN] coordinated shutdown
post_main: global stop event + drain delay
pre_shutdown: verify no new items accepted
shutdown: each agent drains inflight (parallel)
post_shutdown: verify all interfaces idle
│
▼ clean state → extract_phaseKey takeaways
SoC bring-up: pre_reset per clock domain, reset_phase for shared reset sync.
RAL configuration belongs in configure_phase with readback verify.
VIP sub-phases are the reusable integration contract for integrators.
Coordinated shutdown via events + shutdown_phase prevents truncated transactions.
Common pitfalls
RAL config in test run_phase while agents use configure_phase — ordering race.
VIP that only implements main_phase — integrator must handle reset manually.
Shutdown without inflight counter — drain completes before transactions finish.
Different drain times per agent — fastest agent drops while others still busy.