Understanding covergroup options
SystemVerilog was not the first language to include the concept of functional coverage, nor was it the first to be difficult to fully understand. There are many intricacies to the language which can greatly affect the results you observe from simulation. Defining simple covergroups is fairly straightforward, however, the complexity greatly increases once you introduce the concept of trying to merge multiple instances of the same covergroup, which can often lead to vastly different outcomes depending on the implementation approach.
Understanding them becomes more complicated when you have embedded covergroups and then trying to merge them across various instances in the design. You could potentially end up with covergroups which simply cannot be merged, which makes it impossible to see where you truly are with regards to your coverage goals.
You can potentially introduce unnecessary performance overhead, or restrict your debug visibility into the covergroups themselves if they are not created correctly. These types of decisions are often made early on in a project, and in some cases, there is no other recourse to solving the problem then to make extensive changes to the testbench environment. Proper understanding of the way covergroups are created and function is needed to avoid this scenario before it can become a problem.
In this paper we will outline a set of guidelines for writing an unambiguous coverage model. What to do, what not to do, and how.