覆盖率

覆盖率是一个用于衡量完成设计验证进度的通用术语。覆盖率报告以百分比(%)表示。

覆盖率的需求
帮助我们了解设计的所有特性是否都被测量,以及代码中的每一行是否都被执行。

覆盖率的类型

  1. 代码覆盖率
  2. 功能覆盖率

覆盖率类型

代码覆盖率#

代码覆盖率涉及实现部分,即检查你的测试是否执行了设计规范的“实现”部分,但不会检查验证计划。它将衡量测试用例的质量。

  1. 行覆盖率:检查执行了多少行。
  2. 路径覆盖率:检查代码在哪些路径中执行。
  3. 切换覆盖率:检查哪些单比特变量曾经或正在具有值0或1。
  4. 有限状态机(FSM)覆盖率:检查状态机中的哪些状态和转换被访问过。

代码覆盖率的局限性
它依赖于设计代码,因此可以衡量已编写代码的覆盖率,但不能对尚未编写的软件做出任何说明。

功能覆盖率#

功能覆盖率定义了在验证中设计规范的执行程度,或者说功能覆盖率衡量了所有测试在满足验证计划要求方面的进展。它衡量了设计验证(DV)的质量。

功能覆盖率的局限性
如果设计中有15个特性,而我们只提到了其中的10个,它会得出所有特性都被覆盖的结论。所以请确保在功能覆盖率块中包含所有设计特性。

需求
功能覆盖率用于跟踪所有被测单元(DUT)特性是否都已被验证,并衡量验证的质量。功能覆盖率帮助我们针对未验证的DUT特性进行测试。

功能覆盖率与代码覆盖率的区别

序号功能覆盖率代码覆盖率
1.检查刺激覆盖了多少功能检查代码被刺激测试的程度
2.如果设计中缺少某个代码块,功能覆盖率可以识别出这个错误如果设计中缺少某个代码块,代码覆盖率无法识别出这个错误
3.依赖于设计规范依赖于设计代码

覆盖率比较#

覆盖率比较

当功能覆盖率和代码覆盖率都低时

  • 项目刚开始

当功能覆盖率高而代码覆盖率低时

  • 代码需要更多的覆盖点/案例
  • 存在无用代码
  • 可能是测试计划中缺少了一些需要覆盖的功能

当功能覆盖率低而代码覆盖率高时

  • 刺激质量差(尝试不同的种子)

当功能覆盖率和代码覆盖率都高时

  • 设计结束,检查错误率

覆盖组和覆盖点#

在System Verilog中,覆盖组是一种用户定义类型,它封装了覆盖模型的规格。它必须实例化才能收集数据。这类似于类,可以定义一次并在不同的地方使用new函数多次实例化。我们通常使用sample函数显式触发覆盖组。如果不对覆盖组进行采样,则功能覆盖率将视为零函数被覆盖。

每个覆盖组规格可以包括:

  • 同步采样覆盖点的时钟事件

  • 一组覆盖点

  • 覆盖点之间的交叉覆盖

  • 可选的形式参数

  • 覆盖选项

  • 语法:

covergroup covergroup_name ;    
   .....  
endgroup 
  • 示例:

以下示例显示了覆盖组的声明和执行。

covergroup cgrp;
   c1: coverpoint a;  
   c2: coverpoint b;  
endgroup  
cgrp cg = new();  

initial begin
   repeat (5) begin
      a = $random();
      b = $random();
      cg.sample();      
      $display("a=%d ; b=%d ; coverage = %.2f", a, b, cg.get_inst_coverage());    
   end
end

定义了一个名为cgrp的覆盖组,并实例化了一个名为‘cg’的实例。c1和c2是覆盖点的标签,a和b是声明的变量。使用其句柄名称(cg)通过new函数创建一个对象。a和b变量被随机化,在5次迭代中具有不同的值,并在此随机化过程中通过sample函数触发覆盖组,并使用handle.get_inst_coverage()函数显示功能覆盖率。

  • 输出截图

下图显示了一个简单覆盖组的输出。

覆盖组输出

  • 在第一次迭代中,a=0,b=1。在这一迭代中,分别计算覆盖点c1和c2的覆盖率。c1和c2的平均值即为实例覆盖率百分比。这里a和b可以有四个值,从0到3,在这四个值中只有值0被分配给变量’a’,因此覆盖率为(1/4)*100 = 25%。同样地,变量b的值为1,因此覆盖率为(1/4)*100 = 25%。现在,c1和c2的平均值为(25+25)/2 = 25%。

  • 在第二次迭代中,a=1,b=3;此时变量’a’的四个值中有两个值已被分配,因此覆盖率为(2/4)*100 = 50%。同样地,变量’b’的覆盖率为50%。现在覆盖点c1和c2的平均值为(50+50)/2 = 50%。

  • 在第三次迭代中,a=1,b=1,此时’a’的值重复为1。但这个值在第二次迭代中已经覆盖,因此’a’只覆盖了4个值中的2个值,其覆盖率为(2/4)*100 = 50%。同样地,变量’b’的值在第一次迭代中已经覆盖,因此4个值中有2个值被分配,因此覆盖率为(2/4)*100 = 50%。现在c1和c2的平均值为(50+50)/2 = 50%。

  • 在第四次迭代中,a=1,b=2;此时变量’a’覆盖了2个值,但变量’b’覆盖了4个值中的3个值。因此,c1的覆盖率为50%,c2的覆盖率为75%。现在c1和c2的平均值为(50+75)/2 = 62.50%。

  • 在第五次迭代中,a=1,b=1;‘a’覆盖了2个值,‘b’覆盖了4个值中的3个值。因此,c1的覆盖率为50%,c2的覆盖率为75%。现在c1和c2的平均值为(50+75)/2 = 62.50%。

  • 覆盖率报告

覆盖组输出

注意: 为了获得更高的覆盖率百分比,可以增加迭代次数,从而增加覆盖所有功能的概率。

覆盖点#

一个覆盖组可以包含一个或多个覆盖点。覆盖点仅指定整数值或整数表达式。覆盖组被采样时可以评估覆盖点。它可以用分号 : 可选地标记。如果覆盖点被标记,那么System Verilog会给出覆盖点的名称。每个覆盖点都会有bins。bins可以由模拟器自动创建或显式定义。

语法:

// without label name //  
covergroup covergroup_name;
  coverpoint variable_name;
endgroup

// with label name//
covergroup covergroup_name;
label_name: coverpoint variable _name;
endgroup

序号覆盖组声明
1.模块内定义的覆盖组
2.类内定义的覆盖组
3.类和模块外定义的覆盖组

1. 模块内定义的覆盖组#

当我们在模块内定义一个覆盖组时,访问数据值很容易,并且实例化和句柄创建不是强制性的。相反,我们可以直接使用covergroup_name来执行相应的覆盖点。为了使用覆盖组,我们需要使用new函数创建一个对象。

  • 语法:
            module tb;  
              datatype var;  
   
               covergroup covergroup_name;  
                      label : coverpoint var;  
               endgroup   

              initial begin  
            covergroup_name = new();  
  
            endclass      

示例:

                           module cvgrp_inside_mod;
                               covergroup cvgrp ;
                                     c1: coverpoint p.a;
                                     c2: coverpoint p.b ;
                                endgroup
                                 cvgrp cg;
                           initial begin
                              cg=new;
                           repeat (5) begin
                             void'(p.randomize);
                             cg.sample();
                             $display ("a=%d ; b=%d ; coverage =%.2f",p.a,p.b,cg.get_inst_coverage());     

在这里,cover group 在模块内定义,而变量在类内声明。c1 和 c2 是覆盖点的标签,p.a 和 p.b 是在类中声明的变量。为 cover group 创建了一个名为 ‘cg’ 的句柄。使用句柄名,通过 new 函数创建了一个对象。在这种随机化过程中,使用 class_handle.randomize 函数对变量 ‘a’ 和 ‘b’ 进行随机化,并使用 sample 函数触发 cover group,功能覆盖率使用 group_handle.get_inst_coverage() 函数显示。

  • 输出截图

