第九章. 功能覆盖率
9.1覆盖率类型

功能覆盖率:功能覆盖率和设计意图是紧密相连的。用来衡量哪些设计特性已经被测试程序测试过的一个指标。

代码覆盖率:包括行覆盖率,路径覆盖率,翻转覆盖率,状态机覆盖率,衡量验证进展最简易的方式,仿真器自带代码覆盖率工具进行统计。

断言覆盖率:断言是用于一次性地或在某一段时间内核对两个设计信号之间关系的声明性代码。

9.2功能覆盖率策略

收集信息而非数据

只测量工你将会使用到的内容

测量的完备性

9.3 覆盖组

覆盖组与类相似,一次定义后便可以进行多次实例化。覆盖组包含覆盖点,选项,形式参数和可选触发。一个覆盖组必须被实例化后才可以用来收集数据。

9.3.1 在类中定义覆盖组

覆盖组可以在程序,模块或类里定义。如果覆盖组定义在类里,实例化时使用最初的名字即可,不用另起名字。

class Transactor;Transaction tr;mainbox mbx_in;covergroup CovPort;coverpoint tr.port;endgroupfunction new(mailbox mbx_in);CovPort = new();this.mbx_in = mbx_in;endfunctiontask main;foreverbegintr = mbx_in.get;ifc.cb.port <= tr.port;ifc.cb.data <= tr.data;CovPort.sample();endendtask
endclass
9.4 覆盖组的触发

功能覆盖率的两个主要部分是采样的数据数据被采样的时刻。数据在准备好了以后,测试平台便会触发覆盖组,这个过程可以通过直接使用sample函数来完成。

如果希望在程序代码中显式地触发覆盖组,或者不存在可以标识采样时刻的信号或事件,或者在一个覆盖组里有多个实例需要独立触发,可以使用sample方法。如果想借助已有的事件或信号来触发覆盖组,可以在covergroup声明中使用阻塞语句。

9.4.1 使用回调函数进行采样

将功能覆盖组继承到测试平台中,比较好的方法是使用回调函数,此方法可以建立一个灵活的测试平台,不需要限定覆盖率的采样时间。

program automatic test;Environment env;initialbeginDeiver_cbs_coverage dcc;env = new();env.gen_Cfg();env.build();//实例化覆盖组实例dcc = new();env.drv.cbs.push_back(dcc);env.run();env.wrap();end
endprogramclass Driver_cbs_coverage extends Driver_cbs;covergroup CovPort;...endgroup//回调函数中触发覆盖组采样virtual task post_tx(Transaction tr);CovPort.sample();endtask
endclass

9.4.2 使用事件触发覆盖组

event trans_ready;
covergroup CovPort @(trans_ready);coverpoint ifc.cb.port;
endgroup

与直接调用sample方法相比,使用事件触发的好处在于可以借助已有的事件进行触发覆盖组采样

9.4.3 使用SV断言进行触发

如果已经有了一个诸如事件结束等有用事件的SVA,那就可以增加一个事件触发来唤醒覆盖组。

module mem(simple_bus sb);bit [7:0] data.addr;event write_event;//时序检查通过触发事件write_eventcover property(@(posedge sb.clock) sb.write_ena == 1)-> write_event;
endmoduleprogram automatic test(simple_bus sb);//阻塞在事件write_event,直到事件被触发开始采样covergroup Write_cg@($root.top.m1.write_event);coverpoint $root.top.m1.data;coverpoint $root.top.m1.addr;endgroupWrite_cg wcg;initialbeginwcg = new();sb.write_ena <= 1;...#10000 $finish;end
endprogram
9.5 数据采样

当你在覆盖点上指定一个变量或表达式时,SV便会创建很多"仓(bin)"来记录每个数值被捕捉到的次数,这些仓是衡量功能覆盖率的基本单位。

9.5.1 个体仓和总体覆盖率

为了计算出一个点上的覆盖率,首先必须确定所有可能数值的个数,这也被成为。一个仓中可能有一个或多个值,覆盖率就是采样值的数目除以与中仓的数目。如:一个3 bit变量覆盖点的域是0:7,正常情况下会除以8个仓,如果在仿真过程中有7个仓的值被采样到,那么报告会给出这个点的覆盖率是7/8或是87.5%。所有这些点组合在一起便构成了一个组的覆盖率,而所有组合组合在一起就可以给出整个仿真数据库的覆盖率。

