随机约束测试(CRT)
当定向测试无法满足要求时,受约束的随机化测试(CRT)随之出现。定向测试集能找到你认为可能存在的bug,CRT方法通过随机激励,可以找到你都无法确定的Bug。
组成:随机数据包和种子
随机变量
通常和面向对象编程(OOP)同时使用。随机变量的声明使用关键字rand,randc
rand:随机值出现在指定范围的概率相同
randc:随机值周期出现在指定范围内,在上一次周期结束前不会出现重复的值。
约束constraint
在定义完随机变量后,可以对该随即变量的值进行约束。其声明方式为:
constraint name{
rand_value_expression;
}
采用约束块{}的形式,每个约束块都有其名字,块内为随机变量的约束表达式称为约束语句。
随机化函数randomize()
randomize()函数会对随机变量进行随机化操作,并返回。随机化成功则返回值为1,否则为0.
- 该函数无需自定义
- 如果括号内指定了随机变量,那么只会对该变量随机化
- 其他随机函数:$urandom(),返回32位无符号随机数;$urandom_range(max,min),指定随机范围
- 其他随机数函数详见绿皮书P153,不做过多介绍
约束语句
1.表达式
- 简单表达式,仅支持一个语句一个表达式,不能将两个表达式合并到一个语句中。
rand bit [7:0] lo,med,hi;
constraint bad{
lo<med<hi;
}
rand bit [7:0] lo,med,hi;
constraint bad{
lo<med;
med<hi;
}
- 等效表达式,约束块内只能包含表达式,不能进行赋值,所以如果要给随机变量赋一个固定值需要使用==
2.权重分布
使用操作符dist可以对增加某些值的随机概率。dist操作符带有一个值的列表以及相应的权重,中间用:=或:/分开
:=表示指定的值具有相同的权重
:/表示指定的数值均分权重,如[1:3]:/60 则是1,2,3均分60,即每个数值的权重是20
rand int src,dst;
constraint ctr_dist{
src dist {0:=40,[1:3]:=60}; //总权重220
src dist {0:/40,[1:3]:/60}; //总权重100
}
3.范围操作符inside
指定随机变量的取值范围,每个值的机会是相等的,inside {}集合里也可以使用变量
如果想选择集合外的值只需要对约束取反。
集合里面也可以使用数组/枚举,每个值的机会均等,即使一个值多次出现在数组里面
rand [6:0] src,dst;
rand int f;
int inf[5] = '{1,3,5,7,9,9,9};
constraint ctr_inside{
src inside {[0:100]}; //这里的范围左小右大
dst inside {[$:100],[20:$]}; //取交集
f inside inf; //在整型数组inf里面随机取值
}
4.条件约束
SV支持两种条件关系操作符:if-else和->
->可以产生和case操作符效果类似的语句块,它可以用于枚举类型的表达式。操作符前条件满足触发操作符后面的表达式,同时若满足操作符后面的表达式,仿真器会检查前面的条件是否满足。
5.双向约束
约束块内的语句是声明性代码,是并行的,所有约束同时有效。
SV中的约束是双向约束,它会同时计算所有的随机变量的约束,增加或删除任一个变量的约束会直接或间接影响所有相关变量的值的选取。
rand logic [15:0] r,s,t;
constraint c_bidir {
r < t;
s==r;
t < 30;
s > 25;
}
r,s,t的取值相互影响,需要满足所有约束条件
6.sovle...before
通常情况下约束语句是同时进行的。可以使用sovle...before声明随机变量的仿真器求解的先后顺序。sovle...before不会改变解的个数,只会改变各个值的概率分布。
7.控制约束块及随机变量
调用constraint_mode()函数可以打开或者关闭约束,调用方式如下
<handle>.<ctr_name>.constraint_mode()
关闭对应的约束块。也可以不指定约束块名,直接关掉对象所有的约束块。
【静态约束:当一个类中的两个或者两个以上约束块中有静态声明static时,使用该函数打开或关闭静态约束块时,其他约束块也会被关闭或打开】
打开或关闭随机变量:rand_mode()
<handle>.<value_name>.rand_mode()
8.内嵌约束
很多测试只会在代码的一个地方随机化对象,因此SV允许使用randomize() with { A;B;C;}来增加额外的约束。而with{}块使用的是类的作用域,无需自行添加索引对象。
9.使用变量的约束语句
在对随机变量进行约束时,约束语句如果采用变量,可以使约束易于修改。尤其是在使用dist对随机变量的值分配权重时,采用变量“赋值”可以修改成任意你希望得到的权重。
软约束
带有soft描述的约束块称为软约束,与之相对的则为硬约束。在对同一随机变量进行二次约束(如使用内嵌约束)时硬约束会覆盖软约束,这样就不会使约束发生冲突。
外部约束
同外部方法一样,约束块也可以使用外部定义的方式。甚至它可以定义在另一个文件中,从而在不同的测试里复用外部约束。外部约束对类的所有的实例都起作用,而内嵌约束仅影响一次randomize()调用。这种方法只能增加约束,而不能改变已有的约束,而且必须事先在原来的类里定义外部约束的原型(类似外部方法)。
扩展类的约束
在扩展类中定义的约束块名字与基类的约束名字相同,那么扩展的约束将取代基类的约束。
有符号类型变量的使用
在约束中使用带有符号类型的随机变量,可能会使求解器解出负数的情况,这种情况并不是我们期望的。因此一般使用无符号的数据类型,同时要注意变量的位宽,在计算表达式结果后会不会发生高位截断的情况,这种情况对于代码要求,仿真结果是否有影响。
随机化数组句柄
如果要产生多个随机对象,就需要建立随机句柄数组。在随机化前需要保证每个句柄对象非空。
class handle_array
rand class_name array[ ];
constraint ctr{对数组内的元素个数.size()进行约束}
function new
array = new[设置句柄个数];
foreach(array[i])
array[i]=new(); //对句柄分配对象,之后就可以使用随机化函数
endfunction
handle_array.randomize();