Merging SystemVerilog Covergroups with Examples

The Problem

SystemVerilog has the concept of covergroups which can keep track of certain conditions the user specifies during a simulation. If you have a single instance of a covergroup in your design, you don't need to deal with merging the results across all of the instances of that covergroup.

If you do have multiple instances of a covergroup and want to merge the results, there are implementation details that can make a big difference on what you will see in the end.

The source for my examples that I go through below, and the one liners to launch them for Mentor Questa, are published on my github account here.


Note: June 15, 2014 -
This article and the one following were revised and published in the June 2014 issue of Mentor's "Verification Horizons" quarterly publication under the title "Merging SystemVerilog Covergroups by Example".  I recommend the published version which has a lot more editing and simplifications.

First Example Union Merge

The first example is "union_merge.sv" which merges the two instances of the covergroup "c1_cg_inst" in a way where if either instance meets a specific condition the condition is marked as met.  This could be thought of as the union of both covergroup instances.

You might be a person who likes looking directly at the code (then click on the link above covmerge1.sv) or if you are like me, you would get a lot more out of the structural block diagram below.

The implementation detail that is important, is that you are setting values like: option.per_instance, option.get_inst_coverage, and type_option.merge_instances all equal to one.  This will properly setup a union merge.

Block Diagram of union_merge.sv

Block Diagram of union_merge.sv

Seeing how the covergroups are interpreted in a simulator will help make this more clear.  Below is a screen capture of how Mentor Questa interprets the union_merge.sv design.  You can see that there are two "INST" lines in the Covergroups window.  This is for instantiating the "c1_cg_inst" that is in both "duta" and "dutb".  We can see that the "duta" instance only had hits for the bin "_0" while "dutb" had hits for the bin "_1".  So each "INST" is only 50% covered because each is only hitting half of their described bins.  But, because we set the variables dealing with how we want to merge the values to do the union merge we get the overall coverpoint called "c1_cg::x" being marked as 100%.

The coverpoint "c1_cg::x" also shows the number of hits it had for each bin: 2 in this case.  Which is exactly the union of what happened with "duta" and "dutb".

Mentor Questa View of the Coverage of union_merge.sv

Mentor Questa View of the Coverage of union_merge.sv

Second Example Non-Union Merge

Lets do a very small change where we just changes the values of: option.per_instance, option.get_inst_coverage, and type_option.merge_instances to 0 - this is handled in "weighted_merge.sv".  This will be a non-union merge.  Now when we look at the overall coverpoint "c1_cg::x", we see that the simulator now shows the coverpoint "c1_cg::x" as a greyed out un-expandable entry (in the previous example it was expandable).  The for value for "c1_cg::x" is 50% this time opposed to 100% previously.  That is because it is not doing a union merge.

The merge used in this example is taking the average of all of the instances of the coverpoints of that type and giving you a number of completeness.  It doesn't have visibility into what bins were there anymore; that is why you can't expand it and see those "_0" and "_1" bins.

Block Diagram of weighted_merge.sv

Block Diagram of weighted_merge.sv

Mentor Questa View of the Coverage of weighted_merge.sv

Mentor Questa View of the Coverage of weighted_merge.sv

Covergroup Defined in a Module - Watch Out!

The last iteration, and the one that confused me when I first starting implementing coverage, is the diagram below "module_merge.sv" which defines the covergroup within the "dut" module.  This is a perfectly legal thing to do, but you will see that even if you setup the union merge you will not get the result you may think you are getting.

Block Diagram of module_merge.sv

Block Diagram of module_merge.sv

What you see below is that Mentor Questa did not pull out what I called the "overall coverpoint" that was named "c1_cg::x" as it did before.  It doesn't have any idea that even though "duta" and "dutb" are the same it can't pull out the covergroup "c1_cg" as a shared component.

You cannot do a union merge if you define your covergroup this way.

Mentor Questa View of the Coverage of module_merge.sv

Mentor Questa View of the Coverage of module_merge.sv

Conclusion

When you merge covergroups you get to choose the merge method - union or non-union merge depending on what you need to measure.  You also may have to evaluate where the covergroups are being defined and evaluate if that will meet your needs.

The IEEE System Verification Language Reference Manual is actually pretty good at explaining more about covergroups if you want to learn more.