Skip to content

VHDL · Chapter 14.9 · Testbench Development

Behavioral and Reference Models

Every checked test, whether self-checking, vector-based, or random, compares the design under test against an expected value, and that value comes from a reference or golden model, an independent and behavioral description of correct output. The key word is behavioral. The model describes what the design should produce, not how the hardware does it, written abstractly in the full language with functions, integers, reals, queues, and wait rather than as RTL. Independence is essential, because a model built from the same flawed assumptions as the design will agree with it and hide the bug, so the golden model should come from the specification, ideally by a different route. The model abstracts timing, computing the right values while the testbench aligns them to the design's latency. This lesson covers what makes a good reference model and its common forms.

Foundation14 min readVHDLTestbenchReference ModelGolden ModelVerificationSpecification

1. Engineering intuition — an independent oracle of correctness

A checker is only as trustworthy as the answers it checks against. Those answers come from a reference model — your oracle of what correct looks like. Two things make it a good oracle. It is behavioral: it states the intended result directly, in whatever abstract terms are clearest (plain integers, a function, a queue), never mirroring the DUT's gate-level structure — describe what, not how. And it is independent: if you build the model by copying the DUT's logic (or the same misreading of the spec), it will reproduce the very bug you are hunting and the test will pass while the design is wrong. The model should trace back to the specification, arrived at by a different path than the implementation.

2. Formal explanation — behavioral, independent, timing-abstract

reference_model.vhd
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
-- A reference model describes WHAT the output should be — abstractly, NOT as RTL.
-- PURE-FUNCTION model: ideal for combinational / per-transaction results.
function ref_alu (op : op_t; a, b : integer) return integer is
begin
  case op is                       -- the SPECIFICATION's behavior, in plain terms
    when ADD => return a + b;
    when SUB => return a - b;
    when AND_OP => return a and b;  -- 'what', computed simply (independent of DUT structure)
    when others => return 0;
  end case;
end function;
 
-- It abstracts TIMING: it returns VALUES; the testbench handles the DUT's latency/pipeline.
--   expected := ref_alu(op, a, b);          -- value now
--   wait for DUT_LATENCY cycles;            -- align to when the DUT actually produces it
--   assert dut_y = to_slv(expected) ...     -- compare at the latency-correct cycle (14.4)

A reference model is behavioral (describes the result, not the circuit), independent (derived from the spec, not the DUT), and timing-abstract (it produces correct values; the testbench aligns them to the DUT's latency). It uses the full, non-synthesizable language — functions, abstract types, queues — because it only ever simulates.

3. Production usage — function, transaction, and algorithmic models

model_forms.vhd
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
-- (1) PURE-FUNCTION model: stateless, one call per transaction (ALU, encoder, arithmetic).
--     expected := ref_alu(op, a, b);
 
-- (2) TRANSACTION / QUEUE model (stateful): for pipelines / streaming, push expected, pop on result.
--     Built on a protected type (13.6) holding a queue (13.7):
shared variable golden : scoreboard_t;
issue_p : process begin wait until rising_edge(clk);
  if issue='1' then golden.push( ref_alu(op,a,b) ); end if;   -- model result enqueued in order
end process;
result_p: process begin wait until rising_edge(clk);
  if dvalid='1' then golden.check( to_int(dut_y) ); end if;   -- DUT result matched to model's
end process;
 
-- (3) ALGORITHMIC model: a behavioral process implementing the algorithm abstractly
--     (e.g. a reference FIR computed in 'real', or a CRC computed with integer math),
--     against which the optimized RTL is checked for equivalence.

What hardware does this become? None — a reference model is simulation-only and deliberately unoptimized: it favors clarity over efficiency because its only job is to be obviously correct. A pure-function model suits combinational/per-transaction blocks; a transaction/queue model (protected type

  • queue) handles pipelines and streams where results lag and must be matched in order; an algorithmic model describes the intended computation abstractly so heavily-optimized RTL can be checked for equivalence. In every case the model is the trusted side of the comparison the checker performs.

4. Structural interpretation — spec to model versus DUT

specification driving an independent reference model compared for equivalence against the DUTindependentimplementedexpectedactualspecificationintended behaviorreference modelbehavioral, independent(what)DUToptimized RTL (how)equivalence checkexpected vs actual(latency-aligned)12
A reference model is an independent, behavioral path from the specification to the expected output, checked for equivalence against the DUT. The same stimulus drives both the DUT (an optimized implementation) and the reference model (an abstract, obviously-correct description derived independently from the spec); a comparator checks them for equivalence at the latency-correct cycle. Independence matters: a model copied from the DUT would reproduce its bugs. The model abstracts timing, producing values the testbench aligns to the DUT's latency. This is a verification-architecture structure, captured by a diagram rather than a waveform.

5. Why this is structural, not timing

A reference model is a verification-architecture element — an independent, behavioral path from spec to expected value, checked for equivalence against the DUT — so the structure above (two paths into a comparator) is the right picture, not a waveform. The model deliberately abstracts timing, producing values rather than cycle- accurate signals; the testbench supplies the latency alignment. Its essence is independence and behavioral abstraction — design-time properties of how the test is built — not a particular signal trace, which is exactly why the model is shown as structure.

6. Debugging example — the model that inherited the DUT's bug

Expected: the reference model catches DUT errors. Observed: the test passes, but the DUT is later found wrong in the field — the model agreed with a buggy DUT. Root cause: the model was not independent — it was written by copying the DUT's logic (or by the same engineer making the same misreading of the spec), so it reproduced the identical error and the comparison always matched; or the model mirrored the DUT's structure/ optimizations instead of describing the intended behavior. Fix: derive the model from the specification, by a different route (different person, different formulation, abstract math), describing what the result should be rather than how the DUT computes it — so a DUT bug makes them disagree. Engineering takeaway: a reference model must be independent of the DUT and tied to the spec; a model copied from the implementation validates nothing because it shares the implementation's bugs.

independent_from_spec.vhd
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
-- BUG: model copies the DUT's (buggy) computation → always agrees, hides the bug.
-- function ref(a,b) return ... is begin return dut_internal_formula(a,b); end;
-- FIX: describe the SPEC's intended behavior, independently and abstractly.
function ref_add (a, b : integer) return integer is begin return a + b; end function;  -- 'what'

7. Common mistakes & what to watch for

  • Non-independent models. Do not derive the model from the DUT's logic; tie it to the spec, ideally via a different formulation/person.
  • Modeling 'how' not 'what'. Describe intended behavior abstractly; mirroring the RTL's structure imports its bugs and complexity.
  • Cycle-accurate models when values suffice. Abstract timing — compute values and let the testbench align latency; do not over-specify timing.
  • Optimizing the model. Favor obvious correctness over efficiency; the model's worth is being trustworthy, not fast.
  • Stateless model for stateful DUTs. Pipelines/streams need a transaction/queue model (protected type), not a pure function, to match lagged results.

8. Engineering insight & continuity

A reference model is the trusted oracle behind every checked test: behavioral (describes what, not how), independent (from the spec, not the DUT, so it does not share its bugs), and timing-abstract (produces values the testbench aligns to latency) — in pure-function, transaction/queue, or algorithmic form. It is what makes self-checking and random testing meaningful. With stimulus, checking, files, vectors, randomness, and models all covered, the module closes by assembling them into reusable infrastructure: the next lesson, VHDL Verification Frameworks — OSVVM, UVVM, and VUnit — which package these patterns into standard libraries.