Continuing our journey to achieving better coverage
In part two of our journey into achieving better code coverage, we looked at property coverage and how it checks functional correctness of the design by comparing its behaviour against design properties. We also understood how property coverage requires some coding in PSL (or SVA) and underlined this with a design example. In the final part of achieving better code coverage, we look at ‘smart’ functional coverage and how to accomplish this with the Open Source VHDL Verification Methodology – OSVVM.
The reason why we need to consider functional coverage is that sometimes the coverage goal is hard to express in terms of behaviour, and it may be easier to specify using values of design variables.
For example, let’s consider the following the function of a climate controller reading data from the 8-bit humidity sensor:
Now, if we define all possible values of sensor variable as below, how can we verify that testing of all ranges, without them being over-tested?
The answer is that we can ensure with Functional Coverage and the use of bins.
Functional coverage counts values of design variables according to previously defined bins which are groups of values that have a special meaning in the design.
Bins using just one variable create a data structure that we call a coverage item or coverage point. So for our humidity controller, we have five sub-ranges that represent valid behaviour and one final sub-range which represents illegal sensor readout (6 bins).
We can also create cross-coverage bins combining values of multiple variables to obtain a cross-coverage item. To imagine this in our sensor design, we could introduce an action variable into our climate control design. We can use the values Idle, Humidify, Dehumidify and Alarm and then create cross-coverage bins like this:
(Low, Humidify), (Normal, Idle), (High, Dehumidify), (Illegal, Alarm), and so on.
Bins can be labelled differently for simulation such that bins marked as regular, count hits. In contrast, bins marked as illegal trigger errors or even ignored during simulation by labelling such.
Functional coverage on its own is quite valuable, but when combined with constrained random stimulus, becomes extremely powerful.
Applying this to our humidity sensor example, we could randomly generate stimulus for the readouts and stop the simulation when at least one hit occurs for each bin. This way, we complete tests much faster than in the case of scanning through all possible sensor readouts.
Some languages (especially high-level languages) have elaborate constraint systems for random variables that require dedicated constraint solvers and work independently from functional coverage. While this can be considered a benefit, it is prohibiting the use of other valuable features. For example, consider being able to have live feedback coming from the FC engine that controls randomisation … which is possible with Smart Functional Coverage.
Smart functional coverage was introduced to VHDL by the Open Source VHDL Verification Methodology (OSVVM). It contained both randomisation and functional coverage packages that can work independently. However, working together; they also create coverage -> randomisation feedback that enables smarter, more efficient verification.
It works through the smart coverage, which controls the randomisation process to ensure that values belonging to already covered bins are no longer randomly generated.
Smart functional coverage is a huge benefit when we consider a random number generator produces uniformly distributed values from the range 1..n and it takes approximately n log(n) trials to cover all values in the range. This number is even higher for non-uniform distributions. Smart coverage reduces the number of trials to precisely n.
In other words, smart coverage gives you the guarantee that each value in the randomised range show up only once.
Let us look at a smart coverage example where we have a 100 x 100 display matrix that we want to test randomly to ensure the test of each pixel at least once.
We can employ the use of the coverage package from OSVVM which defines a special protected type CovPtype. We also set our variables X and Y for the array. We then operate on our coverage object by creating cross-coverage items and use two calls of the GenBin procedure, each one stating the requirement for an individual bin for each value (so a matrix of 100 x 100 coverage bins). We then initialise the random number generator using the instance name of our object, which is a very convenient way for the process.
Finally, we need a loop responsible for collecting the coverage and randomising values. The exit condition method IsCovered attached to each coverage object yield a true result when coverage is achieved, which exits from the loop. We can use any convenient sampling event in the loop, for example system clock or similar. RanCovPoint is the smart coverage which checks for reached cover values and creates new X, Y values not yet covered and adds the values to the coverage by using the ICover function.
It is important to note that the while loop has exactly 10000 iterations (size of array) due to the use of smart functional coverage which is typically several thousand less than in the case of ‘dumb’ randomisation.
We introduced smart functional coverage by use of the Open Source VHDL Verification Methodology (OSVVM). Use of coverage bins and OSVVM packages ensure that simulation time is kept to a minimum when using randomisation.
Our look at coverage over the series has led us to look at three general types: Code Coverage, Property Coverage and Functional Coverage. We can summarise the key points discussed in the following comparison table:
As we can see in the comparison table, there is no single kind of coverage that is a clear winner. Code coverage checks code structure but may be expensive. Property coverage is excellent for checking behaviour, but maybe expensive, too. Functional coverage with OSVVM requires some coding which may be considered a drawback. However, we can reach one conclusion, and that is a balanced use of each of the three coverage kinds should dramatically increase design quality and reduce verification time.