Part 11 · Senior Prep · Intermediate

Mismatch Triage: First-Failing-Transaction Protocol

Checking-bucket playbook for scoreboard and checker failures — isolate the first mismatch, compare at transaction granularity, and avoid waveform noise.

Checking bucket first moves

For UVM_ERROR mismatch failures , the senior move is: print the first failing transaction at UVM_MEDIUM, compare fields systematically, then decide if the bug is TB, RTL, or spec.

diagram
[DEBUG][SENIOR][UVM] mismatch triage flow

1) grep first UVM_ERROR (not last)
2) print expected vs actual txn at MEDIUM
3) identify which field diverged first
4) trace that field to source (monitor / ref model / RTL)
5) only then open targeted waveform window
systemverilog
function void compare_txn(my_item exp, my_item act, output bit match);
  match = 1;
  if (exp.addr !== act.addr) begin
    `uvm_error("SB", $sformatf("addr exp=%0h act=%0h", exp.addr, act.addr))
    match = 0; return;
  end
  if (exp.data !== act.data) begin
    `uvm_error("SB", $sformatf("data exp=%0h act=%0h", exp.data, act.data))
    match = 0; return;
  end
endfunction

Key takeaways

  • Always debug the first mismatch — later errors are often cascades.

  • Compare at transaction field granularity before signal-level waves.

  • Separate TB bug, RTL bug, and spec ambiguity before filing.

Common pitfalls

  • Scrolling to the last UVM_ERROR instead of the first.

  • Opening full-chip waves for a single-field mismatch.

  • Fixing the scoreboard compare without checking monitor packing.


Scoreboard debug toolkit

Instrument scoreboards for senior triage: transaction counters, queue depth, and first-mismatch capture.

First-mismatch capture

systemverilog
class my_scoreboard extends uvm_scoreboard;
  my_item exp_q[$], act_q[$];
  bit first_mismatch_seen;
  my_item first_exp, first_act;

  function void write_exp(my_item t);
    if (!first_mismatch_seen) exp_q.push_back(t);
  endfunction

  function void write_act(my_item t);
    my_item exp;
    if (first_mismatch_seen) return;
    if (exp_q.size() == 0) begin
      `uvm_error("SB", "unexpected actual before expected")
      return;
    end
    exp = exp_q.pop_front();
    if (!exp.compare(act)) begin
      first_mismatch_seen = 1;
      first_exp = exp; first_act = t;
      `uvm_error("SB", "FIRST MISMATCH — stopping compare flood")
      exp.print(); act.print();
    end
  endfunction
endclass
diagram
[DEBUG][SENIOR][UVM] mismatch root-cause matrix

field wrong on first txn:
  monitor packing bug OR ref model init

field wrong after N txns:
  reorder / queue / pipelining issue

intermittent same seed:
  race in scoreboard OR clock domain

passes with SB disabled:
  compare logic bug (not RTL)

Log analysis commands

bash
# find first scoreboard error
grep -n "UVM_ERROR.*SB\|MISMATCH" sim.log | head -1

# extract transaction context around first error
LINE=$(grep -n "FIRST MISMATCH" sim.log | head -1 | cut -d: -f1)
sed -n "$((LINE-5)),$((LINE+15))p" sim.log
  • Disable compare after first mismatch to keep logs readable.

  • Log transaction ID / timestamp for waveform correlation.

  • Check expected queue vs actual queue ordering separately.

  • Verify both analysis ports are connected in connect_phase.

Common pitfalls

  • Compare flooding — thousands of identical errors hide the first divergence.

  • Scoreboard comparing before both streams have matching handshake.

  • Assuming RTL bug when monitor and ref model disagree on byte order.