SystemVerilog TIPs

SystemVerilog(8-9)

定义

1.covergroup

定义范围:module/program/interface/class/package等结构体

语法:

1
2
3
4
5
6
covergroup name [(<list_of_args>)][<clocking_event>];
<cvoer_option>;
<cover_type_option>;
<cover_point>;
<cover_cross>;
endgroup [:identifier]

2.coverpoint

定义范围:covergroup内

1
2
3
4
5
6
7
8
9
10
11
[覆盖点名称 :]coverpoint <表达式> [iff(<表达式>)]
{
[<coverage_option>]
bins name [[]] = {value_set}[iff(<expr)];
bins name [[]] = (transitions)[iff(<expr)];
bins name [[]] = {default}[sequence][iff(<expr)];
ignore_bins name [[]] = {value_set};
ignore_bins name [[]] = (transitions);
illegal_bins name [[]] = {value_set};
illegal_bins name [[]] = (transitions);
}

覆盖点内会有对应的一组分组柜 (bin),计数器可以是用户自定义的或者是自动创建的

采样方式(两种):

  • 法1:在covegroup后的<expr>使用@或wait自动采样
  • 法2:手动调用covergroup实例的sample()方法
  • iff主要做补充采样条件(常用于复位)

示例:

1
2
3
4
bit [1:0] so;
covergroup g4;
cover1:coverpoint s0 iff(!reset);//仅当reset为低电平,覆盖点cover1才对变量s0做统计
endgroup

3.bins 分组柜

定义范围:coverpoint内

4.cross 交叉覆盖点

定义范围:covergroup内(可以理解为另一种由coverpoint组合成的coverpoint)

定义:对两个或者多个覆盖点指定交叉覆盖点,交叉覆盖点是其定义中覆盖点成员的分类柜的所有组合情况

要点:覆盖点变量、覆盖点表达式、binsof结构

1
2
3
4
5
6
7
[交叉点名称 :]cross<cover_list> [iff(<expr>)]
{
bins name = binsof(binname) 操作符 binsof(binname) 操作符 ... [iff(expr)];
bins name = binsof(binname) intersect {value | [range]}[iff(expr)];
ignore_bins name = binsof(binname)...;
illegal_bins name = binsof(binnale)...;
}

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
//覆盖点变量交叉示例:
bit [3:0] a, b;
covergroup cov @(posedge clk);
aXb: cross a, b;
endgroup
//覆盖点表达式交叉示例:
bit [3:0] a,b,c;
covergroup cov2 @(posedge clk);
BC:coverpoint b+c;
aXb:cross a, BC;
endgroup
//交叉覆盖点中交叉分组柜的总数就是其定义的成员覆盖点分组柜的所有组合情况
bit [31:0] a_var;
bit [3:0] b_var;
covergroup cov3 @(posedge clk);
A:coverpoint a_var {bins yy[] = {[0:9]};}
CC: cross b_var, A;
endgroup
//binsof结构示例
bit [7:0] v_a, v_b;
covergroup cg @(posedge clk);
a:coverpoint v_a//a定义了4个分组柜
{
bins a1 = {[0:63]};
bins a2 = {[64:127]};
bins a3 = {[128:191]};
bins a4 = {[192:255]};
}
b:coverpoint v_b//b定义了4个分组柜
{
bins b1 = {0};
bins b2 = {[1:84]};
bins b3 = {[85:169]};
bins b4 = {[170:255]};
}
c:cross a,b//c定义了3个交叉分组柜
{
//c1其指定了覆盖点a中没有和数值范围100到200有交集的分组柜
bins c1 = !binsof(a) intersect {[100:200]};//4 cross products
//c2指定了交叉项中或者存在分组柜a2,或者存在分组柜b2
bins c2 = binsof(a.a2) || binsof(b.b2);//7 cross products
//c3定义了交叉项必须同时包括a1和b4
bins c3 = binsof(a.a1) && binsof(b.b4);//1 cross products
//其他可能在自动生成交叉分组柜中出现的但在本例中没有显示定义出来的交叉项,不是交叉覆盖点关心的对象,其是否被击中不会在任何统计中影响交叉覆盖点c
}
endgroup

例1:覆盖组cov中定义了两个4比特变量a和b的交叉覆盖点aXb,系统会自动为a和b两个变量分别创建两个覆盖点。每个覆盖点默认情况下是16个分组柜,那么因为a和b的分组柜之间存在256种组合,所以交叉覆盖点aXb就会自动产生256个分组柜

