Part 2 · Phases & Lifecycle · Intermediate
Reset, Configure, Main, Shutdown: The Four Groups
What belongs in each runtime group, canonical code for each phase, cross-agent coordination guarantees, and common misplacements.
RESET group: safe starting state
The reset group ensures every agent drives its interface to a safe idle state and waits for reset deassertion before any configuration or traffic begins.
class apb_driver extends uvm_driver #(apb_item);
task reset_phase(uvm_phase phase);
phase.raise_objection(this, "APB idle during reset");
vif.psel <= 0;
vif.penable <= 0;
vif.pwrite <= 0;
vif.paddr <= '0;
vif.pwdata <= '0;
@(negedge vif.preset_n); // wait for reset assert
@(posedge vif.preset_n); // wait for reset release
phase.drop_objection(this, "APB reset released");
endtask
endclass[PHASE][RUN] reset group coordination
Agent A reset_phase: drive idle, wait reset release ──► drop
Agent B reset_phase: drive idle, wait reset release ──► drop
Agent C reset_phase: drive idle, wait reset release ──► drop
│
▼ ALL drops → reset group done → configure group beginsreset_phase: drive safe idle, wait for reset deassertion.
post_reset_phase: optional settle delay after reset release.
All agents must drop reset objections before configure begins.
CONFIGURE group: DUT programming
The configure group is the natural home for register programming — typically via RAL frontdoor sequences:
class env extends uvm_env;
ral_block_my_dut regmodel;
task configure_phase(uvm_phase phase);
reg_cfg_seq cfg_seq;
phase.raise_objection(this, "register configuration");
cfg_seq = reg_cfg_seq::type_id::create("cfg_seq");
cfg_seq.regmodel = regmodel;
cfg_seq.start(reg_adapter_sequencer);
phase.drop_objection(this, "register configuration done");
endtask
endclass[PHASE][RUN] configure group flow
pre_configure: verify clocks/reset stable, check prerequisites
configure: RAL frontdoor writes, mode register setup
post_configure: wait N cycles for config to propagate
guarantee: NO main traffic until ALL agents finish configure groupconfigure_phase pairs naturally with UVM RAL frontdoor access.
post_configure_phase: add pipeline settle cycles if DUT needs them.
Never start stimulus in configure_phase — that belongs in main_phase.
MAIN group: primary stimulus
main_phase holds the bulk of verification activity — sequence execution, traffic generation, and active checking:
class axi_driver extends uvm_driver #(axi_item);
task main_phase(uvm_phase phase);
axi_item req;
phase.raise_objection(this, "AXI main traffic");
forever begin
seq_item_port.get_next_item(req);
drive_axi(req);
seq_item_port.item_done();
end
// real drivers drop via controlled stop, not unreachable code
endtask
endclass
class my_test extends uvm_test;
task main_phase(uvm_phase phase);
fork super.main_phase(phase); join_none
phase.raise_objection(this, "main virtual sequence");
main_vseq.start(env.v_sqr);
phase.drop_objection(this, "main vseq done");
endtask
endclass[RUN][PHASE] main group activity map
TEST: raise → start virtual sequence → drop
DRIVER: raise → forever get/drive loop (drop on stop)
MONITOR: sample bus (typically no objection — passive)
SCOREBOARD: compare queue (typically no objection — passive)
COVERAGE: sample coverage (passive)Test raises/drops for sequence duration; driver raises for its service loop.
Passive components (monitor, coverage) usually don't raise objections.
post_main_phase: stop accepting new sequences, signal wind-down.
SHUTDOWN group: graceful drain
The shutdown group ensures in-flight transactions complete before the runtime schedule ends and cleanup phases begin:
class axi_driver extends uvm_driver #(axi_item);
uvm_event stop_ev;
function void build_phase(uvm_phase phase);
super.build_phase(phase);
stop_ev = uvm_event_pool::get_global("stop_ev");
endfunction
task shutdown_phase(uvm_phase phase);
phase.raise_objection(this, "draining AXI");
stop_ev.trigger(); // tell main_phase loop to stop accepting
wait_for_inflight_complete(); // wait for outstanding bursts
drive_idle(); // return bus to safe state
phase.drop_objection(this, "AXI drained");
endtask
endclass[PHASE][RUN] shutdown sequence
post_main: stop accepting new sequences/items
pre_shutdown: signal agents to wind down
shutdown: drain in-flight, drive idle
post_shutdown: final settle cycles
│
▼ ALL drops → runtime schedule complete → extract_phaseKey takeaways
RESET: idle interfaces + wait reset release — all agents coordinated.
CONFIGURE: RAL/register programming — no traffic until all agents done.
MAIN: primary stimulus — test owns sequence duration objection.
SHUTDOWN: drain in-flight transactions — graceful stop before cleanup.
Common pitfalls
Stimulus in configure_phase — breaks 'config before traffic' guarantee.
Reset handling in run_phase while other agents use reset_phase — desync.
Skipping shutdown group — in-flight transactions lost at phase kill.
Driver forever loop in main_phase without stop mechanism — can't drain.