in_mod

这里变量 ‘a’ 可以有 4 个值,即 [0-3],变量 ‘b’ 可以有 8 个值,即 [0-7]。

  • 在第一次迭代中 a=0 和 b=0;c1 的覆盖率是 (1/4)*100 = 25%,c2 的覆盖率是 (1/8)*100 = 12.5%;因此 c1 和 c2 的平均覆盖率是 (25+12.5)/2 = 18.75%。
  • 在第二次迭代中 a=0 和 b=2;c1 的覆盖率是 (1/4)*100 = 25%,c2 的覆盖率是 (2/8)*100 = 25%;因此 c1 和 c2 的平均覆盖率是 (25+25)/2 = 25%。
  • 在第三次迭代中 a=1 和 b=1;c1 的覆盖率是 (2/4)*100 = 50%,c2 的覆盖率是 (3/8)*100 = 37.5%;因此 c1 和 c2 的平均覆盖率是 (50+37.5)/2 = 43.75%。
  • 在第四次迭代中 a=0 和 b=2;c1 的覆盖率是 (2/4)*100 = 50%,c2 的覆盖率是 (3/8)*100 = 37.5%;因此 c1 和 c2 的平均覆盖率是 (50+37.5)/2 = 43.75%。
  • 在第五次迭代中 a=2 和 b=7;c1 的覆盖率是 (3/4)*100 = 75%,c2 的覆盖率是 (4/8)*100 = 50%;因此 c1 和 c2 的平均覆盖率是 (75+50)/2 = 62.50%。

覆盖率报告

in_mod1


2. 类中定义的 Covergroup#

类中的 cover group 可以采样该类中的变量以及嵌入对象中的数据值。如果 cover group 定义在类中,它被称为嵌入式 cover group。嵌入式 cover group 可以通过 class_handle.covergroup_name 在类外调用。

  • 语法:
          class class_name;  
               data_type var;  
   
               covergroup covergroup_instantiate;   
                    label: coverpoint var; 
               endgroup   
 
           endclass   

示例:

                              class pack;
                                rand  bit [1:0] a;
                                rand  bit [1:0] b;

                                 covergroup cg;
                                    c1: coverpoint a;
                                    c2: coverpoint b;
                                  endgroup
                                  cg =new();
                                 endclass

                             pack p = new();   

这里 cover group 定义在类内部。为 cover group 创建了一个名为 ‘cg’ 的句柄。在类和模块内部实例化 cover group 时,不需要使用句柄名,可以直接使用 cover group 名称。使用 new 函数创建了一个对象。在随机化过程中,使用 class_handle.randomize 函数对变量 ‘a’ 和 ‘b’ 进行随机化,并使用 sample 函数触发 cover group。

  • 输出截图

in_class

这里变量 a 和 b 可以有 4 个值,即 [0-3]。

  • 在第一次迭代中 a=0 和 b=2;c1 的覆盖率是 (1/4)*100 = 25%,c2 的覆盖率是 (1/4)*100 = 25%;因此 c1 和 c2 的平均覆盖率是 (25+25)/2 = 25%。

  • 在第二次迭代中 a=0 和 b=1;c1 的覆盖率是 (1/4)*100 = 25%,c2 的覆盖率是 (2/4)*100 = 50%;因此 c1 和 c2 的平均覆盖率是 (25+50)/2 = 37.50%。

  • 在第三次迭代中 a=1 和 b=0;c1 的覆盖率是 (2/4)*100 = 50%,c2 的覆盖率是 (3/4)*100 = 75%;因此 c1 和 c2 的平均覆盖率是 (50+75)/2 = 62.50%。

  • 在第四次迭代中 a=0 和 b=2;c1 的覆盖率是 (2/4)*100 = 50%,c2 的覆盖率是 (3/4)*100 = 75%;因此 c1 和 c2 的平均覆盖率是 (50+75)/2 = 62.50%。

  • 在第五次迭代中 a=2 和 b=0;c1 的覆盖率是 (3/4)*100 = 75%,c2 的覆盖率是 (3/4)*100 = 75%;因此 c1 和 c2 的平均覆盖率是 (75+75)/2 = 75%。

  • 覆盖率报告

in_class1


3. 类和模块外定义的 Covergroup#

cover group 可以在程序中的任何地方定义,如果我们在模块或类外定义 cover group,需要用句柄名实例化它,并可以通过创建一个句柄对象来使用 new 函数在程序的任何地方使用它。

一般来说,cover group 的语法如下:

  • 语法:
                     covergroup covergroup_name;  
                        label l: coverpoint var 1;    
                          ...      
                        label N: coverpoint var N;     
                        endgroup        
                      covergroup_name cg_inst = new();      

示例:

                    class cover_group;
                         rand bit [2:0]a;
                         rand bit [1:0]b;
                       endclass
                      cover_group c=new();
                   
                       covergroup cgrp;
                           c1: coverpoint c.a;
                           c2: coverpoint c.b;
                        endgroup 
 
                       module outside;
                         cgrp cg=new();
                         initial begin
                              repeat (5)begin
                              void'(c.randomize());
                               cg.sample();
                              $display("a =%d b=%d; coverage %%= %0.2f",c.a,c.b,cg.get_inst_coverage());
                          end  

这里 cover group 定义在类和模块外,而变量在类内声明。为类创建了一个名为 ‘c’ 的句柄,使用这个句柄名 (‘c’),通过 new 函数创建了一个对象。同样,为 cover group 创建了一个名为 ‘cg’ 的句柄,使用这个句柄名,通过 new 函数创建了一个对象。然后使用 sample 函数触发 cover group,并使用 randomize 函数对变量 a 和 b 进行随机化。

  • 输出截图

out

这里变量 a 可以有 8 个值,即 [0-7],变量 b 可以有 4 个值,即 [0-3]。

  • 在第一次迭代中 a=0 和 b=2;c1 的覆盖率是 (1/8)*100 = 12.5%,c2 的覆盖率是 (1/4)*100 = 25%;因此 c1 和 c2 的平均覆盖率是 (12.5+25)/2 = 18.75%。

  • 在第二次迭代中 a=3 和 b=1;c1 的覆盖率是 (2/8)*100 = 25%,c2 的覆盖率是 (2/4)*100 = 50%;因此 c1 和 c2 的平均覆盖率是 (25+50)/2 = 37.5%。

  • 在第三次迭代中 a=0 和 b=0;c1 的覆盖率是 (2/8)*100 = 25%,c2 的覆盖率是 (3/4)*100 = 75%;因此 c1 和 c2 的平均覆盖率是 (25+75)/2 = 50%。

  • 在第四次迭代中 a=6 和 b=2;c1 的覆盖率是 (3/8)*100 = 37.5%,c2 的覆盖率是 (3/4)*100 = 75%;因此 c1 和 c2 的平均覆盖率是 (37.5+75)/2 = 56.25%。

  • 在第五次迭代中 a=3 和 b=0;c1 的覆盖率是 (3/8)*100 = 37.5%,c2 的覆盖率是 (3/4)*100 = 75%;因此 c1 和 c2 的平均覆盖率是 (37.5+75)/2 = 56.25%。

  • 覆盖率报告

out1


触发 cover group#

cover group 通常由测试台触发。为了计算函数覆盖率,必须触发 cover group。如果不触发 cover group,覆盖的功能将不会被计算,因此默认情况下将显示为 0.00% 覆盖率。

在过程代码中显式触发 cover group 的一般方法是使用 sample 函数。

序号触发 cover group
1.在相应时钟边沿触发 cover group
2.指定 covergroup 应该在哪个事件上进行采样。

在 cover group 中触发覆盖率收集有两种不同的方法:

1. 在相应时钟边沿触发 cover group。#

  • 语法:
                    covergroup covergroup_name @(clkedge clk) ; // 在相应的时钟边沿采样 coverpoint     
                          coverpoint var;  
                    endgroup    

cover group 在相应的时钟边沿触发,并考虑覆盖点。

