《SystemVerilog验证测试平台编写指南》学习笔记——功能覆盖率(三)

文章目录

一、交叉覆盖率

覆盖点记录的是单个变量或者表达式的观测值,而交叉覆盖率可以同时测量两个或者两个以上覆盖点的值。若其中一个有N种取值,另个一有M种取值,则SV需要N*M个交叉仓来存储所有的组合。

1、基本的交叉覆盖率的例子

SV中的cross结构可以用来记录一个组里两个或两个以上覆盖点的组合值。但是即使每个覆盖点都达到了100%的覆盖率,交叉组合可能会达不到100%。

基本的交叉覆盖率

/*
在tr.kind和tr.port上创建了覆盖点,然后这两个点便交叉显示出各种组合。
SV总共创建了128(8*16)个仓。
*/
class Transaction;
	rand bit[3:0] kind;
	rand bit[2:0] port;
endclass

Transaction tr;

covergroup CovPort;
	kind: coverpoint tr.kind;		//创建覆盖点kind
	port: coverpoint tr.port;		//创建覆盖点port
	cross kind,port;				//把kind和port交叉
endgroup

2、对交叉覆盖仓进行标号

指定交叉覆盖仓的名称

covergroup CovPortKind;
	port: coverpoint tr.port{
		bins port[] = {0:$};
		}
	kind: coverpoint tr.kind{
		bins zero = {0};		//一个仓zero,对kind采样值为0进行计数
		bins lo = {[1:3],5};	//lo仓代表1:3和5的值
		bins hi[] = {[8:$]};	//8个独立的仓8-15,分别保存
		bins misc = default;	//一个仓用来保存没有被选中的值
		}
	cross kind,port;
endgroup

3、排除掉部分交叉覆盖仓

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

在交叉覆盖中排除掉部分bin

covergroup CovPort;
	port: coverpoint tr.port{
		bins port[] = {0:$};
		}
	kind: coverpoint tr.kind{
		bins zero = {0};		//一个仓zero,对kind采样值为0进行计数
		bins lo = {[1:3],5};	//lo仓代表1:3和5的值
		bins hi[] = {[8:$]};	//8个独立的仓8-15,分别保存
		bins misc = default;	//一个仓用来保存没有被选中的值
		}
	cross kind,port{
		ignore_bins hi = binof(port) intersect {7};			//排除掉了所有代表port为7和任意kind值组合的仓
		ignore_bins md = binof(port) intersect {0} &&		//排除掉了port为0和kind为9、10、11的组合,共3个仓。
						 binof(kind) intersect {[9:11]};
		ignore_bins lo = binof(kind.lo);					//使用仓名排除掉了整个仓
		}
endgroup

4、从总体覆盖率的度量中排除掉部分覆盖率

指明交叉覆盖率的权重

covergroup CovPort;
	port: coverpoint tr.port{
		bins port[] = {0:$};
		options.weight = 0;		//不占任何分量
		}
	kind: coverpoint tr.kind{
		bins zero = {0};		//一个仓zero,对kind采样值为0进行计数
		bins lo = {[1:3],5};	//lo仓代表1:3和5的值
		bins hi[] = {[8:$]};	//8个独立的仓8-15,分别保存
		bins misc = default;	//一个仓用来保存没有被选中的值
		options.weight = 5;		//在总体中所占比重
		}
	cross kind,port{
		options.weight = 10;	//给予交叉更高的权重
		}
endgroup

5、从多个值域中合并数据

交叉覆盖的一个问题就是,可能需要从不同的时间域里采样数据。可以拷贝信号到临时变量中,然后在一个新的覆盖组里对它们进行采样,这个新的覆盖组可以用于计算交叉覆盖率。

6、交叉覆盖的替代方式

使用仓名的交叉覆盖率

//覆盖点都有事先定义好的仓的情况
class Transaction;
	rand bit a,b;
endclass