9.5.2 自动创建仓

SV会自动为覆盖点创建仓。他通过被采样的表达式的域来确定可能跟值的范围。对于一个位宽N位的表达式,有2^N个可能值。对于枚举类型,其域就是署名值的个数。

9.5.3 限制自动创建仓的数目

覆盖组选项auto_bin_max指明了自动创建仓的最大数目,缺省值是64。

如果覆盖点变量或表达式的值域超过指定的最大值,SV会把值域范围平均分配给auto_bin_max个仓。如:一个16 bit变量有65536个可能值,所以64个bin中每一个都覆盖率1024个值(65536/64)。实际这种自动分配值域的方式不实用,因为不容易找到没有被覆盖的数值。实际多用明确定义仓的范围或者把仓的值数量限制在8或者16

covergroup CovPort;coverpoint tr.point   {options.auto_bin_max=2;}  //分成2个仓
endgroup

上例中只是八auto_bin_max作为一个覆盖点的选项来用,其实也可以把它用作整个组的选项。

covergroup CovPort;options.auto_bin_max = 2;    //对覆盖点port和data均起作用coverpoint tr.port;coverpoint tr.data;
endgroup

9.5.4 对表达式进行采样

如果需要对表达式进行采样,需要根据实际的运算调整最大的仓数。

