What is the recommended way to implement coverage driven verification in UVM (connection between coverage and sequence)?

Hi,

When implementing coverage driven verification, how should a sequence get information on one or several covergroups instantiated at different places in the testbench (in objects derived from uvm_subscriber for instance, or from an interface) ?

We can use hierarchical reference from the test environment to the object where the covergroup is instantiated but, for a better reuse, is there a way to pass a reference to a covergroup through the config DB from the object it is instantianted in and get this reference in the sequence ? or something equivalent ?

Thank you for your help

Norbert

Why are you concerned with information contained in covergroups in your sequences? They should be two completely different entities with no interaction between them. The purpose of a sequence is to generate valid random stimulus for the DUT. The purpose of a covergroup is to quantitatively evaluate what status has been generated, independent of the source.

In reply to cgales:

You are right, this is the classical way.

But in the case you need to implement a coverage driven stimulation (Coverage Driven Verification), there is a feedback loop where you will tune the sequences to hit parts of the covergroup that have not been covered yet.

The idea of CDV is to orientate the stimulation to get a better efficiency (simulation time vs coverage increase rate), and not hit twice items that have already been covered.

In reply to Norbert:

Coverage Driven Verification is designed to be completely random with no feedback involved. This eliminates the human element that that a directed environment has. In your case, why would you not simply iterate over all the possible combinations if you are looking from a pure coverage goal? The ideal environment will uniquely generate stimulus independent of any previously generated data.

In reply to cgales:

In my understanding, constrained random stimulation covers the all gamut of possibilities from full random(few constraints only to get legal transactions) to almost directed(very constrained) stimulation.
What I mean here is changing the level of control on the randomization, starting from a full random and tuning/constraining taking into account current coverage results, while still not being in a directed mode.

I believe that you mean using a stimulation similar to a randc approach, where each value is generated only once.
But, in the case the covergroup contains coverpoint on parameters that don’t directly depends on stimuli, like for instance measurements of an internal state vector of your DUT, then I think you need to measure the coverage results and tell your sequence how to reach the uncovered states (i.e. giving it the relation between stimuli and state of DUT).
In this case, if you rely on pure random stimulation, it probably won’t be very efficient. And you can’t just say to random constraint solver : please generate the transactions that will cover all the state vectors value in my DUT.

What do you think ?

In reply to Norbert:

I think you can use a virtual sequencer which has references to UVCs in which you instantiate your covergroups.

In reply to Wanglj:

Thank you. Actually I did something like that, declaring a reference to my coverage collector object (uvm_subscriber) inside my sequence, and setting this reference from the test (uvm_test) with a hierarchical path inside the uvm testbench structure.

This is working, but I was wondering if there was a better recommendation, more in a “UVM mindset” (something better for reuse). I could have passed the reference to the object through the config DB for instance but I don’t know if it is really better.

Norbert

In reply to Norbert:

Norbet,

i am in a similar situation and i agree with your assessment. I am using abstraction sequencers to completely decouple my random stimulus generation from my UVC sequencer and driver.

I need to create coverage metrics on the data that i am sending to the driver, not the coverage on the data pins themselves.
To sign off a required i need to know that my randomisation has covered the entire range of values. If not then i need to change my constraints or run the same tests for longer, but ii need those numbers out from the sequence.

In my case i intend to create a uvm_sequencer and sample data at the abstraction sequencer level.

In reply to Norbert:

The right methodology is to collect the info from the bus with your monitor and deduce from the bus what is the randomization you have triggered. This is normally done in the scoreboard by accumulating some xfers from the monitor.
I known it is easier to create a channel from the sequencer of your virtual sequence to your coverage class. However, that is incorrect from the methodology point of view. If you create a channel from the virtual sequenceR to pass that information, then you will do your scoreboard or your coverage class not reusable.
Your scoreboard/coverage class will only work if you have a sequence which provides that specific sequence input. That is not the methodology in UVM. What if you want to test another testcase? what if you use other extern sequence which doesn´t send that info? What if you change your sequence master by another VHDL Master?. In those cases your scoreboard/coverage class will not be complete because depends on the sequence.

Having said that. There are some cases where you would like to create a special coverage which is only valid for a specific sequence. For example, you want to test a data error insertion and you want to cover the position of this error on a data stream as master. The error position coming from the master sequence in the bus is not detectable from the bus even in the datastream has CRC. You introduce errors because you would like to see that the slave doesn´t hang or that the slave detects the error with CRC (although position is not possible to detect).
In those cases, the BUS is not enough to know in which byte the error was introduced. You can only detect that an error was introduced with the CRC.

I would propose to split these two kind of coverage because one is only for that sequence and the other is the correct coverage for your block. Later, on in your testplan you can select what covergroups you want to see if you want from the sequence coverage or from the block coverage. In other words, you will have one coverage class for your block in your scoreboard, and another covergroups inside your sequence. covergroup in sequences | Verification Academy
So you will not use config data base to pass sequence coverage to your block coverage. You just declare the covergroups in the sequence (ensuring per_instance=0).

I am still not sure if that is acceptable from the methodology point of view. What do you think?