Verification map¶
Verification answers a stronger question than “did the waveform look right?”:
For every tested requirement, did the observed behavior match an independent expectation, and can the entire test be repeated automatically?
Verification layers¶
| Layer | Purpose | Typical mechanism |
|---|---|---|
| Compile | Language/type correctness | xvhdl -2008 |
| Elaboration | Binding, generics, hierarchy | xelab |
| Directed test | Known scenarios and corners | Procedures plus assertions |
| Exhaustive test | Every combination in a small space | Nested loops |
| Reference-model test | Compare algorithmic result | Pure function or independent model |
| File-driven test | Import externally generated cases | TextIO |
| Random test | Explore many sequences | Reproducible PRNG and constraints |
| Coverage | Measure what was exercised | Counters or framework coverage |
| Regression | Re-run every test consistently | PowerShell/Python/CI runner |
| Static analysis | Timing, CDC, DRC | Vivado reports |
| Hardware test | Confirm physical integration | Board smoke/system test |
Recommended progression¶
- Learn plain VHDL assertions.
- Write self-checking directed tests.
- Use loops and reference functions.
- Add a timeout and clean finish.
- Run tests through the XSim command line.
- Add file-driven vectors when another tool generates expected values.
- Add randomized sequences and coverage when the state space grows.
- Adopt VUnit or OSVVM when a test suite needs framework features.
Testbench architecture¶
As complexity grows, separate roles:
test control
│
├── driver ──────> DUT inputs
├── monitor <───── DUT outputs
├── reference model
├── scoreboard: expected versus actual
└── coverage: what scenarios occurred?
For small exercises, all roles can live in one process. For larger interfaces, separation prevents the testbench from becoming harder to trust than the DUT.
Verification plan template¶
Before writing stimulus, create a table:
| Requirement | Stimulus | Expected result | Checker | Coverage |
|---|---|---|---|---|
| Reset clears counter | Assert reset across edge | count=0 after edge | assertion | reset seen |
| Enabled count increments | enable=1 for N edges | previous+1 each edge | model/scoreboard | N increments |
| Disabled count holds | enable=0 | unchanged | assertion | hold seen |
| Overflow wraps | start=max, enable | zero | assertion | overflow seen |
This makes tests traceable to requirements.
Independence matters¶
If the testbench calculates the expected output with exactly the same algorithm and mistakes as the DUT, both can agree while being wrong.
Prefer:
- A mathematical expression rather than copied RTL.
- A table from the specification.
- A Python/NumPy model for complex signal processing.
- A simple transaction-level model.
- Independently generated known-answer vectors.
What “passed” means¶
A test passes only if:
- Compilation and elaboration succeeded.
- No failure/error assertion occurred.
- The intended checks actually executed.
- A watchdog did not terminate the run.
- The simulator returned success.
- The log contains an explicit pass summary.
Printing “PASS” without counting assertions or reaching the expected end condition is not sufficient.