Part 11 · Senior Prep · Intermediate

Interview Q&A: Virtual Sequences

Model answers on virtual sequencers, p_sequencer, multi-agent fork/join, encapsulation rules, and chip-level scenario coordination.

Virtual sequence fundamentals

Q: Why virtual sequences?

diagram
[INT][SENIOR][UVM] MODEL ANSWER

Q: Why virtual sequences?

A:
  MECHANISM:  Sequence on uvm_virtual_sequencer holds handles to real sequencers;
              starts sub-sequences on each without driving pins itself.
  MOTIVATION:  Chip scenarios span DMA + CPU + interrupt — agents stay encapsulated.
  WHEN:       Multi-agent coordinated tests at subsystem/chip level.
  NOT WHEN:   Single-agent block TB — virtual seq adds indirection for no gain.
  PITFALL:    Virtual seq reaches agt.drv or vif — breaks VIP boundary.
  EXAMPLE:    dma_fill_vseq: prog_dma_seq.start(apb_sqr); fork axi_rd/wr on axi_sqr.

Q: What is a virtual sequencer?

diagram
[INT][SENIOR][UVM] MODEL ANSWER

Q: Virtual sequencer?

A:
  MECHANISM:  uvm_sequencer subclass with no driver — only holds sequencer handles
              (apb_sqr, axi_sqr) assigned in env connect_phase.
  MOTIVATION:  Single start point for chip vseq; test does not hunt agent handles.
  WHEN:       env owns v_sqr; connect_phase: v_sqr.axi_sqr = axi_agt.sequencer.
  PITFALL:    Virtual sequencer with seq_item_port connected to driver — wrong.
  EXAMPLE:    soc_virtual_sequencer { apb_sqr, axi_sqr, pcie_sqr } — no driver child.

Q: Explain uvm_declare_p_sequencer

diagram
[INT][SENIOR][UVM] MODEL ANSWER

Q: uvm_declare_p_sequencer?

A:
  MECHANISM:  Macro declares typed p_sequencer handle matching virtual sequencer class.
  MOTIVATION:  Type-safe access to apb_sqr, axi_sqr in vseq body without $cast.
  WHEN:       Every virtual sequence targeting a typed virtual sequencer.
  PITFALL:    Declaring p_sequencer as plain uvm_sequencer — loses typed handles.
  EXAMPLE:    uvm_declare_p_sequencer(soc_virtual_sequencer)
              p_sequencer.apb_sqr — compile-time typed.
diagram
[INT][SENIOR][UVM] virtual layer whiteboard

  TEST.start(env.v_sqr, dma_vseq)
       │
       ▼
  [VSEQ] dma_vseq — NO start_item, NO driver
       ├─ prog_seq.start(p_sequencer.apb_sqr)
       └─ fork
            data_seq.start(p_sequencer.axi_sqr)
            poll_seq.start(p_sequencer.apb_sqr)
          join

Key takeaways

  • Virtual sequences orchestrate via start() — never drive pins.

  • Virtual sequencer = handle container, no driver connection.

  • p_sequencer gives typed multi-agent access in vseq body.

Common pitfalls

  • Virtual seq with start_item — only real sequencers have drivers below.

  • Test reaching into agt.sequencer — env should expose v_sqr.


Coordination patterns

Q: fork/join vs fork/join_any in virtual sequences?

diagram
[INT][SENIOR][UVM] MODEL ANSWER

Q: fork/join vs join_any in vseq?

A:
  MECHANISM:  join waits for all branches; join_any proceeds when first completes;
              join_none detaches (dangerous without objection accounting).
  MOTIVATION:  Parallel traffic (AXI read + write); join_any for 'wait IRQ then stop bulk'.
  WHEN:       join for coordinated stress; join_any for event-triggered scenario phase.
  PITFALL:    join_none + immediate drop_objection — branches killed mid-sequence.
  EXAMPLE:    fork bulk_seq.start(axi_sqr); irq_wait_seq.start(apb_sqr); join_any
               disable bulk when IRQ fires.

Q: Where should virtual sequences live in the hierarchy?

diagram
[INT][SENIOR][UVM] MODEL ANSWER

Q: Vseq placement — env vs test?

A:
  MECHANISM:  Reusable scenario vseqs in env pkg or seq_lib; test starts chosen vseq.
  MOTIVATION:  Tests stay thin (objection + start); scenarios reusable across tests.
  WHEN:       dma_fill_vseq used by smoke, stress, and merge tests — lives in env seq_lib.
  PITFALL:    200-line body() in test class — not reusable, not reviewable.
  EXAMPLE:    chip_stress_test.run_phase: vseq.start(env.v_sqr, chip_stress_vseq::type_id::get()).

Q: How do virtual sequences interact with objections?

diagram
[INT][SENIOR][UVM] MODEL ANSWER

Q: Vseq and objections?

A:
  MECHANISM:  Test (or top-level vseq) raises objection before start(); drop after
              vseq body completes — including all fork/join branches.
  MOTIVATION:  Objections track task-phase activity; vseq body is a task.
  WHEN:       Test raises/drops for simple cases; vseq raises for long multi-fork scenarios.
  PITFALL:    fork/join_none in vseq then test drops objection — parallel branches killed.
  EXAMPLE:    vseq body: raise_objection(this); fork ... join; drop_objection(this).

Q: Block seq reuse at chip — what changes?

diagram
[INT][SENIOR][UVM] MODEL ANSWER

Q: Block sequences at chip level?

A:
  MECHANISM:  Same axi_burst_seq.start(axi_sqr) — only the sequencer handle comes from
              v_sqr instead of test reaching into block agt.
  MOTIVATION:  Agent sequences unchanged; chip adds coordination layer only.
  WHEN:       Block sign-off seq_lib imported into chip env; vseq composes them.
  PITFALL:    Rewriting block sequences for chip — destroys reuse economics.
  EXAMPLE:    Block: test.start(agt.sqr, axi_rand_seq). Chip: vseq.start(p_sequencer.axi_sqr, same seq).

Key takeaways

  • fork/join_any for event-driven phases; never drop objection before join.

  • Reusable vseqs in env pkg; tests select and start them.

  • Chip integration adds vseq layer — block agent seqs stay unchanged.

Common pitfalls

  • join_none without objection ownership plan — mid-scenario kill.

  • Rewriting agent sequences at chip instead of composing via vseq.