Tudor timisescu also known as the verification gentleman in verification community posted this question on twitter.
His question was, can we create transition coverage using cross between two different types of objects? He named it as heterogeneous cross.
His requirement has very useful application in CPU verification to cover transitions of different instructions. For RISC-V (and basically all other ISAs), different instructions have different formats, so you end up with cases where you get such heterogeneous transitions.
So, let’s jump into understanding the question further. I know it’s not easy to understand it on first impression. So let’s do bit of deep dive into question. Followed by that we will take a look in to one of the proposed solution and scalable automation using the code generation approach.
Can we do heterogeneous cross coverage in SystemVerilog?
Partial screenshot of the question on twitter.
Tudor clarifies the question in his own words.
Heterogeneous cross coverage is cross between two different object types.
Let me clarify by what I mean with heterogeneous. First, I’m trying to model some more involved form of transition coverage. I imagine the best way to do this is using cross coverage between the current operation and the previous operation.
Assuming you only have one category of operations, O, each with a set of properties P0, P1, P2, … it’s pretty easy to write this transition coverage. Let the tilde (‘) denote previous. The cross would be between the values of P0, P1, P2, … and P0′, P1′, P2′, …
If you have two categories of operations, Oa and Ob, each with different sets of properties: Pa0, Pa1, …, Pam for Oa and Pb0, Pb1, …, Pbn (with m and n possibly different), the cross gets a bit more involved.
If the current operation is of type Oa and the previous is of type Oa, then you want to cover like in the case where all operations are the same (i.e. Pa0, Pa1, …, Pa0′, Pa1′). This also goes for when both are of type Ob.
If the current operation is of type Oa and the previous is of type Ob, then what you want to cross is something like Pa0, Pa1, Pa2, …, Pb0′, Pb1′, Pb2’, … The complementary case with the operation types switched is analogous to this one.
I don’t see any way of writing this in #SystemVerilog without having 4 distinct covergroups (one for each type transition).
Imagine you add a third operation type, Oc, and suddenly you need 9 covergroups you need to write.
The more you add, the more code you need and it’s all pretty much boilerplate.
The only thing that the test bench writer needs to provide are definitions for the cross of all properties of each operation. Since it’s not possible to define covergroup items (coverpoints and crosses) in such a way that they can be reused inside multiple covergroup definitions, the only solution I see is using macros.
Code generation would be a more robust solution, but that might be more difficult to set up.
He was kind enough to provide the solution for it as well. So what was he looking for? He was looking for, is there any easier and scalable ways to solve it?
Following are the two different data types that we want to cross.
When you create all 4 possible combinations of transition crosses, it would look as following:
I thought we could follow the precedence of scientific community and refer the heterogeneous cross as “Tudor cross” for formulating the problem and defining the solution.
Okay, before we invest our valuable time understanding automation are there any real life use cases?
Tudor was facing this real problem for project he worked on related to critical pieces of security. For confidentiality reasons he could not provide any more details about it. He was kind enough to share another example where this type of problem would be faced again and hence the solution would be useful.
In Tudor’s own words, an example from the top of my head (completely unrelated to the one I was working on) where this might be useful is if you have to cover transitions of different instructions. For RISC-V (and basically all other ISAs), different instructions have different formats, so you end up with cases where you get such heterogeneous transitions.
The same CPU will be executing all of those instructions and you can get into situations that the previous instruction busted something that will cause the current instruction to lock up, which is why you want to at least test all transitions.
One step even further is if you also add the state of the CPU to the cross. Different parts of the state are relevant to different instructions. It could be that transition a -> b is fine in state Sa0, but is buggy in state Sa1.
The CPU example is maybe even better than my concrete use case where only a history of 1 is needed. A fancy CPU has a deep pipeline and it may well be the case that the depth of the pipeline should be the length of the history for which you collect these transitions. Even for lengths of 2 it becomes a huge problem, too laborious to write by hand.
Here we apply two concepts:
High-level modeling of operation is done in very limited way to keep the solution simple. We have done it for USB power delivery protocol layer over here, which is much more involved than this problem.
Solution can easily scale for:
Yes, you can write it. It’s not such a big effort for specific problem. But if you are embarking in this direction, you will need more and more capabilities. That’s where the well thought out and tested library will save you lot of time allowing you to focus on the real problem.
Steps involved in automation are following:
If you are interested in programmable number of stages solution, just drop me an email: anand@verifsudha.com
Following code shows both the python input and generated SystemVerilog code output.
[xyz-ips snippet=”curiosity-eval-common”]
[xyz-ips snippet=”post-heterogeneous-cross-pc”]