带有随机变量的简单类
与之前定义的类不一样的地方,这里的类都具有随机属性 。这些随机属性,在类例化以后,可以通过类的随机化函数randomize()被随机化。
注意:
randomize()随机化函数是系统预定义的,任何一个类都可以调用这个函数。随机化函数有返回值,随机化成功是1,失败是0。
随机化失败的原因很大可能是随机约束发生了冲突。
class Packet;
//随机变量
rand bit [31: 0] src, dst, data[8];
randc bit [ 7:0] kind ;
//src的约束
constraint c {src > 10;
src <15;}
//在类 Packet 约束块中,要求成员变量src大于10同时小于15
//其他没有被约束的变量,随机值范围是它们的理论值范围
endclass
Packet p;
initial begin
p =new () ;//产生一个包
if (!p.randomize())
$finish;
transmit(p);
end
约束块
有用的激励不仅会约束随机变量,变量之间也有着相互约束关系。
没有约束的随机变量会包含许多无效的和非法的值,这会使得有效激励的产生变得低效。
带有随机变量的类需要用一个或者多个约束块来描述变量之间的关系。
约束块有很多形式。
约束形式——成员集合(inside)
约束块支持整形通过inside操作符来设置它们的可取值范围。
这些可取值范围通过组合的形式,单一指定或者依照范围指定
取值范围中的数值,可以由定值、变量、非组合型数组表示
rand integer x, y,Z;
constraint c1 {x inside {3,5,[9:15],[24:32],[y:2*y],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] ; }
约束形式——权重分布
除了成员集合设置,约束块也支持设置可取值的同时也为其设置随机时的权重。
- := 操作符,表示每一个值的权重是相同的。
- :/ 操作符,表示权重会平均分配到每一个值。
示例:
1、x在100,101,102,200和300的权重是1 - 1 - 1 - 2 - 5。
x dist { [100: 102] := 1,200 := 2,300 := 5}
2、x在100,101,102,200和300的权重是1/3 - 1/3 - 1/3 - 2 - 5。
x dist { [100: 102] :/ 1,200 := 2,300 := 5}
约束形式——唯一标识(unique)
unique可以用来约束一组变量,使得其在随机后变量之间不会有相同的数值。
示例:
a[2] , a[3], b和excluded在随机化之后将包含不相同的数值。
rand byte a[5];
rand byte b;
rand byte excluded;
//a[2] , a[3], b和excluded在随机化之后将包含不相同的数值
constraint u { unique {b, a[2:3],excluded} ; }
//excluded在随机化后,给与定值5
constraint exclusion { excluded == 5; }
//该对象在随机化时,应该同时满足这两个约束块的要求
条件约束
有时,约束是要满足条件的 。
条件约束使用的操作符:
- if-else
- ->
//在c1约束块中,对len的约束,取决于变量mode的数值
//如果mode为little,len < 10;如果mode为big,len >100
constraint c1 {
mode == little -> len < 10;
mode == big ->len > 100; }
//在c2约束块中,如果a被随机化为0,那么b就会被随机化为1
bit [3:0] a,b;
constraint c2 { (a == 0)->(b == 1); }
//c3和c1约束块作用相同
constraint c3 {
if (mode == little)
len < 10;
else if (mode == big)
len > 100 ; }
迭代约束
对于一些数组的约束,可以通过迭代的方式来进行约束数组中的每一个元素。
迭代约束的方法:
- foreach
- 数组的缩减方法
foreach
foreach可以用来迭代约束数组中的元素。
适用的数组:
- 定长数组
- 动态数组
- 关联数组
- 队列
示例:
class C;
rand byte A[] ;
//c1约束块,要求动态数组中的每一个元素,都应该在2,4,8,16中取值
constraint C1 { foreach (A[i])
A[i] inside {2,4,8,16};}
//c2约束块,要求动态数组的每一个元素都应该大于该元素索引值的2倍
constraint C2 { foreach (A[j])
A[j] >2*j; }
endclass
注意:
在上面的动态数组中,没有约束动态数组的大小,这一点比较危险。 对于动态数组的约束,应该关心数组的大小,以及每一个元素的数组。
数组的缩减
使用数组的缩减方法做迭代约束。
class C;
rand bit [7:0]A[] ;
//c1,要求A数组数组元素的个数为5
//c2,要求A数组元素总和<1000
//随机化时,要同时满足c1和c2,才能随机化成功
constraint c1 { A.size() = 5; }
constraint c2 { A.sum() < 1000; }
endclass
//A[0] +A[1] +A[2] + A[3] + A[4] <1000
函数调用
有时候在一些表达式中无法简单地来表述约束,使用函数调用的方式很有用。
示例:计算一个组合数组中的‘1’的个数
定义计算 一个组合数组中的‘1’的个数的函数 count_ones
function 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描述时的约束,称之为硬约束
软约束适用的场景:
- 外部约束对同一个变量做二次约束
- 用户定义了子类,也对同一个变量做二次约束时,硬约束和软约束没有冲突时,可以共同综合
硬约束和软约束有冲突
两个约束发生了冲突,优先遵循硬约束。
硬约束可以“覆盖”软约束,并且不会导致随机数产生的失败。
示例:
class Packet;
rand int length;
//软约束 deflt,要求length长的范围是32或者1024
constraint deflt {soft length inside {32,1024} ; }
endclass
//例化该类
Packet p = new () ;
//做随机化时,通过外部嵌入约束,要求随机化时,length取值为1512(硬约束)
p.randomize() with { length == 1512;}
//此时两个约束发生了冲突,优先遵循硬约束。
//最后随机化依然成功,成员变量length会被随机成1512.