Bootstrap

vcs 覆盖率收集1——三种覆盖率类型、covergroup、bins、数据采样、覆盖率选项


前言

2023.3.15
2023.3.20
2023.9.12 更新


一、覆盖率知识

1、覆盖率类型

1.1 代码覆盖率

衡量RTL代码是否被充分运行的指标,100%是验证工作完备的必要性,一般设置为95%

  • 语句覆盖率(statement coverage):指的是程序的每一行代码是否被执行过。
  • 条件覆盖率(condition coverage) :指的是每个条件中的逻辑操作数被覆盖的情况。
  • 分支覆盖率(branch coverage) :指的是在if, case, _while,repeat, forever,for和loop语句中各个分支执行的情况。
  • 事件覆盖率(event coverage):该覆盖率用来记录某一个事件被触发的次数。
  • 跳转覆盖率(toggle coverage):用来记录某个设计边界信号数据位的0/1跳转情况,例如从0到1,或者从1到0的跳转。
  • 状态机覆盖率(finite stage machine coverage) :仿真器的覆盖率功能可以识别出设计中的状态机部分,记录各种状态被进X的次数,以友状态之间的跳转情况。

1.2 功能覆盖率

覆盖率分析

  • 覆盖率稳步增长:添加种子或者加长测试
  • 增速放缓:添加额外的约束
  • 增长停止:创建新的测试
  • 覆盖率达到100%还有设计漏洞:某些功能点没有进行测试

功能覆盖率策略

  • 收集信息而非数据:数量太大的话,应当拆分成多个小范围+边界。着眼于状态而不是某个数据
  • 只测量需要的内容:收集覆盖率的时候开销是很大的
  • 验证的完备性同时驱动高的代码覆盖率和高的功能覆盖率
    代码覆盖率低功能覆盖率高:没有执行所有的代码,验证计划也不完整
    代码覆盖率高功能覆盖率低:可以执行所有代码,没有所有功能点都测试到了

代码覆盖率达到100%,并不意味着工作结束,因为有可能代码有漏洞或者功能点并没有测全。代码覆盖率没有达到100%,那么意味着设计测试激励不足或者设计代码有冗余等情况

1.3 断言覆盖率

断言描述本身也支持覆盖率收集,一般可以通过仿真或者硬件加速的方式来收集,也可以通过形式验证的工具来收集。

定义:用于一次性地或在一段时间对一个或者多个设计信号在逻辑或者时序上的声明性代码,也可以用其他task/function来进行断言,是等价的

关心某个信号值或者状态是否改变,断言覆盖率需要自己设置,覆盖率会被收集到一个覆盖率数据库中。

  • 在常见的仿真中,仿真器会记录断言的先决条件是否被触发,以及判断语句成功或者失败。
  • 根据选择的验证方法不同,我们可以将断言覆盖率分为:
    基于动态仿真或者硬件加速的断言覆盖率
    基于形式验证的静态断言覆盖率

2、覆盖组/covergroup

  • 需要例化才能采样数据,一次定义就可以多次实例化
  • 衡量这些变量在某些特定时间采样到的值,定义采样哪些变量、数值,定义采样事件。
  • 可在classinterfacemodule里面定义
  • 一个类可以有多个covergroup,都是独立的,可以自行使能或者禁止(之前的有constraint、randomize可以使能)
  • sample():手动采样,显示采样
    wait/@:借助已有的事件阻塞触发
//采样方式一 : sample() 
covergroup Covport;
	coverpoint port;  //没有定义数值,意思就是采样所有的值
endgroup
Covport cg1 = new();   //例化  
cg1.sample();   //手动采样

//采样方式二 : 事件触发,最好不用这种方式
event trans_ready;   //定义事件
covergroup Covport@(trans_ready);   //也可以用wait
	coverpoint port;
endgroup

3、数据采样

3.1 bins/仓

  • bin/仓衡量功能覆盖率的基本单位记录每个数值被捕捉到的次数
    可以手动或者SV自动定义bin
  • :可能数值的个数。
  • 每一个coverpoint组合成covergroup的覆盖率,所有的covergroup组成整体的覆盖率。
  • 覆盖率 = 采样值的数目 / bin的数目
    例如:一个3bit变量的域是7:0,正常情况下会自动分配8个bin。如果仿真过程中有7个值被采样到,那么最终的coverpoint的覆盖率就是7/8
  • 采样变量范围太大时,系统会默认分配64bin,再将数值平均分配到64个。
    auto_bin_max:指定自动创建bin的最大数目,
  • 定义在 covergroup 的option设置会影响整个covergroup ,即当前covergroup下的所有coverpoint都被设置了。coverpoint里面的设置会覆盖covergroup的设置。
covergroup Covport;
    option.auto_bin_max = 8;//covergroup中的option
    coverpoint tr.port{
        //这个option会覆盖covergroup的设置
		option.auto_bin_max = 2;//coverpoint中的option
    }
endgroup

//-----------------------------------------------
covergroup Covkind;
	coverpoint tr.kind{
		bins zero = {0};  //1个仓代表kind=0
		bins lo = {[1:3], 5};  //1个仓表示1:3和5
		bins hi[] = {[8:$]};   //8个独立的仓代表8:15
		bins misc = default;  //1个仓表示剩余的所有值
	}
endgroup

下面定义的covergroup有输入参数output和inout不能作为covergroup的参数),且定义在时钟上升沿进行采样

