Author: Craig Maiman, Principal RTL Design Consultant
Welcome to the RTL Design Success series — Part 5 of 9
A good unit-level test (and system-level for that matter) generally consists of two distinct sections: Directed tests and randomized tests.
Directed tests are non-random tests of all the functions of the block, including:
- All normal functions from all interfaces (e.g., All request types, all pertinent addresses, etc.)
- Any potential corner cases (see Section 7 below)
Randomized tests are useful for fully stressing a block in an automated manner. Good, randomized tests randomize everything concerning any inputs to the block. Random request types, addresses, data, gaps between requests and random responses the block is expecting from its interfaces. You can also control how the randomization is distributed. For example, randomized gaps between requests, but control that in a way that forces the gaps to be mostly on the shorter side.
A well designed randomized self-checking testbench should be able to run indefinitely.
A typical testbench will first do all the directed tests which are then followed by the randomized test section. The testbench ends after some number of iterations of the randomized tests and prints out the results.
One additional feature that is often added to testbenches is performance calculations so any performance goals can be confirmed. This is usually done in the directed test section during a test that maximizes any data throughput (e.g., zero gap between requests).
If there are multiple clock domains, you might consider running with different frequencies to find any clock domain crossing issues.
Further testing might include combinations of directed and randomized tests to more adequately cover specific parts of the design to satisfy coverage requirements.
Corner cases are situations that would “stress” the RTL (could be areas of the block that are of greater concern to the designer due to the complexity of the design). Cases such as:
- Race conditions (e.g., Request or response alignment between interfaces, state machine transitions, functional loops, etc.)
- Potential lock conditions (e.g., two requestors competing for a resource) and any other input combinations that the designer believes could “stress” the RTL
- Backpressure: State machine handling, FIFO overflow, etc.
Backpressure testing is particularly important for testing designs containing pipelines (stall conditions) and/or FIFOs. FIFO overflows (and underflows!) must be handled properly with no loss of data.
Backpressure can be created on block interfaces if there are wait-type signals on an interface bus or by delaying bus request acknowledgements. For directed tests I suggest a test which is guaranteed to causes your block to back up to the point that there are either extended periods of pipeline stalls and/or FIFOs overflow.
For randomized tests, build in randomized long and short waits and/or bus acknowledgements. For example, try to make it so there will be long periods with lots of backpressure on one interface and blasting requests on another.
Along with the varying backpressure on the block, you should have varied “forward pressure” on the request inputs to the block. No gap between requests and long gaps between requests. Varying pressure from all sides will really push the corner case testing.
With total self-checking, your testbench shouldn’t skip a beat in hours of runs.
Stress the block!
An example of testbench output (This shows 3 different stimulus processes starting up):
# Starting Get Complete Interface…
# Starting RX Side…
# Starting TX Side…
# TX’s and GO’s Match! TX: 10 GO’s: 10
# TX Count: 10 ACK Count: 0 Timeout Count: 10 Get Timeout Count: 0
# CMD Complete Count: 10 Fail Count: 10
# All Drops accounted for! Expected: 10 Retries: 0 FailRetries: 10
# OPB Unit-Level Test PASSES!
If your block interfaces to standard busses, you may want to create a state machine which just watches the protocol to ensure that all the activity on the bus are legal (assertion commands can also be used for this purpose). The FPGA or ASIC vendor may have such protocol checkers, so it’s worth looking into, but if not, these are easy to build and can save much grief later.
These checkers are not checking for correct data or any higher-level protocol, but just the low-level bus protocol.