随机化
一、随机变量类型
随机化变量以及随机约束都只能在类class中声明
。
1.1.rand与randc随机变量
1)、使用关键字rand声明随机变量,随机变量的值在指定范围内均匀分布;如果不添加约束,随机变量可以是指定有效范围内的任何值。
rand bit[7:0] y; //y为8bit无符号整形数,取值范围:0~255, 每个数出现的概率都为1/256
2)、使用关键字randc声明周期性随机变量,取值按照声明的有效范围周期性出现,且数据类型只可以是bit或者enum型。
randc bit[1:0] y; //y为2bit无符号整形数,取值范围:0~3, 在一个周期内必然会产生0、1、2、3四个数,顺序不定
注:rand 理解为有放回抽样;randc 无放回抽样。
1.2.constraint指定约束范围
使用关键字constraint来添加约束语句块,指定随机变量的取值范围,或者各个变量之间的相互关系。
约束块不像是自上而下执行的程序性代码,它们是声明性代码,是并行的,所有的约束表达式同时有效。
class date;
rand bit [2:0] month;
rand bit [4:0] day;
rand int year;
constraint c_date{
month inside {[1:12]};
day inside {[1:31]};
year inside {[2010:2030]};
}
endclass
二、随机约束操作
2.1.声明约束(>、<、=、>=、<=)
2.2.范围约束(inside)
使用$指定最大值和最小值。
rand bit [6:0] b; //0 <= b <= 127
rand bit [5:0] e; //0 <= e <= 63
constraint c_range {
b inside {[$:4], [20:$]}; //0<= b <=4 || 20 <= b <=127
e inside {[$:4], [20:$]}; //0<= b <=4 || 20 <= b <=63
2.3.权重分布约束(dist)
2.4.条件约束(if-else; ->)
class BusOp;
...
constraint c_io {
(io_space_mode) -> addr[31] == 1'b1;
}
//->操作符可以产生和case操作符类似效果的语句块,可以用于枚举类型的表达式。->与if-else约束可以相互转化。
constraint c_io_if {
if(io_space_mode)
addr[31] == 1'b1;
}
class BusOp;
...
constraint c_len_rw {
if(op == READ)
len inside {[BYTE:LWRD]};
else
len == LWED;
2.5.双向约束
对于约束而言,是双向约束,是一种声明性质的代码,并行的,所有约束表达式同时有效。
rand logic [15:0] r, s, t;
constraint c_bidir {
r < t;
s == r;
t < 30;
s > 25;
}
//结果见表6.1
2.6.内嵌约束randomize ( )with{ }
SV允许使用randomise( )with{}
来增加额外的约束,这和在类里面增加约束是等效的
注意:
-
在with{}语句里,SV使用了类的作用域,所以在上例中使用了addr变量,而不是t.addr。
-
在使用randomise()with语句时常犯的错误就是使用()而不是{}内嵌的约束。
-
记住,约束块应该使用{},内嵌约束也应该使用{},{}用于声明性的代码。
2.7.solve…before约束
前面的约束 (符号约束、inside约束、条件约束、内嵌约束)条件下,其随机值出现的概率是均等的。
**randc类型变量不被允许使用solve…before约束;**这个也好理解,无放回怎么保证每个值的特定概率。
class transaction;
rand bit a;
rand bit[1:0] data; //data 取值0,1,2,3
constraint c1{ a -> data==3'h3; //条件约束 a =1,那data=3
solve a before data;} //在给出data随机值之前先给出a的随机值
endclass
module gen_data;
initial begin
transaction tr=new() ;
for(int i=0; i<10; i++ ) begin
tr.randomize() ;
$display("a= %0d, data= %0d",tr.a, tr.data) ;
end
end
endmodule
打印结果如下:
a= 1, data= 3;
a= 0, data= 2;
a= 0, data= 0;
a= 0, data= 1;
a= 1, data= 3;
a= 0, data= 2;
a= 1, data= 3;
a= 0, data= 3;
a= 0, data= 1;
a= 0, data= 1;
a | data | 概率 |
---|---|---|
0 | 0 | 1/2*1/4 = 1/8 |
0 | 1 | 1/2*1/4 = 1/8 |
0 | 2 | 1/2*1/4 = 1/8 |
0 | 3 | 1/2*1/4 = 1/8 |
1 | 3 | 1/2*1 = 1/2 |
三、 随机化函数
- $random —— 系统随机化调用函数,返回32bit有符号数;
- $urandom() —— 系统随机化调用函数,返回32bit无符号数;
- $urandom_range()——
系统
随机化调用函数,返回指定范围内的无符号随机整数; - srandom() ——
对象
和线程(手动添加种子seed)的随机化方法; - randomize() ——
对象
的随机化方法;
- 调用randomize( )函数可以为对象中的所有随机变量赋值,随机变量的值要符合约束;
- randomize( )函数成功时,返回1,失败时返回0。如果随机变量没有添加约束,那么产生的值是有效范围内的任何值。
class Rising;
byte low; //未被随机约束变量
rand byte med, hi; //随机化的变量,8位有符号值
constraint up
{ low < med; med < hi;}
endclass
initial begin
Rising r;
r = new();
r.randomize(); // 随机化hi,但是不改变low
r.randomize(med); // 只随机化med
r.randomize(low); // 只随机化low
end
上述代码中,例化了r之后,先调用r.randomize(low),那么low,med和hi的组合值可能是下面哪一组?
(A)low = -1,med=0, hi=0
(B)low = -1,med=1, hi=2
(C)low = 报错,med=0, hi=0
(D)low = 报错,med=null, hi=报错
此时 只随机low,而med和hi不被随机。 C
注:low 没有被rand 修饰也能被随机。
3.1.关闭或打开随机变量与约束
constraint_mode()函数打开或关闭约束
值 | 含义 | 描述 |
---|---|---|
0 | OFF | 将约束语句块 设为非激活态(INACTIVE),constraint约束将不起作用 |
1 | ON | 将约束语句块 设为激活态(ACTIVE),constraint约束将起作用 |
class packet();
rand int src, dst;
constraint filter {src>2*dst;}
endclass
function int toggle_rand(Packet p);
if(p.filter.constraint_mode() == 1)
p.filter.constraint_mode(0); //关闭约束
else
p.filter.constraint_mode(1); //打开约束
toggle_rand = p.randomize(); //随机化返回函数值
endfunction
rand_mode()函数可以打开或关闭随机变量
值 | 含义 | 描述 |
---|---|---|
0 | OFF | 将随机变量 设为非激活态(INACTIVE),不能通过randomize()函数随机化赋值 |
1 | ON | 将随机变量 设为激活态(ACTIVE),可以通过randomize()函数随机化赋值 |
四、数组的约束
4.1.动态数组的随机化
在约束随机标量 的同时,我们还可以对随机化的数组进行约束
class dyn_size;
rand logic [31:0] d[]; //随机化d[]数组;
constraint d_size (d.size() inside {[1:10]};) //调用d.size对数组长度范围进行约束
endclass
动态数组分别可以对其长度和内容做随机化处理。此外,还可以通过在约束中结合数组的其它方法sum(), product(), and(), or()和xor()。例如要求随机出来的数组 元素满足(1)个数在1-8 之间;每个数组的数值大小在1-255之间;每个数组的求和要小于1024。
class good_sum5;
rand uint len[];
constraint c_len{
foreach (len[i]) len[i] inside {[1:255]};
len.sum() < 1024;
len.size() inside {[1:8]};
}
4.2. 产生唯一元素的数组
class UniqueSlow;
rand bit [7:0] ua[64];
constraint c {
foreach (ua[i]) //对数组中每一个元素操作
foreach (ua[j])
if(i != j) //除了元素自己
ua[i] != ua[j]; //和其它元素比较
}
使用randc变量辅助生成唯一元素,无放回约束。
class randc8;
randc bit [7:0] val; //随机变量的值的范围为0~255,每一次randmize的256次值都不相同
endclass
class LittleUniqueArray;
bit [7:0] ua [64]; //定义一个含有64个元素的数组
function void pre_randomize();
randc8 rc8;
rc8 = new();
foreach (ua[i]) begin
assert(rc8.randomize()); //从256个元素中随机化64次,每次随机化的值都不同
ua[i] = rc8.val; //之后将随机化后的值赋值给数组
end
endfunction
endclass
pre_randomize主要的功能是:
LittleUniqueArray lua = new();
lua.randmozie();
在外部声明句柄lua, 通过句柄调用函数lua.randomize()函数时,先调用pre_randomize,其作用就是把每个值后复制到每个数组中,因为LittleUniqueArray中没有元素被声明为rand。
4.3. 随机化句柄数组
数组里面的每一个元素都指向一个对象,这就是句柄数组。
parameter MAX_SIZE = 10;
class RandStuff;
bit[1:0] value = 1;//没有rand,和绿皮书不一样
endclass
class RandArray;
rand RandStuff array[];//不要忘记使用rand
constraint c {
array.size() inside
{[1:MAX]};
}
function new();
//分配最大容量
array = new[MAX_SIZE];
foreach (array[i])
array[i] = new();
endfunction
endclass
RandArray ra;
initial begin
//构造数组所有对象
ra = new();
//随机化数组,但是可能会减小数组
assert(ra.randomize());
foreach (ra.array[i])
$display(ra.array[i].value);
end
问:ra.randomize() with {array.size == 2}的合法求解是多少呢?
分析ra.randomize随机化函数, 首先随机化句柄的个数为2;同时由于 rand RanfStuff array[];语句,因此还需要随机化句柄中的动态数组元素。句柄为randomize表明句柄指向的类中变量,但本例中类中的变量违背randomize修饰,因此该值一直为1。
注:句柄不同悬空。开始要对变量数组分配最大容量,每次new一次对象,让对象中变量得到随机化
五、随机控制
或者使用随机树。
参考: