Skip to content
DenseChip
Learn
PracticeCode labInterview

DenseChip

Navigate

Menu

LearnPracticeCode labInterview

Tools

All toolsSV editorCode repoResume
DenseChip

Practice, courses, and chip-design tools in one focused workspace.

LearnPracticeCode labInterviewToolsLearning paths

© 2026 DenseChip

AboutContactPrivacyTerms
Skip to lesson

Course contents

  • UVM Foundations6
  • UVM Phases & Simulation Lifecycle78
  • Factory & Configuration30
  • Transaction-Level Modeling (TLM)30
  • UVM Sequences & Stimulus30
    • Sequence Items: Fields, Constraints, and Randomization
      • Item vs Driver Boundary: What Belongs Where
      • Field Macros: Print, Compare, Copy Automation
      • Constraints & randomize() with Blocks
      • Layered & Derived Items: Constraint Inheritance
      • Copy, Clone & Scoreboard Queue Safety
    • Sequence Body Handshake: start_item / finish_item
    • Sequencer Arbitration & lock/grab
    • Virtual Sequences & Multi-Agent Coordination
    • Layered Sequences & uvm_sequence_library
    • Sequence Debugging: Hangs, Null p_sequencer, and Tracing
  • UVM Agents & Protocol VIP54
  • Environment & Test Classes48
  • Scoreboards, Models & Coverage in UVM26
  • UVM Register Abstraction Layer (RAL)36
  • Advanced UVM Topics32
  • Senior UVM Prep & Interviews72
  • Coding Practice47
Loading lesson

‹Sequence Items: Fields, Constraints, and Randomization
  1. Topics
  2. UVM Verification
  3. UVM Sequences & Stimulus
  4. Sequence Items: Fields, Constraints, and Randomization
  5. Item vs Driver Boundary: What Belongs Where

Part 5 · Sequences · Intermediate

Item vs Driver Boundary: What Belongs Where

Why sequence items carry transaction data only — not pin timing, virtual interfaces, or protocol state machines.

