«…лишь недалекие люди боятся конкуренции, а люди подлинного творчества ценят общение с каждым талантом…» А. Бек, Талант.

Coverage Cookbook/Coding for analysis/ru

Материал из Wiki

Перейти к: навигация, поиск
Aqua pencil.png Эта статья требует перевода на русский язык

Taking care with the implementation of covergroups is an investment in time that can pay back when you or someone else need to understand where the missing functional coverage is.

Содержание

Covergroup Labeling

The way in which you use labeling when coding a covergroup can have a huge impact on understanding the coverage results. A covergroup can be assigned a option.name string which helps with identification of which particular part of a testbench the coverage is associated with. In side a covergroup, coverpoints can be labelled and bins can be named. Using all of these techniques makes it much easier to understand the coverage results during analysis.

Covergroup naming

If multiple instances of the same covergroup are used within a testbench, then the option.name parameter can be used to assign an identity string to each instance. The name string can be passed in as an argument when the covergroup is constructed. In a UVM environment, the name could be passed in using get_full_name() method.See the following code example.

// Class containing a covergroup
class my_cov_mon;
 
  covergroup my_cg(string instance_name);
    option.per_instance = 1;
    option.name = instance_name;
  // ...
  endgroup: my_cg
 
  function new(string cg_inst_nmae);
    my_cg = new(cg_inst_name);
  // ...
  endfunction
 
endclass: my_cov_mon
 
// UVM Component containing a covergroup
class my_cov_mon extends uvm_subscriber #(my_txn);
 
  covergroup my_cg(string instance_name);
    option.per_instance = 1;
    option.name = instance_name;
  // ...
  endgroup: my_cg
 
  function new(string name = "my_cov_mon", uvm_component parent = null);
     super.new(name, parent);
     my_cg = new(this.get_full_name());  // Gets the UVM hierarchy for the component
  endfunction
 
endclass: my_cov_mon


A covergroup can also be named programatically using the covergroup set_inst_name() built-in method.

// UVM Covergroup based component
class my_cov_mon extends uvm_subscriber #(my_txn);
 
  covergroup my_cg;
  //...
  endgroup: my_cg
 
  function new(string name = "my_cov_mon", uvm_component parent = null);
    super.new(name, parent);
    my_cg = new();
  endfunction
 
  function void build_phase(uvm_phase phase);
    my_cg.set_inst_name("TLB_coverage"); // Sets the instance name
    //...
  endfunction: build_phase
endclass: my_cov_mon

Coverpoint and bin labeling

As an example consider the following functional coverage problem from the UART example. In this example the UART word format is determined by the contents of the Line Control Register (LCR):

LCR Bit Value Description
[1:0] 2'b00 5 bit data character
2'b01 6 bit data character
2'b10 7 bit data character
2'b11 8 bit data character
2 1'b0 1 Stop bit
1'b1 2 Stop bits
[5:3] 3'b??0 No Parity
3'b001 Odd parity
3'b011 Even parity
3'b101 Stick 0 parity
3'b111 Stick 1 parity

Lower Analysis Potential

covergroup tx_word_format_cg()
  with function sample(bit[5:0] lcr);
 
  option.name = "tx_word_format";
  option.per_instance = 1;
 
  coverpoint LCR[5:0];
 
endgroup: tx_word_format_cg

Higher Analysis Potential Arrow.png

