Part 2 · Phases & Lifecycle · Intermediate
Runtime Sequencer Order: Starting Sequences Across Phases
Which sequencer starts sequences in which phase, default_sequence automation, phase-aware sequence launch, and stopping sequences at group boundaries.
Sequences belong to specific runtime phases
When using runtime sub-phases, sequences should start in the appropriate phase — reset sequences in reset_phase, config sequences in configure_phase, traffic sequences in main_phase. The starting_phase handle tells the sequence which phase context it runs under.
[PHASE][RUN][UVM] sequence-to-phase mapping
reset_phase: reset_seq (hold idle, wait release)
configure_phase: reg_cfg_seq (RAL frontdoor writes)
main_phase: traffic_seq, virtual_seq (stimulus)
shutdown_phase: drain_seq (optional graceful stop)
starting_phase = the phase handle active when sequence.start() is calledSequence starting_phase determines which phase's objections it affects.
pre_body/post_body raise/drop against starting_phase automatically.
Starting a sequence in the wrong phase raises objections against the wrong counter.
Manual sequence start in phase tasks
class my_test extends uvm_test;
task configure_phase(uvm_phase phase);
reg_cfg_seq cfg;
fork super.configure_phase(phase); join_none
phase.raise_objection(this, "register config");
cfg = reg_cfg_seq::type_id::create("cfg");
cfg.regmodel = env.regmodel;
cfg.start(env.reg_sqr); // starting_phase = configure_phase
phase.drop_objection(this, "register config done");
endtask
task main_phase(uvm_phase phase);
traffic_vseq tvseq;
fork super.main_phase(phase); join_none
phase.raise_objection(this, "main traffic");
tvseq = traffic_vseq::type_id::create("tvseq");
tvseq.start(env.v_sqr); // starting_phase = main_phase
phase.drop_objection(this, "main traffic done");
endtask
endclass[RUN] sequence launch timeline
configure_phase:
test raises → cfg.start(reg_sqr) → RAL writes → test drops
configure group objections drain → main group begins
main_phase:
test raises → tvseq.start(v_sqr) → subseqs on agents → test dropsTest raises/drops bracket the sequence; sequence can also self-manage.
super.configure_phase/main_phase spawns child phase tasks first.
Virtual sequences orchestrate sub-sequences on agent sequencers.
default_sequence and phase automation
UVM supports setting a default_sequence on a sequencer for a specific phase — the sequence starts automatically when that phase begins:
class my_agent extends uvm_agent;
function void build_phase(uvm_phase phase);
super.build_phase(phase);
// Auto-start bg_traffic_seq when main_phase begins
uvm_config_db#(uvm_object_wrapper)::set(
this, "sqr.main_phase", "default_sequence", bg_traffic_seq::type_id::get()
);
endfunction
endclass
// bg_traffic_seq self-manages via pre_body/post_body
class bg_traffic_seq extends uvm_sequence #(item_t);
task pre_body();
if (starting_phase != null)
starting_phase.raise_objection(this, "bg traffic");
endtask
task body();
repeat (num_pkts) `uvm_do(req)
endtask
task post_body();
if (starting_phase != null)
starting_phase.drop_objection(this, "bg traffic done");
endtask
endclass[UVM][PHASE] default_sequence flow
main_phase begins on agent
→ UVM auto-starts bg_traffic_seq on sqr
→ pre_body raises objection on main_phase
→ body runs traffic
→ post_body drops objection
main_phase ends when all objections (test + default_seq) draindefault_sequence removes manual start() calls from test code.
Self-managed sequences (pre_body/post_body) pair well with default_sequence.
Set via uvm_config_db on sequencer.<phase_name> path.
Stopping sequences at phase boundaries
When a runtime phase ends, running sequences on that phase's sequencer are killed. Plan sequence duration to fit within the phase, or use phase jump for mid-simulation resets.
// Controlled stop: sequence checks phase objection count or event
class stoppable_seq extends uvm_sequence #(item_t);
uvm_event stop_ev;
task body();
stop_ev = uvm_event_pool::get_global("stop_ev");
forever begin
if (stop_ev.is_on()) break;
`uvm_do(req)
end
endtask
endclass
// post_main triggers stop before shutdown group
task post_main_phase(uvm_phase phase);
phase.raise_objection(this, "stop sequences");
uvm_event_pool::get_global("stop_ev").trigger();
#(drain_ns);
phase.drop_objection(this, "sequences stopped");
endtask[PHASE][RUN] sequence lifetime vs phase boundary
sequence started in main_phase
main_phase objections drain (all drops)
→ main_phase ENDS
→ running sequences KILLED if still active
prevention:
1) sequence completes before test drops main_phase objection
2) post_main triggers stop + drain before main_phase ends
3) use stoppable_seq with event pollingKey takeaways
Start sequences in the phase that matches their purpose (config in configure, traffic in main).
starting_phase links sequence objections to the correct phase counter.
default_sequence automates sequence launch when a phase begins.
Plan sequence lifetime — phases kill running sequences at boundary.
Common pitfalls
Starting traffic sequence in configure_phase — objections on wrong counter.
default_sequence without pre_body/post_body — phase may end before seq completes.
Long-running sequence outliving main_phase — killed mid-transaction.
Multiple default_sequences on same sequencer same phase — unpredictable.