Skip to content

UVM

Data Checking

The comparison itself — how the scoreboard compares a paired observed and expected transaction field by field, why it must compare only the meaningful fields (masking don't-cares), and how to report a precise mismatch (which field, got vs expected) for fast debugging.

Scoreboards · Module 18 · Page 18.4

The Engineering Problem

The predictor produces the expected (Module 18.2) from a faithful reference model (18.3), and the scoreboard receives the observed from the monitor. Now comes the comparison itselfdata checking: given a paired observed and expected transaction, decide if they match. This sounds trivial — "are they equal?" — but it carries two real decisions that make or break the check. First: which fields to compare. Not all fields matter — a transaction often carries fields the spec leaves unspecified (reserved bits, a randomized tag, a timestamp) that the predictor can't predict; comparing those produces false mismatches (the DUT is fine, but a don't-care field differs). Second: how to report a mismatch — a vague "mismatch" message turns every failure into an investigation, while a precise one (which field, got vs expected) makes debugging instant. The problem this chapter solves is the comparison done right: comparing only the meaningful fields and reporting precisely.

Data checking is the scoreboard's field-by-field comparison of a paired observed and expected transaction. It compares the meaningful fields — the ones the spec defines and that matter for correctness — and masks the don't-cares (unspecified or irrelevant fields the predictor can't predict). On a match (all meaningful fields equal), it passes; on a mismatch (some meaningful field differs), it flags a bug with a precise report: which field differed, the got (observed) value, the expected value, and the transaction context. The two decisions are symmetric dangers: comparing too many fields (including a don't-care) → false mismatches (noise, wasted debug, eroded trust); comparing too few (masking a meaningful field) → missed bugs (a silent hole, like a reference-model gap, Module 18.3). Data checking is grading the answer: compare the DUT's answer against the key, field by field, grading only the parts that count, and marking precisely what's wrong. This chapter is the comparison: which fields to compare, the masking of don't-cares, precise mismatch reporting, and the false-mismatch bug.

How does the scoreboard compare a paired observed and expected transaction — comparing only the meaningful fields (masking don't-cares the predictor can't predict) and reporting a precise mismatch (which field, got vs expected) — and why is comparing the wrong set of fields the central data-checking hazard?

Motivation — why comparison is more than "are they equal?"

The comparison seems like a == b, but the which-fields and how-to-report decisions determine whether the check is correct and usable. The reasons:

  • Not all fields matter for correctness. A transaction carries meaningful fields (the spec defines them — address, data, response) and don't-cares (reserved bits, a tracking tag, a timestamp the spec leaves unspecified). Only the meaningful ones should be compared.
  • The predictor can't predict a don't-care. For an unspecified field, the spec doesn't say what the value should be — so the reference model has no basis to predict it. Comparing it pits the DUT's arbitrary value against the predictor's default → a false mismatch.
  • Comparing too many fields is noise. A false mismatch on every transaction with a don't-care difference floods the log, wastes debug time chasing a non-bug, and erodes trust in the scoreboard (the "boy who cried wolf").
  • Comparing too few fields is a blind spot. Masking a meaningful field (one that does matter) means a bug in that field is never caught — a silent hole, exactly like a reference-model gap (Module 18.3's blind spot).
  • The report determines debug speed. A mismatch is a signal — but a vague one ("mismatch occurred") forces a fresh investigation, while a precise one (field, got, expected, context) points straight at the problem. The report is part of the check's value.

The motivation, in one line: the comparison is more than a == b because which fields you compare determines correctness (compare only the meaningful ones — don't-cares the predictor can't predict produce false mismatches, masking meaningful ones produces missed bugs) and how you report determines debug speed (a precise mismatch — field, got, expected — is instant to debug; a vague one is an investigation).

Mental Model

Hold data checking as grading the answer — comparing against the key field by field, grading only what counts, marking precisely what's wrong:

Data checking is grading an answer against the key: you compare the student's answer field by field, but you grade only the parts that count — not the handwriting, the margin doodles, or the scratch work — and you mark precisely what's wrong, so the student knows exactly where they erred. Grade a doodle as 'wrong' and the grade is unfair; skip a real answer and you miss a mistake; write 'wrong' with no detail and the feedback is useless. Picture grading a filled-in answer sheet (the observed transaction) against the answer key (the expected). You go field by fieldquestion by questioncomparing each. But you grade only the parts that count: the answers the exam tests, not the handwriting, the margin doodles, the scratch work in the corner (the don't-cares — fields irrelevant to whether the answer is right). Three things must be right. First, grade only what counts: if you mark a margin doodle as "wrong" (compare a don't-care), the grade is unfair — you've failed a correct student over something that doesn't matter (a false mismatch). Second, don't skip a real answer: if you skip grading question 3 (mask a meaningful field), you miss a real mistake (a missed bug). Third, mark precisely: writing "wrong" with no detail leaves the student guessing; writing "question 3: you put 24, the answer is 42" (the field, the got, the expected) tells them exactly where they erreduseful feedback. So good grading is comparing the right things (the answers, not the doodles) and marking precisely (which question, what you wrote, what's correct) — so the grade is fair and the feedback is actionable.