covergroup tx_word_format_cg
  with function sample(bit[5:0] lcr);
 
  option.name = "tx_word_format";
  option.per_instance = 1;
 
  WORD_LENGTH: coverpoint lcr[1:0] {
    bins bits_5 = {0};
    bins bits_6 = {1};
    bins bits_7 = {2};
    bins bits_8 = {3};
  }
 
  STOP_BITS: coverpoint lcr[2] {
    bins stop_1 = {0};
    bins stop_2 = {1};
  }
 
  PARITY: coverpoint lcr[5:3] {
    bins no_parity = {3'b000, 3'b010, 3'b100, 3'b110};
    bins even_parity = {3'b011};
    bins odd_parity = {3'b001};
    bins stick1_parity = {3'b101};
    bins stick0_parity = {3'b111};
  }
 
  WORD_FORMAT: cross WORD_LENGTH, STOP_BITS, PARITY;
 
endgroup: tx_word_format_cg

In order to check that all possible word formats have been transmitted we could implement a covergroup by creating a coverpoint for LCR[5:0] and not specifying any bins. This would create a set of default bins, one for each possible value of the register, as shown in the left hand code example. If the functional coverage collected samples these bits at least once, then there is no problem, but if not then it is reasonably difficult to figure out which bin corresponds to which condition - see the 'before' screen shot from the Questa covergroup browser. Here, not using labels has caused the simulator to use auto-bins, which means that the missing bin values need to be converted to binary and then mapped to the register fields to identify the missing configurations.

A better way to implement the covergroup is to use a labeled coverpoint for each register field and then using the bins syntax for each of the values in the register truth table. When this is simulated, the cross products created reflect the different bin labels, which makes it much easier to determine which functional coverage conditions have not been sampled. It also makes it easier to see whether there are any gross coverage conditions that have been missed. See the 'after' screen shot from the Questa covergroup GUI for the refactored covergroup.

500px-Coverage-LCR-CG-both-together.JPG


How Covergroup options affect the reporting and computation of coverage

Implementation Options

The analysis of functional coverage information is affected by the way in which the coverage results are reported. There are three covergroup options which impact coverage reporting and can cause considerable confusion, and these are:

  • option.per_instance
  • option.get_inst_coverage
  • type_option.merge_instances

If these options are not specified in the code that implements a covergroup, then they are not enabled by default. In other words, they are set to 0.

These three options should be explicitly declared in covergroup to ensure that the coverage computation and reporting is consistent and as required.

Covergroup types and instances

When a covergroup is declared it becomes a type that may be instantiated several times in the testbench - for instance the same type of interface is used for several ports in a design and therefore the same covergroup is used to measure protocol coverage. The default coverage reporting method is to report the coverage for the covergroup type as a weighted average of the coverage from all of the covergroups of that type. What this means is that if one of the ports has been exercised to achieve 100% coverage, but others have not, then the coverage reported will not be less than 100% and it will not be possible to analyse which interfaces have not been exercised.

per_instance option

If the covergroup option.per_instance is set to 1, then the covergroup reporting is broken out per instance, but the overall coverage reported is still the weighted average. In the example quoted, this would enable the coverage for each port to be examined, possibly leading to a detection of a design bug or a short-coming in the stimulus generation.

merge_instances option

If the covergroup type_option.merge_instances is set to 1, then the overall coverage reported for all the instances of the covergroup is a merge, or logical OR, of all the coverage rather than a weighted average. This is potentially useful if you have multiple instances of the same design IP and and it is being exercised in different ways by different parts of the testbench. One outcome from using the merge_instances option is that one covergroup instance achieves 100% coverage masking another instance that achieves 0% coverage, since the overall coverage will be reported as 100%.

get_inst_coverage option

To help with the scenario where the merge_instances option has been enabled, the option.get_inst_coverage variable can be set to 1 to enable the SystemVerilog $get_inst_coverage() system call to return the coverage for an instance of a covergroup, therefore allowing the coverage for all individual instances to be checked. If the merge_instances option is set to 0, then the get_inst_coverage variable has no effect.

Summary

Interaction between per_instance and merge_instances settings:

option.per_instance type_option.merge_instances Coverage reporting behaviour
0 0 Overall coverage reported as a weighted average of the coverage for all instances of the covergroup
1 0 Overall coverage reported as a weighted average of the coverage for all instances of the covergroup,
and broken out for each instance of the covergroup.
0 1 Overall coverage reported as a merge of the coverage for the individual instances of the covergroup
1 1 Overall coverage reported as a merge of individual coverage results, get_inst_coverage() enabled,
coverage reporting broken out for each instance of the covergroup

Interaction between merge_instances and get_inst_coverage

type_option.merge_instances option.get_inst_coverage Data returned by $get_inst_coverage()
1 0 Type based coverage - i.e. merge of all instance coverage
1 1 Instance specific coverage
0 1|0 Instance specific coverage

Simulator Specific Run Time Options

The options described are covergroup options defined in the SystemVerilog LRM and can therefore be added to covergroup code. Simulators also add command line options which allow users to change the way in which coverage is reported, although these options tend to be global affecting all covergroups within the testbench being simulated.