Part 4 · TLM & Analysis · Intermediate

Sequencer-Driver TLM: seq_item_port / export Pull Pattern

How driver seq_item_port and sequencer seq_item_export implement a specialized TLM pull protocol with get_next_item/item_done semantics.

The canonical UVM pull handshake

The sequencer-driver path is a specialized TLM connection: driver pulls sequence items using seq_item_port connected to sequencer seq_item_export. This is the core handshake that converts abstract sequence intent into pin-level drive actions.

Although APIs differ from generic put/get names, behavior is conceptually similar to blocking pull plus completion acknowledgment.

diagram
Legend: [UVM] [TLM]

[UVM][TLM] seq-driver handshake

sequence.start(seqr)
    |
    v
sequencer arbitrates requests
    |
driver.seq_item_port.get_next_item(req)   // blocking pull
driver drives req on interface
driver.seq_item_port.item_done(rsp?)      // completion notification
  • Driver is pull-based: it asks sequencer for next item.

  • get_next_item blocks until work exists.

  • item_done releases sequencer-side flow and enables next grant.


Connection and run-phase implementation

systemverilog
class bus_driver extends uvm_driver #(pkt);
  `uvm_component_utils(bus_driver)
  virtual bus_if vif;

  function new(string name, uvm_component parent);
    super.new(name, parent);
  endfunction

  task run_phase(uvm_phase phase);
    pkt req;
    forever begin
      seq_item_port.get_next_item(req); // blocking pull from sequencer
      drive_one(req);
      seq_item_port.item_done();
    end
  endtask

  task drive_one(pkt req);
    @(posedge vif.clk);
    vif.valid <= 1'b1;
    vif.data  <= req.data;
    do @(posedge vif.clk); while (!vif.ready);
    vif.valid <= 1'b0;
  endtask
endclass

class bus_agent extends uvm_agent;
  `uvm_component_utils(bus_agent)
  uvm_sequencer #(pkt) seqr;
  bus_driver driver;

  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    seqr = uvm_sequencer#(pkt)::type_id::create("seqr", this);
    driver = bus_driver::type_id::create("driver", this);
  endfunction

  function void connect_phase(uvm_phase phase);
    super.connect_phase(phase);
    driver.seq_item_port.connect(seqr.seq_item_export);
  endfunction
endclass
diagram
[UVM] relationship to generic TLM

driver.seq_item_port.get_next_item(req) ~ blocking_get(req)
driver.seq_item_port.item_done()        ~ completion/ack to producer side

This specialized API adds sequence arbitration semantics on top of TLM pull.

Response path and advanced handshake options

If the protocol produces per-item responses, drivers can return response objects either via item_done(rsp) or explicit response APIs, depending on sequence style.

systemverilog
task run_phase(uvm_phase phase);
  pkt req;
  pkt rsp;
  forever begin
    seq_item_port.get_next_item(req);
    rsp = pkt::type_id::create("rsp");
    rsp.set_id_info(req);

    drive_and_collect(req, rsp);
    seq_item_port.item_done(rsp); // return response associated with req
  end
endtask

task drive_and_collect(pkt req, ref pkt rsp);
  // drive request then capture result
  rsp.data = req.data ^ 32'h00FF_00FF;
endtask
diagram
[TLM] ordering guarantees

Driver contract:
  get_next_item(req)
  ... exactly one terminal action ...
    item_done() or item_done(rsp)

Missing item_done causes sequencer flow stall.
  1. Call exactly one completion action per granted item.

  2. Use set_id_info(req) when building rsp to preserve correlation.

  3. Guard against early returns/exceptions that skip item_done.


Debugging deadlocks and starvation in seq-driver links

diagram
[UVM] common seq-driver failure signatures

driver stuck on get_next_item:
  - sequence never started
  - arbitration blocked by locks/grabs
  - wrong sequencer connection path

sequencer grants once then stalls:
  - driver forgot item_done
  - driver thread exited unexpectedly
  - protocol wait loop never exits
systemverilog
task run_phase(uvm_phase phase);
  pkt req;
  forever begin
    `uvm_info("DRV", "waiting get_next_item", UVM_HIGH)
    seq_item_port.get_next_item(req);
    `uvm_info("DRV", "got item, driving", UVM_HIGH)
    drive_one(req);
    seq_item_port.item_done();
    `uvm_info("DRV", "item_done sent", UVM_HIGH)
  end
endtask

Key takeaways

  • seq_item_port/export is UVM's standardized pull TLM channel for drivers.

  • get_next_item is blocking; item_done is mandatory completion signaling.

  • Most sequencer-driver deadlocks come from missing start/connect/done steps.

Common pitfalls

  • Skipping item_done on error paths.

  • Connecting driver port to wrong sequencer instance.

  • Assuming sequence runs automatically without explicit start.