Part 7 · Environment & Tests · Intermediate

Virtual Sequencer Role: Coordination Boundary and Non-Goals

Define what the virtual sequencer owns, what stays in virtual sequence objects, and what must remain inside protocol-local agents.

Role Definition

The virtual sequencer is a handle container and coordination anchor . It should not become a scenario engine, a protocol scoreboard, or a place for timing-sensitive protocol code.

diagram
[TEST][UVM] role split

test class:
  picks scenario and starts vseq

virtual sequencer:
  stores typed child sequencer handles
  exposes helper validation methods

virtual sequence:
  orchestrates order and dependencies

agent sequencer:
  local arbitration and protocol-specific sequence service

driver:
  pin-level protocol execution
systemverilog
class cfg_then_stream_vseq extends uvm_sequence #(uvm_sequence_item);
  `uvm_object_utils(cfg_then_stream_vseq)
  `uvm_declare_p_sequencer(soc_virtual_sequencer)

  task body();
    apb_cfg_seq cfg;
    axi_stream_seq stream;
    cfg = apb_cfg_seq::type_id::create("cfg");
    stream = axi_stream_seq::type_id::create("stream");

    cfg.start(p_sequencer.apb_sqr_h);
    stream.start(p_sequencer.axi_sqr_h);
  endtask
endclass

Key takeaways

  • Virtual sequencer remains stable when it is mostly declarative.

  • Scenario behavior belongs in virtual sequence objects.

  • Protocol behavior remains inside protocol-specific sequences/drivers.

Common pitfalls

  • Putting virtual-sequence business logic into component-level methods.

  • Letting agent sequencers reference sibling-agent handles directly.

  • Mixing protocol timing code with env-level orchestration code.


Boundary Enforcement

diagram
[TEST][UVM][ENV] boundary checks

check 1:
  no direct test->driver invocation

check 2:
  v_sqr contains no protocol state machine

check 3:
  vseq uses p_sequencer handles only

check 4:
  per-agent sequence code remains agent-local

check 5:
  barrier logic is explicit and named
systemverilog
function void end_of_elaboration_phase(uvm_phase phase);
  super.end_of_elaboration_phase(phase);
  if (apb_sqr_h == null)
    `uvm_fatal("VSQR_ROLE", "required handle apb_sqr_h missing")
  if (axi_sqr_h == null)
    `uvm_fatal("VSQR_ROLE", "required handle axi_sqr_h missing")
endfunction
  • Enforce boundary checks at elaboration, not after runtime hangs.

  • Keep check messages explicit with handle/interface names.

  • Review code by ownership zone before reviewing syntax details.


Applied Patterns

diagram
[TEST][UVM][VSEQ] role guardrails

virtual sequencer should expose:
  typed handles
  validate_handles() helper
  light-weight status reporting

virtual sequencer should NOT expose:
  protocol transactions
  scoreboard compare APIs
  timing loops with @posedge or #delay

virtual sequence should own:
  scenario phases
  dependency graph
  barrier wait logic

tests should own:
  profile selection
  objection envelope
  plusarg/config parsing
systemverilog
function void validate_handles(bit need_apb, bit need_axi, bit need_irq);
  if (need_apb && apb_sqr_h == null)
    `uvm_fatal("VSQR_REQ", "APB handle required")
  if (need_axi && axi_sqr_h == null)
    `uvm_fatal("VSQR_REQ", "AXI handle required")
  if (need_irq && irq_sqr_h == null)
    `uvm_fatal("VSQR_REQ", "IRQ handle required")
endfunction
  • Guardrails prevent architecture drift as scenarios grow more complex.

  • Role clarity reduces flaky orchestration behavior in regression.

  • Keep helper APIs small and strongly typed.