class Transaction;rand bit [2:0] hdr_len;            //[0:7]rand bit [3:0] payload_len;      //[0:15]rand bit [3:0] kind;            //[0:15]
endclassTransaction tr;covergroup CovLen;len16: coverpoint {tr.hdr_len + tr.payload_len};len32: coverpoint {tr.hdr_len + tr.payload_len + 5'b0};
endgroup

因其中的表达式进行了加法运算,所以值的可能范围为[0,22],因此再定义最大仓数量为2^3就不合适了,所以在len32中使用了5‘b0将位宽拓展到了5bit,SV会自动创建2^5(32)个仓来收集数据。

9.5.5 命名覆盖点的仓

可以对仓名指定明确的仓名,以增加覆盖率报告的准确度。SV会自动为枚举类型的仓命名。直接看例子。

covergroup CovKind;coverpoint tr.kind {bins zero = {0};     //一个名为zero的仓代表kind==0bins lo = {[1:3], 5};   //一个名为lo的仓代表1:3和5bins hi[] = {[8:$]};  //8个独立的仓:8...15,[]会为其内的值各建立一个仓bins misc = default;  //1个仓代表剩余的所有的值}                         //注意这里不带分号
endgroup

当你定义仓时,实际上是把用来计算覆盖率的数值限制在你感兴趣的范围内,此时SV不再自动创建仓。计算功能覆盖率时只会使用你创建的仓。建议使用default仓标识语句来捕捉那些可能已经被忽略的数值

使用$符号指定区间的上下界。

int i;
covergroup range_cover;coverpoint i{bins neg = {[$:-1]};   //下界bins zero = {0};bins pos={[1:$]};     //上界}
endgroup

9.5.6 条件覆盖率

可以使用关键字iff给覆盖点添加条件。应用场景常为在复位期间关闭覆盖以忽略掉一些杂散的触发。

covergroup CoverPort;
//当reset==1时不要手机覆盖率数据coverpoint port iff (!bus_if.reset);
endgroup

也可以使用start和stop函数来控制覆盖组里的各个独立的实例。

initial
beginCovPort ck = new();# 1ns ck.stop();       //复位期间停止收集覆盖率数据bus_if.reset=1;# 100ns bus_if.reset=0; //复位结束ck.start();               //收集覆盖率数据...
end

9.5.7 为枚举类型创建仓

对于枚举类型,SV会为每个可能值创建一个仓。

typedef enum{INIT, DECODE, IDLE} fsmstate_e;
fsmstate_e pstate, nstate;
covgroup cg_fsm;coverpoint pstate;
endgroup

auto_bin_max在收集枚举类型的覆盖率时不起作用。

9.5.8 翻转覆盖率

covergroup CoverPort;coverpoint port{bins t1=(0=>1), (0=>2), (0=>3);}
endgroup

使用范围表达式可以快速地确定多个转换过程。表达式(1,2 => 3,4)创建了四个翻转过程,分别是(1=>3), (1=>4), (2=>3), (2=>4)。

还可以确定任何长度的翻转次数。(0=>1=>2)和(0=>1=>1=>2),(0=>1=>1=>1=>2)是不一样的。可以使用缩略形式来表示(0=>1=>1=>1=>2),(0=>1[*3]=>2)。1[*3:5]表示1重复3~5次。

9.5.9 在状态和翻转中使用通配符

使用关键字wildcard来创建多个状态或翻转。在表达式中,任何X,Z或?都会被当成0或1的通配符。

9.5.10 忽略数值

使用ignore_bins排除掉那些不用来计算功能覆盖率的数值。

bit [2:0] low_ports_0_5;             //只使用数值0-5
covergroup CoverPort;coverpoint low_ports_0_5{ignore_bins hi = {[6,7]};        //忽略最后的两个仓}
endgroup

ignore_bins和auto_bin_max可以结合使用。

bit [2:0] low_ports_0_5;
covergroup CoverPort;coverpoint low_port_0_5{options.auto_bin_max = 4; //仓最大数量为4ignore_bins hi = {[6:7]}; //忽略最后两个值}
endgroup

上例中被忽略掉的仓hi不会被用于计算覆盖率。

9.5.11 不合法的仓

有些采样数值不仅应该被忽略,而且如果出现还应该报错。此情形最好在测试平台中使用代码进行检测,但也可以使用illegal_bins对仓进行标识。如果在覆盖组中发现了不合法的数值,那就是你得测试程序或者bin定义出了问题。

bit [2:0] low_ports_0_5;             //只使用数值0-5
covergroup CoverPort;coverpoint low_ports_0_5{illegal_bins hi = {[6, 7]};      //如果出现便报错}
endgroup

9.5.12 状态机的覆盖率

使用代码覆盖率工具来自定提取状态寄存器,状态以及翻转轨迹,查看翻转覆盖率,状态机覆盖率。

9.6 交叉覆盖率

交叉覆盖率可以同时测量两个或者两个以上覆盖点的值。注当你想测量两个变量的交叉覆盖率,其中一个有N种取值,另一个由M种取值,SV需要NxM个交叉仓来存储所有的组合。

9.6.1 基本的交叉覆盖率

SV使用cross关键字来记录一个组里两个或两个以上覆盖点的组合值。cross语句只允许带覆盖点或者简单的变量名。如果你想使用表达式,层次化的名字或者对象中的变量。例如handle.variable,必须首先对coverpoint里的表达式使用标号,然后把这个标号用在cross语句里。

class Transaction;rand bit [3:0] kind;rand bit [2:0] port;
endclassTransaction tr;covergroup CovPort;kind: coverpoint tr.kind;     //创建覆盖点kindport: coverpoint tr.port;        //创建覆盖点portcross kind, port;
endgroup

9.6.2 对交叉覆盖仓进行标号

可以对各个覆盖点的仓进行单独标号,SV在创建交叉仓时就会使用这些名称。

covergroup CovPortKind;prot: coverpoint tr.port;{bins port[] = {[0:$]};}kind: coverpoint tr.kind{bins zero = {0};      //仓zero代表0bins lo = {[1:3]};       //仓lo代表1~3bins hi[] = {[8:$]}; //8个独立的仓bins misc = default;   //一个仓代表剩余的所有值}
endgroup

9.6.3 排除掉部分交叉覆盖仓

使用ignore_bins可以减少仓的数目。在交叉覆盖中,可以使用binsof和intersect分别指定覆盖点和数值集,这样可以使单个的ignore_bins结构清除掉很多个体仓。

covergroup Covport;
port: coverpoint tr.port {bins port[] = {[0:$]};}
kind: coverpoint tr.kind{bins zero = {0};bins lo = {[1:3]};bins hi[] = {[8:$]};bins misc = default;
}cross kind, port{//排除掉所有port为7和任意kind值组合的仓,因kind为4bit,所以此语句排除掉了16个仓ignore_bins hi=binsof(port)intersect{7};//忽略掉port为0和kind为9,10,11的组合,一共3个仓ignore_bins md=binsof(port)intersect{0}&&binsof(kind)intersect{9:11};//忽略掉kind定义中的lo包含的所有数值ignore_bins lo=binsof(kind.lo);
}
endgroup

注:binsof使用的是小括号(),而intersect指定的是一个范围所以使用的是大括号{}

9.6.4 从总体覆盖率的度量中排除掉部分覆盖点

一个组的总体覆盖率是基于所有简单覆盖点和交叉覆盖率的。如果只希望对一个coverpoint上的变量或表达式进行采样,而这个coverpoint将会被用到cross语句中,那么应该把他的权重设置成0,这样他就不会对总体的覆盖率造成影响。

covergroup CovPort;kind: coverpoint tr.kind{bins zero={0};bins lo={[1:3]};bins hi[]={[8:$]};bins misc=default;option.weight=5;      //在总体中所占的分量}port: coverpoint tr.port{bins port[]={[0:$];option.weight=0;      //在总体中不占任何分量}}cross kind, port {option.weight = 10;}       //给予交叉更高的权重
endgroup

9.6.5 交叉覆盖的替代方法

假设有两个随机比特变量a和b,他们带着三种感兴趣的状态,{a==0, b==0}, {a==1, b==0}和{b==1}。

使用仓名的交叉覆盖率

class Transaction;rand bit a, b;
endclasscovergroup CrossBinNames;a: coverpoint tr.a{bins a0={0};bins a1={1};option.weight=0;}b: coverpoint tr.b{bins b0={0};bins b1={1};option.weight=0;}ab: cross a, b{bins a0b0=binsof(a.a0) && binsof(b.b0);bins a1b0=binsof(a.a1) && binsof(b.b0);bins ba=binsof(b.b1);}
endgroup

使用binsof的交叉覆盖率

class Transaction;rand bit a, b;
endclasscovergroup CrossBinsofIntersect;a: coverpoint tr.a{option.weight=0;}b: coverpoint tr.b{option.weight=0;}ab: cross a, b{bins a0b0=binsof(a)intersect{0} && binsof(b)intersect{0};bins a1b0=binsof(a)intersect{1} && binsof(b)intersect{0};bins b1=binsof(b)intersect{1};}
endgroup

使用通配符来定义交叉覆盖率

covergroup CrossManual;ab: coverpoint{tr.a, tr.b}{bins a1b0 = {2'b00};bins a1b0 = {2'b11};wildcard bins b1 = {2'b?1};}
endgroup
9.7 通用的覆盖组

SV允许创建一个通用的覆盖组,这样在对它进行实例化时可以指定一些独特的细节。SV不允许把覆盖组的触发参数传递给实例,作为变通,可以把覆盖组放到一个类里,然后把触发参数传递给构造函数。

9.7.1 通过数值传递覆盖组参数

bit [2:0] port;
covergroup CoverPort(int mid);coverpoint port{bins lo = {[0:mid-1]};bins hi = {[mid:$]};}
endgroupCoverPort cp;
initial
begincp = new(5);          //通过构造函数传递参数
end

9.7.2通过引用传递覆盖组参数

如果不仅想在调用构造函数时使用数值,还希望覆盖组在整个仿真过程中可以对数值进行采样,那么可以通过引用的方式来指定需要进行采样的变量。

bit [2:0] port_a, port_b;
covergroup CoverPort(ref bit [2:0] port, input int mid);coverpoint port{bins lo = {[0:mid-1]};bins hi = {[mid:$]};}
endgroup
CoverPort cpa, cpb;
initial
begincpa = new(port_a, 4);cpb = new(port_b, 2);
end

注:上例中,与任务和函数相似,覆盖组的参数在方向上遵循就近缺省的原则。如果mid遗漏了input的方向,则参数mid的方向就是ref。

9.8 覆盖选项

使用SV提供的选项为覆盖组指定额外的信息。选项分为两种类型,一种是实例选项用于特定的覆盖组实例;一种是类型选项用于所有的覆盖组实例。类似于类中的静态数据成员,选项可以放在覆盖组中并对组里的所有覆盖点有效,也可以防在单个覆盖点中以便实现更加精细的控制

9.8.1 单个实例的覆盖率

如果测试平台对一个覆盖组进行了多次实例化,那么缺省情况下,SV会把所有实例的覆盖率数据汇集到一起。如果需要对每个实例单独查看覆盖率,则使用option的per_instance选项来指定单个实例的覆盖率。

covergroup CoverLength;coverpoint tr.length;option.per_instance = 1;    //将此covergroup的每个实例单独计算覆盖率,不合并
endgroup

注:选项per_instance只能放在覆盖组里不能用于覆盖点和交叉点

9.8.2 覆盖组的注释

可以在覆盖率报告中增加注释以使报告更易于分析。

//为覆盖组添加注释
covergroup CoverPort;type_option.comment = "Section 3.2.14 Port number";coverpoint port;
endgroup

注:如果有多个实例,可以为每个实例加入单独的注释,前提是同时也是用了per-instance选项。

//为每个覆盖组实例指定注释
covergroup CoverPort(int lo, hi, string comment);option.comment=comment;option.per_instance=1;coverpoint port{bins range={[lo:hi]};}
endgroup
...
CoverPort cp_lo = new(0,3,"Low port numbers");
CoverPort cp_hi = new(4,7,"High port numbers");

9.8.3 覆盖阈值

使用option.at_least可以设置覆盖阈值,即一个仓被命中覆盖阈值后,此仓才被认为被覆盖到。

option.at_least如果定义咋覆盖组里,那么会用作所有的覆盖点。如果定义在一个点上,那么就只对该点有效。

9.8.4 打印空仓

缺省情况下,覆盖率报告只会给出带有采样值的仓。使用cross_num_print_missing选项可以让仿真和报告工具给出所有的仓,尤其是没有命中的仓。

covergroup CovPort;kind: coverpoint tr.kind;port: coverpoint tr.port;cross kind, port;option.cross_num_print_missing = 1000;
endgroup

9.8.5 覆盖率目标

一个覆盖组或覆盖点的目标是达到该组或该点被认为已经完全覆盖的水平。缺省情况下时100%的覆盖率。

covergroup CoverProt;coverpoint port;option.goal=90;        //覆盖率目标设定为90%
endgroup
9.9 在仿真过程中进行覆盖率统计

在仿真进行的过程中,可以查询功能覆盖率的水平,允许你检查是否已经达到覆盖目标,并且可以对随机测试施加控制。

在全局层面上,使用getcoverage可以得到所有覆盖组的总覆盖率。get_coverage可以得到所有覆盖组的总覆盖率。getc​overage可以得到所有覆盖组的总覆盖率。get_coverage返回一个介于0~100的实数,该系统任务可以查询到所有的覆盖组。

可以使用get_coverage()和get_inst_coverage()函数来缩小测量范围。

CoverGroup::get_coverage();          //使用覆盖组名作用域调用
CgInst::get_coverage();             //使用覆盖组实例名作用域调用
cgInst.get_inst_coverage();         //通过实例获取实例的覆盖率

以上函数的用处是:在一个长的测试中检测覆盖率数据。如果覆盖率水平在给定数量的事务或周期内之后并无提高,那么这个测试就应该停止了。

写在最后:SV绿皮书到此已经暂时全部更新完毕。剩余三章暂时用不到,以后用到时或时间充裕时再用一篇文章来更新。其中第10章高级接口有部分知识点比较实用,第11章SV的验证平台个人感觉可忽略直接学习UVM,第12章SV与C接口可以学习一下。SV绿皮书中知识点是使用比较频繁的内容,完整的内容可以学习SV官方手册。接下来验证部分更新UVM实战这本教材。

创作不易,感觉对自己有帮助的话希望不要吝啬自己的点赞,转发,收藏!!!

参考文献:

SystemVerilog验证 测试平台编写指南(原书第二版)张春 麦宋平 赵益新 译

SV绿皮书笔记(九)暂时完结相关推荐

  1. SV绿皮书笔记(四)

    第四章. 连接设计和测试平台 4.1 测试平台和DUT之间通信 DUT和测试平台(Test)通常是分开的模块(module,描述硬件),可以在顶层(top)中将DUT和Test例化,然后根据对应信号进 ...

  2. SV绿皮书笔记(六)

    第六章. 随机化 6.1 哪些对象需要随机化 随机时需考虑设计输入的各个方面,器件配置,环境配置,原始输入数据,封装后的输出数据,协议异常,延时,事务状态,错误和违例等情况. 6.2 SV中的随机化 ...

  3. SV绿皮书笔记(七)

    第七章. 线程以及线程间的通信 在实际硬件中,时序逻辑通过时钟沿来激活,而组合逻辑的输出则随着输入的变化而变化.所有这些并发的活动在V的寄存器传输级上是通过initial和always块语句,实例化和 ...

  4. SV绿皮书笔记(五)

    第五章. 面向对象编程基础 5.1 OOP概述 V属于过程性编程语言(代码逐行执行,无数据结构,类似C语言),V中没有结构,只有位向量和数组.而在对总线事务建模时往往需要数据结构,使用过程性语言不够便 ...

  5. SV绿皮书笔记(二)

    第二章. 数据类型 2.1 基本数据类型的两个属性 双状态/四状态:根据存储数据类型中的每一bit位的可能数分为双状态类型和四值状态类型. 双状态:可能值0,1,双状态默认初始值为0.双状态值具有更低 ...

  6. SV绿皮书笔记(三)

    第三章. 过程语句和子程序 3.1 循环语句 continue:在循环中跳出本轮循环剩下的语句直接进入下一轮循环. break:用于终止并跳出循环 bit[127:0] cmd; int file, ...

  7. SV绿皮书笔记(一)

    第一章. 验证导论 1.1 验证概述 验证的目的:保证设计文件能够完成预期的功能,寻找设计漏洞. 验证计划:参考设计文档,描述需要验证哪些特性,采用什么样的技术. 验证的流程:设计文档(自然语言)→设 ...

  8. Clamav杀毒软件源码分析笔记[九]

    Clamav杀毒软件源码分析笔记[九] 刺猬@http://blog.csdn.net/littlehedgehog [数据流病毒扫描] 数据流病毒扫描,听上去貌似很牛逼的称呼,其实就是一个传送数据流 ...

  9. IOS学习笔记(九)之UIAlertView(警告视图)和UIActionSheet(操作表视图)基本概念和使用方法...

    IOS学习笔记(九)之UIAlertView(警告视图)和UIActionSheet(操作表视图)基本概念和使用方法 Author:hmjiangqq Email:jiangqqlmj@163.com ...

最新文章

  1. 万万没想到 I 这 7 件超酷的事情,让开发更有效率
  2. scrapy爬取百万小说
  3. 经典C语言程序100例之三二
  4. 三十四 Python分布式爬虫打造搜索引擎Scrapy精讲—scrapy信号详解
  5. ModChip and more
  6. 一篇 vSAN 入门,送给大家
  7. oracler日期函数相差六个月_oracle中计算两个日期的相差天数、月数、年数、小时数、分钟数、秒数等...
  8. 设计模式--工厂模式(c++)
  9. oracle 存档终点修改,Oracle 归档模式与非归档模式的切换
  10. 【韩顺平 零基础30天学会Java】(第三阶段)(自用)
  11. 将字符串中的大写字母转换为小写字母
  12. 2022年最新常用的浏览器排行榜单
  13. android冷启动优化方案汇总
  14. 天大、中南、中山、北师、中科院地图学与地理信息系统GIS及遥感RS专业推免夏令营面试经历与题目汇总
  15. ArcEngine加载图层的五个步…
  16. 实用系列1 —— 视频中的语音转换成文字
  17. 本周内外盘行情回顾2022.3.6
  18. (Get the office2019)Download Office Tool
  19. windows防火墙设置_详解关闭Windows防火墙操作技巧,让你彻底断开与外网的连接...
  20. 微信小程序跳转微信小程序实现免登录

热门文章

  1. ES6_1.块级作用域绑定_临时死区TDZ
  2. 概率的性质——连续性
  3. ASCII码与16进制的互相转换(表)
  4. Qemu Fuzzer学习
  5. 过拟合与欠拟合及解决方法
  6. 网络初级 关于ensp动态路由rip协议
  7. go基础知识学习笔记-篇幅很长写的我想吐
  8. 批量压缩图片大小 – Caesium简体中文
  9. 强化学习笔记3-Python/OpenAI/TensorFlow/ROS-规划博弈
  10. quick框架之MyApp详解