覆盖率的类型
- 代码覆盖率
- 功能覆盖率
1. 代码覆盖率#
代码覆盖率涉及实现部分,即检查你的测试是否执行了设计规范的“实现”部分,但不会检查验证计划。它将衡量测试用例的质量。
1.1 行覆盖率 Line Coverage#
行覆盖率检查哪些代码行在测试过程中已经被执行。它的目的是确认程序中的每一行代码是否都被至少执行过一次。这有助于确保所有的代码路径都经过测试,减少遗漏的风险。
例如:
如果一个函数包含多个条件判断,行覆盖率可以帮助确认这些判断语句是否都被测试过。它确保每行代码都至少执行一次。
1.2 路径覆盖率 Path Coverage#
路径覆盖率检查在测试过程中执行了哪些代码路径。它不仅关心哪些行被执行,还关心代码执行的路径是否覆盖了所有可能的控制流路径。例如,函数中的分支和循环都会形成不同的路径,路径覆盖率会检查是否所有路径都被测试过。
例如:
如果某个函数中有多个 if 判断,路径覆盖率会确保所有的 if 条件(及其组合)都已经被测试过,涵盖了每种条件组合下的执行路径。
1.3 翻转覆盖率 Toggle Coverage#
翻转覆盖率检查每个单比特变量的值是否经历过从 0 到 1 或从 1 到 0 的变化。它主要用于验证信号或变量的变化,确保设计中的每个信号都经历了可能的状态转换。特别是在硬件设计中,可能需要检查信号在不同时刻的变化,以验证电路的行为。
例如:
如果设计中有一个 flip-flop,翻转覆盖率可以确认该信号是否经历过所有的状态变化(比如从 0 到 1,再从 1 到 0)。
1.4 有限状态机覆盖率 FSM Coverage#
FSM 覆盖率检查有限状态机(FSM)中的哪些状态和状态转移(transition)被访问过。对于复杂的硬件控制单元,FSM 是常见的设计元素。FSM 覆盖率有助于确保测试时所有状态和可能的状态转移都得到了验证,防止遗漏某些关键状态或转移。
例如:
如果设计中有一个状态机,FSM 覆盖率可以确认每个状态(如 S0, S1, S2 等)是否都被执行过,同时检查状态之间的转移(例如从 S0 到 S1,再到 S2)是否都经历过。
1.5 代码覆盖率的局限性#
它依赖于设计代码,因此可以衡量已编写代码的覆盖率,但不能对尚未编写的软件做出任何说明。
2. 功能覆盖率#
功能覆盖率定义了在验证中设计规范的执行程度,或者说功能覆盖率衡量了所有测试在满足验证计划要求方面的进展。它衡量了设计验证(DV)的质量。
2.1 功能覆盖率作用#
功能覆盖率用于跟踪所有被测单元(DUT)特性是否都已被验证,并衡量验证的质量。功能覆盖率帮助我们针对未验证的DUT特性进行测试。
2.2 功能覆盖率的局限性#
如果设计中有15个特性,而我们只提到了其中的10个,它会得出所有特性都被覆盖的结论。所以请确保在功能覆盖率块中包含所有设计特性。
3. 功能覆盖率与代码覆盖率的区别#
序号 | 功能覆盖率 | 代码覆盖率 |
---|---|---|
1. | 检查测试激励(stimulus)是否覆盖了设计的各个功能。功能覆盖率关注的是设计中各个功能模块是否得到了充分的测试。 | 检查测试激励(stimulus)如何测试代码。代码覆盖率关注的是测试激励是否覆盖了所有的代码行、路径和其他代码元素。 |
2. | 如果设计中有任何功能模块未被覆盖,功能覆盖率可以发现这个问题。它能帮助找到没有被测试到的功能部分。 | 如果设计中有任何功能未被覆盖,代码覆盖率无法发现这个问题。代码覆盖率只关心代码是否被执行,不关心设计的功能是否完整。 |
3. | 功能覆盖率依赖于设计规格说明。它基于设计的功能需求,测试是否满足这些需求。 | 代码覆盖率依赖于设计代码。它关注的是代码本身,测试代码的哪些部分被执行和测试。 |
4. 覆盖率分析#
在硬件设计验证中,功能覆盖率和代码覆盖率是衡量测试充分性的重要指标。它们的不同组合可以反映设计验证中的不同问题或进展阶段。以下是根据不同的覆盖率组合进行的分析:
情况 | 可能的原因 | 改进建议 |
---|---|---|
功能覆盖率和代码覆盖率都低 | 项目初期,测试场景和用例尚未完善。 | 开始进行全面的测试,增加测试用例,完善激励设计。 |
功能覆盖率高,代码覆盖率低 | 代码中可能存在死代码,或测试计划缺少覆盖某些代码的用例。 | 增加更多的代码 coverpoint ,检查死代码,补充遗漏的测试用例。 |
功能覆盖率低,代码覆盖率高 | 测试激励质量差,可能无法覆盖所有设计的功能。 | 改进测试激励,增加不同的输入场景,确保功能全面覆盖。 |
功能覆盖率和代码覆盖率都高 | 设计接近完成,测试覆盖到位,缺陷率可以作为重点。 | 开始进行缺陷分析,修复潜在的设计缺陷,进行边界条件测试。 |
这个覆盖率对比有助于团队在不同阶段识别设计验证的关键问题,并采取适当的措施优化测试过程,确保设计质量。
5. covergroup 和 coverpoint#
在 SystemVerilog 中,covergroup 和 coverpoint 是用来实现功能覆盖的重要工具。它们帮助验证人员收集和分析设计中的功能覆盖情况,确保设计的所有重要部分都得到了充分的测试。
5.1 Covergroup(覆盖组)#
- Covergroup 是一个用户定义的类型,用来封装覆盖模型的规格。可以将其理解为一个自定义类型,类似于类。在定义了一个 covergroup 后,必须实例化它才能开始收集数据,类似于类的实例化。
- 每个 covergroup 可以包含多个 coverpoint(覆盖点),以及交叉覆盖(cross coverage)等,来定义需要收集的覆盖数据。
- 通常,covergroup 通过
sample
函数显式地触发。若没有显式调用sample
,则该 covergroup 的覆盖情况将被认为没有任何函数被覆盖。
- 语法:
covergroup covergroup_name ;
.....
endgroup
5.2 Coverpoint(覆盖点)#
- Coverpoint 用于定义要监控的设计信号。每个 coverpoint 代表一个被测试的变量或表达式,并记录它的值或状态。在 covergroup 中,多个覆盖点可以定义以监控不同的设计信号。
- 通过 coverpoint,你可以检查信号的不同值、范围、状态转换等。
语法:
// without label name //
covergroup covergroup_name;
coverpoint variable_name;
endgroup
// with label name//
covergroup covergroup_name;
label_name: coverpoint variable _name;
endgroup
5.3 covergroup 的组成#
一个 covergroup 的规格通常包括以下几个元素:
时钟事件(Clocking Event):
- 在 covergroup 中,你可以指定一个时钟事件,用来同步覆盖点的采样。时钟事件用于确定何时触发覆盖数据的采集。
- 例子:
@(posedge clk)
表示在时钟上升沿采样覆盖点。
覆盖点(Coverage Points):
- coverpoint 用来定义你希望监控的设计信号。例如,你可以监控某个信号的值是否为特定状态,或是监控信号的组合。
- 例子:
coverpoint data;
监控data
信号的值。
交叉覆盖(Cross Coverage):
- 你可以定义多个 coverpoint 之间的组合覆盖,这通常用于检查信号之间的交互。通过 cross 关键字,交叉覆盖可以帮助检测不同信号值的组合情况。
- 例子:
covergroup cg @(posedge clk); coverpoint data; coverpoint addr; cross data, addr; // 检查 data 和 addr 的交叉覆盖 endgroup
可选的形式参数(Optional Formal Arguments):
- covergroup 可以包含可选的参数,这些参数可以用于控制覆盖的行为。例如,可以通过这些参数调整某些测试条件或覆盖目标。
- 例子:
covergroup cg #(int size = 8) @(posedge clk); // 可选的形式参数 coverpoint data[size-1:0]; // 根据参数 size 定义覆盖点 endgroup
覆盖选项(Coverage Options):
- 在定义覆盖组时,你可以指定一些选项来控制覆盖的行为。例如,设置覆盖的粒度、类型等。
- 例子:
option automatic
用于设置自动化的覆盖行为。
5.4 covergroup 的示例#
以下示例显示了 covergroup 的声明和执行。
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的 covergroup ,并实例化了一个名为‘cg’的实例。c1和c2是 coverpoint 的标签,a和b是声明的变量。使用其句柄名称(cg)通过new
函数创建一个对象。a和b变量被随机化,在5次迭代中具有不同的值,并在此随机化过程中通过sample
函数触发 covergroup ,并使用handle.get_inst_coverage()
函数显示功能覆盖率。
输出截图
下图显示了一个简单 covergroup 的输出。
在第一次迭代中,a=0,b=1。在这一迭代中,分别计算 coverpoint 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%。现在 coverpoint 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%。
覆盖率报告
注意: 为了获得更高的覆盖率百分比,可以增加迭代次数,从而增加覆盖所有功能的概率。
5.5 covergroup 的声明#
序号 | covergroup 声明 |
---|---|
1. | 模块内定义的 covergroup |
2. | 类内定义的 covergroup |
3. | 类和模块外定义的 covergroup |
- 模块内定义的 covergroup
当我们在模块内定义一个 covergroup 时,访问数据值很容易,并且实例化和句柄创建不是强制性的。相反,我们可以直接使用covergroup_name来执行相应的 coverpoint 。为了使用 covergroup ,我们需要使用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 是 coverpoint 的标签,p.a 和 p.b 是在类中声明的变量。为 cover group 创建了一个名为 ‘cg’ 的句柄。使用句柄名,通过 new
函数创建了一个对象。在这种随机化过程中,使用 class_handle.randomize
函数对变量 ‘a’ 和 ‘b’ 进行随机化,并使用 sample
函数触发 cover group,功能覆盖率使用 group_handle.get_inst_coverage()
函数显示。
- 输出截图
这里变量 ‘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%。
覆盖率报告
- 类中定义的 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。
- 输出截图
这里变量 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%。
覆盖率报告
- 类和模块外定义的 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 进行随机化。
- 输出截图
这里变量 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%。
覆盖率报告
5.6 触发 cover group#
cover group 通常由测试台触发。为了计算函数覆盖率,必须触发 cover group。如果不触发 cover group,覆盖的功能将不会被计算,因此默认情况下将显示为 0.00% 覆盖率。
在过程代码中显式触发 cover group 的一般方法是使用 sample
函数。
序号 | 触发 cover group |
---|---|
1. | 在相应时钟边沿触发 cover group |
2. | 指定 covergroup 应该在哪个事件上进行采样。 |
在 cover group 中触发覆盖率收集有两种不同的方法:
- 在相应时钟边沿触发 cover group。
- 语法:
covergroup covergroup_name @(clkedge clk) ; // 在相应的时钟边沿采样 coverpoint
coverpoint var;
endgroup
cover group 在相应的时钟边沿触发,并考虑 coverpoint 。
示例:
bit clk;
always #5 clk=~clk;
covergroup cvgp @ (posedge clk);
c1: coverpoint a;
c2: coverpoint b;
endgroup
在这个例子中,我们使用时钟边沿来触发 cover group。在这个例子中,每隔 5ns 时钟边沿变化一次,在时钟的正边沿触发 cover group,采样并随机化 coverpoint 的值。
输出截图
变量 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%。
覆盖率报告
- 指定 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 并采样每个 coverpoint 的值。使用事件而不是直接调用采样方法的好处是可以使用现有事件。
- 输出截图
这里变量 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%。
覆盖率报告
6. 条件覆盖 Conditional Coverage#
6.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 的总体覆盖率。
- 输出截图
这里变量 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%。
覆盖率报告
6.2 使用 start 和 stop 函数来控制 cover groups 的各个实例。#
Covergroup_name cg_inst = new;
initial begin
if(condition)
cg_inst.stop();
else
cg_inst.start();
end
在上面的例子中,使用 if 和 else 语句来解释 start
和 stop
函数。这些函数可以在过程代码中的任何地方调用。一般来说,stop
和 start
函数是在 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
在此示例中,变量 a 和 b 在类中声明。为了从类中访问这些变量,我们创建了一个带有句柄的对象(此处类的句柄为“s”)。触发覆盖组后,将显示覆盖率百分比。如果覆盖率超过 65%,则使用 cg.stop (group_handle_name.stop) 函数停止覆盖裁剪的执行。因此,覆盖率百分比将保持不变,即使为变量分配了新值,覆盖点也会忽略这些值并显示之前的百分比。可以使用 cg.start (group_handle.start) 函数触发并继续执行。
7. 交叉覆盖率 Cross Coverage#
交叉覆盖率是指在 coverpoint 或变量之间的交叉覆盖。交叉覆盖率是使用 cross
构造来指定的。表达式不能直接用于交叉覆盖。交叉覆盖可以同时测量两个或多个 coverpoint 的覆盖率。如果我们测量一个具有 N 个值的变量和另一个具有 M 个值的变量的交叉覆盖,内部将有 N * M 个 bins 来存储所有 ‘NM’ 组合的结果。
语法:
covergroup covergroup_name;
label1: coverpoint var1;
label2: coverpoint var2;
label3:cross label1,label2;
endgroup
示例:
covergroup cg;
c1: coverpoint a;
c2: coverpoint b;
c3: cross c1,c2;
endgroup
cg = new();
在此示例中,交叉覆盖在覆盖点 c1 和 c2 之间进行。变量 a 和 b 都是单数位,因此其值可以是 0 或 1。执行 c1 和 c2 后,使用 cross 关键字计算这些覆盖点的交叉。由于变量“a”和“b”各自可以有 2 个值,因此其交叉可以是 a 和 b 的组合,即 { {0,1} , {0,1} , {1,0}, {1,1} }。
使用交叉覆盖率的优势#
交叉覆盖率提供了一种有效的方法来确保所有可能的变量组合都得到充分测试。这在测试复杂系统时尤为重要,因为不同变量的组合可能会揭示系统行为中的潜在问题。此外,交叉覆盖率还可以帮助识别特定组合的边缘情况,从而提高测试的全面性和覆盖率。
语法:
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 示例:#
在这个示例中,我们将交叉 coverpoint c1
和 c2
。变量 a
和 b
是单比特,因此它们可以有值 0 或 1。在执行 c1
和 c2
之后,通过使用 cross
关键字计算这些 coverpoint 的交叉覆盖。由于变量 a
和 b
各自可以有 2 个值,交叉覆盖可以有 a
和 b
的组合,即 { {0,0}, {0,1}, {1,0}, {1,1} }
。
示例:
covergroup cvgrp;
c1: cross a, b;
endgroup
cvgrp cg = new();
通过使用变量名直接交叉的方式,我们可以减少代码行数。这种方式会隐式地创建变量 a
和 b
的单独 coverpoint ,以及它们的交叉 coverpoint 。这与之前的示例 1 类似,因此示例 1 和示例 2 的输出相同。
- 输出截图
迭代详细信息:#
这里变量 a
和 b
可以有 2 个值,即 0 或 1,而交叉值是这两个 coverpoint 值的组合,它们是 {0,0}, {0,1}, {1,0}, {1,1}
。
第一次迭代:
a=1
和b=0
c1
的覆盖率是(1/2)*100 = 50%
c2
的覆盖率是(1/2)*100 = 50%
c3
的覆盖率是(1/4)*100 = 25%
- 平均覆盖率是
(50 + 50 + 25)/3 = 41.67%
第二次迭代:
a=1
和b=0
c1
的覆盖率是(1/2)*100 = 50%
c2
的覆盖率是(1/2)*100 = 50%
c3
的覆盖率是(1/4)*100 = 25%
- 平均覆盖率是
(50 + 50 + 25)/3 = 41.67%
第三次迭代:
a=0
和b=1
c1
的覆盖率是(2/2)*100 = 100%
c2
的覆盖率是(2/2)*100 = 100%
c3
的覆盖率是(2/4)*100 = 50%
- 平均覆盖率是
(100 + 100 + 50)/3 = 83.33%
第四次迭代:
a=1
和b=0
c1
的覆盖率是(2/2)*100 = 100%
c2
的覆盖率是(2/2)*100 = 100%
c3
的覆盖率是(2/4)*100 = 50%
- 平均覆盖率是
(100 + 100 + 50)/3 = 83.33%
第五次迭代:
a=1
和b=1
c1
的覆盖率是(2/2)*100 = 100%
c2
的覆盖率是(2/2)*100 = 100%
c3
的覆盖率是(3/4)*100 = 75%
- 平均覆盖率是
(100 + 100 + 75)/3 = 91.67%
警告示例:#
如果我们在某些变量上定义了 coverpoint ,并且在这些变量上进行了交叉覆盖,则会出现警告。例如:
covergroup cvgrp;
c1: coverpoint a;
c2: coverpoint b;
c3: cross a, b;
endgroup
在这个示例中, coverpoint 和交叉覆盖都是在相同的变量上进行的。早些时候我们看到了 coverpoint 之间的交叉和变量之间的交叉,但在这里我们在已经显式定义 coverpoint 的变量上执行交叉覆盖。
模拟器中会出现冲突。冲突是因为变量 a
和 b
已经在 coverpoint 中定义,因此我们可以直接在这些 coverpoint c1
和 c2
上编写交叉覆盖。否则,如果我们不需要使用 c1
和 c2
,则模拟器将隐式地在 a
和 b
上创建另一个 coverpoint ,以及这些变量的交叉覆盖。因此,总共将有 5 个 coverpoint 。
- 覆盖率报告截图
详细迭代:#
这里变量 a
和 b
可以有 2 个值,即 0 或 1。 covergroup 内有 c1
、c2
和 c3
coverpoint 。c3
将隐式生成 3 个 coverpoint ,c3[0]
用于变量 a
,c3[1]
用于变量 b
,c3[2]
用于 a
和 b
的交叉。
第一次迭代:
a=0
和b=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%
第二次迭代:
a=1
和b=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%
第三次迭代:
a=1
和b=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%
第四次迭代:
a=1
和b=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%
第五次迭代:
a=1
和b=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%
coverpoint 可以通过多种方式指定:
- 使用值的 coverpoint
- 使用表达式的 coverpoint
- 使用函数返回值的 coverpoint
- 使用部分选择的 coverpoint
使用值的 coverpoint#
语法:
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
在 covergroup ‘cg’ 中, coverpoint a1 使用值 ‘a’ 来指定。每次都会通过数组 ‘arr’ 分配 ‘a’ 的值。‘a’ 是一个4位的数字,因此 ‘a’ 有16种可能的取值。
输出截图:
覆盖率报告:
在上面的例子中,在第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 自动为 coverpoint 创建了 ‘自动 bins’。如果相同的值出现多次,那么 SystemVerilog 会认为它已经被覆盖了,不会在下一次计算时再算,它只是被忽略。
使用表达式的 coverpoint#
语法:
cover_exp: coverpoint expression;
在 coverpoint 中,可以使用整数算术表达式来指定 coverpoint 。
代码片段:
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
在这里, coverpoint a x b 是使用算术表达式指定的。 coverpoint a x b 被计算,并且 a x b 的位数等于 a 和 b 的位数中的最大值。
输出截图:
- 覆盖报告
这里 ‘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%。
使用函数返回值的 coverpoint#
可以使用函数调用来指定 coverpoint ,返回类型必须是整数值。
- 语法:
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
在这个例子中,每当采样 covergroup 时,函数 func 被调用,并计算 coverpoint func 的覆盖率百分比。
输出快照:
- 覆盖报告
在这个例子中,使用函数调用 sum() 来指定 coverpoint 。函数的返回值有4位,因此可能的最大值为 2^4=16。 coverpoint func 将计算函数调用的覆盖率百分比,每当采样 covergroup 时。
使用部分选择的 coverpoint#
可以通过选择变量的一部分来指定 coverpoint ,比如 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 个可能值的覆盖率。
- 输出快照:
- 覆盖报告
在 coverpoint a1 中,从 ‘a’ 的最后2位(从LSB)选择了位。因此, coverpoint a1 有 2^2=4 个可能值。对于 coverpoint a2,选择了[0]位,因此 a2 有 2^1=2 个可能值。对于 coverpoint a3,从MSB选择了2位,因此有 4 个可能值。基于每个 covergroup 覆盖的值,将计算覆盖率百分比。
覆盖率 bins#
coverpoint 必须在 covergroup 内声明,它可以包含一个或多个 coverpoint 。 coverpoint 可以是整数变量或表达式。每个 coverpoint 与“bins”相关联。
coverpoint bin 将名称和计数与值序列或一组值转换关联起来。如果 bin 选择一组值,则每当 coverpoint 匹配该值集合中的一个值时,计数就会增加。如果 bin 选择一系列值转换,则每当 coverpoint 匹配整个值转换序列时,计数就会增加。
- 语法:
Coverpoint_name: coverpoint variable{bins bin 1 = {values};
....
{bins bin N = {values};}
- Bins 的类型
- 自动或隐式 bins
- 显式 bins
- 转换 bins
- 通配符 bins
- 忽略 bins
- 非法 bins
Bins 备忘单
序号 | Bins |
---|---|
1. | 自动或隐式 bins |
2. | 显式 bins |
3. | 转换 bins |
4. | 通配符 bins |
5. | 忽略 bins |
6. | 非法 bins) |
Bins 可以被隐式(自动)或显式地创建。
1. 自动或隐式 bins#
在定义 coverpoint 时,如果没有指定任何 bins,则会为 coverpoint 创建自动 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 的输出。
- 覆盖报告
这里会自动创建 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 创建方法。在 coverpoint 中,并非所有值都是有趣或相关的,因此当用户知道要覆盖的确切值时,用户可以使用显式 bins。显式 bins 在 coverpoint 标识符后立即在花括号 { } 内与 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 是 coverpoint ,它有两个 bins- b1=2 和 b2=3。 当 ‘a’ 取得这些 bin 值中的任何一个时,该特定 bin 被视为命中。
输出快照:
下图显示了显式 bin 的输出。
覆盖报告
分母取决于 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 允许指定 coverpoint 的一个或多个有序值转换集合。
- 语法:
covergroup cg;
c1: coverpoint a;
{
bins u[] = (value1=>value2);
}
转换类型:
- 单值转换
- 转换序列
- 转换集合
- 连续重复
- 重复范围
- 跳转重复
单值转换:
单值转换被指定为 < 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 的输出。
- 覆盖报告
当 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 来 coverpoint ‘a’ 从 1 到 2 到 3 的过渡,另一个是从 1 到 2 到 4。
- 输出快照:
下图显示了转换序列 bin 的输出。
- 覆盖报告
转换集合:
转换集合被指定为 <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 的输出。
- 覆盖报告
当 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 的输出。
- 覆盖报告
重复范围:
重复范围可以指定为 <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 的输出。
- 覆盖报告
跳转重复:
跳转重复使用 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 的输出。
- 覆盖报告
非连续重复:
非连续重复可以指定为 <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 = {4’b11??};
示例:
让我们通过一个通配符 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 的输出。
覆盖报告
5. 忽略 bins#
可以通过将它们指定为 ignore_bins 明确将与 coverpoint 相关的一组值或转换排除在覆盖范围之外。
- 语法:
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 的输出。
- 覆盖报告
在上面的示例中,值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#
可以通过将与 coverpoint 相关的一组值或转换指定为 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
- 输出截图:
下图显示了非法区段的输出。
- 覆盖率报告
在上面的示例中,值 7 被视为非法值,因此当值为 7 时,我们将收到错误消息:“在值=1 处触发了非法状态区段”。
覆盖率选项:#
覆盖率选项控制 covergroup、coverpoint 和 cross 的行为。您可以使用选项在 cover group 中指定额外的信息。选项方法可以为特定实例或整个程序的所有实例指定。
- at_least: 这是可以在 coverpoint 内部定义的重要选项之一。通过使用 option.at_least,我们可以识别已覆盖特定周期数的特征。at_least 的默认值为'1’。
例如,如果有一个变量,其值范围从 0 到 7(3 位),在执行 cover group 时,如果某个值被分配了 2 个周期,而其余的值只分配了一次。那么使用 option.at_least
=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。
- 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
在这个代码片段中, covergroup 选项被定义为某些特定的 coverpoint 。option.at_least
只考虑那些至少覆盖了 2 个周期的值,option.weight
被定义为 coverpoint c2,通过将 coverpoint 百分比乘以 2 来改变整体覆盖率,option.auto_bin_max
用于为 coverpoint c3 生成只有 2 个 bin。第一个 bin 的范围是 [0:7],第二个 bin 的范围是 [8:15]。
在这个示例中,c1 的权重是 1(默认值),c2 的权重是 2(使用选项指定),c3 的权重是 1(默认值)。
输出截图:
这里变量 a 可以有 8 个值,即 [0-7],变量 ‘b’ 可以有 16 个值,即 [0-15]。覆盖率取决于不同 coverpoint 中使用的选项。
在第一次迭代中,a=0,b=8;对于 coverpoint 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%;总体百分比为所有 coverpoint 的总和/权重总和,(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%
覆盖率报告