例2:BC就是事先定义好的对应表达式b+c的覆盖点,因为b+c应该是一个4比特的数值,所以可以为该覆盖点分配16个分组柜;而 a可以分配8个分组柜,最后交叉覆盖点aXb,总共可以分配128个分组柜,来表示a和b+c的各种组合情况

例3:我们对于变量 a_var只关心0到9十个数值,为此在覆盖点 A中显性的定 义了yy[0],yy[1],…yy[9]十个分组柜,作为交叉覆盖点CC中定义的成员分别是b_var和A。 系统会为变量b_var自动创建16个分组柜(auto[0],auto[1],…auto[15])。由于没有显示定义分组柜,系统会自动为交叉覆盖点CC分配交叉分组柜,其总数为:16*10=160;如下所示:

image-20221204212638720

为此,我们在定义的时候要小心使用交叉覆盖点,以免系统自动创建大量冗余的分组 柜,因为每个交叉分组柜都是一个计数器,频繁采样统计,会对仿真速度带来影响

补充概念:

交叉项——组成——>分组柜——组成——>交叉覆盖点

image-20221204222941413

SVA

5层语法结构

image-20221219140503897

  1. Assertion units(断言封装层,通过module/class/program/interface封装,从而实现重用)
  2. Directives(断言指示层,使用assert对特定properties检查,或对sequences行为检查;或者采用cover做统计)
  3. Properties(属性层,重要的封装方式,属性内部可定义蕴涵操作符:|->|=>
  4. Sequences(序列层,一种封装格式,有操作符时隙、重复、序列等等)
  5. Boolean Expressions(布尔表达式,与verilog相同)

操作符:

  • 时隙延时:##n,n表示延时n个时钟周期
  • 指定窗口:[m:n]
  • ##[m:n]一起用,如:##[1:5],表示后续事件在[1:5]周期内都成立,补充举例##[1:5] z
1
##[1:5]z 等效于:##1 z或##2 z或##3 z或##4 z或##5 z
  • 蕴含操作符:|->,|=>
    • |->:表示当前置表达式成立后同一时钟检查后置表达式
    • |=>:表示要延迟一个时钟,等效于 |-> ##1
    • 使用于property

使用示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//使用module封装的sva_3
module sva_test(input clk, req, ack);
property p2;
@(posedge clk) $rose(req) |-> ##[1:3] $rose(ack);
endproperty
sva_3: assert property(p2);
endmodule

//通过嵌入,在不同设计中重用sva_3
module testbench();
...
dut(req, ack, ...);
sva_test sva_ins(clk, req, ack);
...
endmodule

bind结构

像 sva_test这样用模块封装的断言能否不影响设计结构,直接探测到设计内部某个例化层次的接口上呢?答案是可以的。 下面我们将通过一个石头、剪刀、布的例子来讲述,如何采用bind这个结构,让SVA断言和设计分离

SV支持通过bind(绑定)将断言属性封装 模块绑定到任意的设计模块或者其特定例化中。这个功能可以实现以下几个目的:

  • 验证工程师可以最少的改动原有的设计代码和文件结构
  • 验证IP可以方便的绑定到特定的设计模块或者例化中
  • 对现有的断言没有任何语法上的影响,断言可以通过这种方式实现层次化的访问

bind可访问的接口:bind的能力不仅可以捕获例化模块接口上的信号,还可以探测到这个例化模块内部的信号

bind的语法结构如下:

1
bind 层次化实例(target) 断言载体(assertions_container) 断言实例(instance_name)

image-20221219203105845

  • target一般是设计对象,可以是模块名或者是例化名,也就是我们可以通过层次性的例化名访问设计内部例化
  • container是断言的封装载体,可以使用module、interface或者program来封装
  • 例化名就是本次绑定的例化名

bind定义位置:可以在module/interface或者编译层次内定义

针对所有例化的使用示例:

1
bind cpu fpu_props fpu_rules_1(a, b, c);
  • cpu是设计的模块名
  • fpu_props是一个封装了属性或断言的program/interface/module
  • fpu_rules_1是例化名
  • 例化端口(a, b, c)获取来自cpu模块的信号
  • cpu的每个例化都被绑定了这个断言

针对特定实例的使用示例:

1
bind top.cpu_instance1 fpu_props fpu_rules_1(a, b, c);

使用SVA的五点注意:

  • 断言描述的是设计的属性
  • 断言应该绝对正确
  • bind保证验证和设计分离
  • 验证关心顶层接口
  • 更多的使用OVL

系统函数

get_coverage():查询整个验证环境中的覆盖率

专题补充

覆盖率

SV复习(七)覆盖率:https://blog.csdn.net/whddddddddddd/article/details/126809571