Part 5 · Sequences · Intermediate

Sequencer Arbitration & lock/grab

Hub — multiple sequences on one driver, FIFO arbitration, lock/grab/unlock/ungrab, priority, set_arbitration modes, and starvation triage.

Overview

One uvm_sequencer serves one driver on one interface — but many sequences may run concurrently on that sequencer. The sequencer arbitrates which sequence's pending start_item gets the driver next. Without understanding arbitration, tests that mix background traffic with directed setup produce mysterious interleaving, register programming races, and hangs that look like driver bugs but are really forgotten unlocks.

This topic breaks sequencer arbitration into five focused lessons. Each answers a different why question: why one driver needs an arbiter, how default FIFO interleaves items, when lock/grab provides atomic multi-beat access, how priority and set_arbitration change ordering, and how to triage starvation when sequences block forever at start_item.

Lessons in this topic

  1. Why Arbitration Exists — one driver, many sequences, the serialization problem.

  2. FIFO Default Arbitration — interleaving at start_item boundaries with timeline diagram.

  3. lock / grab / unlock / ungrab — exclusive access and atomic register programming.

  4. Priority & set_arbitration — set_priority, UVM_SEQ_ARB modes, weighted selection.

  5. Starvation & Debug Triage — forgotten unlock, hang signatures, verbosity playbook.

Arbitration in the stimulus stack

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

  [STIM] MULTIPLE SEQUENCES  ONE SEQUENCER  ONE DRIVER

  TEST / VSEQ
      │
      │  bg_seq.start(sqr)     test_seq.start(sqr)     prog_seq.start(sqr)
      ▼
  ┌─────────────────────────────────────────────────────────┐
  │ [UVM] SEQUENCER — arbitration engine                    │
  │                                                         │
  │   pending queue:  [bg] [test] [bg] [prog] [bg] ...      │
  │                         │                               │
  │                         ▼  one item at a time           │
  │                    get_next_item  driver               │
  └─────────────────────────────────────────────────────────┘
      │
      ▼
  ┌─────────────┐
  │   DRIVER    │  [STIM] executes one item  DUT pins
  └─────────────┘

  [SEQ] Each start_item/finish_item pair = one arbitration slot
  Without lock: items from different sequences interleave

Arbitration sits between procedural sequence threads and the single driver executor. Every lesson below expands one mechanism in this box.

diagram
[SEQ] arbitration decision tree

  Sequence calls start_item(req)
      │
      ▼
  Is sequencer locked by another sequence?
      │
      ├─ YES  block until unlock/ungrab
      │
      └─ NO   enter arbitration queue
                  │
                  ▼
             set_arbitration mode picks winner:
               FIFO       first pending start_item
               WEIGHTED   priority-weighted selection
               RANDOM     random among pending
               USER       custom hook (rare)
                  │
                  ▼
             driver gets item  finish_item unblocks sequence

Key takeaways

  • One driver, many sequences — the sequencer serializes access via arbitration.

  • Default FIFO interleaves at start_item boundaries — not at fork/join thread boundaries.

  • lock/grab for atomic multi-beat ops; priority and set_arbitration for ordering policy.

  • Forgotten unlock is the #1 arbitration hang — always pair lock with unlock.

Common pitfalls

  • Assuming fork join order equals item order — arbitration interleaves freely.

  • Using grab in every sequence — defeats concurrent stimulus purpose.

  • Setting priority without knowing the active arbitration mode.