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.
[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 executionclass 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
endclassKey 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
[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 namedfunction 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")
endfunctionEnforce 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
[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 parsingfunction 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")
endfunctionGuardrails prevent architecture drift as scenarios grow more complex.
Role clarity reduces flaky orchestration behavior in regression.
Keep helper APIs small and strongly typed.