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.

diagram
[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 called
  • Sequence 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

systemverilog
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
diagram
[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 drops
  • Test 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:

systemverilog
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
diagram
[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) drain
  • default_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.

systemverilog
// 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
diagram
[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 polling

Key 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.