covergroup cg (ref int ra, input int low, int high ) @(posedge clk);
coverpoint ra 
{
	bins good = { [low : high] };
	bins bad[] = default;
}
endgroup

int va, vb;
cg c1 = new( va, 0, 50 ); // cover variable va in the range 0 to 50
cg c2 = new( vb, 120, 600 ); // cover variable vb in the range 120 to 600

3.2 条件覆盖率

关键词iff:需要满足条件才会采样,附加条件

covergroup Covport;
    coverpoint port iff(!vif.rstn) {bins t1 = default;}  //复位期间不采样
endgroup 

3.3 翻转覆盖率

covergroup Covport;
    coverpoint port{
        bins t1 = (0 => 1),(0 => 2) , (0 => 3) ;//满足其中任何一个,就会记录一次
    }
endgroup 

3.4 wildcard覆盖率

X/Z/?:会被当成0或者1

使用通配符进行匹配,例如下面的奇数、偶数仓

wildcard bins even = {3'b??0};//偶数
wildcard bins odd = {3'b??1};//奇数

3.5 ignore_bins

有些coverpoint可能始终无法得到全部的域值,可以用 ignore_bins来排除不计算功能的域,最终这些值不会计入coverpoint的覆盖率

bit [2:0] low_ports;
covergroup Covport;
	coverpoint low_ports{
		ignore_bins hi = {[6,7]};   //排除6和7
	}
endgroup

3.6 illegal_bins

不想要某些值,出现这些数值就会报错
非法仓的优先级高于其他任何仓

coverpoint port{
    illegal_bins hi = {[6,7]};//出现6~7就停止仿真,报错
}

3.7 default关键词

除了已经定义好的bins外,其他默认的值都放在default里面

3.8 with关键词

附加约束条件,0-255中能被3整除的数

a: coverpoint x
{
	bins mod3[] = {[0:255]} with (item % 3 == 0);
}

4、覆盖选项

4.1 option

option:某个covergroup的实例的选项
per_instance选项只能在covergroup定义时进行设置,其他选项也可以在covergroup实例化之后进行设置

选项含义默认值
weightcovergroup实例的权重或某个coverpoint的权重,1表示最终会进行计算1
goalcovergroup实例或coverpoint的目标90
name = stringcovergroup实例的名称,未指定的话工具会自动生成
comment = string注释,最终会显示在覆盖率数据的总结报告中
at_least每个仓至少命中的次数,小于该值的话不认为被覆盖0
auto_bin_max仓的最大数量64
per_instance每个实例都对covergroup类型的总体覆盖率做出贡献,等于1会单独列出每个covergroup实例的覆盖率0
covergroup CoverLegth;
    coverpoint tr.length;
    option.per_instance = 1; //设置覆盖选项,单独列出每一个的覆盖率
endgroup

//----------------------------------
covergroup CoverLegth(int hi,lo, string comment);//传入comment
    option.comment = comment; //设置注释
    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");

4.2 type_option

type_option:某个covergroup类型整体选项
这些选项可以在任意时刻进行设置

选项含义默认值
weight权重1
goal目标90
comment注释
strobe设置为1的话,采样会发生在仿真结束,类似于系统函数$strobe0

5、交叉覆盖率cross

某一时刻多个变量之间值的组合,cross出来的数据量一般比较大,可以手动忽略一些,更好的方法是自己声明感兴趣的cross bin。
binsof:指定覆盖点 coverpoint
intersect:指定数值集

//第一种:这种写法是去忽略某些值
class Transaction;
    rand bit [3:0] kind;
    rand bit [2:0] port;
endclass
transaction tr;

covergroup Covkind;
	port: coverpoint tr.port{
		bins port[] = {[0:$]};   //port是3bit,所以是8个bin
	}
	
	kind: coverpoint tr.kind{
		bins zero = {0};  //1个仓代表kind=0
		bins lo = {[1:3], 5};  //1个仓表示1:3和5
		bins hi[] = {[8:$]};   //8个独立的仓代表8:15
		bins misc = default;  //1个仓表示剩余的所有值
	}   //这里总共11个bins,看bins的数量是看前面是数组还是变量

	cross kind, port{
		ignore_bins hi = binsof(port) intersect {7};  //忽略port为7时的11个kind bin
		ignore_bins md = binsof(port) intersect {0} && binsof(kind) intersect {[9:11]};  //忽略port为0时,kind里面的hi[]
		ignore_bins lo = binsof(kind.lo);   //忽略kind.lo,也就是当kind=1,2,3,5时忽略
	}
endgroup
//第二种:首先不去收集覆盖率,设置为0;然后去采样特定的cross交叉覆盖率
//哪个写起来更方便就可以使用哪种
class Transaction;
	rand bit a, b;
endclass

Transaction tr;

covergroup CovTrans;
	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 b1 = binsof(b.b1);
	}
endgroup

6、covergroup函数

6.1 预定义的覆盖率函数

sample():采样
get_coverage():加权后的覆盖率,返回0-100的real数值
get_inst_coverage():当前实例的覆盖率,返回0-100的real数值
set_inst_name(string):设置coverpoint的名称,体现在数据报告上

start()/stop():使能或者关闭覆盖率的收集

Covport cb = new();
cb.stop();
if(vif.rstn = 1'b1)begin
	cb.start();
end

$get_coverage():系统函数,获得总体的覆盖率

6.2 覆盖内嵌的采样函数(自定义函数)

covergroup p_cg with function sample(bit a, int x);
	coverpoint x;
	cross x, a;
endgroup : p_cg
p_cg cg1 = new;
;