So data checking is grading the answer against the key: compare field by field, grade only the parts that count (the meaningful fields — not the don't-care doodles), and mark precisely what's wrong (which field, got vs expected, context). The two grading errors are symmetric: grading a doodle (comparing a don't-care) → unfair fail (false mismatch); skipping a real answer (masking a meaningful field) → missed mistake (missed bug). And vague marks (no detail) make the feedback useless. Grade only what counts, don't skip what matters, and mark exactly what's wrong.

Visual Explanation — the field-by-field comparison

The defining picture is the comparison: the scoreboard compares the meaningful fields of the observed and expected, masks the don't-cares, and on a mismatch reports precisely.

The scoreboard compares the meaningful fields of observed and expected, masks don't-cares, reports precise mismatchesmeaningful fieldsmeaningful fieldsmasked (notcompared)mismatch → field, got, expectedmismatch →field, got,…Observed txnaddr, data, resp (+ don't-cares)Expected txnaddr, data, resp (+ defaults)Compare meaningful fieldsfield by fieldDon't-care fieldsreserved, timestampMaskedno false mismatchPrecise mismatch reportfield · got · expected · context12
Figure 1 — the field-by-field comparison. The observed and expected transactions each have meaningful fields (address, data, response) and don't-care fields (a reserved field, a timestamp). The scoreboard compares the meaningful fields and masks the don't-cares. If all meaningful fields match, it passes. If a meaningful field differs, it reports a precise mismatch: which field, the got (observed) value, the expected value, and the transaction context. The don't-cares are not compared, so their differences don't cause false mismatches.

The figure shows the field-by-field comparison with its two key behaviors: comparing only the meaningful fields and reporting precisely. The observed and expected transactions each have meaningful fields (address, data, response) and don't-care fields (a reserved field, a timestamp). The scoreboard compares the meaningful fields field by field, and masks the don't-cares (they are not compared). If all meaningful fields match, it passes. If a meaningful field differs, it produces a precise mismatch report: which field, the got (observed) value, the expected value, and the transaction context. The crucial reading is the two design choices made visible. First, the warning-colored don't-cares are maskedrouted away from the comparison — so their differences (which are legitimate, since the spec doesn't define them) don't cause false mismatches. Second, the success-colored report is precise — it names the field and shows both values — so a real mismatch is immediately actionable. This is the anatomy of a correct, usable comparison: compare what matters (meaningful fields), ignore what doesn't (don't-cares), and report what's wrong (field, got, expected). The separation of the meaningful fields (compared) from the don't-cares (masked) is the correctness decision; the precision of the report is the usability decision. The diagram is the comparison done right: a focused check (only the meaningful fields) with a clear verdict (a precise mismatch) — fair (no false marks for don't-cares) and useful (exactly which field, and what each value is).

RTL / Simulation Perspective — comparing with field masking and precise reporting

In code, the scoreboard compares the transactions — masking don't-cares (via field-automation flags or a custom compare) and reporting the precise mismatch. The code shows both.