On this page

    Why the boundary exists

    UVM splits stimulus into intent (sequence + item) and execution (driver). The item is the serialized intent — a struct-like object the sequence fills and the driver reads. Pin-level timing, ready/valid handshakes, and clock alignment belong in the driver because they depend on the DUT's current state, not on what the test wants to send.

    Violating this boundary is the most common mistake in junior UVM benches. Putting a virtual interface inside an item couples transaction data to a specific hierarchy level. Putting wait loops inside an item makes randomization and reuse impossible — the item becomes a mini-driver that cannot run in passive agents or scoreboard-only contexts.

    The boundary also enables checking: monitors reconstruct items from pin samples. If your item class assumes driver-side state, the monitor cannot build the same type cleanly.

    Diagram
    [ITEM] vs [DRV] — responsibility split
    
      ┌─────────────────────────────────────────────────────────────┐
      │ [ITEM] apb_item                                              │
      │   rand bit [31:0] addr, data                                 │
      │   rand bit        write                                      │
      │   // NO vif, NO @(posedge), NO pready loop                   │
      └──────────────────────────┬──────────────────────────────────┘
                                 │ read-only during drive_apb()
                                 ▼
      ┌─────────────────────────────────────────────────────────────┐
      │ [DRV] apb_driver.drive_apb(apb_item req)                     │
      │   @(vif.pclk);                                               │
      │   vif.paddr <= req.addr;    ← reads item fields              │
      │   vif.pwrite <= req.write;                                   │
      │   while (!vif.pready) @(vif.pclk);  ← timing HERE            │
      └─────────────────────────────────────────────────────────────┘

    What a sequence item IS

    A uvm_sequence_item extends uvm_object with hooks the library uses during start_item/finish_item. It carries the logical transaction: one APB beat, one AXI burst descriptor, one Ethernet frame header. The sequence randomizes or assigns fields; the driver interprets them on the bus.

    design.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    class apb_item extends uvm_sequence_item;
      rand bit [31:0] addr;
      rand bit [31:0] data;
      rand bit        write;   // 1 = write, 0 = read
      bit [31:0]      rdata;   // filled by driver on reads — not rand
    
      `uvm_object_utils_begin(apb_item)
        `uvm_field_int(addr,  UVM_ALL_ON)
        `uvm_field_int(data,  UVM_ALL_ON)
        `uvm_field_int(write, UVM_ALL_ON)
        `uvm_field_int(rdata, UVM_ALL_ON)
      `uvm_object_utils_end
    
      function new(string name = "apb_item");
        super.new(name);
      endfunction
    endclass
    • Extend uvm_sequence_item — not uvm_object — for sequencer linkage during handshake.

    • rand on fields the sequence should vary; plain bit for driver-filled response data.

    • One item = one logical transaction (one APB beat, not an entire burst stream).

    • Field macros register members for print/compare/copy — covered in the next lesson.

    Why extend uvm_sequence_item instead of uvm_object

    • uvm_sequence_item adds sequencer association hooks used by start_item/finish_item.

    • Drivers typed with uvm_driver #(T) expect T extends uvm_sequence_item.

    • Parallel hierarchy: uvm_sequence for procedure, uvm_sequence_item for payload.


    What NOT to put in items

    The following belong in the driver, agent config, or interface — never in the item class:

    Diagram
    [ITEM] anti-patterns — keep these OUT
    
      ✗ virtual apb_if vif;           → driver owns interface handle
      ✗ task drive_beat();            → that is driver code
      ✗ int unsigned wait_cycles;     → timing policy, not payload
      ✗ semaphore bus_lock;           → resource arbitration in agent
      ✗ uvm_event beat_done;          → synchronization in driver/seq
    
      ✓ addr, data, write, strb, id  → protocol payload
      ✓ rand constraints on legality → legal transaction space

    A practical test: could a monitor reconstruct this object from sampled pins alone? If the item requires driver-internal state to make sense, the design is wrong.


    APB write walkthrough — boundary in action

    Follow one APB write from sequence randomization through driver execution. Notice where each layer touches the item — and where pin timing lives.

    Diagram
    [STIM] → [SEQ] → [ITEM] → [DRV]  APB write addr=0x4000 data=0xDEAD
    
      Step 1 [SEQ] apb_wr_seq.body()
        req = apb_item::type_id::create("req");
        start_item(req);
        req.randomize() with { write==1; addr==32'h4000; data==32'hDEAD; };
        finish_item(req);                    ← blocks here
    
      Step 2 [SEQ] SEQUENCER forwards req to driver via get_next_item
    
      Step 3 [DRV] apb_driver.run_phase
        get_next_item(req);                  ← receives same object handle
        vif.paddr  <= req.addr;   // 0x4000  ← reads [ITEM] fields only
        vif.pwdata <= req.data;   // 0xDEAD
        vif.pwrite <= req.write;  // 1
        @(posedge vif.pclk);
        vif.psel <= 1;
        while (!vif.pready) @(posedge vif.pclk);  ← [DRV] timing, not in item
        vif.psel <= 0;
        seq_item_port.item_done();           ← unblocks finish_item
    
      Step 4 [SEQ] sequence resumes after finish_item — req fields still valid
    design.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    class apb_wr_seq extends uvm_sequence #(apb_item);
      `uvm_declare_p_sequencer(apb_sequencer)
      rand int unsigned num_trans = 1;
      `uvm_object_utils(apb_wr_seq)
    
      task body();
        apb_item req;
        repeat (num_trans) begin
          req = apb_item::type_id::create("req");
          start_item(req);
          if (!req.randomize() with { write == 1; })
            `uvm_fatal("RAND", "apb_item randomize failed")
          finish_item(req);
        end
      endtask
    endclass
    • Sequence never touches vif — only creates and randomizes req.

    • Driver never randomizes — only reads req and drives pins.

    • finish_item blocks until item_done — sequence cannot mutate req during drive.


    Monitor symmetry — why clean items matter

    The monitor samples pins and builds an apb_item (or bus_txn) for the scoreboard. If the driver-side item contained timing state, the monitor could not produce a matching type. Clean items make monitor and driver agree on the transaction representation.

    Diagram
    [UVM] monitor rebuilds [ITEM] from pins — same class, different path
    
      DRIVER path:  seq → req (randomized) → drive_apb(req) → pins
      MONITOR path: pins → sample at PREADY → build apb_item → analysis port
    
      Both produce apb_item { addr, data, write, rdata }
      Scoreboard compares monitor item vs expected — NOT driver item
    design.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    // Monitor — builds item from sampled pins, no driver state needed
    function void sample_apb();
      apb_item txn = apb_item::type_id::create("txn");
      txn.addr  = vif.paddr;
      txn.data  = vif.pwdata;
      txn.write = vif.pwrite;
      txn.rdata = vif.prdata;
      ap.write(txn);
    endfunction

    Design rules for sequence items

    • Keep virtual interface handles OUT of items — breaks portability and reuse.

    • Keep timing (delays, clock cycles) OUT of items — that is driver policy.

    • One item = one logical transaction (one APB beat, one AXI burst descriptor).

    • Use rand on every field you want variation; use constraints for legality, not tests.

    • Provide post_randomize() only when derived fields must be computed after randomize.

    • Response fields (rdata) are plain bit — driver fills them, sequence reads after finish_item.

    Key takeaways

    • Items carry WHAT; drivers carry HOW — the most important UVM stimulus rule.

    • If a monitor cannot reconstruct the item from pins, the item has driver leakage.

    • uvm_sequence_item is the only payload type the driver seq_item_port accepts.

    Common pitfalls

    • Putting virtual interface handles inside items — breaks agent reuse across hierarchies.

    • Embedding wait loops in items — makes randomization and passive agents impossible.

    • One mega-item for an entire burst stream — use a sequence loop instead.

    • Mutating req after finish_item until driver returns item_done — race with driver reads.

    Previous

    145 / 489

    Next: Field Macros: Print, Compare, Copy Automation

    Up next

    Up nextField Macros: Print, Compare, Copy Automation

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • Constraints & randomize() with Blocks
    • Layered & Derived Items: Constraint Inheritance
    • Copy, Clone & Scoreboard Queue Safety