Cover failures have always been a challenge for me. Unlike model checking or induction failures, coverage checking leaves no trace behind upon failure. How then shall a cover failure be resolved?
Let’s look at a couple of possibilities:
In general, and as described above, the easiest way to resolve a cover failure is to cover a sufficient number of intermediate steps to know where the problem happened.
If this isn’t sufficient to find the bug, then try covering the step before where the cover failed, followed by the appropriate inputs at that step that would lead your design to the next step. This might look like,
cover($past(step_prior_to_failure) && expected_inputs). This should yield a trace, which might help show you what’s going on within your design.
Typically, the biggest thing I need to review with respect to cover statements are the incoming assumptions. Indeed, every assumption should be well justified.
Sometimes disabling an input assumption will yield a cover trace. If so, then that trace will often tell me where to look for the bug.
In some SPI designs I’ve worked with, I can get the induction proof down to 4 cycles. Cover, however, may take hundreds of cycles. Sometimes you just have to double the number of cycles searched and just try again.
In one case, I even turned a
cover(A)statement into an
assert(!A). When the assertion passed induction, I then knew why the cover statement was failing–there was just no way the design would make it true. In this case, it wasn’t necessarily a bad thing–but it did lead me to a greater understanding of my own design and what command combinations were allowed.
Don’t forget to check that the design comes out of reset! I’ve just worked with too many designs where I’ve (accidentally) assumed the reset was active throughout the life of the design. You’d think by now I’d know better, but I still got caught with this bug just last week.
I’m sure there are other ideas you could try, but perhaps this list will get you going.