Coding for covergroup with coverpoint and cross

Hi,

I want to create a covergroup that can use two coverpoint and cross them.
One of the coverpoint will be one hot of 9 bits.
So I want to check that coverpoint A which is an enable is used with coverpoint B which is a set of 9 register bits.

Please don’t use UVM or complicated “class” coding.

I only want simple to use systemverilog coding.

I think the coding may be something like

 covergroup cg_x @(posedge clk);
    coverpoint enable;
    coverpoint mode[8:0];  // somehow need to only define onehot bits [8], [7], [6], [5], [4], [3], [2], [1], [0]
    cross enable, mode;
endgroup

In reply to davidct:

I’m not sure what do you mean by complicated class or UVM, both are systemverilog coding,

In anyways if your simulator supports 1800-2012 IEEE SV you could create an array with the valid values you want in this case the one hot, something similar to the following


module test();
  
  parameter N = 8;
  bit [N-1:0] values[N]; //this will contain the relevant values you want in your bins
  bit [N-1:0] mode;
  bit enable;
  bit clk;
  
  covergroup cg @(posedge clk);
    
    enable_cp: coverpoint enable;
    
    one_hot_mode_cp: coverpoint mode {
      bins one_hot[N] = values;
    }
    
    cross enable_cp, one_hot_mode_cp;
    
  endgroup
      
  cg m_cg;
  
  initial begin
    forever #10 clk = ~clk;
  end
  
  initial begin
    
    foreach(values[i]) values[i] = 1 << i; //first populate with the one hot values
    m_cg = new; //create the covergroup
    
    repeat (N) begin
      @(posedge clk);
      mode = $urandom_range(2**N-1, 0);
      enable = $urandom_range(1, 0);
      $display("@ %0t mode =  %b enable = %b coverage = %f", $time,  mode, enable, m_cg.get_coverage());
    end
	$finish;
  end
  
endmodule

Keep in mind the order First the values array got populated then the covergroup gets constructed, I guess you could optimise this more.
HTH,
-R

In reply to rgarcia07:

Thank you for your help.

On edaplayground VCS 2019 won’t compile that code because the one_hot was not supported yet
so I switched to using
Incisive 15.20

It compiles now but because of the $urandom it may take a long time to achieve
the one hot bit for mode:

00000001
00000010
00000100
00001000
00010000
00100000
01000000
10000000

Updated code below and added “-coverage functional” as option in edaplayground

module test();
 
  parameter N = 8;
  bit [N-1:0] values[N]; //this will contain the relevant values you want in your bins
  bit [N-1:0] mode;
  bit enable;
  bit clk;
  bit abc;
 
  covergroup cg @(posedge clk);
 
    enable_cp: coverpoint enable;
 
    one_hot_mode_cp: coverpoint mode {
      bins one_hot[N] = values;
    }
 
    cross enable_cp, one_hot_mode_cp;
 
  endgroup
 
  cg m_cg;
 
  initial begin
    forever #10 clk = ~clk;
  end
 
  initial begin
 
//    foreach(values[i]) values[i] = 1 << i; //first populate with the one hot values
    foreach(values[i]) begin values[i] = 1 << i; $display("values[%d] = %h, mode[%d] = %h", i, values[i], i, mode[i]); end //first populate with the one hot values
 
    m_cg = new; //create the covergroup
 
//    mode = 1;
    repeat (N) begin
      @(posedge clk);
      mode = $urandom_range(2**N-1, 0);
//      mode = mode << 1;
      enable = $urandom_range(1, 0);
      $display("@ %0t abc = %b, mode =  %b enable = %b coverage = %f", $time,  abc, mode, enable, m_cg.get_coverage());
    end
	$finish;
  end
  
 
endmodule

Incisive Simulation run
Why is mode not one of “00000001, 00000010, 00000100, 00001000, 00010000, 00100000, 01000000, 10000000” and why is coverage incrementing when one_hot and enable is not correct ?

ncsim> run
values[ 0] = 01, mode[ 0] = 0
values[ 1] = 02, mode[ 1] = 0
values[ 2] = 04, mode[ 2] = 0
values[ 3] = 08, mode[ 3] = 0
values[ 4] = 10, mode[ 4] = 0
values[ 5] = 20, mode[ 5] = 0
values[ 6] = 40, mode[ 6] = 0
values[ 7] = 80, mode[ 7] = 0
@ 10 abc = 0, mode = 00011010 enable = 1 coverage = 0.000000
@ 30 abc = 0, mode = 00101010 enable = 1 coverage = 16.666667
@ 50 abc = 0, mode = 11110101 enable = 0 coverage = 16.666667
@ 70 abc = 0, mode = 10011101 enable = 1 coverage = 33.333333
@ 90 abc = 0, mode = 00110110 enable = 1 coverage = 33.333333
@ 110 abc = 0, mode = 11100100 enable = 1 coverage = 33.333333
@ 130 abc = 0, mode = 10001000 enable = 1 coverage = 33.333333
@ 150 abc = 0, mode = 00110101 enable = 0 coverage = 33.333333
Simulation complete via $finish(1) at time 150 NS + 0
./testbench.sv:46 $finish;
ncsim> exit