compare meaningful fields, mask don't-cares, report the precise mismatch
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
class bus_txn extends uvm_sequence_item;
  rand bit [31:0] addr;                            // MEANINGFUL — compare
  rand bit [31:0] data;                            // MEANINGFUL — compare
  rand bit [1:0]  resp;                            // MEANINGFUL — compare
  bit  [7:0]      tag;                             // DON'T-CARE — tracking only, do NOT compare
  time            timestamp;                        // DON'T-CARE — unspecified, do NOT compare
  `uvm_object_utils_begin(bus_txn)
    `uvm_field_int(addr, UVM_ALL_ON)               // included in compare
    `uvm_field_int(data, UVM_ALL_ON)
    `uvm_field_int(resp, UVM_ALL_ON)
    `uvm_field_int(tag,  UVM_NOCOMPARE)            // ← masked: excluded from compare (don't-care)
    // timestamp: not registered for compare at all
  `uvm_object_utils_end
endclass
 
// === SCOREBOARD: compare paired observed vs expected; report PRECISELY on mismatch ===
function void my_scoreboard::check(bus_txn observed, bus_txn expected);
  if (observed.compare(expected)) `uvm_info("SB", "MATCH", UVM_HIGH)   // compares only meaningful fields
  else `uvm_error("SB", $sformatf("MISMATCH addr=%0h: data got=%0h exp=%0h, resp got=%0h exp=%0h",
                                   observed.addr, observed.data, expected.data, observed.resp, expected.resp))
endfunction
// ✗ comparing a DON'T-CARE (e.g., tag/timestamp) → false mismatches (DebugLab)
// ✗ masking a MEANINGFUL field → missed bugs (silent hole)

The code shows field masking and precise reporting. The transaction declares meaningful fields (addr, data, respcompared) and don't-care fields (tagtracking only; timestampunspecified). The field automation controls the comparison: uvm_field_int(addr, UVM_ALL_ON) includes a field in compare, while uvm_field_int(tag, UVM_NOCOMPARE) masks it (excluded from compare), and timestamp is not registered (so never compared). So observed.compare(expected) compares only the meaningful fields. The scoreboard's check calls compare — and on a mismatch, reports precisely: the uvm_error names the address context, and shows data got=... exp=..., resp got=... exp=...which fields, got vs expected. The two comments mark the symmetric dangers: comparing a don't-care (tag/timestamp) → false mismatches (the DebugLab); masking a meaningful field → missed bugs (a silent hole). The shape to carry: control which fields are compared (via field-automation flags — UVM_NOCOMPARE to mask don't-cares, or a custom do_compare), comparing only the meaningful fields, and report the mismatch precisely (which field, got, expected, context — via $sformatf). The field flags are where the which-fields decision lives; the $sformatf report is where the debuggability lives. Getting both right — mask the don't-cares, report precisely — is what makes the comparison correct (no false mismatches, no missed bugs) and usable (fast to debug).

Verification Perspective — the two failure modes of field selection

The which-fields decision has two symmetric failure modescomparing too many (false mismatches) and comparing too few (missed bugs) — and the right set is exactly the meaningful fields. Seeing both frames the decision.

Comparing too many fields gives false mismatches; comparing too few gives missed bugs; the right set is the meaningful fieldsdon't-care differsmeaningful field uncheckedmeaningfulfield…exactly the meaningful fieldsexactly themeaningful…Compare too manyincludes a don't-careFalse mismatchescorrect DUT flagged (noise)Compare too fewmasks a meaningful fieldMissed bugssilent holeThe meaningful fieldsspec-defined,correctness-relevantCorrect checkno noise, no blindness12
Figure 2 — the two failure modes of field selection. Compare too many — including a don't-care field the predictor can't predict — and you get false mismatches: a correct DUT flagged, noise, wasted debug. Compare too few — masking a meaningful field that matters — and you get missed bugs: a real bug in that field never caught, a silent hole. The correct set is exactly the meaningful fields: every field the spec defines and that matters for correctness, and no don't-cares. Field selection is a balance between noise and blindness.

