Welcome ! This website will help YOU (recent graduates/professionals) learn verification languages like SystemVerilog and UVM. Register for free and access more content !
4 minutes reading time (741 words)

Inheritance of covergroups

covergroup-inheritance

Object oriented programming has a feature called inheritance that allows child classes to inherit members from its parent class without having to redeclare them in the child class. It's a great way to reuse existing code, and to make changes to testbenches without touching the base class structure. A covergroup is a System Verilog keyword that allows the user to declare and define the variables to be sampled for functional coverage. In this post, I'll just share what simulation results tell us about how inherited covergroups behave and how their coverage numbers are affected.

To start with, let us define a parent class A with covergroup cgA.

 
class A;
  rand bit[3:0] var1;
 
  covergroup cgA;
    coverpoint var1 {
          bins each[16] = {[0:$]};
    }
  endgroup
 
  function new ();
      cgA = new;
  endfunction
endclass
 

Next we'll declare a child class called B from A and have another covergroup for the new variable. Note that we are attempting to cross between a coverpoint declared in the parent class's covergroup cgA with the new variable.

 
class B extends A;
  rand bit[3:0] var2;
 
  covergroup cgB(); 
    coverpoint var2 {
          bins all = {[0:$]};
      }
    cross cgA.var1, var2; 
  endgroup
 
  function new ();
    super.new();
    cgB = new;
  endfunction
endclass
 

The code should compile well because cgA is defined in B because of inheritance. In the testbench we'll simply randomize the variables and call the sample() method and finally display the coverage. We'll try out a few things here, and observe how coverage changes.

Trial 1

In this case, we'll simply randomize A and B and sample only A.

 
module tb;
  A a;
  B b;
  initial begin
    a = new();
    b = new();
 
    for (int i = 0;i < 5; i++) begin
      a.randomize();
      b.randomize();
      a.cgA.sample();
    end
 
    $display ("A.cgA get_coverage = %0.2f %%   get_inst_coverage = %0.2f %%", a.cgA.get_coverage(), a.cgA.get_inst_coverage());
    $display ("B.cgA get_coverage = %0.2f %%   get_inst_coverage = %0.2f %%", b.cgA.get_coverage(), b.cgA.get_inst_coverage());
    $display ("B.cgB get_coverage = %0.2f %%   get_inst_coverage = %0.2f %%", b.cgB.get_coverage(), b.cgB.get_inst_coverage());
 
  end
endmodule
 

Its visible from the simulation that cgA only A got sampled, because the instance coverage for A is greater than zero while for others, it stays at zero.

Simulation Log
ncsim> run
a.var1=0xf b.var1=0xd b.var2=0xe
a.var1=0xf b.var1=0xf b.var2=0xe
a.var1=0x2 b.var1=0xa b.var2=0x5
a.var1=0x9 b.var1=0xd b.var2=0x3
a.var1=0xe b.var1=0x3 b.var2=0xd
A.cgA get_coverage = 25.00 %   get_inst_coverage = 25.00 %
B.cgA get_coverage = 25.00 %   get_inst_coverage = 0.00 %
B.cgB get_coverage = 0.00 %    get_inst_coverage = 0.00 %
ncsim: *W,RNQUIE: Simulation is complete.
Trial 2

In this case, we'll try sampling cgA from both A and B. The only difference is what goes into the for loop when compared to the previous code.

 
    for (int i = 0;i < 5; i++) begin
      a.randomize();
      b.randomize();
      $display ("a.var1=0x%0h b.var1=0x%0h b.var2=0x%0h", a.var1, b.var1, b.var2);
      a.cgA.sample();
      b.cgA.sample();
    end
 

Because B is also randomized and sampled, we get a higher coverage in this case. The overall coverage for cgA goes higher also.

Simulation Log
ncsim> run
a.var1=0xf b.var1=0xd b.var2=0xe
a.var1=0xf b.var1=0xf b.var2=0xe
a.var1=0x2 b.var1=0xa b.var2=0x5
a.var1=0x9 b.var1=0xd b.var2=0x3
a.var1=0xe b.var1=0x3 b.var2=0xd
A.cgA get_coverage = 43.75 %   get_inst_coverage = 25.00 %
B.cgA get_coverage = 43.75 %   get_inst_coverage = 25.00 %
B.cgB get_coverage = 0.00 %    get_inst_coverage = 0.00 %
ncsim: *W,RNQUIE: Simulation is complete.
Trial 3

Now we'll sample cgB also along with the other covergroup.

 
    for (int i = 0;i < 5; i++) begin
      a.randomize();
      b.randomize();
      $display ("a.var1=0x%0h b.var1=0x%0h b.var2=0x%0h", a.var1, b.var1, b.var2);
      a.cgA.sample();
      b.cgA.sample();
      b.cgB.sample();
    end
 

As expected, cgB now reports a value greater than zero. The cross between cgA and var2 yields 62.5% which can be explained as follows. var1 has 16 bins and var2 has one bin, and the cross between the two should give 16 bins (16 x 1), out of which 4 are covered and yields 25% for the cross. The other bin which is for var2 is covered 100% and the average of both coverages give 62.5%.

Simulation Log
ncsim> run
a.var1=0xf b.var1=0xd b.var2=0xe
a.var1=0xf b.var1=0xf b.var2=0xe
a.var1=0x2 b.var1=0xa b.var2=0x5
a.var1=0x9 b.var1=0xd b.var2=0x3
a.var1=0xe b.var1=0x3 b.var2=0xd
A.cgA get_coverage = 43.75 %   get_inst_coverage = 25.00 %
B.cgA get_coverage = 43.75 %   get_inst_coverage = 25.00 %
B.cgB get_coverage = 62.50 %   get_inst_coverage = 62.50 %
ncsim: *W,RNQUIE: Simulation is complete.

In short, covergroups are also inherited by a child class in addition to variables and methods, and it should be possible to cross coverpoints belonging to two different covergroups within the base and child classes.

HDL routines for error injection
Stressing the interconnect for performance bugs

Related Posts

 

Comments

No comments made yet. Be the first to submit a comment
Already Registered? Login Here
Guest
Tuesday, 14 August 2018

We use cookies to personalize content and ads, to provide social media features and to analyze our traffic. You consent to our cookies if you continue to use our website. To find out more about the cookies we use and how to delete them, see our privacy policy.

  I accept cookies from this site.
Agree
EU Cookie Directive plugin by www.channeldigital.co.uk