Skip to content

VHDL · Chapter 14.5 · Testbench Development

assert and report Statements

Self-checking rests on two language constructs. The assert statement evaluates a condition and, when it is false, prints a message at a given severity, which is the basic check. The report statement prints unconditionally, for logging and progress. Both classify their output with a severity level, ordered note, warning, error, then failure, and the simulator is configured to halt at a chosen threshold, commonly error or failure. Good messages are built with concatenation and image attributes so they show the offending values. Assertions are not only for testbenches, since an assert with failure severity makes a great illegal-state guard in RTL, for example a case that should never reach its others branch. This lesson covers the mechanics of both statements, severities and the stop threshold, message building, and the testbench and RTL uses.

Foundation13 min readVHDLassertreportSeverityTestbenchVerification

1. Engineering intuition — say something when reality disagrees

An assertion is a statement of expectation: "this had better be true." When it is, the simulation is silent; when it is not, the assertion speaks up — printing a message you wrote, tagged with how serious it is. That single idea powers checking: every comparison in a self-checking testbench is an assert. The companion report is just the unconditional version — say this regardless, for logging a phase or a value. The severity is the volume knob: a note is informational, a warning is suspicious, an error is wrong, a failure is fatal — and the simulator can be told to stop once things reach a chosen level, so a real failure halts the run instead of scrolling past.

2. Formal explanation — assert, report, and severity

assert_report.vhd
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
-- ASSERT: fires its report ONLY when the condition is FALSE.
assert sum = expected
  report "MISMATCH: got " & to_hstring(sum) & " exp " & to_hstring(expected)   -- message via &
  severity error;                                                              -- severity level
 
-- REPORT: prints UNCONDITIONALLY (logging / progress).
report "starting phase 2 at " & time'image(now) severity note;
 
-- SEVERITY ladder (increasing): note < warning < error < failure.
--   note    : information
--   warning : suspicious but continue
--   error   : a real problem (sims often set the STOP threshold here)
--   failure : fatal — stop now
-- The simulator halts when severity reaches its configured threshold.
 
-- Building messages: concatenation '&' plus 'image / to_hstring / integer'image.
report "count=" & integer'image(n) & " state=" & state_t'image(st) severity note;

assert evaluates a condition and emits its report clause when false; report emits unconditionally. Each carries a severity (note/warning/error/failure), and the simulator stops at a configurable threshold. Messages are ordinary strings built with & and value-to-string conversions ('image, to_hstring).

3. Production usage — checks, logging, and RTL guards

assert_uses.vhd
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
-- (1) TESTBENCH CHECK: the heart of self-checking.
assert dout = golden report "output mismatch at " & time'image(now) severity error;
 
-- (2) LOGGING / progress (unconditional):
report "applied " & integer'image(n_vectors) & " vectors" severity note;
 
-- (3) RTL ILLEGAL-STATE GUARD: assert something that must never happen.
case state is
  when IDLE => ...
  when RUN  => ...
  when others =>
    assert false report "FSM reached illegal state" severity failure;   -- should be unreachable
end case;
-- Synthesis IGNORES assertions (no hardware), but in simulation this catches the bug loudly.

What hardware does this become? Nothing — assertions and reports are ignored by synthesis; they generate no logic. That is exactly why they are safe to sprinkle through both testbenches and RTL: in simulation they catch problems and print context, and in synthesis they simply vanish. A severity failure on an "impossible" branch turns a silent latent bug into an immediate, labeled stop during simulation, at zero hardware cost. Use assert for checks and guards, report for the running commentary that makes a log readable.

4. Structural interpretation — the severity ladder and assert flow

assert condition false emits report at a severity; severity ladder note to failure with a stop thresholdseverityassert conditionfires report when FALSEnote / warninglog; run continueserrorreal problem (common stop)failurefatal — halts now12
assert and report classify their output on a severity ladder: note (information) below warning (suspicious) below error (a real problem) below failure (fatal). An assert evaluates its condition and, only when false, emits its report clause at the chosen severity; a report emits unconditionally. The simulator halts when severity reaches a configured threshold (commonly error or failure), so genuine failures stop the run while notes and warnings let it continue. Synthesis ignores both, so they are free to use in RTL as illegal-state guards. This is a reporting-mechanism structure, captured by a diagram rather than a waveform.

5. Why this is structural, not timing

assert/report are a reporting mechanism — a condition, a message, and a severity classified on a fixed ladder — so the structure above (the ladder and assert flow) captures them, not a waveform. They produce text and a possible stop, not signal behavior; their only run-time effect is when, during simulation, a condition happens to be false and a message prints. Because synthesis discards them entirely, they have no hardware timing at all. What matters is the mechanism: false condition → message at severity → maybe halt.

6. Debugging example — the wrong-polarity assert (and the useless message)

Expected: an assertion fires on a real failure with a helpful message. Observed: the assertion fires constantly on correct behavior (or never fires on a wrong one), and/or its message gives no useful information. Root cause: the assert condition has inverted polarity — remember assert reports when the condition is false, so you assert the expected-true property, not the failure condition; writing assert sum /= expected fires on every match. The unhelpful message omitted the values. Fix: assert the property that should hold (assert sum = expected), and build the message with the actual/expected values (to_hstring, 'image) and now so a failure is diagnosable. Engineering takeaway: assert fires when its condition is false, so assert what must be true; and always include the offending values and time in the report.

assert_what_is_true.vhd
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
-- BUG: inverted condition fires on every CORRECT result; message has no values.
-- assert sum /= expected report "error" severity error;
-- FIX: assert the property that must hold; include the values.
assert sum = expected
  report "mismatch got=" & to_hstring(sum) & " exp=" & to_hstring(expected) severity error;

7. Common mistakes & what to watch for

  • Inverted assert polarity. assert reports when the condition is false; assert what must be true, not the failure condition.
  • Uninformative messages. Include actual/expected values (to_hstring/'image) and now; a bare "error" wastes the assertion.
  • Wrong severity / stop threshold. Use error/failure for real problems so the run halts; do not bury failures as note.
  • Assuming assertions synthesize. They are ignored by synthesis — great for RTL guards, but they enforce nothing in hardware.
  • Overusing failure. Reserve failure for truly fatal/impossible conditions; routine mismatches are usually error so the test can tally them.

8. Engineering insight & continuity

assert and report are the language's checking and messaging primitives: assert fires its message when the condition is false, report logs unconditionally, both classified on the note < warning < error < failure ladder with a simulator stop threshold — and both are ignored by synthesis, so they double as RTL illegal-state guards. Clear conditions, value-rich messages, and the right severity make failures obvious. These messages often need to go beyond the console — into files of expected vectors or results logs — which is the next lesson, File I/O with textio: reading stimulus from and writing results to files.