1. 在类中可以定义多个覆盖组,一个功能点的测试可以对应一个覆盖组,每个覆盖组可以单独使用使能来控制,每个组可以单独设置触发的事件
2. 覆盖组的覆盖点可以会自动建仓或者自定义仓,对于自动建仓,会根据采样点的取值范围来生成仓,例如一个N比特的就有2的N次方个仓,
自动建仓可以通过option.auto_bin_max设置最大的bin数(默认是64个仓)来控制划分的bin(自动按照数值范围切分,每个仓平分,枚举类型不适用);
如果是自己定义的仓,若没有把所有的取值范围都列在bins里面,则不会自动去建仓,覆盖率的计算也只是在自定义的仓里面计算
覆盖点采样的可以是表达式、变量、总线信号或者设计里面的信号
(1) 如何定义含有多个值的仓(拼接符的应用)
bins a = {[0:7]}
(2) 如何批量指定仓名(中括号的应用)
bins a[] = {[0:7]}
总的来说,在名字后面加[]表明是为每一个取值建一个仓,使用{}表示拼接多个数值
wildcard;
wildcard bins g12_15 = { 4'b11?? }; //只要在1100~1111间的任何一个踩到了,就收到了;
wildcard bins g12_15_array[] = { 4'b11?? }; //加了[], 会给每一个符合条件的都产生一个bin
3. 在覆盖组包含形式参数、覆盖点、触发事件以及选项
option.per_instance: 对一个covergroup 例化多次,默认情况下SV会将所有实例的覆盖率合并到一起。单独列出每个covergroup实例的覆盖率,
则设置覆盖选项option.per_instance=1(只能在覆盖组中使用,不能在覆盖点或者bin中使用)
option.per_instance: 如果有多个covergroup实例,可以通过参数来对每一个实例传入单独注释。这些注释最终会显示在覆盖率数据的总结报告中,便于分析报告。
option.cross_num_print_missing: 将没有命中的仓和没有采样值的仓也报告出来
4. 覆盖率的计算方法
单个覆盖点的计算方法:该覆盖点被击中的bins除以该覆盖点总的bins
整个覆盖组的覆盖率计算方法:该组的所有覆盖点的组合
整体功能覆盖点的计算方法:所有覆盖组的覆盖率的组合
5. 每个覆盖组、覆盖点以及仓都可以命名
6. 覆盖组在哪里使用?
下面展示常规的几种做法:
(1) 在env中例化,定义的coverage类继承于uvm_component组件类,
需要在new函数中实例化覆盖组,使得覆盖组件在实例化时也把覆盖组也实例化了
采样的是总线上的信号,因此需要通过configdb设置虚拟接口或者通过set_interface进行设置
在run_phase中定义不同覆盖组的采样时刻,在run_phase中执行的语句,会交给uvm_component的phase机制统一调度
(2)
7. 覆盖组对什么进行采样?
(1) 采样monitor监听到的事务,由于monitor监听的事务是动态变化的,也就是说虽然采样的是某种事务类型的某个变量,但是具体所属的实例是会变化的
(2) 直接采样总线上的事务,信号线不会发生变化,只需要一致监听感兴趣的信号线即可(monitor的事务也是从总线上抓取的)
------------------------------------------------------------------------------------*/
//
// 可以存在多个覆盖组,一个覆盖组可以实例化多次,可以使用start()以及stop()函数来使能某个覆盖组实例
covergroup cg(ref bit[2:0] port, input int mid) @(event);
// 这里采用ref引用的方式来实现通过外部传入port的值,可以实现不同实例监听不同端口的功能
// 同时,这里的mid形参,可以控制一些仓的取值范围
// iff(event),条件事件,只有在event发生时才收集该覆盖点
port:coverpoint port iff(event){
option.weight = 0; // 权重为0,指的是不收集该点的覆盖率,这里只使用在精细指定交叉覆盖中
option.goal = ;
option.comment = "";
option.at_least = ; // 至少击中几次
option.auto_bin_max = ; // 划分为几个域
ignore_bins igb = ; // 忽略哪些仓
illegal_bins ilb = ; // 哪些仓是非法的,出现则报错结束仿真
bins b1 = {[2:7], 10}; // 表示一个仓,取值{2,3,4,5,6,7,10}
bins b2[] = {[8:9]}; // 两个仓,自动命名成b2_8,b2_8
bins t1 = (0=>1), (1=>2), (2=>3); // 翻转信号,只要有一个翻转的信号满足,则该仓被击中;
wildcard bins w1 = {3'b??1};// 通配
} // 注意,这里不用加分号
kind:coverpoint kind{
bins k1 = {[1:3]};
option.weight = 0;
}
// 使用交叉覆盖组,并且排除掉一些情况,可以直接使用intersect来排除覆盖点的具体取值,也可以直接binsof(bins_name)来指定某个仓
cross kind,port{
ignore_bins hi = binsof(port) intersect(7); // port==7;
ignore_bins md = binsof(port) intersect(0) && // port==0且kind==[1:2];
binsof(kind) intersect([1:2]);
}
// 可以使用精细地指定交叉覆盖,而不用排除过多地情况
cross kind,port{
bins k1p2 = binsof(port) intersect(2) && binsof(kind) intersect(1);
}
endgroup : cg
$get_coverage(); // 在全局层面上获取所有覆盖组的总覆盖率(返回一个实数)
CoverGroup::get_coverage(); // 获取该覆盖组所有实例的覆盖率
cg_inst.get_inst_coverage(); // 获取特定的覆盖组实例的覆盖率
/*-----------------------------断言和断言覆盖率-------------------------------------------------
一、 SVA
1. 立即断言,类似if else语句那样,只能在程序语块中使用,用于动态仿真,没有时间的概念
并发断言,基于时钟周期进行(在每个感兴趣的时钟周期都会触发检查),可以放置于procedural block、module、interface及program中,不能出现在class中
在静态(形式)验证及动态仿真工具中均可以应用。
2. 并发断言的使用流程
(1) 在sequence中定义检查的序列
sequence name_of_sequence;
<test_expression>;
endsequence
(2) 将多个sequence包含在property关键字中
property property_name;
<test expression>; or
<complex sequence expression>;
endproperty
(3) assertion_name:assert/cover property (property_name);
二、 断言语法
1. [=m] 非连续(无需跟随)重复操作符, 重复发生多次,但不需要连续发生, 也不需要在满足条件时马上匹配(不需要跟随)
[*m] 连续重复运算符,重复发生多次,且连续发生
[->m] 非连续跟随重复符,a非连续重复3次,只在第3次重复时刻点匹配(跟随的含义)。
三、一些实际例子
1. 保持不变/有变化:$stable() 当前和上一个周期保持不变
2. 访问过去的周期:$past(req, 2) 一般会把过去周期的某个数据保存在变量里面,然后再和后续的数据作比较
3. 表示同时:
(1) seq1 and seq2 同时开始,可以不同时结束,序列的终点是最长的那个
(2) seq1 intersect seq2 同时开始,同时结束
以上是表示两个序列的,都是包含时钟,若是表示同一时刻的某两个信号满足的条件,那应该是&&(与) || (或)
4. 贯穿某个序列:seq1/exp throughout seq2 序列或者表达式贯穿seq2期间均成立
5. 包含关系:seq1 within seq2 表示seq2序列包含了seq1,可以不用同时开始或者同时结束
6. 序列的终点:seq.ended 序列是否已经结束
7. 如何表示连续的两次读写操作:$rose(penable) |-> (##[2:$] ($rose(penable)))
8. 下一次传输开始前某个值保持不变:判断到下一次传输的条件下,用past取出前一个的值与上次传输是否一致
四、内置的一些函数
1. $countbits(expression, a) 计算expression中数值为a的位数
2. $countones(expression) 计数表达式中为1的比特的个数
等同于$countbits(expression, `1)
3. $onehot(expression) 检查是否只有一个比特位为1
等同于$countbits(expression, `1)==1
4. $isunknown(expression) 检查是否有任意比特为 X或 Z.
等同于$countbits(expression, `X, `Z)!=0