Author: Craig Maiman, Principal RTL Design Consultant
Welcome to the RTL Design Success series — Part 3 of 9
5.1 Why Unit-level Verification?
Unit-level verification is for designers (and/or verification engineers) to confirm that the RTL matches what was specified in the block micro-architecture specification. It is used to confirm that it comes out of reset properly, matches expected functionality, doesn’t exhibit bad behavior (e.g., stuck states) and adheres to expected and proper interface protocols.
Doing an effective unit-level Testbench allows for the ability to test a unit/block design in ways that a system-level test might not achieve easily. For example, to flood the block with input requests faster than typically would be seen in system-level verification or in the “real” world. To hit a block hard for long periods of time with randomized inputs can weed out corner-case bugs that might be very difficult or take a long time to detect at the system level.
Fixing bugs at the unit-level is usually much easier to debug in your own environment than a system-level testbench, so it’s worth putting in the effort to make an extensive and effective unit-level testbench.
A thorough unit-level testbench can take as long, if not longer, to write than the RTL itself.
5.2 Unit-level vs. System-level verification
As previously mentioned, the unit-level testing confirms the block RTL meets the designer’s specification. The system-level verification, on the other hand, is to confirm that the various blocks communicate, and that the unit-level and top-level design meets the architectural specifications.
If the designer misunderstands the architecture and both the micro-architecture specification and design reflect this misunderstanding, the unit-level test will only confirm those things match – not catching the architectural bug. Therefore system-level verification is also essential and preferably done by someone other than the designer.
System-level verification is typically done by someone other than the designer so that the verification is not biased by the details (and bugs) of the micro-architecture and RTL.
5.3 General Structure of a Unit-level Testbench
The typical testbench consists of the following components:
- DUT – Design Under Test
- Stimulus Generator(s) – Code that drives the inputs to your design
- Clock/Reset Generators
- FIFOs – This is design dependent but is a common way to pass to the Output Checkers on the other side what to expect. Verification engineers would typically refer to these FIFOs as “scoreboards.” If the DUT can do things out of order than a FIFO might not be appropriate.
- BFMs – Bus Functional Models to model any other blocks the design talks to. These can vary greatly in complexity (e.g., Other custom blocks, DDR I/F, Serial I/O, etc.).
- Output Checkers – Watches the outputs of the DUT and possibly using data coming from the FIFO’s determines if the outputs are correct.
- Protocol Checkers – These are small checkers on the various interfaces to sniff on those busses to ensure the bus meets expected protocols (e.g., AXI Bus, custom bus).
The following diagram shows an example testbench structure:
