文章目录
1.覆盖率类型
覆盖率是衡量设计验证完备性的一个通用词语。
2.代码覆盖率
1.代码覆盖率:记录程序的各行代码被执行的情况
常见的代码覆盖率如下:
- 行覆盖率:多少行代码已经被执行过
- 路径覆盖率:在穿过代码和表达式的路径中有哪些已经被执行过
- 翻转覆盖率:哪些单位比特变量的值为0或1
- 状态机覆盖率:状态机哪些状态和状态转换已经被访问过
代码覆盖率最终结果用于衡量你执行了设计中的多少代码。
代码覆盖率达到了100%,并不意味着验证的工作已经完成,但代码覆盖率100%是验证工作完备性的必要条件。
为了保证验证的完备性,在收集覆盖率时,要求代码覆盖率和功能覆盖率同时达到要求。
3. 断言覆盖率
断言是用于一次性地或在一段时间内核对两个设计信号之间关系的声明性代码。
断言最常用于查找错误,例如两个信号是否应该互斥,或者请求与许可信号之间的时序等。
4.漏洞率曲线
每次漏洞率下降时,就应该寻找各种不同的办法去测试可能的边界情况,漏洞率可能每周都有变化,这跟很多因素都有关。不过漏洞率如果出现意外的变化,可能预示着潜在的问题。
5.功能覆盖率
验证的目的就是为了确保设计在实际环境中的行为正确。
- 功能覆盖率和功能设计意图紧密相连的,有时也被称为“描述覆盖率”,而代码覆盖率则是衡量设计的实现情况。
- 某个功能在设计中可以被遗漏,代码覆盖率不能发现这个错误,但功能覆盖率可以。
通过将每次仿真收集的覆盖率信息合并,分析覆盖率数据就可以决定如何修改回归测试集。 - 如果覆盖率稳步增长,那么就添加新种子或者加长测试时间
- 如果覆盖率增速放缓,那么添加额外的约束来产生更多激励
- 如果覆盖率停止增长,然而设计某些测试点没有被覆盖到,那么就创建新的测试
- 如果覆盖率为100%但依然有新的设计漏洞,那么覆盖率可能没有覆盖到设计中某些设计功能区域
5.1功能覆盖策略
- 收集信息而非数据:关注感兴趣的状态,而不是具体数值
- 只测量需要的内容:收集功能覆盖率数据的开销很大,所以只测量你会用来分析并且改进测试的那部分数据
- 验证的完备性:同时驱动高的代码覆盖率和功能覆盖率
1.如果代码覆盖率低但功能覆盖率高,这说明验证计划不完整,测试没有执行设计的所有代码
2.如果代码覆盖率高但功能覆盖率低,说明测试没有把设计定位到所有感兴趣的状态上,或者可能设计没有实现某功能
5.2功能覆盖率建模
功能覆盖率主要关注设计的输入、输出和内部状态:
- 对于输入,它检测数据端的输入和命令组合类型,以及控制信号与数据传输的组合情况
- 对于输出,它检测是否有完整的数据传输类别,以及各种情况的反馈时序
- 对于内部设计,需要检查的信号与验证计划中需要覆盖的功能点相对应。通过对信号的单一覆盖、交叉覆盖或时序覆盖来检查功能是否被触发,以及执行是否正确
5.3覆盖组-covergroup
覆盖组与类相似——一次定义后可以进行多次实例化。它含有覆盖点、选项、形式参数和可选触发(trigger)。一个覆盖组包含了一个或多个数据点,全都在同一时间采集。
- covergroup至少要有一个coverpoint,且全都在同一时间采集
- covergroup可以定义在类中,也可以定义在接口或者module中
- covergroup必须要被例化才能采样数据
1.covergroup的采样触发
- covergroup由采样的数据和数据被采样的事件构成,两个条件都准备好,测试平台便会触发covergroup
- 直接使用 sample() 函数完成
covergroup Covport
coverpoint port;
endgroup
Covport cg1 = new();
cg1.sample();//收集覆盖率
2.covergroup使用事件触发
与直接调用sample()相比,使用事件触发的好处在于你能够借助已有的事件
event trans_ready;
covergroup CovPort @(trans_ready);
coverpoint ifc.cb.port;
endgroup
5.4数据采样
- bin是衡量功能覆盖率的基本单位
- 计算coverpoint上的覆盖率,首先需要确定可能数值的个数,即域
覆盖率 = 采样值的数据 / bin的数目 - 所有coverpoint的覆盖率最终构成covergroup的覆盖率,所有covergroup的覆盖率最终构成整体的功能覆盖率
1.bin的创建和使用
- SV会默认为某个coverpoint创建bin,自动创建bin的最大数目由auto_bin_max内置参数决定,默认值为64.用户也可以自己定义bin的采样域。
- 在实际操作中,自动创建bin的方法不实用,建议用户自行定义bin。
- 用户自定义bin可以增加覆盖的准确度
显示定义bins,可以通过关键字default将未分配到的数值进行分配。
covergroup CovKind;
//kind变量的取值范围为0~15,不设置显示bins时,理论上会有16个bin
coverpoint tr.kind{
bins zero = {0};//取值为0
bins lo = {[1:3],5};//取值为1,2,3,5
bins hi[] = {[8:$]};//取值为8~15
bins misc = default;//余下所有值:4,6,7
}
endgroup
注意:coverpoint定义使用{ }而不是begin … end,大括号的结尾不带分号,这和end一样。
6.条件覆盖率
使用关键字iff给covergroup添加条件
使用start()和stop()函数来控制covergroup各个独立实例
covergroup CoverPort;
coverpoint port iff (!bus_if.reset);
endgroup
initial begin
CovPort ck = new();
#1ns;
ck.stop();
bus_if.reset = 1;
#100ns bus_if.reset = 0;
ck.start();
end
7.翻转覆盖率
coverpoint也可以用来记录变量从A值到B值的跳转情况
除了在bins中定义数值,还可以定义数值之间的跳转,操作符 =>
covergroup CoverPort;
coverpoint port{
//满足其中任何一个,就会记录一次
bins t1 = (0 =>1), (0 => 2), (0 => 3);
//跳转次序为3->4->5,如果没有执行这个次序,则这个bins没有覆盖
bins t2 = (3 => 4 => 5);
}
endgroup
除操作符外,还可使用关键词wildcard和通配符 ? 来表示状态和状态跳转;
- wildcard来创建多个状态或者翻转
- 在表达式中,任何x,z或者 ? 都会被当成0或1的通配符
wildcard bins abc = {2'b1?};//覆盖10,11
//覆盖 10=>00, 10=>10,11=>00,11=>10
wildard bins abc = {2'b1x => 2'bx0};
bit [2:0] port;
covergroup CoverPort;
coverpoint port{
wildcard bins even = {3'b??0};//偶数
wildard bins odd = {3'b??1};//奇数
}
endgroup
8 忽略的bin和非法的bin
- 有些coverpoint可能始终无法得到全部的阈值
- 对于那些不计算功能的阈值可以使用ignore_bins来排除,最终它们并不会计入coverpoint的覆盖率
coverpoint port{
ignore_bins hi = {[6,7]};//忽略数值6~7
}
有些采样值不仅想要忽略,并且出现还应该报错,可以用illegal_bins
coverpoint port{
illegal_bins hi = {[6,7]};//出现6~7就停止仿真,报错
}
9.交叉覆盖率
- coverpoint是记录单个变量或者表达式的观测值
- 要想记录在某一时刻,多个变量之间值的组合情况,需要使用交叉覆盖率
- cross 语句只允许带coverpoint或者简单的变量名
class Transaction;
rand bit [3:0] kind;
rand bit [2:0] port;
endclass
transaction tr;
covergroup Covport;
kind : coverpoint tr.kind;
port : coverpoint tr.port;
cross kind,port;//交叉覆盖
endgroup
排除部分cross bin
通过使用ignore_bins、binsof和intersect分别指定coverpoint和值域,这样可以清除很多不关心的cross bin
binsof指定覆盖点,intersect指定数值集
class Transaction;
rand bit [3:0] kind;
rand bit [2:0] kind;
endclass
transaction tr;
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的情况
ignore_bins hi = binsof(port) intersect(7);
ignore_bins lo = binsof(kind.lo);
}
endgroup
10.覆盖选项
10.1 单个实例覆盖率
如果对一个covergoup例化多次,那么默认情况下SV会将所有实例的覆盖率合并到一起。如果需要单独列出每个covergroup实例的覆盖率,需要设置覆盖选项。
option.per_instance
covergroup CoverLength
coverpoint tr.length;
option.per_instance = 1;
endgroup
10.2 覆盖组注释
当有多个covergroup的实例时,可以通过设置option.cemment选项,来对每个实例传入单独的注释,这些注释会显示在覆盖率的报告中。
10.3 次数限定
默认情况下,数值采样了1次就可以计入有效的bin。可以通过修改at_least来修改每个bin的数值最少采样次数,如果低于at_least数值,则不会被计入bin中。
- at_least在covergroup中声明可以影响所有的coverpoint
- at_least在coverpoint中声明仅仅影响所有的coverpoint中的bin
10.4覆盖率目标
一般一个covergroup或者coverpoint的目标是100%覆盖率,不过你也可以将其设置为低于100%的目标,这个选项只会影响覆盖率报告。
covergroup
coverpoint port;
option.goal = 90;
endgroup
10.5 covergroup方法
方法 | 释义 |
---|---|
sample() | 采样 |
get_coverage() | 获取该covergroup返回0-100的 real 数值 |
get_inst_coverage() | 获取某个实例的覆盖率, 返回0-100的 real 数值 |
set_inst_name(string) | 设置covergroup的名称 |
start() | 使能覆盖率的收集 |
stop() | 关闭覆盖率的收集 |