covergroup CrossBinNames;
	a: coverpoint tr.a{
		bins a0 = {0};
		bins a1 = {1};
		options.weight = 0;
		}
	b: coverpoint tr.b{
		bins b0 = {0};
		bins b1 = {1};
		options.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

使用binsof的交叉覆盖率

//覆盖点没有事先定义好的仓的情况
class Transaction;
	rand bit a,b;
endclass

covergroup CrossBinofIntersect;
	a: coverpoint tr.a{
		options.weight = 0;
		}
	b: coverpoint tr.b{
		options.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 a0b0 = {2'b00};
			bins a1b0 = {2'b10};
			wildcard bins b1 = {2'b? 1};
		}
endgroup

二、通用的覆盖组

1、通过数值传递覆盖组参数

bit[2:0] port;
covergroup CoverPort(int mid);
	coverpoint port{
		bins lo = {[0:mid-1]};
		bins hi = {[mid:$]};
		}
endgroup

CoverPort cp;
initial begin
	cp = new(5);
	...
end

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 begin
	cpa = new(port_a,4);
	cpb = new(port_b,2);

三、覆盖选项

1、单个实例的覆盖率

指定单个实例(per-instance)的覆盖率

covergroup CoverLength;
	coverpoint tr.length;
	option.per_instance = 1;				//per_instance只能放在覆盖组里,不能用于覆盖点或交叉点
	option.comment = $psprintf("%m");		//在注释comment中使用层次化路径
endgroup

2、覆盖组的注释

为一个覆盖组指定注释

covergroup CoverPort;
	type_option.comment = "comment";
	coverpoint port;
endgroup

为单个覆盖组实例指定注释

covergroup CovPort(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");
CoverPort cp_hi = new(4,7,"high");

3、覆盖阈值

你的设计可能没有足够的可见度以至于不能收集到稳健的覆盖率信息,只有在确实无法直接测量覆盖率的情况下可以使用option.at_least。如果option.at_least定义在覆盖组里,将会作用于所有的覆盖点,如果定义在一个点上,只会对该点有效。

4、打印空仓

缺省的情况下,覆盖率报告只会给出带有采样值得仓。使用cross_num_print_missing选项可以给出所有的仓,尤其是那些没有被命中的仓。

5、覆盖率目标

指定覆盖率目标

covergroup CoverPort;
	coverpoint port;
	option.goal = 90;
endgroup

四、覆盖率数据的分析

事务长度的原始类

class Transaction;
	rand bit[2:0] hdr_len;
	rand bit[3:0] payload_len;
	rand bit[4:0] len;
	constraint length {
		len == hdr_len + payload_len;
	}
endclass

这个类len同时受到两个长度之和的约束,len值得分布并不均匀。
《SystemVerilog验证测试平台编写指南》学习笔记——功能覆盖率(三)
可以使用solve…before约束

class Transaction;
	rand bit[2:0] hdr_len;
	rand bit[3:0] payload_len;
	rand bit[4:0] len;
	constraint length {
		len == hdr_len + payload_len;
		solve len before hdr_len,payload_len;
	}
endclass

五、在仿真过程中进行覆盖率统计

使用$get_coverage可以得到所有覆盖组的总覆盖率。
使用get_coverage(),可以带覆盖组名和实例,用于给出一个覆盖组所有实例的覆盖率。
使用get_inst_coverage(),可以返回一个特定覆盖组实例的覆盖率。

这些函数最实际的用处是在一个长测试中监测覆盖率,如果覆盖率水平在给定数量的事务或周期之后 并无提高,那么这个测试就应该停止,重启新的种子或测试可能有希望提高覆盖率。验证团队可以建立自己的SQL数据库,用来收集从仿真中得到的覆盖率数据。有些形式验证工具能够提取设计状态并创建输入激励去测试所有可能的状态。

上一篇:深度解析 | K8S API Server之入门须知


下一篇:使用FDBatchMove导入TXT,CSV文件到数据库