Writing a Simple Verification Plan
Turn a specification into features to check, boundary cases, verification methods, and completion criteria.
Verify more than the code
A verification plan starts from the specification, not from the RTL implementation. If the same detail is misunderstood in both the design and the testbench, comparing one against the other will not expose the error.
Review the requirements independently and record ambiguous areas before writing tests. A sentence such as “the result is valid after the calculation” needs clarification: after how many cycles, what happens when the output is not ready, and must the result remain stable?
One row per verifiable feature
A simple plan can take the form of a table:
| Feature | Scenarios | Check | Coverage | Priority |
|---|---|---|---|---|
| Reset | startup, reset during activity | expected outputs and internal state | every useful interruption point | high |
| Transfer | nominal, stalls, bursts | protocol scoreboard | crossed lengths and wait states | high |
| Error | overflow, illegal command | error code and absence of prohibited effects | every error | medium |
Each row must map to a directed test, a random constraint, an assertion, or a coverage point. If a requirement has no associated check, it is not actually being verified.
The five jobs of a testbench
A complete environment must:
- generate transactions;
- apply them to the DUT;
- observe inputs and outputs;
- compare the behavior with a reference;
- measure what has been exercised.
A small project may implement these roles with a few tasks, while a larger environment may use separate components. The plan remains the same.
Choose the right kind of stimulus
Directed tests provide fast diagnosis: they prove reset, a nominal transfer, and boundary values with little noise. Constrained randomization then explores interactions that would be impractical to enumerate completely.
Varying control is more useful than changing only the data: DUT configuration, transaction type and length, legal delays, concurrency between interfaces, responses, and injected errors. Every run must record its seed, test, configuration, and simulator version. A seed is reproducible only with a comparable environment and random-call order.