示例:

                     bit clk;
                    always #5 clk=~clk;
                    covergroup cvgp @ (posedge clk);
                         c1: coverpoint a;
                         c2: coverpoint b;
                       endgroup 

在这个例子中,我们使用时钟边沿来触发 cover group。在这个例子中,每隔 5ns 时钟边沿变化一次,在时钟的正边沿触发 cover group,采样并随机化覆盖点的值。

输出截图

clk

变量 a 可以有 8 个值,即 [0-7],而变量 ‘b’ 只能取 0 和 1 两个值。

  • 在第一次迭代中,a=4 和 b=1;c1 的覆盖率是 (1/8)*100 = 12.5%,c2 的覆盖率是 (1/2)*100 = 50%;因此 c1 和 c2 的平均覆盖率是 (12.5+50)/2 = 31.25%。

  • 在第二次迭代中,a=1 和 b=0;c1 的覆盖率是 (2/8)*100 = 25%,c2 的覆盖率是 (2/2)*100 = 100%;因此 c1 和 c2 的平均覆盖率是 (25+100)/2 = 62.50%。

  • 在第三次迭代中,a=1 和 b=0;c1 的覆盖率是 (2/8)*100 = 25%,c2 的覆盖率是 (2/2)*100 = 100%;因此 c1 和 c2 的平均覆盖率是 (25+100)/2 = 62.50%。

  • 在第四次迭代中,a=3 和 b=0;c1 的覆盖率是 (3/8)*100 = 37.5%,c2 的覆盖率是 (2/2)*100 = 100%;因此 c1 和 c2 的平均覆盖率是 (37.5+100)/2 = 68.75%。

  • 在第五次迭代中,a=5 和 b=0;c1 的覆盖率是 (4/8)*100 = 50%,c2 的覆盖率是 (2/2)*100 = 100%;因此 c1 和 c2 的平均覆盖率是 (50+100)/2 = 75%。

  • 覆盖率报告

clk1

2. 指定 covergroup 应该在哪个 event 上进行采样。#

覆盖率事件可以使用 @ 来阻止信号或事件。在过程代码中,覆盖率组可以使用 “-> event_name” 来触发。

  • 语法:
                covergroup covergroup_name @ e; // e is an event name and can be triggered using ->e
                      label: coverpoint var;
                endgroup     

示例:

                   event e;
                     covergroup cgrp @ e;
                       c1 : coverpoint a;
                       endgroup
                      cgrp cg;
                   initial begin
                      cg = new();
                  repeat (5)begin
                       a=$random;
                      #1 -> e;
                      $display("a = %0d ; coverage = %0.2f",a,cg.get_inst_coverage());
                   end     

另一种触发 cover group 的方法是使用事件。在这个例子中,定义了一个事件 ’e’ 并通过 ->e(event_name) 触发它,这反过来触发 covergroup 并采样每个覆盖点的值。使用事件而不是直接调用采样方法的好处是可以使用现有事件。

  • 输出截图

event

这里变量 a 可以有 4 个值,即 [0-3]。

  • 在第一次迭代中,a=0;c1 的覆盖率是 (1/4)*100 = 25%。

  • 在第二次迭代中,a=1;c1 的覆盖率是 (2/4)*100 = 50%。

  • 在第三次迭代中,a=1;c1 的覆盖率是 (2/4)*100 = 50%。

  • 在第四次迭代中,a=3;c1 的覆盖率是 (3/4)*100 = 75%。

  • 在第五次迭代中,a=1;c1 的覆盖率是 (3/4)*100 = 75%。

  • 覆盖率报告

event report


条件覆盖#

条件覆盖变化的速查表

序号条件覆盖变化
1.使用 iff 关键字为 coverpoint 添加条件
2.使用 startstop 函数来控制 cover group 的各个实例

1. 使用 iff 关键字为 coverpoint 添加条件#