In reply to davidct:

Coverage is computed taking into account each coverpoint in the covergroup so you are just seen the contribution of covering enable 0, 1 if you don’t want this you need to add option.weight = 0 to the coverpoints you don’t care about.

Section 19.7 Specifying coverage options of the 2017 LRM may help you to understand further, also section 19.11 Coverage computation

In reply to rgarcia07:

I want these coverage combinations
enable mode
1 00000001
1 00000010
1 00000100
1 00001000
1 00010000
1 00100000
1 01000000
1 10000000

but I’m not sure how the coverage tool is calculating the coverage.

How to refine the coverage to only check the above combinations ?

In reply to davidct:

I recommend you read the sections I mentioned, regarding to the last question one possible way is this

module test();
  
  parameter N = 9;
  bit [N-1:0] values[N];
  bit [N-1:0] mode;
  bit enable;
  bit clk;
  
  covergroup cg @(posedge clk);
    
    enable_cp: coverpoint enable { 
      option.weight = 0;
      bins v = {1}; // you only care enable  = 1
    }
    
    one_hot_mode_cp: coverpoint mode { 
      option.weight = 0;
      bins one_hot[] = values;
    }
    
    cross enable_cp, one_hot_mode_cp;
    
  endgroup
      
  cg m_cg;
  
  initial begin
    forever #10 clk = ~clk;
  end
  
  initial begin

    mode <= 1;
    
    foreach(values[i]) values[i] = 1 << i;
	m_cg= new;
    
    repeat (N) begin
      @(posedge clk);
      mode   <= mode << 1;
      enable <= $urandom_range(1, 0);
      $display("@ %0t mode =  %b enable = %b coverage = %f", $time,  mode, enable, m_cg.get_coverage());
    end
	$finish;
  end
endmodule

Outputs the following

KERNEL: @ 10 mode = 000000001 enable = 0 coverage = 0.000000

KERNEL: @ 30 mode = 000000010 enable = 1 coverage = 11.111111

KERNEL: @ 50 mode = 000000100 enable = 1 coverage = 22.222222

KERNEL: @ 70 mode = 000001000 enable = 0 coverage = 22.222222

KERNEL: @ 90 mode = 000010000 enable = 1 coverage = 33.333333

KERNEL: @ 110 mode = 000100000 enable = 1 coverage = 44.444444

KERNEL: @ 130 mode = 001000000 enable = 0 coverage = 44.444444

KERNEL: @ 150 mode = 010000000 enable = 0 coverage = 44.444444

KERNEL: @ 170 mode = 100000000 enable = 1 coverage = 55.555556

In reply to rgarcia07:

You can also do

covergroup cg @(posedge clk) {
 
    enable_cp: coverpoint enable;
        bins v = {1};
}
    one_hot_mode_cp: coverpoint mode {
      bins one_hot[N] = one_hot_mode_cp with ($onehot(item));
}
  cross enable_cp, one_hot_mode_cp;
endgroup

In reply to rgarcia07:

For RGarcia, with Incisive 15.20 I get different coverage number

ncsim> run
@ 10 mode = 000000001 enable = 0 coverage = 0.000000
@ 30 mode = 000000010 enable = 0 coverage = 3.703704
@ 50 mode = 000000100 enable = 1 coverage = 7.407407
@ 70 mode = 000001000 enable = 0 coverage = 48.148148
@ 90 mode = 000010000 enable = 1 coverage = 51.851852
@ 110 mode = 000100000 enable = 1 coverage = 59.259259
@ 130 mode = 001000000 enable = 0 coverage = 66.666667
@ 150 mode = 010000000 enable = 1 coverage = 70.370370
@ 170 mode = 100000000 enable = 1 coverage = 77.777778
Simulation complete via $finish(1) at time 170 NS + 0
./testbench.sv:58 $finish;
ncsim> exit

Maybe there is a bug for Incisive 15.20

In reply to rgarcia07:

Yes. I copied and ran again with same results.
I think it’s a bug with Incisive 15.20.

Also, I tried dave_59 code and I also got error with Incisive 15.20

irun: 15.20-s038: (c) Copyright 1995-2017 Cadence Design Systems, Inc.
bins one_hot[N] = one_hot_mode_cp with ($onehot(item));
|
ncvlog: *E,NOTPAR (testbench.sv,19|52): Illegal operand for constant expression [4(IEEE)].

In reply to davidct:

In reply to rgarcia07:
Yes. I copied and ran again with same results.
I think it’s a bug with Incisive 15.20.
Also, I tried dave_59 code and I also got error with Incisive 15.20
irun: 15.20-s038: (c) Copyright 1995-2017 Cadence Design Systems, Inc.
bins one_hot[N] = one_hot_mode_cp with ($onehot(item));
|
ncvlog: *E,NOTPAR (testbench.sv,19|52): Illegal operand for constant expression [4(IEEE)].

