Part 5 · Sequences · Intermediate

Sequencer Connection & p_sequencer

connect_phase port wiring, null sequencer handles, declare macro typing, and virtual sequence start targets.

Checklist 2 — Sequencer–driver connection

The seq_item_port on the driver must connect to seq_item_export on the sequencer in connect_phase. A typo or missing connect is silent — get_next_item blocks forever with no error message.

  • connect_phase: drv.seq_item_port.connect(sqr.seq_item_export) — only in UVM_ACTIVE.

  • Typo in port or export name — compiles if wrong component, silent at runtime.

  • Multiple drivers on one sequencer export — illegal; only one driver per sequencer.

  • Reconnect without disconnect — some simulators warn, connection order matters.

systemverilog
function void connect_phase(uvm_phase phase);
  super.connect_phase(phase);
  if (is_active == UVM_ACTIVE) begin
    drv.seq_item_port.connect(sqr.seq_item_export);
    `uvm_info("AGT", "driver seq_item_port connected to sequencer", UVM_LOW)
  end
  mon.ap.connect(/* ... */);
endfunction

Checklist 3 — start() and sequencer handle

The seq.start(sqr) call requires a non-null sequencer handle to the agent's sequencer — not the env, not the agent component itself.

systemverilog
// Guard before start — catches null early with readable fatal
if (env.axi_agent.sqr == null)
  `uvm_fatal("NULL_SQR", "axi sequencer null — passive agent?")

`uvm_info("TEST", $sformatf(
  "starting %s on %s", seq.get_type_name(), env.axi_agent.sqr.get_full_name()),
  UVM_LOW)
seq.start(env.axi_agent.sqr);
  • Virtual sequence: start on v_sqr; sub-sequences start on p_sequencer.axi_sqr etc.

  • Starting same sequence twice on same sequencer without kill — can deadlock with lock.

  • seq.start(agent) is wrong — agent is uvm_component, not uvm_sequencer.


Checklist 4 — Null or wrong p_sequencer

Inside body(), p_sequencer is populated by start(). The declare macro binds the typed handle — if the macro says apb_sequencer but you started on

a virtual sequencer, fields like p_sequencer.axi_sqr do not exist and you get compile errors or null access at runtime.

systemverilog
class axi_burst_seq extends uvm_sequence #(axi_item);
  `uvm_declare_p_sequencer(axi_sequencer)  // MUST match start() target

  task body();
    if (p_sequencer == null)
      `uvm_fatal("NULL_PSEQ", "p_sequencer null — wrong start() or missing macro")
    `uvm_info(get_type_name(), $sformatf(
      "running on %s", p_sequencer.get_full_name()), UVM_LOW)
    // ...
  endtask
endclass

class chip_vseq extends uvm_sequence;
  `uvm_declare_p_sequencer(chip_virtual_sequencer)  // virtual type

  task body();
    axi_burst_seq burst = axi_burst_seq::type_id::create("burst");
    burst.start(p_sequencer.axi_sqr);  // agent sequencer — NOT p_sequencer alone
  endtask
endclass

Walkthrough — wrong start target

diagram
Legend: [STIM] [SEQ] [UVM]

  BUG: chip_vseq declares chip_virtual_sequencer
       but axi_burst_seq.start(p_sequencer) — started on VIRTUAL sqr

  RESULT:
    axi_burst_seq.p_sequencer = virtual sequencer handle
    start_item  virtual sequencer has no seq_item_export to driver
    HANG at start_item forever

  FIX:
    axi_burst_seq.start(p_sequencer.axi_sqr)  — real agent sequencer

item_done pairing — the finish_item hang

If the sequence blocks at finish_item but start_item already completed, the driver pulled the item but never called item_done().

  • Every get_next_item needs exactly one item_done — no exceptions.

  • Early return or exception path in drive() that skips item_done.

  • drive() fork without join — item_done in parent before child drive completes.

  • item_done in wrong thread without proper synchronization.

systemverilog
task drive(axi_item req);
  fork
    drive_write_channel(req);
    drive_addr_channel(req);
  join
  seq_item_port.item_done();  // MUST run after drive completes — not before fork
endtask

Key takeaways

  • connect_phase wiring is silent-failure territory — log the connect.

  • p_sequencer type must match start() target; vseq uses child sequencer handles.

  • finish_item hang = missing item_done, not sequencer connection.

Common pitfalls

  • Starting vseq sub-seq on p_sequencer instead of p_sequencer.agent_sqr.

  • declare_p_sequencer(apb) but start on axi_sqr — field access compile fail.

  • connect only in test, not agent — breaks encapsulation and reuse.

  • item_done before drive finishes — sequence releases item too early.