一、随机数函数
- $random()——平均分布,返回32位有符号随机数
- $urandom()——平均分布,返回32位无符号随机数
- $urandom_range()——指定范围内的平均分布
- $dist_exponential()——指数衰落
- $dist_normal()——钟型分布
- $dist_poisson()——钟型分布
- $dist_uniform()——平均分布
二、约束的技巧和技术
1、使用变量的约束
使用变量设定上限的约束
class bounds;
rand int size;
int max_size = 100;
constraint c_size{
size inside {[1:max_size]};
}
endclass
带有权重变量的dist约束
typedef enum{READ8,READ16,READ32} read_e;
class ReadCommands;
rand read_e read_cmd;
//可以通过修改权重,来改变命令产生的概率,置0的话相当于禁止某些命令的产生
int read8_wt = 1, read16_wt = 1, read32_wt = 1;
constraint c_read{
read_cmd dist {
READ8:=read8_wt,
READ16:=read16_wt,
READ32:=read32_wt
};
}
endclass
2、使用非随机值
可以设置固定激励值,来得到想要的结果。设定的固定激励值可以违反相关的约束。
用rand_mode禁止变量的随机化
class Packet;
rand bit[7:0] length,payload[];
constraint c_valid {
length > 0;
payload.size == length;
}
function void display(string msg);
$display("\n% s", msg);
$write("Packet len=%0d,payload size=%0d,bytes=",length, payload.size());
for(int i = 0; (i < 4 && i < payload.size(); i++)
$write("%0d",payload[i]);
$display;
endfunction
endclass
Packet p;
initial begin
p = new();
assert(p.randomize());
p.display("Simple randomize");
p.length.rand_mode(0); //设置包长为非随机值
p.length = 42; //设置包长为常数
assert(p.randomize()); //然后再随机化payload
p.display("Randomize with rand_mode");
end
3、用约束检查值的有效性
在随机化一个对象并改变它的变量的值后,可以通过检查值是否遵守约束来检查对象是否仍然有效。
4、随机化个别变量
随机化类里的一部分变量
class Rising;
byte low; //非随机变量
rand byte med,hi; //随机变量
constraint up{
low < med;
med < hi;
}
endclass
initial begin
Rising r;
r = new();
r.randomize(); //随机化med,hi,但不改变low
r.randomize(med); //随机化med
r.randomize(low); //也可以传递一个非随机变量,随机化low
5、打开或关闭约束
可以使用条件操作符->或者if-else来构建由非随机变量控制的约束。
把条件约束当成case语句使用
class Instruction;
typedef enum{NOP,HALT,CLR,NOT} opcode_e;
rand opcode_e opcode;
bit[1:0] n_operands;
...
constraint c_operands{
if(n_operands == 0)
opcode == NOP || opcode == HALT;
else if(n_operands == 1)
opcode == CLR || opcode == NOP;
...
}
endclass
使用constraint_mode打开或关闭约束
//当约束表达式越来越多,越来越复杂时,通常对每一种指令建立一套独立的约束,在使用时关闭其他所有的约束。
class Instruction;
typedef enum{NOP,HALT,CLR,NOT} opcode_e;
rand opcode_e opcode;
bit[1:0] n_operands;
...
constraint c_no_operands{
opcode == NOP || opcode == HALT;
}
constraint c_one_operand{
opcode == CLR || opcode == NOP;
}
endclass
Instruction instr;
initial begin
instr = new();
//产生没有操作数的指令
instr.constraint_mode(0); //关闭所有的约束
instr.c_no_operands.constraint_mode(1);
assert(instre.randomize());
//产生只有一个操作数的指令
instr.constraint_mode(0);
instr.c_one_operands.constraint_mode(1);
assert(instr.randomize());
end
三、迭代和数组约束
1、数组的大小
约束动态数组的大小
class dyn_size;
rand logic[31:0] d[];
constraint d_size{
d.size() inside {[1:10]};
}
endclass
2、元素的和
随机脉冲类
parameter MAX_TRANSFER_LEN = 10;
class StrobePat;
rand bit strobe[MAX_TRANSFER_LEN];
constraint c_set_four{
strobe.sum() == 4'h4;
}
endclass
initial begin
StrobePat sp;
int count = 0;
sp = new();
assert(sp.randomize());
foreach(sp.strobe[i]) begin
@bus.cb;
bus.cb.strobe <= sp.strobe[i];
if(sp.strobe[i])
bus.cb.data <= data[count++];
end
end
3、产生具有唯一元素值的数组
使用foreach产生唯一的元素值
//循环产生过多的独立的约束,会降低仿真的速度
class UniqueSlow;
rand int[7:0] ua[64];
constraint c{
foreach(ua[i])
foreach(ua[j])
if(i!=j)
ua[a]!=ua[j];
}
endclass
使用randc辅助类产生唯一的元素值
class randc8;
randc bit[7:0] val;
enclass
class LittleUniqueArray;
bit[7:0] ua[64]; //每一个元素具有唯一值的数组
function void pre_randomize;
randc8 rc8;
rc8 = new();
foreach(ua[i]) begin
assert(rc8.randomize());
ua[i] = rc8.val;
end
endfunction
endclass
唯一值的发生器
class RandRange;
randc bit[15:0] value;
int max_value;
function new(int max_value = 10);
this.max_value = max_value;
endfunction
constraint c_max_value{
value < max_value;
}
endclass
产生元素具有唯一值的随机数组的类
class UniqueArray;
int max_array_size,max_value;
rand bit[7:0] a[]; //每个元素具有唯一值的数组
constraint c_size{
a.size() inside {[1:max_array_size]};
}
function new(int max_array_size = 2, max_value = 2);
this.max_array_size = max_array_size;
//如果max_value小于数组的大小,说明数组里有重复的值,要调整max_value
if(max_value < max_array_size)
this.max_value = max_array_size;
else
this.max_value = max_value;
endfunction
//为数组a[]填充唯一值
function void post_randomize;
RandcRange rr;
rr = new(max_value);
foreach(a[i]) begin
assert(rr.randomize());
a[i] = rr.value;
end
endfunction
function void display();
$write("Size: % 3d:", a.size());
foreach(a[i])
$write("%4d", a[i]);
$display;
endfunction
endclass
program automatic test;
UniqueArray ua;
initial begin
ua = new(50);
repeat(10) begin
assert(ua.randomize());
ua,display();
end
endprogram
4、随机化句柄数组
和整数数组不同的是,句柄数组需要在随机化前分配所有的元素,因为随机求解器不会创建对象。在随机化时,动态句柄数组的大小可以保持不变或者减小,但是不能增加。
parameter MAX_SIZE = 10;
class RandStuff;
rand int value;
endclass
class RandArray;
rand RandStuff array[];
constraint c{
array.size() inside {[1:MAX_SIZE]};
}
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