Part 5 · Sequences · Intermediate

Randomize Failures & Arbitration Locks

Constraint conflicts, unchecked randomize, lock/grab without unlock, and background sequence starvation.

Randomize failures — silent or loud

If randomize() fails and you do not check the return value, behavior depends on your code path: you may call finish_item with stale defaults, skip the beat entirely, or hit an assert. Constraint conflicts are common when layering adds inline constraints on top of item constraints.

systemverilog
if (!req.randomize() with { addr[1:0] == 2'b00; len inside {[1:8]}; }) begin
  `uvm_error("RAND", "constraint conflict — printing item state")
  req.print();
  // do NOT call finish_item with illegal item unless testing error path
  return;
end
  • Conflicting inline + with constraints and item constraints — solver returns 0.

  • rand_mode(0) on fields you forgot to assign manually before finish_item.

  • constraint_mode(0) on legal_addr — randomize produces addresses driver rejects.

  • Hard constraint added in send_beat conflicts with test soft override — solver fail.


Diagnosing constraint conflicts

Raise solver visibility with UVM_FULL verbosity on the sequence or item class, or run with the standard plusarg:

bash
# Full solver trace (verbose — use narrow scope when possible)
+UVM_VERBOSITY=UVM_FULL

# Or per-component after sim starts
+uvm_set_verbosity=env.axi_agent.sqr,_ALL_,UVM_FULL,time

Walkthrough — conflicting burst constraints

diagram
[SEQ] constraint conflict example

  axi_item constraint:     burst_len inside {0, 1, 3, 7}
  send_beat inline:        burst_len inside {[4:15]}
  solver:                  empty solution set  randomize() == 0

  LOG: UVM_ERROR RAND constraint conflict
  FIX: align inline with item constraints OR disable item constraint for this seq
systemverilog
// Temporary debug — see which constraints clash
req.rand_mode(1);
req.constraint_mode(1);
assert(req.randomize() with { burst_len == 7; });  // narrow to one legal value

Arbitration lock and grab

When a sequence calls lock() or grab() on the sequencer, it holds exclusive access. Other sequences block at start_item until unlock() or ungrab(). A forgotten unlock is one of the most common long-hang root causes in multi-sequence environments.

diagram
Legend: [SEQ] [UVM]

  bg_config_seq.body()
    p_sequencer.lock(this)
    // ... long config sequence ...
    // BUG: forgot unlock — holds lock forever

  test_seq.body()
    start_item(req)  ◄── BLOCKS forever waiting for lock release
  • Search codebase for lock( and grab( — every call needs matching unlock/ungrab.

  • Background seq started in env run_phase before test seq — may hold lock.

  • uvm_do_with macros inside locked region — nested start_item still obeys lock.

  • kill() on locked sequence — verify unlock in cleanup or pre_abort hook.


Starvation patterns

systemverilog
// Safe lock pattern — unlock in all paths
task body();
  p_sequencer.lock(this);
  begin
    // config traffic — limited beats
    repeat (10) send_beat(req);
  end
  p_sequencer.unlock(this);  // mandatory
endtask

// Background seq that never finishes — starves others without lock
task body();
  forever begin
    send_beat(req);  // hogs arbitration fairly but never yields scenario
  end
endtask

Walkthrough — lock hang timeline

diagram
[STIM] lock starvation timeline

  T0  env run_phase: bg_config_seq.start(sqr) — calls lock()
  T1  bg_config_seq: slow register programming via APB beats
  T2  test run_phase: stress_seq.start(sqr)
  T3  stress_seq: start_item(req) — BLOCKED (lock held)
  T4  sim runs forever — no error, no bus activity on AXI
  T5  grep "lock" in log — see bg_config_seq locked, no unlock message

  FIX: add unlock after config OR do not start bg seq before test seq
       OR use grab with timeout policy (custom sequencer subclass)

Key takeaways

  • Always check randomize() return; print item on failure.

  • lock/grab without unlock/ungrab blocks all other sequences at start_item.

  • Background forever-seq starves scenario seq even without explicit lock.

Common pitfalls

  • assert(req.randomize()) without message — hard to trace which constraint failed.

  • unlock in forked thread racing with parent's next start_item.

  • Assuming hang is finish_item when log shows hang at start_item — check lock first.

  • Killing sim without identifying which sequence holds lock — bug reproduces next run.