概述
- 随着设计越来越大,要产生一个完整的激励来测试功能也变得越来越困难。定向激励的测试方法早已经无法满足检查功能完整性的要求。
- SoC的集成度提高带来的模块之间交互的复杂度也是指数攀升,这就使得无法预测接下来用户使用过程中会发生什么样的状况。
- 随机-约束,两个词组合在一起就构成了目前动态仿真验证的主流方法。
- 随机约束测试(CRT,Constrained-Random Test)即能够产生你感兴趣的、你想不到的的测试向量,通过回归测试、替随机种子的方式来提高单位测试用例的覆盖率收集效率。
- 随机测试带来的额外负担是环境的复杂度会提高,因为从环境组件上考虑不再只需要发送激励的组件,而且还包括监测器、比较器等。
- 随机测试带来的环境复杂度还包括由于对环境复用和测试复用带来的组件封装要求,这会使得代码量加大。
- 这种额外的代码量、环境集成要求也随之带来了更加灵活、更易集成复用的验证环境。
产生随机数
1 | module stim; |
约束随机变量
- 以上我们独立地生成一些随机数,在面向DUT的随机激励发生过程中,为了符合协议、满足测试需求,我们还需要添加一些约束。这些“约束”会使得变量朝着希望他们变化的方向去随机。不但如此,这些约束也会对变量与变量之间的关系生效。
- 我们需要一个“载体“去容纳这些变量以及它们之间的约束这个“载体”即是类(在SV中只能是类),而类的成员变量均可声明为“随机“属性,用rand或者randc来表示。
随机变量
任何类中的整型(bit/byte/int)变量都可以声明为rand/randc。
定长数组、动态数组、关联数组和队列都可以声明为rand/randc,可以对动态数组和队列的长度加以约束。
1
2
3rand bit [7:0] len;
rand integer data[]
constraint db{data.size==len;}指向对象的句柄成员,也可以声明为rand(不能被声明为randc),随机时该句柄指向对象中的随机变量也会一并被随机。
带有约束随机的类
1 | class Packet; |
修饰符rand和randc
- 对于rand修饰符,表示在可生成的范围内,每个值的可能性相同的(每次随机都从整个范围内随机选取)。
- 对于randc修饰符,它的值将会随机并且遍历其可取值范围(在整个范围内,每个数只可能出现一次)。
1
rand bit [7:0] y;
约束块
- 有用的激励不仅仅是随机值,变量之间也有着相互关系。
- 没有约束的随机变量会包含许多无效的和非法的值,这会使得有效激励的产生变得低效。
- 需要用包含一个或多个约束表达式的约束块定义这些相互关系。
- 约束块支持整形通过set操作符来设置它们的可取值范围。
- 除了成员集合设置(以下代代码均声明在类中),约束块也支持设置可取值的同时也为其设置随机时的权重。
1
2
3
4
5
6
7
8
9rand integer x,y,z;
constraint cl {x inside {3, 5, [9:15], [24:32], [y:2*y], z};} //可取范围:3、5、9-15、24-32、y-2y、z
rand integer a,b,c;
constraint c2 {a inside {b,c};}
integer fives[4]='{5,10,15,20};
rand integer v;
constraint c3{v inside {fives};} //可取范围:five数组的成员
权重分布
对于:=操作符,它们表示每一个值的权重是相同的。
对于:/操作符,它们表示权重会平均分配到每一个值。
1 | //操作符控制权重分布 |
唯一标识
- unique可以用来约束一组变量,使得其在随机后变量之间不会有相同的数值。
1
2
3
4
5rand byte a[5];
rand byte b;
rand byte excluded;
constraint u {unique {b, a[2:3], excluded};} //a[2], a[3], b和excluded在随机化之后将包含不相同的数值。
constraint exclusion {excluded==5;}
条件约束
- 可以使用if-else或者 ->操作符来表示条件约束。
1
2
3
4
5
6
7
8mode==little -> len<10;
mode==big -> len>100;
bit [3:0]a,b;
constraint c{(a==0)->(b==1);}
if(mode==little)
len<10; else if(mode==big)
len>100;
迭代约束
- foreach可以用来迭代约束数组中的元素,这些数组可以是长数组、动态数组、关联数组或者队列。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18class C;
rand byte A[];
constraint C1 { foreach (A[i]) A[i] inside{2,4,8,16}; } //A[]的成员在{2、4、8、16}中选取
constraint C2 { foreach (A[j]) A[j]>2*j; } //未限定A[]的size,则size默认是0,成员大小也是0
endclass
constraint {
{ foreach (A[i]) A[i] inside{2,4,8,16};
foreach (A[j]) A[j]>2*j;
A.size()<100 } //限定数组大小之后,用VCS可以仿真出来,questsim无法仿真(不同仿真器底层不同)
//数组缩减的方法做迭代约束
class C;
rand bit [7:0] A[];
constraint cl{A.size()==5;}
constraint c2{A.sum()<1000;}
endclass
A[0]+A[1]+A[2]+A[3]+A[4]<1000
函数调用
- 有时候在一些表达式中无法简单地来表述约束,可以在约束块中调用该函数来描述约束。
1
2
3
4
5
6function //例如要计算合并数组中的1
int count_ones(bit [9:0]w);
for(count_ones=0; W!=0; W=W>>1)
count_ones +=w &1'b1;
endfunction
constraint C1 {length ==count_ones)v);} //约束中调用函数计数
软约束
- 在没有soft描述时的约束,我们称之为硬约束,而带有soft描述是软约束。
- 软约束用来指定变量的默认值和权重。
- 如果用户在使用时,指定了外部约束对同一个变量做二次约束,用户定义了子类,也对同一个变量做二次约束时,那么硬约束可以软约束,并且不会导致随机数产生的失败。
1
2
3
4
5
6class Packet;
rand int length;
constraint deflt {soft length inside {32,1024};} //软约束 长度可选32和1024 如果有多个软约束采用就近原则
endclass
Packet p=new();
p.randomize() with {length==1512;} //硬约束 长度为1512 优先级高于软约束
内嵌约束
1 | class C1; |
local域指向
- 之前在使用内嵌约束随机时,对于同名的变量处在不同的域中可能会出现指向模糊的情况,之前我们已经给出了一种方法。
- 接下来我们可以通过local::的域索引方式来明确随机变量的指即local::指向的变量会在包含randomize()方法的对象中。
1
2
3
4
5
6class C;
rand integer x;
endclass
function int F(C obj, integer x=20);
F=obj.randomize() with {x < local::x;}; //索引当前文本域中的x,即function中的x
endfunction
随机控制
- rand_mode可以使能或者禁止随机变量,当随机数被禁止时,同普通变量一样,不参与随机化。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15class Packet;
rand integer source value, dest value;
... other declarations
endclass
int ret;
Packet packet a=new;
//关闭所有变量的随机化
packet a.rand_mode(0);
//使能souce_value的随机化
packet a.source_value.rand_mode(1);
ret=packet_a.dest_value.rand_mode();
randomize(source_value) //使用randomize,不管变量在定义的时候有没有rand属性,传入参数都可以直接随机化,并且原来定义时候的rand属性在有参数之后不起作用。
约束控制
- 类似于随机控制,一些约束块或者某个类的约束块集合都可以使用constraint_mode实现单个控制或者集体控制。
1
2
3
4
5
6
7
8
9
10class Packet;
rand integer source value;
constraint filterl {source value>2*m;}
endclass
function integer toggle_rand(Packet p); //实现反转
if(p.filterl.constraint_mode())
p.filterl.constraint_mode(0);
else p.filterl.constraint_mode(1);
toggle_rand=p.randomize();
endfunction
内嵌变量控制
- 在使用类的随机化函数randomize()时,如果伴有参数,那么只会随机化这些变量(参数优先级高于声明优先级),而其余变量无论是否之前被声明为rand/randc,都将不会参与到随机化当中。
1
2
3
4
5
6
7
8
9
10class CA;
rand byte x,y;
byte v,w;
constraint cl{x<v && y>w;};
endclass
CA a=new;
a.randomize(); //随机变量:x, y
a.randomize(x); //随机变量:x
a.randomize(v,w);//随机变量:v, w
a.randomize(w,x);//随机变量:w,x
思考问题
- 随机测试相比于定向测试,就你目前的认识,你认为有哪些优缺点?