这样做的最常见原因是关闭覆盖,直到满足指定条件,以便忽略不相关的触发器。

  • 语法:
                covergroup covergroup_name;  
                       coverpoint var iff (condition) { //bins for var}  
                 endgroup      

iff 类似于 if 条件。只有当 iff 内的条件为真时,它才会进入 bins 并检查覆盖率。如果条件不满足或为假,则 bins 被忽略,整个 coverpoint 的覆盖率将为 0.00%。

示例:

covergroup cvgrp @ (posedge clk);  
    c1: coverpoint a iff(b==2) {
        bins b1 = {4};  
        bins b2 = {5};
    }  
endgroup   

在这个例子中,coverpoint 是为变量 ‘a’ 定义的,只有在条件 (b==2) 满足时,coverpoint 的 bins 才会执行。这里如果 b 的值是 2,那么 coverpoint 的 bins 将检查它们的条件 b1 和 b2。只有当变量 ‘a’ 被赋值为 4 时,bin b1 才被认为是命中/覆盖的,同样,只有当变量 ‘a’ 被赋值为 5 时,bin b2 才被认为是命中/覆盖的。最后,它会平均 bins 的覆盖百分比,这就是该特定 coverpoint 的总体覆盖率。

  • 输出截图

iff

这里变量 a 可以有 8 个值,即 [0-7],变量 ‘b’ 可以有 4 个值,即 [0-3]。覆盖率取决于明确定义的 bins。

  • 在第一次迭代中,a=4 和 b=1;检查 ‘b’ 的值;iff 条件 (b==2) 为 ,因此 b1 的覆盖率为 0%,b2 的覆盖率为 0%;coverpoint 的平均覆盖率为 (0+0)/2 = 0.00%。

  • 在第二次迭代中,a=1 和 b=3;检查 ‘b’ 的值;iff 条件 (b==2) 为 ,因此 b1 的覆盖率为 0%,b2 的覆盖率为 0%;coverpoint 的平均覆盖率为 (0+0)/2 = 0.00%。

  • 在第三次迭代中,a=5 和 b=1;检查 ‘b’ 的值;iff 条件 (b==2) 为 ,因此 b1 的覆盖率为 0%,b2 的覆盖率为 0%;coverpoint 的平均覆盖率为 (0+0)/2 = 0.00%。

  • 在第四次迭代中,a=5 和 b=2;检查 ‘b’ 的值;iff 条件 (b==2) 为 ,因此 b1 的覆盖率为 0%,b2 的覆盖率为 100%;coverpoint 的平均覆盖率为 (0+100)/2 = 50%。

  • 在第五次迭代中,a=1 和 b=1;检查 ‘b’ 的值;iff 条件 (b==2) 为 ,因此 b1 的覆盖率为 0%,b2 的覆盖率为 100%;coverpoint 的平均覆盖率为 (0+100)/2 = 50%。

  • 在第六次迭代中,a=6 和 b=1;检查 ‘b’ 的值;iff 条件 (b==2) 为 ,因此 b1 的覆盖率为 0%,b2 的覆盖率为 100%;coverpoint 的平均覆盖率为 (0+100)/2 = 50%。

  • 在第七次迭代中,a=5 和 b=0;检查 ‘b’ 的值;iff 条件 (b==2) 为 ,因此 b1 的覆盖率为 0%,b2 的覆盖率为 100%;coverpoint 的平均覆盖率为 (0+100)/2 = 50%。

  • 在第八次迭代中,a=1 和 b=2;检查 ‘b’ 的值;iff 条件 (b==2) 为 ,因此 b1 的覆盖率为 0%,b2 的覆盖率为 100%;coverpoint 的平均覆盖率为 (0+100)/2 = 50%。

  • 覆盖率报告

iff1

2. 使用 startstop 函数来控制 cover groups 的各个实例。#

Covergroup_name cg_inst = new;   
initial begin     
    if(condition)    
        cg_inst.stop();     
    else   
        cg_inst.start();   
end  

在上面的例子中,使用 if 和 else 语句来解释 startstop 函数。这些函数可以在过程代码中的任何地方调用。一般来说,stopstart 函数是在 handle 中定义的,以 start()handle.stop() 的方式调用。

示例:

                     covergroup cgrp;
                        c1: coverpoint s.a;
                        c2: coverpoint s.b;
                        endgroup
                  module cvgrp_start_stop;
                             cgrp cg;
                      initial begin
                          cg = new();
                          for(int i=0;i<6;i++) begin
                               void'(s.randomize());
                               cg.sample();
                                $display("a=%d ; b=%d ; coverage = %0.2f",s.a,s.b,cg.get_inst_coverage());
                                if (cg.get_inst_coverage()>65)begin
                                cg.stop;
                                 $display("if coverage%% is greater than 65%%,stop executing covergroup");
                               end
                            end

交叉覆盖率是指在覆盖点或变量之间的交叉覆盖。交叉覆盖率是使用 cross 构造来指定的。表达式不能直接用于交叉覆盖。交叉覆盖可以同时测量两个或多个覆盖点的覆盖率。如果我们测量一个具有 N 个值的变量和另一个具有 M 个值的变量的交叉覆盖,内部将有 N * M 个 bins 来存储所有 ‘NM’ 组合的结果。

示例:

covergroup cg @ (posedge clk);
    cp_a: coverpoint a;
    cp_b: coverpoint b;
    cross_a_b: cross cp_a, cp_b; // Cross coverage between coverpoint a and b
endgroup

在这个例子中,我们为变量 ab 定义了覆盖点 cp_acp_b,并通过 cross 构造指定了交叉覆盖 cross_a_b。这将测量变量 ab 的所有组合覆盖情况。

  • 输出截图

cross_coverage

这里变量 a 可以有 4 个值,即 [0-3],变量 b 可以有 2 个值,即 [0, 1]。

  • 在第一次迭代中,a=0 和 b=1;cross coverage 中的组合 (0,1) 被覆盖,覆盖率为 12.5%。

  • 在第二次迭代中,a=1 和 b=0;cross coverage 中的组合 (1,0) 被覆盖,覆盖率为 25%。

  • 在第三次迭代中,a=1 和 b=1;cross coverage 中的组合 (1,1) 被覆盖,覆盖率为 37.5%。

  • 在第四次迭代中,a=3 和 b=1;cross coverage 中的组合 (3,1) 被覆盖,覆盖率为 50%。

  • 在第五次迭代中,a=2 和 b=0;cross coverage 中的组合 (2,0) 被覆盖,覆盖率为 62.5%。

  • 覆盖率报告

cross_coverage_report

使用交叉覆盖率的优势#

交叉覆盖率提供了一种有效的方法来确保所有可能的变量组合都得到充分测试。这在测试复杂系统时尤为重要,因为不同变量的组合可能会揭示系统行为中的潜在问题。此外,交叉覆盖率还可以帮助识别特定组合的边缘情况,从而提高测试的全面性和覆盖率。

语法:

                     covergroup covergroup_name;     
                             label1: coverpoint var1;        
                             label2: coverpoint var2;         
                             label3:cross label1,label2;             
                       endgroup     

Example - 1:

                        covergroup cg;    
                            c1: coverpoint a;          
                            c2: coverpoint b;    
                            c3: cross c1,c2;       
                         endgroup
                          cg = new();  

Cross Coverage 示例:#

在这个示例中,我们将交叉覆盖点 c1c2。变量 ab 是单比特,因此它们可以有值 0 或 1。在执行 c1c2 之后,通过使用 cross 关键字计算这些覆盖点的交叉覆盖。由于变量 ab 各自可以有 2 个值,交叉覆盖可以有 ab 的组合,即 { {0,0}, {0,1}, {1,0}, {1,1} }

示例:

covergroup cvgrp;   
    c1: cross a, b;   
endgroup   
cvgrp cg = new();   

通过使用变量名直接交叉的方式,我们可以减少代码行数。这种方式会隐式地创建变量 ab 的单独覆盖点,以及它们的交叉覆盖点。这与之前的示例 1 类似,因此示例 1 和示例 2 的输出相同。

  • 输出截图

cross1

迭代详细信息:#

这里变量 ab 可以有 2 个值,即 0 或 1,而交叉值是这两个覆盖点值的组合,它们是 {0,0}, {0,1}, {1,0}, {1,1}

  1. 第一次迭代a=1b=0

    • c1 的覆盖率是 (1/2)*100 = 50%
    • c2 的覆盖率是 (1/2)*100 = 50%
    • c3 的覆盖率是 (1/4)*100 = 25%
    • 平均覆盖率是 (50 + 50 + 25)/3 = 41.67%
  2. 第二次迭代a=1b=0

    • c1 的覆盖率是 (1/2)*100 = 50%
    • c2 的覆盖率是 (1/2)*100 = 50%
    • c3 的覆盖率是 (1/4)*100 = 25%
    • 平均覆盖率是 (50 + 50 + 25)/3 = 41.67%
  3. 第三次迭代a=0b=1

    • c1 的覆盖率是 (2/2)*100 = 100%
    • c2 的覆盖率是 (2/2)*100 = 100%
    • c3 的覆盖率是 (2/4)*100 = 50%
    • 平均覆盖率是 (100 + 100 + 50)/3 = 83.33%
  4. 第四次迭代a=1b=0

    • c1 的覆盖率是 (2/2)*100 = 100%
    • c2 的覆盖率是 (2/2)*100 = 100%
    • c3 的覆盖率是 (2/4)*100 = 50%
    • 平均覆盖率是 (100 + 100 + 50)/3 = 83.33%
  5. 第五次迭代a=1b=1

    • c1 的覆盖率是 (2/2)*100 = 100%
    • c2 的覆盖率是 (2/2)*100 = 100%
    • c3 的覆盖率是 (3/4)*100 = 75%
    • 平均覆盖率是 (100 + 100 + 75)/3 = 91.67%

警告示例:#

如果我们在某些变量上定义了覆盖点,并且在这些变量上进行了交叉覆盖,则会出现警告。例如:

covergroup cvgrp;      
    c1: coverpoint a;         
    c2: coverpoint b;           
    c3: cross a, b;          
endgroup            

在这个示例中,覆盖点和交叉覆盖都是在相同的变量上进行的。早些时候我们看到了覆盖点之间的交叉和变量之间的交叉,但在这里我们在已经显式定义覆盖点的变量上执行交叉覆盖。

模拟器中会出现冲突。冲突是因为变量 ab 已经在覆盖点中定义,因此我们可以直接在这些覆盖点 c1c2 上编写交叉覆盖。否则,如果我们不需要使用 c1c2,则模拟器将隐式地在 ab 上创建另一个覆盖点,以及这些变量的交叉覆盖。因此,总共将有 5 个覆盖点。

  • 覆盖率报告截图

edit

详细迭代:#

这里变量 ab 可以有 2 个值,即 0 或 1。覆盖组内有 c1c2c3 覆盖点。c3 将隐式生成 3 个覆盖点,c3[0] 用于变量 ac3[1] 用于变量 bc3[2] 用于 ab 的交叉。

  1. 第一次迭代a=0b=1

    • c1 的覆盖率是 (1/2)*100 = 50%
    • c2 的覆盖率是 (1/2)*100 = 50%
    • c3 的覆盖率:
      • c3[0](1/2)*100 = 50%
      • c3[1](1/2)*100 = 50%
      • c3[2](1/4)*100 = 25%
    • 平均覆盖率是 (50 + 50 + 50 + 50 + 25)/5 = 45%
  2. 第二次迭代a=1b=1

    • c1 的覆盖率是 (2/2)*100 = 100%
    • c2 的覆盖率是 (1/2)*100 = 50%
    • c3 的覆盖率:
      • c3[0](2/2)*100 = 100%
      • c3[1](1/2)*100 = 50%
      • c3[2](2/4)*100 = 50%
    • 平均覆盖率是 (100 + 50 + 100 + 50 + 50)/5 = 70%
  3. 第三次迭代a=1b=1

    • c1 的覆盖率是 (2/2)*100 = 100%
    • c2 的覆盖率是 (1/2)*100 = 50%
    • c3 的覆盖率:
      • c3[0](2/2)*100 = 100%
      • c3[1](1/2)*100 = 50%
      • c3[2](2/4)*100 = 50%
    • 平均覆盖率是 (100 + 50 + 100 + 50 + 50)/5 = 70%
  4. 第四次迭代a=1b=0

    • c1 的覆盖率是 (2/2)*100 = 100%
    • c2 的覆盖率是 (2/2)*100 = 100%
    • c3 的覆盖率:
      • c3[0](2/2)*100 = 100%
      • c3[1](2/2)*100 = 100%
      • c3[2](3/4)*100 = 75%
    • 平均覆盖率是 (100 + 100 + 100 + 100 + 75)/5 = 95%
  5. 第五次迭代a=1b=0

    • c1 的覆盖率是 (2/2)*100 = 100%
    • c2 的覆盖率是 (2/2)*100 = 100%
    • c3 的覆盖率:
      • c3[0](2/2)*100 = 100%
      • c3[1](2/2)*100 = 100%
      • c3[2](3/4)*100 = 75%
    • 平均覆盖率是 (100 + 100 + 100 + 100 + 75)/5 = 95%

覆盖点可以通过多种方式指定:

  • 使用值的覆盖点
  • 使用表达式的覆盖点
  • 使用函数返回值的覆盖点
  • 使用部分选择的覆盖点

使用值的覆盖点#

语法: cover_value: coverpoint value_name;

代码片段:

              bit [3:0] a;
              bit [3:0] arr[4]='{2,5,0,12};

              covergroup cg; //creating covergroup cg
                 a1:coverpoint a; //declaring coverpoint a1
              endgroup
 
              cg cg_inst; //instantiating covergroup cg 
 
              initial begin
                 cg_inst = new();
                 foreach(arr[i]) begin
                     a=arr[i]; //assigning array values to a
                     cg_inst.sample(); //sampling the covergroup cg
                     $display("a=%d coverage %%=%0.2f",a,cg_inst.get_inst_coverage());
                 end
              end 

在覆盖组 ‘cg’ 中,覆盖点 a1 使用值 ‘a’ 来指定。每次都会通过数组 ‘arr’ 分配 ‘a’ 的值。‘a’ 是一个4位的数字,因此 ‘a’ 有16种可能的取值。

输出截图:

imageedit_1_3441847334

覆盖率报告:

imageedit_4_6832207354

在上面的例子中,在第1次迭代中,一个值被覆盖,因此覆盖率等于 (1/16)*100=6.25%。在第2次迭代中,‘a’ 的值被覆盖了两个值,因此覆盖率为 (2/16)*100=12.5%。在第3次迭代中,‘a’ 的值被覆盖了三个值,因此覆盖率为 (3/16)*100=18.75%。在第4次迭代中,‘a’ 的值被覆盖了四个值,因此覆盖率为 (4/16)*100=25%。这里没有指定 bins,所以 SystemVerilog 自动为覆盖点创建了 ‘自动 bins’。如果相同的值出现多次,那么 SystemVerilog 会认为它已经被覆盖了,不会在下一次计算时再算,它只是被忽略。

使用表达式的覆盖点#

语法:

cover_exp: coverpoint expression;

在覆盖点中,可以使用整数算术表达式来指定覆盖点。

代码片段

   bit [1:0] a;
   bit [2:0] b;

covergroup cg; //created covergroup cg
  a1:coverpoint a; //declaring coverpoint a1
  b1:coverpoint b; //declaring coverpoint b1
  axb:coverpoint a*b; //declaring coverpoint axb
endgroup:cg

cg cg_inst; //covergroup instantiating

initial begin
  cg_inst = new();

  repeat(10) begin
    a=$random; //assigning random values to a
    b=$random; //assigning random values to b
    cg_inst.sample(); //sampling the covergroup cg
    $display("a=%d b=%d axb=%d coverage %%=%0.2f",a,b,a*b,cg_inst.get_inst_coverage());
  end
end

在这里,覆盖点 a x b 是使用算术表达式指定的。覆盖点 a x b 被计算,并且 a x b 的位数等于 a 和 b 的位数中的最大值。

输出截图:

imageedit_5_8366420681

  • 覆盖报告

imageedit_6_3658649964

这里 ‘a’ 有2位,‘b’ 有3位,因此 a x b 是一个3位数。因此,对于 a x b,将创建 2^3=8 个自动 bins。如果 a x b 有超过3位,则只考虑从最低位开始的3位。因此,在覆盖报告中,a x b 的自动 bins 为8个,其中一个未被覆盖。a、b 和 a x b 的覆盖率分别为75、87.5 和 87.5,因此总覆盖率将是各自覆盖率的平均值,即 83.3%。

使用函数返回值的覆盖点#

可以使用函数调用来指定覆盖点,返回类型必须是整数值。

  • 语法: cover_func:coverpoint func_call();

代码片段:

function bit[3:0] sum(int a, int b); //declaring function
  int c;
  c=a+b;
  return c; //returning the sum value
endfunction

module func_return_value();
class val; //declaring class val
  randc bit [1:0]a;
  randc bit [1:0]b;
endclass

int addition;

covergroup cg; //created covergroup cg
  a: coverpoint v.a;
  b: coverpoint v.b;
  func: coverpoint sum(v.a,v.b); //called the function in covergroup
endgroup

val v;
cg cg_inst; //instantiated covergroup cg

initial begin
  v=new();
  cg_inst=new();

  repeat(5) begin
    void'(v.randomize()); //randomizing the class variables

    addition=sum(v.a,v.b); //storing function return value in addition variable
    cg_inst.sample(); //sampling the covergreoup cg
    $display("a = %d, b = %d; add = %d",v.a,v.b,addition);
    $display("\tcoverage %%=%0.2f",cg_inst.get_inst_coverage());
  end
end

在这个例子中,每当采样覆盖组时,函数 func 被调用,并计算 coverpoint func 的覆盖率百分比。

输出快照:

imageedit_7_3629398804

  • 覆盖报告

imageedit_8_7492486063

在这个例子中,使用函数调用 sum() 来指定覆盖点。函数的返回值有4位,因此可能的最大值为 2^4=16。覆盖点 func 将计算函数调用的覆盖率百分比,每当采样覆盖组时。

使用部分选择的覆盖点#

可以通过选择变量的一部分来指定覆盖点,比如 addr[31:4]。

  • 语法:
cover_part: coverpoint addr[31:4];
  • code snippet:
bit [2:0] a;

covergroup cg; //created covergroup cg
  a1:coverpoint a[1:0]; //declaring coverpoint a1 with 'a' has 2 bits from LSB
  a2:coverpoint a[0];  //declaring coverpoint a2 only with LSB
  a3:coverpoint a[2:1]; //declaring coverpoint a3 with 'a' has 2 bits from MSB
endgroup

cg cg_inst; //covergroup cg instance

initial begin
  cg_inst=new();
  for(int i=0;i<5;i++) begin
    a=$random; //assigining random values to a
    cg_inst.sample(); //sampling the covergroup
    $display("a=%d a1=%b a2=%b a3=%b",a,a[1:0],a[0],a[2:1]);
    $display("\tcoverage %%=%0.2f",cg_inst.get_coverage());
  end
end

在部分选择中,我们可以检查变量的选定部分的覆盖率。根据选定的位数,将创建 2^n 个自动 bins,并检查 2^n 个可能值的覆盖率。

  • 输出快照:

imageedit_9_2213154795

  • 覆盖报告

imageedit_10_6863213851

在覆盖点 a1 中,从 ‘a’ 的最后2位(从LSB)选择了位。因此,覆盖点 a1 有 2^2=4 个可能值。对于覆盖点 a2,选择了[0]位,因此 a2 有 2^1=2 个可能值。对于覆盖点 a3,从MSB选择了2位,因此有 4 个可能值。基于每个覆盖组覆盖的值,将计算覆盖率百分比。


覆盖率 bins#

覆盖点必须在覆盖组内声明,它可以包含一个或多个覆盖点。覆盖点可以是整数变量或表达式。每个覆盖点与“bins”相关联。

覆盖点 bin 将名称和计数与值序列或一组值转换关联起来。如果 bin 选择一组值,则每当覆盖点匹配该值集合中的一个值时,计数就会增加。如果 bin 选择一系列值转换,则每当覆盖点匹配整个值转换序列时,计数就会增加。

  • 语法:
      Coverpoint_name: coverpoint variable{bins bin 1 = {values};  
                                           ....  
                                           {bins bin N = {values};} 
  • Bins 的类型
  1. 自动或隐式 bins
  2. 显式 bins
  3. 转换 bins
  4. 通配符 bins
  5. 忽略 bins
  6. 非法 bins

Bins 备忘单

序号Bins
1.自动或隐式 bins
2.显式 bins
3.转换 bins
4.通配符 bins
5.忽略 bins
6.非法 bins)

Bins 可以被隐式(自动)或显式地创建。

1. 自动或隐式 bins#

在定义覆盖点时,如果没有指定任何 bins,则会为覆盖点创建自动 bins。创建的 bins 数量可以通过 auto_bin_max 参数来控制。

  • 语法:
Coverpoint_name: coverpoint variable;

示例:
让我们通过一个示例来更好地理解隐式 bins。

             module implicit_bin;  
             bit [2:0] a;  
    
             covergroup cov_grp;  
             c1 : coverpoint a;  
             endgroup  
    
             cov_grp cg = new();
  
             initial
             begin
             for(int i=1;i<=5;i++)
             begin
             a=$random;
             cg.sample();
             $display("a=%d, coverage = %0.2f %%",a,cg.get_inst_coverage());
             end
             end
             endmodule  

在这里,变量 ‘a’ 可以有8个值,即 [0-7]。这里会自动创建 bins。

  • 输出快照:

下图显示了隐式 bin 的输出。

1 imp drawio (1)

  • 覆盖报告

1 imp drawio (5)

这里会自动创建 bins,因为有8个值,所以会创建8个 bins。

  • 在第1次迭代中,a=4,c1 的覆盖率为 (1/8)*100 = 12.50%。
  • 在第2次迭代中,a=1,c1 的覆盖率为 (2/8)*100 = 25%。(因为在前一次迭代中已经覆盖了一个值,所以在这次迭代中我们将其视为2)
  • 在第3次迭代中,a=1,c1 的覆盖率为 (2/8)*100 = 25%(因为 a=1 已经被覆盖了)。
  • 在第4次迭代中,a=3,c1 的覆盖率为 (3/8)*100 = 37.50%。
  • 在第5次迭代中,a=5,c1 的覆盖率为 (4/8)*100 = 50%。

2. 显式 bins#

使用 bins 关键字可以将 bins 显式地声明给变量。

建议使用显式 bin 创建方法。在覆盖点中,并非所有值都是有趣或相关的,因此当用户知道要覆盖的确切值时,用户可以使用显式 bins。显式 bins 在覆盖点标识符后立即在花括号 { } 内与 bins 关键字一起声明,随后是 bin 名称和变量值/范围。

  • 语法:
Coverpoint_name: coverpoint variable{bins bin_name = {values};}

示例:

让我们通过一个显式 bin 的示例来更好地理解。

       module explicit_bin;  
       bit [2:0] a;  
   
       covergroup cov_grp;  
       c1 : coverpoint a{  
                         bins b1={2};  
                         bins b2={3};  
                         }  
       endgroup  
   
       cov_grp cg = new();  
    
       initial  
       begin  
       for(int i=1;i<=5;i++)  
       begin  
       a=$random;  
       cg.sample();  
       $display("a=%d, coverage = %0.2f %%",a,cg.get_inst_coverage());  
       end    
       end    
       endmodule  

在这里,变量 ‘a’ 可以有8个值,即 [0-7],对于变量 ‘a’,c1 是覆盖点,它有两个 bins- b1=2 和 b2=3。 当 ‘a’ 取得这些 bin 值中的任何一个时,该特定 bin 被视为命中。

输出快照:

下图显示了显式 bin 的输出。

1 imp drawio (6)

覆盖报告
1 imp drawio (7)

分母取决于 bins 的数量,由于这里只给出了 2 个 bins,因此分母被视为 2。

  • 在第1次迭代中,a=4,b1 的覆盖率为 (0/1)*100=0%,b2 的覆盖率为 (0/1)=0%,因此 b1 和 b2 的平均值是 c1 的覆盖率,即 (0/1+0/1)*100=0%。
  • 在第2次迭代中,a=1,b1 的覆盖率为 (0/1)*100=0%,b2 的覆盖率为 (0/1)=0%,因此 b1 和 b2 的平均值是 c1 的覆盖率,即 (0/1+0/1)*100=0%。
  • 在第3次迭代中,a=1,b1 的覆盖率为 (0/1)*100=0%,b2 的覆盖率为 (0/1)=0%,因此 b1 和 b2 的平均值是 c1 的覆盖率,即 (0/1+0/1)*100=0%。
  • 在第4次迭代中,a=3,b1 的覆盖率为 (0/1)*100=0%,b2 的覆盖率为 (1/1)*100=100%,因此 b1 和 b2 的平均值是 c1 的覆盖率,即 (0/1+1/1)*100=50%。
  • 在第5次迭代中,a=5,b1 的覆盖率为 (0/1)*100=0%,b2 的覆盖率为 (0/1)=0%,因此 b1 和 b2 的平均值是 c1 的覆盖率,即 (0/1+0/1)*100=50%。

3. 转换 bins#

转换功能点 bins 用于检查值的合法转换。SystemVerilog 允许指定覆盖点的一个或多个有序值转换集合。

  • 语法:
         covergroup cg;
            c1: coverpoint a;   
              {   
              bins u[] = (value1=>value2);   
              }   

转换类型:

  1. 单值转换
  2. 转换序列
  3. 转换集合
  4. 连续重复
  5. 重复范围
  6. 跳转重复
  • 单值转换:
    单值转换被指定为 < value1 > => < value2 >,value 1 后面跟着 value 2。

  • 语法:

           coverpoint_name: coverpoint variable {bins bin 1 = (value1 => value2);  
                                             ...    
                                             bins bin N = (value1 => value2); } 

示例:

让我们通过一个单值转换 bin 的示例来更好地理解。

       module single_val_tran_bin;  
       bit [0:3] a;  
       bit [0:2] values[$]= '{1,2,3,4};    
       covergroup cov_grp;  
       c1 : coverpoint a{   
                         bins tran_1 = (1=>2);  
                         bins tran_2 = (3=>4);  
                        }  
      endgroup  
 
      cov_grp cg = new();  
   
      initial  
      begin  
      foreach(values[i])  
      begin  
      a=values[i];  
      cg.sample();  
      $display("val=%d, cov = %0.2f %%",a,cg.get_inst_coverage());  
      end  
      end  
      endmodule  

在上面的例子中,对于变量 ‘a’,有两个 bins trans_1 和 trans_2。为了覆盖 ‘a’ 的过渡,创建了 2 个 bins,分别是从 1 到 2 和从 3 到 4。

  • 输出快照:

下图显示了单值转换 bin 的输出。

1 imp drawio (8)

  • 覆盖报告

1 imp drawio (9)

  • 当 val=1 时,覆盖率为 0%(因为仍然没有完成过渡)

  • 当 val=2 时,覆盖率为 50%(因为 trans_1 的从 1 到 2 的过渡已完成,覆盖率为 100%,所以 val 1 和 val 2 的平均值为 50%)

  • 当 val=3 时,覆盖率为 50%(因为仍然没有过渡,所以采用前一个的覆盖率)

  • 当 val=4 时,覆盖率为 100%(因为 trans_2 的从 3 到 4 的过渡已完成)

  • 转换序列:
    转换序列被指定为 < value1 > => < value2 > => < value3 > => < value4 >,value 1 后面跟着 value 2,然后是 value 3,最后是 value 4。

  • 语法:

           coverpoint_name: coverpoint variable {bins bin 1 = (value 1 => value 2 => value 3);
                                                ...
                                                 bins bin N = (value 1 => value 2 => value 3 => value 4); } 

示例:
让我们通过一个转换序列 bin 的示例来更好地理解。

        module sequence_of_trans_bin;  
        bit [0:2] a;  
        bit [0:2] values[$] = '{1,2,3,4};  
    
        covergroup cov_grp;  
        c1 : coverpoint a {  
                           bins tran_1 = (1=>2=>3);  
                           //bins tran_2 = (1=>2=>4);  
                          }
   
       endgroup  
   
       cov_grp cg = new();  
       initial  
       begin  
       foreach(values[i])  
       begin  
       a  = values[i];  
       cg.sample();  
       $display("val=%d,cov = %.2f %%",a,cg.get_inst_coverage());  
       end  
       end  
       endmodule  

在上面的例子中,创建了两个 bins 来覆盖点 ‘a’ 从 1 到 2 到 3 的过渡,另一个是从 1 到 2 到 4。

  • 输出快照:

下图显示了转换序列 bin 的输出。

vv drawio

  • 覆盖报告

vv drawio (1)

  • 转换集合:
    转换集合被指定为 <transition_set1> => <transition_set2>

  • 语法:

        coverpoint_name: coverpoint variable {bins bin 1[] = (transition_set 1 => transition_set 2); }

示例:
让我们通过一个转换集合 bin 的示例来更好地理解。

        module set_of_trans_bin;
        bit [0:3] a;
        bit [0:2] values[$]= '{1,2,3,4,5};
 
        covergroup cov_grp;
        c1 : coverpoint a {
                          bins tran_1 = (1,2=>3,4);
                          bins tran_2 = (3,4=>5);
                          bins tran_3 = (1,3=>4);
                          }
 
        endgroup
 
        cov_grp cg = new();
        initial
        begin
        foreach(values[i])
        begin
        a = values[i];
        cg.sample();
        $display("val=%d,cov = %.2f %%",a,cg.get_inst_coverage());
        end
        end
        endmodule  

在上面的例子中,bin trans 为覆盖 1=>3、2=>3、1=>4、2=>4、3=>5、4=>5 和 3=>4 创建了 3 个 bin。

  • 输出快照:
    下图显示了转换集合 bin 的输出。

vv drawio (2)

  • 覆盖报告

vv drawio (3)

当 val=1 时,覆盖率为 0%(因为仍然没有完成 bin 过渡)
当 val=2 时,覆盖率为 0%(因为仍然没有完成 bin 过渡)
当 val=3 时,覆盖率为 33.33%(因为 bin 过渡已完成) 当 val=4 时,覆盖率为 66.67%(因为 bin 过渡已完成)
当 val=5 时,覆盖率为 100%(因为 bin 过渡已完成)

  • 连续重复:
    重复范围被指定为 <transition_value> [*< repeat_value >]

  • 语法:

         coverpoint_name: coverpoint variable {bins bin 1[] = (transition_value[*< return_value >]); }

示例:
让我们通过一个连续重复 bin 的示例来更好地理解。

       module consec_repeat_bin;  
       bit [0:3] a;  
       bit [0:2] values[$]= '{2,2,4,4,4};  
    
       covergroup cov_grp;  
       c1 : coverpoint a {  
                          bins tran_1 = (2[*2]);
                          bins tran_2 = (4[*3]);
                         }
 
       endgroup
 
       cov_grp cg = new();
       initial
       begin
       foreach(values[i])
       begin
       a = values[i];
       cg.sample();
       $display("val=%d,cov = %.2f %%",a,cg.get_inst_coverage());
       end
       end
       endmodule  

在这里,trans_item 重复 repeat_range 次,即 2[*2] 相当于 2=>2,4[*3] 相当于 4=>4=>4。

  • 输出快照:
    下图显示了连续重复 bin 的输出。

vv drawio (10)

  • 覆盖报告

vv drawio (11)

  • 重复范围:
    重复范围可以指定为 <transition_value> [*<repeat_range>]

  • 语法:

        coverpoint_name: coverpoint variable {bins bin 1[] = (transition_value[*< return_value >]); }  

示例:

让我们通过一个重复范围 bin 的示例来更好地理解。

        module range_of_repeat_bin;  
        bit [0:3] a;  
        bit [0:2] values[$]= '{2,3,2,2,2,2,4,4};  
    
        covergroup cov_grp;  
        c1 : coverpoint a {  
                           bins tran_1 = (2[*3:5]);
                           bins tran_2 = (4[*3]);
                           }  
   
        endgroup  
        cov_grp cg = new();  
        initial  
        begin  
        foreach(values[i])  
        begin  
        a = values[i];  
        cg.sample();  
        $display("val=%d,cov = %.2f %%",a,cg.get_inst_coverage());  
        end    
        end  
        endmodule  

重复范围的一个示例是 2 [* 3:5],相当于 2=>2=>2、2=>2=>2=>2、2=>2=>2=>2=>2。

  • 输出快照:
    下图显示了重复范围 bin 的输出。

vv drawio (12)

  • 覆盖报告

vv drawio (13)

  • 跳转重复:
    跳转重复使用 trans_item [-> repeat_range] 指定。
    repeat_range 是指定某个特定值的所需出现次数。在指定值的第一次出现之前,可以出现任意数量的采样点,在指定值的每次出现之间也可以出现任意数量的采样点。跟随跳转重复的过渡必须立即跟在重复的最后一次出现之后。

  • 语法:

       coverpoint_name: cover-point variable {bins bin 1[] = (transition_item[->repeat_range]); }  

示例:

让我们通过一个跳转重复 bin 的示例来更好地理解。

       module goto_repeat_bin;  
       bit [0:3] a;  
       bit [0:2] values[$]= '{1,2,3,4,3,4,2,3,4,5};  
       covergroup cov_grp;  
       c1 : coverpoint a {  
                         bins tran_1 = (1=>4[->3]=>5);  
                         //bins tran_2 = (1=>3[=3]=>4);  
                         }   
       endgroup  
   
       cov_grp cg = new();  
       initial  
       begin  
       foreach(values[i])  
       begin  
       a = values[i];  
       cg.sample();  
       $display("val=%d,cov = %.2f %%",a,cg.get_inst_coverage());  
       end  
       end  
       endmodule  
  • 输出快照:
    下图显示了跳转重复 bin 的输出。

vv drawio (14)

  • 覆盖报告

vv drawio (15)

  • 非连续重复:
    非连续重复可以指定为 <transition_value> [= <repeat_range>]

  • 语法:

coverpoint_name: coverpoint variable {bins bin 1 = (transition_value[= < repeat_range >]=> value); }

4. 通配符 bins#

wildcard 关键字用于创建多个状态和转换。在表达式中,X、Z 或 ? 被认为是 0 或 1 的通配符。通配符 bins 也可以定义为转换 bins。

  • 语法:
       wildcard bins p = {4b11??};  

示例:
让我们通过一个通配符 bin 的示例来更好地理解。

      module wildcard_bin;  
      bit [0:3] a;  
      bit [0:3] values[$]= '{4'b1000,4'b1001,4'b1010,4'b1011};  
  
      covergroup cov_grp;  
      c1 : coverpoint a {  
                         wildcard bins b1 ={4'b100x};  
                         wildcard bins b2 ={4'b101x};  
                        } 
      endgroup  
 
      cov_grp cg = new();
      initial  
      begin  
      foreach(values[i])  
      begin  
      a = values[i];  
      cg.sample();  
      $display("val=%d,cov = %.2f %%",a,cg.get_inst_coverage());  
      end  
      end  
      endmodule  
  • 输出快照:
    下图显示了通配符 bin 的输出。

vv drawio (8)

覆盖报告

vv drawio (9)


5. 忽略 bins#

可以通过将它们指定为 ignore_bins 明确将与覆盖点相关的一组值或转换排除在覆盖范围之外。

  • 语法:
      ignore_bins ivals = {value1, value3};    
      ignore_bins itrans = (value1=>value3=>value5); }  

示例:
让我们以忽略 bins 的示例来更好地理解。

       module ignore_bin;  
       bit [0:1] a;  
       bit [0:1] values[$]= '{0,1,2,3};  
   
       covergroup cov_grp;  
       c1 : coverpoint a {  
                         ignore_bins b1 ={1,2};  
                         }  
 
       endgroup  
   
       cov_grp cg = new();  
       initial  
       begin  
       foreach(values[i])  
       begin  
       a = values[i];  
       cg.sample();  
       $display("val=%d,cov = %.2f %%",a,cg.get_inst_coverage());  
       end  
       end  
       endmodule  

在上述示例中,“a”的总可能值范围是从0到3。ignore_bins 指定了要忽略的值1和2。因此,预期的值是0和3。在这些预期值中,只有0和3被生成。

  • 输出快照:

下图显示了忽略 bin 的输出。

vv drawio (6)

  • 覆盖报告

vv drawio (7)

在上面的示例中,值1和值2被视为被忽略的值,即每当’a’命中该值时,它将采用前一个覆盖率。

  • 当 a = 0 时,c1 的覆盖率为 (1/2)*100= 50% (值0不被忽略)
  • 当 a = 1 时,c1 的覆盖率为 50% (值1被忽略,采用前一个覆盖率)
  • 当 a = 2 时,c1 的覆盖率为 50% (值2被忽略,采用前一个覆盖率)
  • 当 a = 3 时,c1 的覆盖率为 (2/2)*100= 100% (值3不被忽略)

6. 非法 bins#

可以通过将与覆盖点相关的一组值或转换指定为 illegal_bins 来将其标记为非法。所有与非法 bins 关联的值或转换都将被排除在覆盖范围之外。如果出现非法值或转换,将发出运行时错误。

  • 语法:
      illegal_bins bad_vals = {value1, value3, value4, value6};   
      illegal_bins bad_trans = (value2=>value1=>value9, value5=>value3); }  

示例:
让我们通过一个非法 bin 的示例来更好地理解。

       module illegal;  
       bit [0:2] y;  
       bit [0:2] values[$]= '{1,6,3,7,3,4,3,5};  
    
       covergroup cg;  
       cover_point_y : coverpoint y {illegal_bins b1 = {7};  
                                    }  
  
       endgroup  
  
       cg cg_inst = new();  
       initial  
       begin  
       foreach(values[i])  
       begin  
       y = values[i];  
   
       cg_inst.sample();  
   
       $display("val =%d, cov = %0.2f %%",y,cg_inst.get_inst_coverage());  
       end  
       end      
       endmodule  
  • 输出截图:

下图显示了非法区段的输出。

vv drawio (4)

  • 覆盖率报告

vv drawio (5)

在上面的示例中,值 7 被视为非法值,因此当值为 7 时,我们将收到错误消息:“在值=1 处触发了非法状态区段”。


覆盖率选项:#

覆盖率选项控制 covergroup、coverpoint 和 cross 的行为。您可以使用选项在 cover group 中指定额外的信息。选项方法可以为特定实例或整个程序的所有实例指定。

1. at_least: 这是可以在 coverpoint 内部定义的重要选项之一。通过使用 option.at_least,我们可以识别已覆盖特定周期数的特征。at_least 的默认值为'1’。

例如,如果有一个变量,其值范围从 0 到 7(3 位),在执行 cover group 时,如果某个值被分配了 2 个周期,而其余的值只分配了一次。那么使用 option.at_least=2,这将覆盖已分配至少 2 个周期的值。

2. auto_bin_max 此选项指定由 coverpoint 创建的 bin 的数量,仅当未明确定义 bin 时。auto_bin_max 的默认值为 64。例如,为任何变量生成了 128 个值(6 位数据),那么它将自动创建 64 个 bin,并且对于每个 bin,将分配 2 个值,它们是 [0:1],[2:3],[4:5],……..[124:125],[126:127]。您甚至可以使用 option.auto_bin_max = 128 创建 128 个 bin。

例如,如果有一个变量,其值范围从 0 到 7(3 位),在执行 cover group 时,将隐式生成 8 个 bin。但是,用户可以通过使用 option.auto_bin_max 设置 bin 的数量。如果 option.auto_bin_max=2,则隐式创建 2 个 bin,而不是 8 个 bin,它们的范围是 [0:3] 用于 auto[0] 和 [4:7] 用于 auto[1]。

**注意:**您可以通过 option.auto_bin_max 创建任意数量的 bin。

3. weight: 此选项通过将权重值与 coverpoint 百分比相乘来指定特定 coverpoint 的权重。使用此选项来计算整体覆盖率百分比,但不计入 coverpoint 百分比。如果我们指定 option.weight=0,则将使该 coverpoint 百分比与 0 相乘,然后该 coverpoint 百分比将为零。默认情况下,cover point 的权重为 1。

  • 公式 整体百分比 =(所有 cover point 的总和)/ 所有权重的总和。

其中,所有 cover point 的总和是指所有 cover point 乘以其权重的总和。 . 所有权重的总和是指所有 cover point 的权重的总和。

示例:

                       covergroup cgrp;
                          c1: coverpoint s.a {bins b1 = {1};    
                                         bins b2 ={3};   
                                         option.at_least=2;}    
                          c2: coverpoint s.a {option.weight=2;}     
                          c3: coverpoint s.b{option.auto_bin_max=2;}   
                        endgroup   

在这个代码片段中,覆盖组选项被定义为某些特定的覆盖点。option.at_least 只考虑那些至少覆盖了 2 个周期的值,option.weight 被定义为覆盖点 c2,通过将覆盖点百分比乘以 2 来改变整体覆盖率,option.auto_bin_max 用于为覆盖点 c3 生成只有 2 个 bin。第一个 bin 的范围是 [0:7],第二个 bin 的范围是 [8:15]。 在这个示例中,c1 的权重是 1(默认值),c2 的权重是 2(使用选项指定),c3 的权重是 1(默认值)。

输出截图:

option

这里变量 a 可以有 8 个值,即 [0-7],变量 ‘b’ 可以有 16 个值,即 [0-15]。覆盖率取决于不同覆盖点中使用的选项。

  • 在第一次迭代中,a=0,b=8;对于覆盖点 c1,bin 中的值必须至少迭代 2 个周期,目前还没有 bin 被覆盖。因此,c1 的覆盖率为 (0/2)100 = 0%;c2 的覆盖率为 (1/8) = 12.5% {对于整体百分比 (12.52),即 25%};c3 的覆盖率为 (auto[0]+auto[1])/2,因此为 {1/2}*100 = 50%;总体百分比为所有覆盖点的总和/权重总和,(0+25+50)/4 = 18.75%。

  • 在第二次迭代中,a=1,b=6;c1 的覆盖率为 (0/2) = 0%;c2 的覆盖率为 (2/8) = 25% {对于整体百分比 (25*2),即 50%};c3 的覆盖率为 (2/2)*100 = 100%;总体百分比为 (0+50+100)/4 = 37.50%。

  • 在第三次迭代中,a=1,b=8;c1 的覆盖率为 (1/2) = 50%;c2 的覆盖率为 (2/8) = 25% {对于整体百分比 (25*2),即 50%};c3 的覆盖率为 (2/2)*100 = 100%;总体百分比为 (50+50+100)/4 = 50%。

  • 在第四次迭代中,a=3,b=4;c1 的覆盖率为 (1/2) = 50%;c2 的覆盖率为 (3/8) = 37.5% {对于整体百分比 (37.5*2),即 75%};c3 的覆盖率为 (2/2)*100 = 100%;总体百分比为 (50+75+100)/4 = 56.25%

  • 在第五次迭代中,a=4,b=4;c1 的覆盖率为 (1/2) = 50%;c2 的覆盖率为 (4/8) = 50% {对于整体百分比 (50*2),即 100%};c3 的覆盖率为 (2/2)*100 = 100%;总体百分比为 (50+100+100)/4 = 62.50%

覆盖率报告

option1