覆盖率是衡量设计验证完备性的一个通用词语。
1.代码覆盖率:记录程序的各行代码被执行的情况
常见的代码覆盖率如下:
断言是用于一次性地或在一段时间内核对两个设计信号之间关系的声明性代码。
断言最常用于查找错误,例如两个信号是否应该互斥,或者请求与许可信号之间的时序等。
每次漏洞率下降时,就应该寻找各种不同的办法去测试可能的边界情况,漏洞率可能每周都有变化,这跟很多因素都有关。不过漏洞率如果出现意外的变化,可能预示着潜在的问题。
验证的目的就是为了确保设计在实际环境中的行为正确。
功能覆盖率主要关注设计的输入、输出和内部状态:
覆盖组与类相似——一次定义后可以进行多次实例化。它含有覆盖点、选项、形式参数和可选触发(trigger)。一个覆盖组包含了一个或多个数据点,全都在同一时间采集。
covergroup Covport
coverpoint port;
endgroup
Covport cg1 = new();
cg1.sample();//收集覆盖率
与直接调用sample()相比,使用事件触发的好处在于你能够借助已有的事件
event trans_ready;
covergroup CovPort @(trans_ready);
coverpoint ifc.cb.port;
endgroup
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一样。
使用关键字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
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 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
coverpoint port{
ignore_bins hi = {[6,7]};//忽略数值6~7
}
有些采样值不仅想要忽略,并且出现还应该报错,可以用illegal_bins
coverpoint port{
illegal_bins hi = {[6,7]};//出现6~7就停止仿真,报错
}
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
如果对一个covergoup例化多次,那么默认情况下SV会将所有实例的覆盖率合并到一起。如果需要单独列出每个covergroup实例的覆盖率,需要设置覆盖选项。
option.per_instance
covergroup CoverLength
coverpoint tr.length;
option.per_instance = 1;
endgroup
当有多个covergroup的实例时,可以通过设置option.cemment选项,来对每个实例传入单独的注释,这些注释会显示在覆盖率的报告中。
默认情况下,数值采样了1次就可以计入有效的bin。可以通过修改at_least来修改每个bin的数值最少采样次数,如果低于at_least数值,则不会被计入bin中。
一般一个covergroup或者coverpoint的目标是100%覆盖率,不过你也可以将其设置为低于100%的目标,这个选项只会影响覆盖率报告。
covergroup
coverpoint port;
option.goal = 90;
endgroup
方法 | 释义 |
---|---|
sample() | 采样 |
get_coverage() | 获取该covergroup返回0-100的 real 数值 |
get_inst_coverage() | 获取某个实例的覆盖率, 返回0-100的 real 数值 |
set_inst_name(string) | 设置covergroup的名称 |
start() | 使能覆盖率的收集 |
stop() | 关闭覆盖率的收集 |