The figure shows the two failure modes of field selection and the correct middle. Compare too many — including a don't-care field the predictor can't predict — → false mismatches (a correct DUT flagged, noise, wasted debug). Compare too fewmasking a meaningful field that matters — → missed bugs (a real bug in that field never caught, a silent hole). The correct set is exactly the meaningful fields: every field the spec defines and that matters for correctness, and no don't-cares → a correct check (no noise, no blindness). The verification insight is that field selection is a balance between noise and blindness, and the two errors are opposite with opposite symptoms. Comparing too many (false mismatches) is loud (the scoreboard flags — you notice), annoying (wasted debug), and trust-eroding (the "boy who cried wolf" — engineers start ignoring mismatches, which is dangerous). Comparing too few (missed bugs) is silent (the scoreboard passes — you don't notice), and dangerous (a real bug escapes). So the two errors pull in opposite directions: err toward more fields and you get false mismatches (loud noise); err toward fewer fields and you get missed bugs (silent holes). The right answer is neither extreme but exactly the meaningful fields — which requires knowing the spec: which fields the spec defines (compare them) and which it leaves unspecified or irrelevant (mask them). The brand-colored "meaningful fields" is the target; the warning-colored extremes are the failures. The figure is the field-selection decision: it's not "compare everything" (false mismatches) nor "compare little" (missed bugs) but compare exactly what the spec makes meaningful — and the don't-care must be masked (it can't be predicted), while the meaningful must be compared (or its bugs escape). Compare the spec's meaningful fields — no more (noise), no less (blindness).

Runtime / Execution Flow — the comparison per transaction

At run time, the scoreboard runs a per-pair comparison: pair the observed with its expected, compare the meaningful fields, and on a mismatch report precisely. The flow shows it.

The comparison flow: pair, compare meaningful fields, pass or report a precise mismatchpair observed with expected → compare meaningful fields (mask don't-cares) → all match? pass : report precise mismatch (field, got, expected)pair observed with expected → compare meaningful fields (mask don't-cares) → all match? pass : report precise mismatch (field, got, expected)1Pair observed with its expectedthe matching expected for this observed transaction (ordering logichandles which).2Compare the meaningful fieldsfield by field, masking the don't-cares the predictor can'tpredict.3All match → passevery meaningful field equal: the DUT was correct for thistransaction.4Any differ → report preciselywhich field, got vs expected, and the context — an instantlyactionable bug report.
Figure 3 — the comparison per paired transaction. Pair the observed transaction with its expected (the matching one). Compare the meaningful fields field by field, masking the don't-cares. If all match, pass. If any meaningful field differs, report a precise mismatch — which field, got vs expected, and the transaction context. This runs for every observed transaction, producing a pass or a precise bug report. The pairing (which expected goes with which observed) is handled by the ordering logic (in-order or out-of-order); data checking is the comparison once paired.

The flow shows the per-pair comparison. Pair (step 1): pair the observed transaction with its expected (the matching one — which expected goes with which observed is the ordering logic's job, in-order or out-of-order, Modules 18.5–18.6). Compare (step 2): compare the meaningful fields field by field, masking the don't-cares the predictor can't predict. Pass (step 3): if all match, pass — the DUT was correct for this transaction. Report (step 4): if any meaningful field differs, report preciselywhich field, got vs expected, the context — an instantly actionable bug report. The runtime insight is the division of labor: data checking (this chapter) is the comparison once paired; the pairing (which expected matches which observed) is separate — handled by the ordering logic (in-order pairs sequentially, out-of-order pairs by ID/key, Modules 18.5–18.6). So data checking assumes a pair and focuses on the field comparison and the report. This separation is clean: the ordering logic answers "which two transactions go together?", and data checking answers "do these two match, and if not, how?". The per-transaction loop produces, for every observed transaction, either a pass (silent or low-verbosity) or a precise bug report — a stream of verdicts, each with enough detail to debug if it's a bug. The flow is the comparison engine: paircompare meaningful fieldspass or report preciselythe focused, usable check that, given a good expected (18.3) and a correct pairing (18.5–18.6), decides correctness per transaction and reports it actionably. Compare the right fields, report precisely — for every paired transaction.

Waveform Perspective — comparing fields, reporting which one differs

The comparison is visible on a timeline: for each transaction, the meaningful fields of observed and expected are compared, and on a mismatch, the report names which field differs. The waveform shows a match and a precise mismatch.

Field-by-field comparison: a match, and a precise mismatch naming the differing field

12 cycles
Field-by-field comparison: a match, and a precise mismatch naming the differing fieldtxn 1: data A4==A4 (meaningful match); tag 11 vs 00 differs but is MASKED → matchtxn 1: data A4==A4 (me…txn 2: data B0 vs C1 differ (meaningful) → mismatchtxn 2: data B0 vs C1 d…report names the field: 'data: got B0, expected C1' (precise)report names the field…clkobs_data--A4------B0------------exp_data--A4------C1------------obs_tag--11------22------------exp_tag--00------00------------sb_matchsb_mismatcht0t1t2t3t4t5t6t7t8t9t10t11
Figure 4 — comparing the meaningful fields, masking the don't-care. For transaction 1, the meaningful fields match: addr and data agree (obs_data=A4 == exp_data=A4), and the don't-care tag differs (obs_tag=11 vs exp_tag=00) but is masked, so sb_match (pass) — the tag difference does NOT cause a mismatch. For transaction 2, the data field differs (obs_data=B0 vs exp_data=C1): sb_mismatch fires, and the report names the field — 'data: got B0, expected C1'. The don't-care tag is never compared; the meaningful data is, and the mismatch report is precise about which field and both values.

The waveform shows the field comparisonmasking the don't-care, reporting precisely. For transaction 1, the meaningful fields match: obs_data=A4 equals exp_data=A4; and the don't-care tag differs (obs_tag=11 vs exp_tag=00) but is masked, so sb_match fires (a pass) — the tag difference does NOT cause a mismatch. For transaction 2, the data field differs (obs_data=B0 vs exp_data=C1): sb_mismatch fires, and the report names the field"data: got B0, expected C1". The crucial reading is the two behaviors visible together: (1) the don't-care tag differs in both transactions but never causes a mismatch (it's maskednot compared), so the correct transaction 1 passes despite the tag difference; and (2) the meaningful data is compared, so transaction 2's real difference is caught, with a precise report (which field, got, expected). The picture to carry is the selectivity and precision: the scoreboard compares the meaningful fields (data) and masks the don't-cares (tag), so it neither false-flags (transaction 1's tag) nor misses (transaction 2's data), and when it does flag, the report is precise (data: got B0, expected C1). The counterfactual (the DebugLab): if tag were compared, transaction 1 would false-mismatch (tag 11 ≠ 00) — noise on a correct DUT. Reading this waveform — do the meaningful fields match? is the don't-care masked? does the mismatch report name the field and both values? — confirms the comparison is correct and usable. The meaningful field compared, don't-care masked, mismatch reported precisely is the signature of data checking done right: fair (the tag difference doesn't fail a correct DUT) and useful (the data mismatch is named exactly).

DebugLab — the scoreboard that flagged a correct DUT on a don't-care field

A flood of false mismatches because the comparison included a field the predictor can't predict

Symptom

A scoreboard flagged mismatches on nearly every transaction — a flood of errors. But the precise mismatch report (good practice!) said: "field 'tag': got 0x2A, expected 0x00" — the same field, every time. The data, address, and response fields all matched; only the tag field differed. The DUT was functionally correct — it was processing the transactions right — but the scoreboard was failing it because of the tag field, which the DUT set to various values while the predictor set to its default (0x00).

Root cause

The comparison included the tag field — a don't-care the spec leaves unspecified, so the predictor can't predict it — so the DUT's legitimate, arbitrary tag differed from the predictor's default, producing a false mismatch on every transaction:

why comparing a don't-care field floods false mismatches
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
✗ COMPARE a don't-care field the predictor can't predict → false mismatch every time:
  `uvm_field_int(tag, UVM_ALL_ON)   // ✗ tag is UNSPECIFIED by the spec → included in compare
  // the DUT sets tag to arbitrary values (legal — the spec doesn't define it)
  // the predictor sets tag to its default (0x00) — it has NO basis to predict an unspecified field
  // → tag always differs → false mismatch on EVERY transaction (DUT is actually correct)
 
✓ MASK the don't-care → compare only the meaningful fields:
  `uvm_field_int(tag, UVM_NOCOMPARE)   // ✓ tag excluded from compare (don't-care)
  // now compare only addr/data/resp (spec-defined, meaningful) → correct DUT passes, real bugs caught

This is the don't-care false-mismatch bug — comparing a field the predictor can't predict, which produces a false mismatch on every transaction with that field. The tag field is unspecified by the spec — the DUT is free to set it to any value (a tracking ID, an internal counter), and doing so is correct. But the predictor has no basis to predict an unspecified field — the spec doesn't say what it should be — so it sets a default (0x00). Comparing tag then pits the DUT's arbitrary-but-legal value against the predictor's default → they differ → a false mismatch — on every transaction. The DUT is functionally correct (data, address, response all match); the scoreboard is failing it over a don't-care. The tellthanks to the precise reporting — is obvious: the same field (tag) mismatches every time, while all other fields match. (This is why precise reporting matters: it immediately shows the false mismatch is one specific don't-care field, not a real DUT bug — a vague "mismatch" would have hidden this, costing a long investigation.) The fix is to mask the don't-care: exclude tag from the compare (UVM_NOCOMPARE), so the scoreboard compares only the meaningful fields (addr, data, resp) — the correct DUT passes, and real bugs are still caught. The general lesson, and the chapter's thesis: compare only the meaningful fields — the ones the spec defines and that matter for correctness — and mask the don't-cares (unspecified or irrelevant fields the predictor can't predict), because comparing a don't-care produces false mismatches (the predictor has no basis to predict it). But beware the opposite: don't over-mask — masking a meaningful field hides real bugs (a silent hole). The right set is exactly the meaningful fields. And precise reporting (which field, got vs expected) is what lets you instantly recognize a don't-care false mismatch (same field every time) versus a real bug. Grade only what counts; a doodle differing isn't a wrong answer.

Diagnosis

The tell is the same field mismatching every time, with others matching. Diagnose don't-care comparisons:

  1. Read the precise mismatch report. If the same field mismatches on every transaction while others match, it's likely a don't-care being compared.
  2. Check the field against the spec. If the spec leaves the field unspecified (reserved, a tracking tag, a timestamp), the predictor can't predict it — don't compare it.
  3. Confirm the meaningful fields match. If data, address, and response all match and only one field differs, the DUT is likely correct and the field is a don't-care.
  4. Beware over-masking, too. Before masking, confirm the field is truly a don't-care — masking a meaningful field hides real bugs.
Prevention

Compare exactly the meaningful fields:

  1. Mask don't-cares. Exclude unspecified or irrelevant fields (UVM_NOCOMPARE or a custom compare) the predictor can't predict.
  2. Compare every meaningful field. Include every spec-defined, correctness-relevant field; masking one hides bugs there.
  3. Derive the field set from the spec. Decide compare-or-mask per field based on whether the spec defines it and it matters for correctness.
  4. Report precisely. A which-field, got-vs-expected report lets you instantly distinguish a don't-care false mismatch from a real bug.

The one-sentence lesson: compare only the meaningful fields the spec defines and that matter for correctness, and mask the don't-cares the predictor can't predict — because comparing a don't-care floods false mismatches (the predictor has no basis to predict an unspecified field), while masking a meaningful field hides real bugs; precise reporting (which field, got vs expected) lets you instantly tell the two apart.

Common Mistakes

  • Comparing a don't-care field. An unspecified or irrelevant field the predictor can't predict floods false mismatches; mask it (UVM_NOCOMPARE).
  • Masking a meaningful field. Excluding a spec-defined, correctness-relevant field hides real bugs there — a silent hole; compare every meaningful field.
  • Vague mismatch reports. A bare "mismatch" turns every failure into an investigation; report which field, got vs expected, and the context.
  • Comparing everything by default. Don't blindly compare all fields; decide compare-or-mask per field from the spec.
  • Not knowing which fields the spec defines. The compare/mask decision requires knowing what the spec specifies; an unspecified field is a don't-care.
  • Ignoring repeated same-field mismatches. The same field mismatching every time is the signature of a don't-care being compared, not a DUT bug.

Senior Design Review Notes

Interview Insights

Data checking is the scoreboard's field-by-field comparison of a paired observed and expected transaction — deciding whether they match. Its two key decisions are which fields to compare and how to report a mismatch. The which-fields decision is to compare only the meaningful fields — the ones the spec defines and that matter for correctness, like address, data, and response — and to mask the don't-cares, fields the spec leaves unspecified or that are irrelevant, like a reserved field, a tracking tag, or a timestamp. This matters because of two symmetric dangers. Comparing too many fields, including a don't-care the predictor can't predict, produces false mismatches: the DUT is correct, but an unspecified field differs because the predictor had no basis to predict it, so you get noise on every transaction. Comparing too few fields, masking a meaningful field, produces missed bugs: a real bug in that field is never caught, a silent hole. The right set is exactly the meaningful fields. The how-to-report decision is to report a mismatch precisely: which field differed, the got or observed value, the expected value, and the transaction context. This matters because a vague mismatch message turns every failure into a fresh investigation, while a precise one points straight at the problem and makes debugging instant. It also lets you instantly recognize a don't-care false mismatch — if the same field mismatches every time while others match, it's a don't-care being compared, not a DUT bug. The mental model is grading an answer against a key: you compare field by field, grade only the parts that count — not the margin doodles — and mark precisely what's wrong, so the grade is fair and the feedback is useful. So data checking is the comparison done right: compare exactly the meaningful fields, and report precisely.

Because the predictor can't predict a don't-care field, so comparing it pits the DUT's arbitrary-but-legal value against the predictor's default, producing a false mismatch every time. A don't-care field is one the spec leaves unspecified or that's irrelevant to correctness — a reserved field, a tracking tag, a timestamp. For such a field, the spec doesn't say what the value should be, so the DUT is free to set it to anything, and doing so is correct. But the reference model has no basis to predict an unspecified value, so the predictor sets a default, like zero. If you compare that field, the DUT's arbitrary value and the predictor's default differ, and you get a false mismatch — and since the DUT sets it on every transaction, you get a flood of false mismatches on a DUT that's actually correct. This is noise: it wastes debug time chasing a non-bug, and worse, it erodes trust in the scoreboard. If engineers start seeing mismatches that turn out to be false, they begin ignoring mismatches, which is dangerous because a real one might get ignored too — the boy who cried wolf. So you mask the don't-cares — exclude them from the compare, using a field flag like UVM_NOCOMPARE or a custom compare — so only the meaningful fields are compared. Then a correct DUT passes, because the meaningful fields match, and the arbitrary don't-care values don't cause failures. The important balance is that you must mask only true don't-cares. If you over-mask and exclude a meaningful field, you create the opposite problem, a missed bug, because a real bug in that field would never be caught. So the rule is to compare exactly the meaningful fields the spec defines, and mask exactly the don't-cares the spec leaves unspecified. Determining which is which requires knowing the spec. Precise reporting helps you catch a mistakenly-compared don't-care, because it shows the same field mismatching every time while others match.

The two failure modes are comparing too many fields, which gives false mismatches, and comparing too few fields, which gives missed bugs, and they have opposite symptoms. Comparing too many means including a don't-care field the predictor can't predict. The symptom is false mismatches: a correct DUT gets flagged, producing noise. This failure is loud — the scoreboard flags errors, so you notice — and it's annoying and trust-eroding, because you waste time chasing non-bugs and may start ignoring mismatches. Comparing too few means masking a meaningful field that matters for correctness. The symptom is missed bugs: a real bug in that field is never caught, a silent hole. This failure is silent — the scoreboard passes, so you don't notice — and it's dangerous, because a real bug escapes, possibly to silicon. So the two errors pull in opposite directions. If you err toward more fields, you get false mismatches, which are loud noise. If you err toward fewer fields, you get missed bugs, which are silent holes. The right answer is neither extreme but exactly the meaningful fields — every field the spec defines and that matters, and no don't-cares. The asymmetry in danger is worth noting: false mismatches are loud and you'll fix them, while missed bugs are silent and may never be found until too late, so over-masking is the more dangerous direction. But both are wrong, and the fix for both is the same: derive the compare-or-mask decision for each field from the spec — is it defined and does it matter? If yes, compare it; if it's unspecified or irrelevant, mask it. Precise reporting helps distinguish a too-many error in practice, because a don't-care false mismatch shows the same field every time, whereas a real bug is more varied. So field selection is a balance between noise and blindness, and you tune it by knowing the spec.

Because the report is part of the check's value — a precise mismatch makes debugging instant, while a vague one turns every failure into a fresh investigation. When the scoreboard flags a mismatch, it's signaling a possible bug, but the signal's usefulness depends on its detail. A vague message like "mismatch occurred" tells you something is wrong but nothing about what, so you have to go investigate from scratch: which transaction, which field, what values. A precise message — which field differed, the got or observed value, the expected value, and the transaction context, like "field data: got 0xB0, expected 0xC1 for addr 0x10" — points straight at the problem. You know immediately which field is wrong and what each side has, which often tells you the nature of the bug at a glance. This dramatically speeds debugging, especially at scale where you might have many mismatches to triage. Precise reporting also serves a second purpose: it lets you instantly recognize false mismatches. If the report shows the same field, say a tag, mismatching on every transaction while all other fields match, you immediately recognize a don't-care being compared rather than a real DUT bug — the precise report makes the pattern obvious. A vague report would have hidden this, costing a long investigation to discover it's just one field. So precise reporting both speeds real-bug debugging and exposes false mismatches. In practice you produce it by formatting the mismatch message with the field name and both values, often using the comparer's miss log or an explicit sformatf with the relevant fields. The principle is that a check that detects a problem but reports it poorly has done only half its job — finding the discrepancy is necessary, but conveying exactly what and where is what makes it actionable. So you invest in the report as much as in the comparison, because a precise, which-field, got-versus-expected message is the difference between a quick fix and a slow hunt.

Data checking is the comparison once two transactions are paired, while the pairing itself — deciding which expected goes with which observed — is a separate concern handled by the ordering logic. There's a clean division of labor. The ordering logic answers the question, which observed transaction corresponds to which expected? For an in-order DUT, this is simple: the observed transactions arrive in the same order as the expected, so you pair them sequentially, the first observed with the first expected, and so on. For an out-of-order DUT, the observed transactions may arrive in a different order than the expected, so you pair by a matching key, like a transaction ID, finding the expected whose ID matches the observed's. Those are the topics of the in-order and out-of-order checking chapters. Data checking takes a pair — one observed and its corresponding expected — and answers the question, do these two match, and if not, how? It compares the meaningful fields field by field, masks the don't-cares, and on a mismatch reports precisely which field differs and the values. So data checking assumes the pairing is done and focuses on the field comparison and the report. This separation keeps each concern manageable: the ordering logic deals with matching and queuing, and the data checking deals with comparison and reporting. In the scoreboard, this often shows up as the ordering logic pulling the matching expected for an arriving observed — popping from a queue for in-order, or looking up by ID for out-of-order — and then calling the comparison routine on the pair. The comparison routine is the data-checking part, independent of how the pair was formed. Understanding this division helps you debug: if the wrong transactions are being compared, that's an ordering problem; if paired transactions are compared wrong or reported poorly, that's a data-checking problem. So data checking is the per-pair comparison, and the pairing is the ordering logic's job, and together they form the complete check.

Exercises

  1. Classify the fields. For a bus transaction with address, data, response, a reserved field, and a timestamp, decide which to compare and which to mask, and why.
  2. Write the report. Write a precise mismatch message for a data-field difference, including the fields a debugger needs.
  3. Diagnose the flood. The same field mismatches on every transaction while others match. Name the cause and the fix.
  4. Avoid both errors. Explain the two failure modes of field selection and how to choose the right set.

Summary

  • Data checking is the scoreboard's field-by-field comparison of a paired observed and expected transaction: compare the meaningful fields, mask the don't-cares, pass on a full match, and on a mismatch report precisely.
  • Compare only the meaningful fields — the ones the spec defines and that matter for correctness — and mask the don't-cares (unspecified or irrelevant fields the predictor can't predict), via field-automation flags (UVM_NOCOMPARE) or a custom compare.
  • The two failure modes are symmetric: comparing too many (a don't-care) → false mismatches (loud noise, eroded trust); comparing too few (masking a meaningful field) → missed bugs (a silent hole) — the right set is exactly the meaningful fields.
  • Report preciselywhich field, got vs expected, context — because a precise report makes debugging instant and lets you instantly recognize a don't-care false mismatch (same field every time) versus a real bug.
  • The durable rule of thumb: compare exactly the meaningful fields (spec-defined, correctness-relevant) and mask the don't-cares the predictor can't predict — comparing a don't-care floods false mismatches, masking a meaningful field hides real bugs — and report every mismatch precisely (which field, got vs expected, context), which makes real bugs instant to debug and don't-care false mismatches obvious.

Next — In-Order Checking: the simplest pairing — in-order checking: when the DUT's outputs arrive in the same order as the inputs, the scoreboard pairs each observed transaction with the next expected from a queue, the FIFO pattern that implements it, and the cases (drops, duplicates, reordering) it catches and the ones it can't.