Yes I think you are correct I tried on version 19.02-a001 and I got the same results as you, sorry about that :(

In reply to rgarcia07:

Now to make this covergroup usable for other similar testing,
I would like to make the coverpoints “enable” and “mode” to be passed to the covergroup
and these “enable” and “mode” are actually hierarchy paths to the design.

Could I modify the covergroup and usage to something like this ?

localparam e1 tb.i_chip.enable1;
localparam e2 tb.i_chip.enable2;

localparam mode1[8:0] tb.i_chip.i_reg1.mode[15:7];
localparam mode2[8:0] tb.i_chip.i_reg2.mode[15:7];

covergroup cg @(posedge clk) (ref logic enable, reg logic [8:0] mode );

enable_cp: coverpoint enable { 
  option.weight = 0;
  bins v = {1}; // you only care enable  = 1
}

one_hot_mode_cp: coverpoint mode { 
  option.weight = 0;
  bins one_hot[] = values;
}

cross enable_cp, one_hot_mode_cp;

endgroup

cg m_cg1 = new(e1, mode1);
cg m_cg2 = new(e2, mode2);

In reply to davidct:

Yes I believe you can, not sure why you want to use localparam, you’ll probably need to add option.per_instance = 1; to the covergroup to see each cg individual coverage.

btw the problem with incisive is the value reported is the covergroup average functional coverage, not per instance

Reported coverage

If you look at the coverage per instance you’ll see the correct value

Instance coverage

Not sure why this is the case, but this forum is not for tool specific stuff.

HTH,

-R

In reply to rgarcia07:

Thanks for the feedback. I’ll read up some more on covergroups and the reporting.

As for localparam, I’m trying to use it to pass the parameter which points to the
design hierarchy. It will make the code look cleaner.

What’s the other option ?

In reply to rgarcia07:

I was to force the covergroup and tb (enable=1) with walking one-hot mode to make 100% coverage.

module test();
 
  parameter N = 9;
  bit [N-1:0] values[N];
  bit [N-1:0] mode;
  bit enable;
  bit clk;
 
//  covergroup cg @(posedge clk); 
//    enable_cp: coverpoint enable {
//        bins v = {1};
//    }
//    
//    one_hot_mode_cp: coverpoint mode {
//      bins one_hot[N] = one_hot_mode_cp with ($onehot(item));
//	}
//  cross enable_cp, one_hot_mode_cp;
//endgroup
  
  covergroup cg @(posedge clk);

// type_option.merge_instances option.get_inst_coverage get_inst_coverage get_coverage
//               0                      ??                       average_of_all_instances average_of_all_instances
//               1                      0                         merge_of_all_instances   merge_of_all_instances
//               1                      1                         individual instance      merge_of_all_instances

    // most common
    // option.per_instance=0;
    // type_option.merge_instances=1
    
    
    option.per_instance = 1;
    type_option.merge_instances = 1;
//    option.get_inst_coverage = 1;
    
    enable_cp: coverpoint enable { 
      option.weight = 0;
      bins v = {1}; // you only care enable  = 1
    }
 
    one_hot_mode_cp: coverpoint mode { 
      option.weight = 0;
      bins one_hot[] = values;
    }

    enable_mod_cross : cross enable_cp, one_hot_mode_cp;

// optional bins creation
//    enable_mod : cross enable_cp, one_hot_mode_cp
//    {bins v_one_hot = binsof(enable_cp) && binsof(one_hot_mode_cp); }
  endgroup
 
  cg m_cg;
 
  initial begin
    forever #10 clk = ~clk;
  end
 
  initial begin
 
    enable <= 1;
    mode <= 1;
 
    foreach(values[i]) values[i] = 1 << i;
	m_cg= new;
 
    repeat (N+1) begin
      @(posedge clk);
      mode   <= mode << 1;
//      enable <= $urandom_range(1, 0);
      enable <= 1;
      $display("@ %0t mode =  %b enable = %b coverage = %f", $time,  mode, enable, m_cg.get_coverage());
    end
	$finish;
  end
endmodule

ncsim> run
@ 10 mode = 000000001 enable = 1 coverage = 0.000000
@ 30 mode = 000000010 enable = 1 coverage = 40.740741
@ 50 mode = 000000100 enable = 1 coverage = 48.148148
@ 70 mode = 000001000 enable = 1 coverage = 55.555556
@ 90 mode = 000010000 enable = 1 coverage = 62.962963
@ 110 mode = 000100000 enable = 1 coverage = 70.370370
@ 130 mode = 001000000 enable = 1 coverage = 77.777778
@ 150 mode = 010000000 enable = 1 coverage = 85.185185
@ 170 mode = 100000000 enable = 1 coverage = 92.592593
@ 190 mode = 000000000 enable = 1 coverage = 100.000000
Simulation complete via $finish(1) at time 190 NS + 0
./testbench.sv:77 $finish;
ncsim> exit