UVM
Reference Models
The golden model the predictor draws on — the executable, independent embodiment of the spec whose fidelity is the ceiling on what the scoreboard can catch, the functional abstraction it uses, the option of C/C++ via DPI, and why it must be independent of the RTL.
Scoreboards · Module 18 · Page 18.3
The Engineering Problem
The predictor produces the expected by applying a model of the intended behavior (Module 18.2). This chapter is that model — the reference model (the golden model): the executable embodiment of the spec that defines what correct is. Building one raises questions that determine the entire value of the checker. What does it model (the functional behavior — not the cycle-accurate micro-architecture)? How faithful must it be (its fidelity to the spec is the ceiling on what the scoreboard can catch — a gap in the model is a blind spot in verification)? How do you build it (SystemVerilog? C/C++ via DPI for a complex DUT?)? And — the subtle, critical one — where does it come from? It must come from the spec, independently — not from the RTL. If the reference model is a re-implementation of the RTL's algorithm, it replicates the RTL's bugs: the model and the DUT are wrong the same way, they agree, and the scoreboard passes — hiding the bug. The problem this chapter solves is building a faithful, independent reference model: the thing that defines correct for the entire checking effort.
A reference model is the executable, independent embodiment of the DUT's specification — the golden model that, given an input (and state), computes the correct output. It is abstracted: it models the functional/algorithmic behavior (what the output should be) — not the cycle-accurate micro-architecture (how the DUT computes it, with pipelines and internal timing) — which makes it simpler, faster, and independent of the DUT's implementation. Its fidelity to the spec is the defining property: the scoreboard can catch exactly the DUT deviations the model correctly captures — so a gap or error in the model is a blind spot (a missed bug) or a false alarm. It must be built independently from the spec — not a re-implementation of the RTL — or it replicates the implementation's bugs and the scoreboard passes them silently. For complex DUTs (codecs, processors, DSP), it's often written in C/C++ and called via DPI, reusing an existing software golden model. This chapter is the reference model: what it embodies, fidelity as the ceiling, functional abstraction, independence from the RTL, and DPI for complexity.
What is a reference model — the executable, independent embodiment of the spec that defines correct — and why is its fidelity the ceiling on what the scoreboard can catch, why must it be abstracted and independent of the RTL, and when is it written in C via DPI?
Motivation — why the reference model defines the verification
The reference model is not a detail — it defines what verification can do. The reasons:
- The reference model is the definition of correct. The scoreboard checks the DUT against the reference model. So the reference model is the standard — whatever it says is correct is what the check enforces. Its correctness is the foundation.
- Its fidelity is the ceiling on what's caught. A faithful model (correct per the spec) lets the scoreboard catch every DUT deviation. A model with a gap (doesn't model a feature) can't catch bugs there (a blind spot); a model with an error false-flags a correct DUT. Verification can't exceed the model's fidelity.
- It must be independent of the implementation. If the model is derived from the RTL (copies its algorithm), it shares the RTL's bugs — they're wrong the same way, agree, and the scoreboard passes. The model must come independently from the spec, so it disagrees with a buggy DUT.
- Abstraction makes it tractable and independent. Modeling the functional behavior (not the cycle-accurate micro-architecture) makes the model simpler, faster to write and run, and independent of the DUT's internal design (so it doesn't accidentally replicate the DUT's implementation choices — and bugs).
- Complex DUTs need a real software model. For a codec, processor, or DSP, the intended behavior is a substantial algorithm — often already implemented as a C/C++ software model (a spec frequently ships with one). DPI lets you call that existing golden model from the testbench.
The motivation, in one line: the reference model is the definition of correct the scoreboard enforces, so its fidelity to the spec is the ceiling on what verification can catch — which requires it to be faithful (or you have blind spots), abstracted to the functional level (tractable, independent), independent of the RTL (or it replicates the DUT's bugs), and — for complex DUTs — often a C/C++ golden model via DPI.
Mental Model
Hold the reference model as a golden ruler, made independently from the specification, that the DUT is measured against:
A reference model is a golden ruler: an authoritative standard, made independently from the specification, that the DUT is measured against. Its accuracy is the ceiling on what you can detect — a faithful ruler catches every deviation, a flawed ruler measures wrong — and a ruler copied from the very thing it measures is useless, because it would call any object 'correct'. Picture measuring a manufactured part (the DUT) against a reference ruler (the reference model). The ruler is the standard of correct — whatever it reads is taken as the truth, and the part is judged against it. Three things follow. First, the ruler's accuracy is the ceiling on what you can detect: if the ruler is accurate (a faithful embodiment of the intended dimensions — the spec), it catches every deviation of the part; if the ruler is off (a gap, a wrong marking), it measures wrong — it misses the part's real errors or flags a good part. You can't measure more accurately than your ruler. Second, the ruler must be made from the design intent, independently — from the blueprint (the spec), by a different process than the part. Third — the crucial trap — a ruler copied from the very part it measures is useless: if you make the ruler by tracing the part, then the part always matches the ruler (they're the same shape), so you'd call any part — including a defective one — correct. The ruler must be made independently of the part, from the intended dimensions, so that a defective part disagrees with it. A good metrology lab never derives its standard from the thing under test; it builds the standard from the specification, independently, so the comparison means something. The whole value of the ruler is its independent fidelity to the intended design.
So the reference model is a golden ruler made independently from the spec: it is the authoritative standard of correct, against which the DUT is measured; its fidelity to the spec is the ceiling on what you can detect (a faithful ruler catches every deviation; a flawed one measures wrong); and it must be made independently of the DUT — from the spec, not the RTL — because a ruler copied from the part would call any part correct (it replicates the part's defects). Build the standard from the design intent, independently — never trace it from the thing you're measuring.
Visual Explanation — the reference model defines correct, from the spec
The defining picture is the origin and role: the reference model is built from the spec independently and defines correct, which the predictor/scoreboard use to judge the DUT.
The figure shows the reference model's origin and role. The specification (the intended behavior) is the source. The reference model is built from it, independently of the RTL — embodying the spec as executable code. It defines what correct is — the predictor applies it to compute the expected, and the scoreboard checks the DUT against that expected. The RTL (DUT) is also built from the spec, but by a different path (a different team, a different discipline — design vs verification). The crucial reading is the two independent realizations of the same spec: the brand-colored reference model and the default RTL are both derived from the warning-colored spec, but independently — so they don't share implementation choices (or bugs). Because they're independent, a DUT deviation from the spec makes the DUT disagree with the reference (which is faithful to the spec), and the scoreboard catches it. The success-colored "definition of correct" and "scoreboard" show the model's role: it is the standard, and the check is DUT vs standard. The independence is structural and essential: if the reference model were built from the RTL (the dashed path that must not exist), it would share the RTL's bugs, and the check would pass them. The diagram is the epistemology of checking: two independent realizations of the spec (reference model and DUT), cross-checked — the reference trusted (it's simpler, abstract, carefully built from the spec), the DUT under test; and the independence of the two paths from the spec is what makes a disagreement reveal a DUT bug. Build the reference from the spec, by a path independent of the RTL, so the two realizations can disagree.
RTL / Simulation Perspective — building the reference model (SV and C/DPI)
In code, the reference model can be SystemVerilog (for simpler behavior) or a C/C++ golden model via DPI (for complex algorithms). The code shows both, and the abstraction.
// === SYSTEMVERILOG reference model: the intended FUNCTION, abstractly (not cycle-accurate) ===
class alu_ref_model;
// models WHAT the output should be — from the SPEC — not HOW the RTL pipelines it
function bit [31:0] compute(bit [31:0] a, b, op_e op);
case (op)
ADD: return a + b; // the spec's intended result — independent of the RTL's adder design
SUB: return a - b;
MUL: return a * b; // no pipeline stages, no internal timing — just the function
// ... full spec coverage: every operation, every corner (overflow, flags) the scoreboard checks
endcase
endfunction
endclass
// === C/C++ GOLDEN MODEL via DPI: reuse an existing software model for a COMPLEX DUT ===
import "DPI-C" function void codec_ref_encode(input byte unsigned in[], output byte unsigned out[]);
// the C reference (often shipped WITH the spec) computes the expected; the predictor calls it:
class codec_predictor extends uvm_subscriber #(frame_txn);
function void write(frame_txn t);
out_txn e = out_txn::type_id::create("e");
codec_ref_encode(t.payload, e.encoded); // ← call the C golden model for the expected output
expected_ap.write(e);
endfunction
endclass
// ✗ NEVER build the reference by copying the RTL's algorithm → it replicates the RTL's bugs (DebugLab).The code shows the two main implementation paths. The SystemVerilog reference model (alu_ref_model) models the intended function — from the spec — abstractly: compute returns the spec's result for each operation (ADD: a + b, etc.) without the RTL's pipeline stages or internal timing — what the output should be, not how the RTL computes it. Its fidelity is full spec coverage (every operation, every corner — overflow, flags — the scoreboard checks). The C/C++ golden model via DPI is for complex DUTs: import "DPI-C" brings in a C reference (codec_ref_encode — often shipped with the spec), and the predictor calls it (codec_ref_encode(t.payload, e.encoded)) to compute the expected output — reusing the existing software golden model rather than re-writing a complex algorithm in SystemVerilog. The closing ✗ comment marks the cardinal rule: never build the reference by copying the RTL's algorithm — it replicates the RTL's bugs (the DebugLab). The shape to carry: a reference model is the intended function, made executable — in SystemVerilog for simpler DUTs (the function, abstractly, from the spec) or via DPI-C for complex ones (reusing a C golden model) — and it models what the output should be (functional), not the DUT's micro-architecture (cycle-accurate), built from the spec, never from the RTL. The abstraction (functional, not cycle-accurate) and the independence (from the spec, not the RTL) are the two defining properties; the implementation language (SV vs C) is a practical choice driven by the model's complexity.
Verification Perspective — fidelity is the ceiling on what's caught
The reference model's fidelity to the spec determines what the scoreboard can catch — it is the ceiling on verification. Seeing how a gap or error in the model limits the check is seeing why fidelity is paramount.
The figure shows fidelity as the ceiling — how the model's correctness and completeness bound what the scoreboard can catch. A faithful model (correct and complete per the spec) gives full correctness coverage — the scoreboard catches every DUT deviation (the brand → success path). A model gap (a feature not modeled) creates a blind spot: bugs in that area are never caught, because there's no expected to compare against — the scoreboard is silent where the model is empty. A model error (modeled wrong) creates a false alarm: a correct DUT is flagged (the model says wrong when the DUT is right). The verification insight is that the model defines, and limits, what correctness checking can find: the scoreboard can catch exactly the deviations the model correctly captures — no more. So a gap in the model is a gap in verification (a silent blind spot — worse than a visible hole, because you don't know it's unchecked), and an error in the model is a false failure (noise that wastes debug time and erodes trust). The warning-colored gap and error are the two ways fidelity falls short. This is why the reference model is the highest-leverage artifact in the checker: improving the model's fidelity directly raises the ceiling on what verification finds, and any model deficiency directly limits it. The practical consequence: the reference model deserves the same rigor as the DUT — it must be reviewed against the spec, covered (every feature modeled), and validated (it must agree with a known-good DUT and catch injected bugs). The figure is the stakes of the reference model: it's not a helper but the standard — whatever it can't model, verification can't check, and whatever it gets wrong, verification gets wrong — so its fidelity to the spec is literally the ceiling on what the entire checking effort can catch.
Runtime / Execution Flow — building a faithful, independent reference model
Building a reference model is a disciplined process: derive it from the spec (independently), abstract to the functional level, cover every feature, and validate it. The flow shows the steps.
The flow shows the disciplined build of a faithful, independent reference model. Derive (step 1): build it from the specification, independently of the RTL — not by copying the RTL's algorithm — so it doesn't share the RTL's bugs (the DebugLab). Abstract (step 2): model what the output should be (the functional behavior), not the cycle-accurate micro-architecture — making it simpler, faster, and independent of the DUT's internal design. Cover (step 3): model every feature the scoreboard checks (every operation, every corner), so there are no blind spots (gaps). Validate (step 4): confirm it agrees with a known-good DUT (so it's not false-flagging) and catches injected bugs (so it's actually checking) — proof it's faithful. The runtime insight is that the reference model is built and validated with the same rigor as the DUT — because it's the standard. Each step guards a failure mode: derive-independently guards the replicated-bug trap (step 1 → DebugLab); abstract guards tractability and independence (step 2); cover guards blind spots (step 3 → Figure 2's gap); validate guards both false alarms (agrees with good DUT) and blind spots (catches injected bugs) (step 4). The implementation choice — SystemVerilog or C/C++ via DPI — is driven by the model's complexity (step alongside, not a separate concern). This is why a reference model is not a quick helper but a first-class deliverable: its fidelity is the ceiling on verification (Figure 2), so it must be derived right (independent), abstracted right (functional), covered (no gaps), and validated (agrees + catches) — a process that produces a trustworthy standard of correct. The flow is the recipe for the golden model: from the spec, independently; functional, not cycle-accurate; complete; and validated — so it can be trusted as the definition of correct the entire check rests on.
Waveform Perspective — functional abstraction: the model computes what, not how
The reference model's abstraction is visible on a timeline: the DUT takes many cycles (pipeline, micro-architecture) to produce an output, while the reference model computes the same output value functionally — they agree on the data, abstracting the how. The waveform shows the level difference.
The DUT computes the result over many cycles; the reference model computes the same value functionally
12 cyclesThe waveform shows the reference model's functional abstraction. The DUT takes several cycles to compute the result: the input (in=12) enters its pipeline (stages S1, S2, S3 on dut_pipe), and the actual output (dut_out=24 — say a doubling) appears a few cycles later, after the micro-architecture's stages. The reference model computes the same result value functionally — ref_out=24 — modeling what the output should be, not the cycle-accurate pipeline. The scoreboard compares the data (dut_out == ref_out → sb_match). The crucial reading is the level difference: the DUT's dut_pipe shows the micro-architecture (the multi-cycle pipeline — how the result is computed), while the reference's ref_out shows just the result value (what the result should be) — available immediately, functionally, without modeling the stages. The reference abstracts the how (the multi-cycle pipeline) and models only the what (the result value 24) — which is why it's simpler (no pipeline to model) and independent of the DUT's micro-architecture (it doesn't care how the DUT computes 24, only that the result should be 24). The picture to carry is that the reference model lives at a higher abstraction level than the DUT: the DUT is cycle-accurate RTL (stages, timing); the reference is functional (the result). They meet at the data — dut_out == ref_out — which is what the scoreboard checks. Reading this — does the DUT's eventual output match the reference's functional result? — confirms the DUT computes the right value (regardless of how its pipeline got there). The DUT's multi-cycle pipeline vs the reference's functional result, agreeing on the data is the signature of functional abstraction: the reference models what, the DUT implements how, and the check is did the how produce the right what — which is exactly the level at which correctness (as opposed to micro-architecture) is defined.
DebugLab — the reference model that shared the DUT's bug
A spec violation that escaped because the reference model was copied from the RTL
A scoreboard passed every test — thorough random regressions, zero mismatches — and the team signed off. In silicon (or late, against a strict spec review), a spec violation was found: the DUT handled a corner case (a particular rounding mode) differently from the specification. But the scoreboard — which should have caught a spec deviation — had passed it. The reference model also handled that corner the same (wrong) way as the DUT, so the two agreed, and the scoreboard saw no mismatch. The check had a blind spot exactly where the DUT and the model shared an error.
The reference model was built from the RTL (its algorithm copied from the implementation, or written by the same engineer the same way) instead of independently from the spec — so it replicated the RTL's bug, and the two were wrong the same way:
✗ reference model DERIVED FROM THE RTL (replicates the RTL's bug → they agree → bug hidden):
// RTL rounds a corner case toward zero (WRONG per spec, which says round-to-nearest)
// reference model was written by COPYING the RTL's rounding logic (round toward zero)
// → ref and DUT BOTH round toward zero → they AGREE → scoreboard PASSES → spec violation HIDDEN
// the model shares the DUT's implementation bug, so it can't catch it
✓ reference model derived INDEPENDENTLY FROM THE SPEC (disagrees with the buggy DUT → caught):
// reference model implements round-to-nearest PER THE SPEC (independent of how the RTL does it)
// → DUT rounds toward zero (bug), ref rounds to nearest (correct) → they DIFFER → MISMATCH → caught
// independence from the RTL is what lets the model catch the RTL's implementation bugsThis is the replicated-bug trap — the subtlest and most dangerous reference-model failure, a circular check (Module 18.1) in its most insidious form: the reference model and the DUT share an implementation error, so they agree and the scoreboard passes the bug. The reference model was not derived independently from the spec — it was built from the RTL (its rounding logic copied from the implementation, or written by the same person who misread the spec the same way). The RTL rounded a corner case toward zero (wrong — the spec says round-to-nearest), and the reference model did the same (because it replicated the RTL's algorithm). So for that corner, ref and DUT both rounded toward zero — they agreed — and the scoreboard saw no mismatch. The check was blind exactly where the model shared the DUT's error. The tell is brutal: the scoreboard passes (no mismatch), so there's no signal — the bug is invisible to the check, discovered only by an independent means (silicon, a spec review). The danger is the false confidence: thorough regressions all passed, so the team believed the corner was verified, when the check was structurally incapable of catching that bug. The fix is to derive the reference model independently from the spec: implement round-to-nearest per the specification (regardless of how the RTL does it) — so the DUT's (buggy) round-toward-zero disagrees with the reference's (correct) round-to-nearest, producing a mismatch that catches the bug. The general lesson, and the chapter's thesis: the reference model must be an independent realization of the spec, not a re-implementation of the RTL — if it replicates the implementation (copied algorithm, or the same misreading of the spec), it replicates the implementation's bugs, and the scoreboard passes them silently (the model and DUT wrong the same way agree), creating a blind spot exactly where it's most dangerous. Build the reference from the spec, by a path independent of the RTL — ideally a different engineer, a different abstraction — so the two realizations can disagree, which is the only way the check catches implementation bugs. Never trace the ruler from the part.
The tell is a passed check that misses a known spec violation. Diagnose replicated bugs:
- Trace where the reference model came from. If it was derived from the RTL (copied algorithm, same author, same approach), it may share the RTL's bugs.
- Cross-check the model against the spec, not the RTL. Review the model line-by-line against the specification to find shared misinterpretations.
- Inject a spec-violating bug into the DUT. If the reference model "agrees" with the violation, it replicates the implementation rather than the spec.
- Look for blind spots at shared corners. Areas where both the model and RTL were written by the same person or from the same (mis)understanding are suspect.
Build the reference independently from the spec:
- Derive from the spec, not the RTL. Implement the intended behavior from the specification, never by copying the implementation's algorithm.
- Use an independent path. A different engineer, abstraction, or language (e.g., a C golden model) reduces shared misinterpretations with the RTL.
- Validate by injecting spec violations. Confirm the reference catches deliberate spec deviations in the DUT — proof it doesn't share the DUT's behavior.
- Review the model against the spec. Treat the reference model as a first-class deliverable, reviewed for fidelity to the specification independently of the RTL.
The one-sentence lesson: the reference model must be an independent realization of the spec, not a re-implementation of the RTL — if it replicates the implementation (copied algorithm or shared misreading of the spec), it replicates the implementation's bugs, and the scoreboard passes them silently (model and DUT wrong the same way agree), so derive it independently from the spec and confirm it catches injected spec violations.
Common Mistakes
- Deriving the reference model from the RTL. It replicates the RTL's bugs; build it independently from the spec, ideally by a different path.
- A gap in the model. A feature not modeled is a silent blind spot — bugs there are never caught; cover every feature the scoreboard checks.
- An error in the model. A wrongly-modeled behavior false-flags a correct DUT; validate the model against a known-good DUT.
- Modeling cycle-accurate micro-architecture. The reference should model the functional behavior (what), not the pipeline (how); cycle-accuracy makes it complex and couples it to the implementation.
- Treating the model as a quick helper. The reference model's fidelity is the ceiling on verification; it deserves first-class rigor, review, and validation.
- Not validating with injected bugs. A model that isn't proven to catch deliberate spec violations may share the DUT's behavior or have blind spots.
Senior Design Review Notes
Interview Insights
A reference model, or golden model, is the executable, independent embodiment of the DUT's specification — given an input and state, it computes the correct output. It's the standard the scoreboard checks the DUT against, so it is the definition of correct for the entire checking effort. Its fidelity is critically important because it's the ceiling on what verification can catch. The scoreboard can find exactly the deviations the model correctly captures — no more. So if the model is faithful, correct and complete per the spec, the scoreboard catches every DUT deviation. But if the model has a gap, a feature it doesn't model, there's a blind spot: bugs in that area are never caught, because there's no expected to compare against, and worse, the blind spot is silent — you don't know it's unchecked. And if the model has an error, a behavior modeled wrong, it creates false alarms: a correct DUT gets flagged. So verification can't exceed the model's fidelity. This makes the reference model the highest-leverage artifact in the checker — improving its fidelity directly raises what verification finds, and any deficiency directly limits it. Two properties define it. It's abstracted to the functional level: it models what the output should be, not the cycle-accurate micro-architecture, which makes it simpler, faster, and independent of the DUT's implementation. And it must be independent of the RTL: built from the spec, not by copying the implementation, or it replicates the RTL's bugs and the scoreboard passes them. For complex DUTs, it's often a C or C++ golden model called via DPI, reusing an existing software model. The mental model is a golden ruler made independently from the specification: its accuracy is the ceiling on what you can detect, and a ruler copied from the thing it measures is useless. So fidelity matters because the model defines, and limits, what correctness checking can find.
Because if it's derived from the RTL, it replicates the RTL's bugs, so the model and the DUT are wrong the same way, they agree, and the scoreboard passes the bug. The whole point of checking is to compare the DUT against an independent notion of correct. The reference model provides that notion. But if you build the reference by copying the RTL's algorithm, or the same engineer writes both with the same misunderstanding of the spec, then the reference shares the DUT's implementation choices, including its bugs. So when the DUT does something wrong, the reference does the same wrong thing, they match, and the scoreboard sees no mismatch. The check is blind exactly where the model and DUT share an error, which is the most dangerous place to be blind, because thorough regressions all pass and you have false confidence that the area is verified. This is a circular check in its subtlest form: instead of the expected coming literally from the DUT's output, it comes from a model that mirrors the DUT's implementation. The fix is to derive the reference independently from the spec — implement the intended behavior from the specification, regardless of how the RTL does it. Then when the DUT deviates from the spec, the reference, being faithful to the spec, disagrees, and the deviation is caught. Independence from the RTL is precisely what lets the model catch the RTL's implementation bugs. In practice you maximize independence by using a different path: a different engineer, a different abstraction level, or a different language like a C golden model, so the reference and RTL are unlikely to share the same misinterpretation. And you validate by injecting spec violations into the DUT and confirming the reference catches them. The ruler analogy captures it: a ruler traced from the part it measures would call any part correct; you must build the standard from the design intent, independently. So independence isn't a nicety — it's what makes the comparison able to catch implementation bugs at all.
A reference model should be at the functional, algorithmic level — modeling what the output should be — not the cycle-accurate micro-architecture, which is how the DUT computes it. The DUT, in RTL, is cycle-accurate: it has pipeline stages, internal timing, and a specific micro-architecture that produces the result over several cycles. The reference model should not replicate that. It should model the intended function: given an input and state, what is the correct result. For an ALU, that means computing a plus b for an add, without modeling the adder's internal stages. For a multiplier, it's the product, without the pipeline. The reference computes the result value functionally, and the scoreboard compares that value against the DUT's eventual output, abstracting away how many cycles the DUT took. There are several reasons for this functional abstraction. It makes the model far simpler to write and maintain, since you're not reproducing the micro-architecture. It makes the model faster to run. And critically, it keeps the model independent of the DUT's implementation: if you modeled the cycle-accurate pipeline, you'd be reproducing the DUT's internal design, which both couples the model to implementation details that aren't part of the spec and risks replicating implementation bugs. The spec defines what the output should be, not how many cycles the pipeline takes, so the reference models the spec's level — the what. Timing and cycle-level behavior, if they need checking, are handled separately, often by protocol checks or by the scoreboard's ordering logic, not by making the reference cycle-accurate. So the rule is: model the function, not the micro-architecture; the result value, not the pipeline. This matches the abstraction at which correctness, as opposed to implementation, is defined, and it's what makes the reference simple, independent, and focused on what the scoreboard actually checks — the data.
You write a reference model in C or C++ via DPI when the DUT's intended behavior is a substantial, complex algorithm — like a codec, a processor's instruction set, or a DSP function — especially when an existing software model already implements it. There are a few drivers. First, complexity: a complex algorithm is often far more natural to implement and maintain in C or C++ than in SystemVerilog, with better data structures, libraries, and tooling. Second, reuse: a specification frequently ships with or is accompanied by a reference software model — an architectural model, a spec implementation, a codec library — and that existing golden model is an authoritative, validated embodiment of the intended behavior. Rather than re-implement it in SystemVerilog and risk introducing errors or divergence, you call the existing C model through DPI. DPI, the Direct Programming Interface, lets SystemVerilog call C functions, so the predictor passes the input transaction's data to the C reference function, which computes the expected output and returns it, and the predictor broadcasts that to the scoreboard. This reuses the trusted software model directly. Third, independence: using a separately-developed C golden model, often written by a different team or as part of the architecture effort, naturally gives the independence from the RTL that the reference model needs, reducing the chance of shared bugs. So the pattern is common for processors, where an ISA simulator serves as the reference; for codecs and crypto, where reference C implementations exist; and for DSP, where numerical models are easier in C. For simpler DUTs, an inline SystemVerilog model is fine and avoids the DPI overhead. The choice is driven by the model's complexity and the availability of an existing software golden model. The key point is that whether SystemVerilog or C, the reference must be an independent, faithful embodiment of the spec; DPI is just the mechanism to bring a complex or existing software model into the testbench.
The reference model is the model of intended behavior, and the predictor is the UVM component that uses it to produce the expected stream — the reference model is the source of correctness, the predictor is the integration into the checking flow. The predictor is the component wired into the testbench between the input observation and the scoreboard: it subscribes to the input monitor, maintains any state, and broadcasts expected output transactions. To compute each expected output, it applies the reference model — the embodiment of what the output should be. So the predictor calls or wraps the reference model. For a simple DUT, the reference model might be just a few lines of computation inside the predictor itself, so the two blur together. For a complex DUT, the reference model might be a substantial separate piece — possibly a C golden model called via DPI — and the predictor is the UVM wrapper that handles the transaction-level plumbing, the subscription to inputs, the state maintenance, and the broadcasting, delegating the core computation to the reference model. A useful division is that the predictor owns the integration concerns — observing the right input, maintaining state in lockstep with the DUT, producing transactions, timing the broadcast — while the reference model owns the correctness concern — given an input and state, what's the right output. The predictor's correctness depends on both: it must integrate correctly, getting the input and state right, and the reference model must be faithful to the spec. The fidelity of the reference model is the ceiling on what's caught, while the predictor's job is to apply it correctly to the actual inputs and state. So they're complementary layers: the reference model is the standard of correct, and the predictor is the machinery that applies that standard to each transaction and feeds the result to the scoreboard. Understanding both is necessary — a perfect reference model applied by a buggy predictor still produces wrong expecteds, and a perfect predictor applying a flawed reference model produces wrong expecteds too.
Exercises
- State the ceiling. Explain why the reference model's fidelity is the ceiling on what the scoreboard can catch, with an example of a gap and an error.
- Choose the abstraction. For a pipelined multiplier, explain what the reference model should and shouldn't model.
- Spot the replicated bug. Given a reference model copied from the RTL, explain why a shared bug escapes and how to fix it.
- Decide SV vs DPI. For a simple adder and a video codec, choose the reference model's implementation and justify.
Summary
- A reference model (golden model) is the executable, independent embodiment of the DUT's specification — it computes the correct output and is the definition of correct the scoreboard enforces.
- Its fidelity to the spec is the ceiling on what the scoreboard can catch: a faithful model catches every deviation; a gap is a silent blind spot (missed bug); an error is a false alarm (a correct DUT flagged) — verification can't exceed the model's fidelity.
- It is abstracted to the functional level — modeling what the output should be, not the cycle-accurate micro-architecture (how) — which makes it simpler, faster, and independent of the DUT's implementation.
- It must be independent of the RTL — derived from the spec, not a re-implementation of the RTL — or it replicates the RTL's bugs (model and DUT wrong the same way agree → the scoreboard passes the bug silently); for complex DUTs, often a C/C++ golden model via DPI.
- The durable rule of thumb: build the reference model as a faithful, independent embodiment of the spec — derived from the specification (not the RTL), abstracted to the functional level (what, not how), covering every feature, and validated to agree with a known-good DUT and catch injected spec violations — because its fidelity is the ceiling on what verification can catch, and a model copied from the RTL replicates the RTL's bugs and hides them.
Next — Data Checking: with the expected in hand, the scoreboard performs the comparison — data checking: how it pairs each observed transaction with its expected, compares the fields, reports a precise mismatch (got vs expected, which field), and the patterns for robust, debuggable comparison of transaction data.