目录
1覆盖率的类型
(概述 覆盖率反馈回路 代码覆盖率 断言覆盖率 漏洞率曲线 功能覆盖率)
概述
- 覆盖率是衡量验证完备性的一个通用词语,用来衡量设计中已经被测部分和未测部分的比例,通常被定义为已达到所需验证部分的百分比。
- 覆盖率工具会在仿真过程中收集信息,进行处理得到覆盖率报告,再根据报告找出覆盖之外的盲区,修改现有测试用例或者创建新的测试用例来填补这些盲区,这个过程可以一直迭代进行,直到达到目标覆盖率
代码覆盖率
代码覆盖率用于衡量你执行了多少设计代码,关注点在设计代码上,而不是测试平台。
仿真工具会自动通过分析源代码和增加隐藏代码来自动完成代码覆盖率统计。代码覆盖率100%,并不意味着验证工作已经完成,它只是验证工作完成的必要条件。
主要包含
- 行覆盖率:多少行代码被执行过
- 路径覆盖率:在穿过代码和表达式的路径中有哪些已经被执行过
- 翻转覆盖率:哪些单位比特变量的值为0或1
- 状态机覆盖率:状态机哪些状态和状态转换已经被访问过
断言覆盖率
- 断言是一种声明性的代码,用于检查RTL代码中的信号之的的关系。最常用语查找错误,例如两个信号是否应该互斥
- 断言可以使用过程性的代码或者使用 Systemverilog Assertions
- 断言可以检查信号的值或者设计的状态
- cover property语句来测量这些关系的信号值是否发生
漏洞率曲线
在一个项目中,应保持追踪每周的漏洞数量。每次漏洞下降时,就应寻找不同的办法取测试可能的边界情况。
在临近流片时,漏洞率会下降,甚至为0,但漏洞率如果出现意外情况,可能预示着潜在的问题
功能覆盖率
验证的目的就是确保设计在实际环境中的行为正确,功能覆盖率和功能设计示意图是紧密相连的,有时也被称为“描述覆盖率”,而代码覆盖率则是衡量设计的实现情况。
若某个功能在设计中遗漏,代码覆盖率是不能发现这个错误,但功能覆盖率可以发现。
通过分析覆盖率数据就可以决定如何修改递归测试集,
- 如果覆盖率稳步增长,那么就添加新种子或者加长测试时间;
- 如果覆盖率增速放缓,那么添加额外的约束来产生更多激励;
- 如果覆盖率停止增长,然而设计某些测试点没有被覆盖到(覆盖率不足100%),那么就创建新的测试;
- 如果覆盖率为100%但依然有新的设计漏洞,那么覆盖率可能没有覆盖到设计中某些设计功能区域;
2 功能覆盖率策略
在动手写测试代码前,我们需要预先弄清楚相关设计的关键特性,边界情形和可能的故障模式。不要只考虑数据数值等内容,相反地,要考虑到设计所包含的信息。
收集信息而非数据
只测量需要的内容
验证的完备性
- 完备的验证测量结果和漏洞率增长曲线,可以帮助确认设计是否被完整地验证过
- 如果代码覆盖率低但功能覆盖率高,说明验证计划不完整,测试没有执行所有的设计代码
- 如果代码覆盖率高但功能覆盖率低,说明虽然测试平台很好的执行了所有设计代码,但测试还是没有把设计定位到所有感兴趣的状态
3 覆盖组Covergroup
covergroup概述
- 覆盖组和类相似,一次定义后便可多次例化,且必须被例化后才能用来收集数据
- covergroup可包含一个或多个coverpoint,且全在同一时间采集
- covergroup可定义在类,interface或module中,
- 它可采样任何可见的变量
covergroup的采样触发
covergroup由采样的数据和数据被采样的事件构成,当两个条件准备好之后,采样便会被触发。
方式一:使用sample()函数,显示的触发覆盖组
//采样方式1,显示的触发
covergroup Coverport; // 类型
coverpoint tr.port; //需要采样的变量port
endgroup
Coverport = new(); //直接实例化覆盖组
Coverpoint cgl = new(); //cgl为实例名,推荐该方法例化
cgl.sample(); //采样
方式二:可借助已有事件触发采样,使用wait或@;
//采样方式2,使用事件触发
event a;//定义时间
covergroup Coverpoint @(a); //采样触发
coverpoint ifc.cb.port;
endgroup
4 数据采样
概述
- 当使用coverpoint 指定采样一个变量和表达式时,sv会创建很多的bin(仓)来记录每个数值被捕捉的次数。这些bin是衡量功能覆盖率的基本单位。
- 为了计算一个coverpoint上的覆盖率,首先应确定可能数值的个数,也称域(比如rand bit [2:0] a可能的数值共有8种,域为8),覆盖率就是采样的值的数目除以bin的数目(若仿真过程只采样到7个数值,那么该coverpoint的覆盖率为7/8)
- 所有coverpoint的覆盖率构成了一个covergroup的覆盖率,所有covergroup的覆盖率构成了整体的功能覆盖率
bin的创建和应用
sv会自动为某个coverpoint创建bin,但推荐自定义bin的采样区域。
如果采样变量的域范围过大而又没有指定bin,那么系统会默认分配一个64个bin,将值域范围平均分配给这64个bin。可以使用covergroup的选项auto_bin_max来指定自动创建bin的最大数目
//覆盖组选项auto_bin_max
covergroup CovPort;
options.auto_bin_max = 8; //所有coverpoint auto_bin数量为8
coverpoint tr.port;
{options.auto_bin_max = 2;} //特定的coverpoint auto_bin为2,其余还是8
endgroup
//大括号结尾没有分号
命名coverpoint和bin
covergroup CovKind;
coverpoint tr.kind{
bins zero = {0}; //一个仓代表kind=0,其中bins关键字,zero仓的名称
bins lo = {[1:3],5}; //一个仓代表1,2,3,5
bins hi[] = {[8:$]}; //8个独立的仓分别代表8-15,$代表上限
bins misc = default; //1个仓代表所有剩余的值
} // 没有分号
endgroup
coverpoint定义使用{}而不是begin...end,是声明性代码而非程序性代码,所以结尾没有分号。
条件覆盖率
使用关键词iff给coverpoint添加条件
也可以使用start和stop函数来控制covergroup各个实例
covergroup Coverport;
coverpoint port iff
(!bus_if.reset); //只收集reset为0时的覆盖率数据
endgroup
initial begin
Coverport ck = new();
#1ns ck.stop(); //复位期间不搜集覆盖率
bus_if.reset= 1;
#100ns bus_if.reset = 0;//复位结束
ck.start(); //开始采样
ck.sample(); //调用sample
end
翻转覆盖率
记录变量从A值到B值的跳转情况
covergroup CovPort;
coverpoint port{
bins t1 = (0=>1),(0=>2),(0=>3); //一个仓,满足任何一个跳转就会记录一次
}
endgroup
wildcard覆盖率
使用关键字wildcard可创建多个转态或跳转,在表达式中x,z或者?会作为0或1的通配符使用
bit [2:0] port;
covergroup CovPort;
coverpoint port {
wildcard bins even = {3'b??0}; // 偶数仓
wildcard bins odd = {3'b??1}; //奇数仓
}
endgroup
忽略的bin和非法的bin
对于那些不需要的域值可以使用ignore_bins来排除,最终它们就不会计算在覆盖率中
进一步地,若有些采样值不仅应忽略,若出现时还应报错,则可以使用illegal_bins进行标志
coverpoint low_ports_0_5{
ignore_bins hi = {[6:7]}; //忽略6-7
}
coverpoint low_ports_0_5{
illegal_bins hi = {[6:7]}; //如果出现便报错
}
交叉覆盖率
coverpoint是记录单个变量或者表达式的观测值,若需要记录多个变量之间的组合情况,需要使用交叉覆盖率(cross)
class Transaction;
rand bit [3:0] kind;
rand bit [2:0] port;
endclass
transaction tr;
covergroup Covport;
kind : coverpoint tr.kind;//kind为该coverpoint的名称
port : coverpoint tr.port;
cross kind,port;//交叉覆盖,sv共创了128个仓(8*16)
endgroup
还可使用ignore-bins 、binsof和intersect分别指定coverpoint和值域,这样可清除不关心的cross bin
cross kind, port{
ignore_bins hi = binsof(port) intersect{7};//排除port为7的取值
}
更精细的交叉覆盖率指定
随着cross覆盖率越来越精细,使用ignore_bins来指定需要忽略的值较为繁琐;更适合的方式是自己声明感兴趣的cross bin.
假设两个随机变量a,b有三种感兴趣的状态{a==0,b==0},{a==0,b==1},{b==1},则可以有三种方式进行覆盖率收集
- 使用仓名的交叉覆盖率(绿皮书9.35)
- 使用binsof的交叉覆盖率(绿皮书9.36)
- 使用串联值来代替交叉覆盖率
//方式3,使用串联值来代替交叉覆盖率
covergroup CrossManual;
ab:coverpoint {tr.a, tr.b} //
{bins a0b0 = {2b'00};
bins a1bo = {2b'10};
wildcard bins b1 = {2b'?1};
}
endgroup
5 覆盖选项
(单个实例的覆盖率、注释、覆盖次数限定、覆盖率目标、covergroup方法)
- 如果对一个covergroup例化多次,sv默认将所有实例的覆盖率合并到一起。若需要单独列出每个covergroup的实例覆盖率则需要设置覆盖选项(option.per_instance = 1);同时也可通过参数来对每个实例传入单独的注释。
- 覆盖率次数限定:默认情况下为1,可通过option.at_least来修改最少采样次数。
- 覆盖率目标:可通过option.goal来设置覆盖率目标
实例说明
covergroup CoverLegth(int hi,lo, string comment);//传入comment
option.comment = comment;//设置注释
option.goal = 90; //覆盖率目标设为90,默认情况是100
option.per_instance = 1;//单独列出每个实例的覆盖率
coverpoint port{
{bins range {[lo:hi]};
}
endgroup
...
Coverlength cp_lo = new(0,3,"Low port numbers"); //注释内容
Coverlength cp_lo = new(2,3,"Hign port numbers");
6 数据分析
- 使用$get_coverage() 得到总体的覆盖率,返回0-100的real数值
- 也可使用covergroup_inst.get_inst_coverage()来获取单个coverpoint实例的覆盖率
- start()/stop() :使能或者关闭覆盖率收集
- 重启新的随机种子或者测试可能有望提高覆盖率