随机化是我们DV强大的工具,帮助我们以极小的代价产生大量的随机组合,极大的加快了验证的收敛速度,但是有时候有些平时不太注意的细节点可能让我们的前期努力功亏一篑,甚至造成rtl bug延后到silicon测试才发现。以下便是笔者在工作中见到的一个随机化的坑,大家慢慢看,先来看一段code:
module my_lib(a,b);
input a;
output b;
assign b=$urandom(0,1)?a:0;
endmodule
module top(c,d);
input [7:0] c;
ouput [7:0] d;
c = $urandom();
genvar i;
generate
for(i=0;i<8;i++) begin:gen_lib
my_lib my_lib_inst(.a(c[i],.b(d[i])));
end
endgenerate
endmodule
代码功能很简单,my_lib是公共的code,功能就是随机化b,random选择a或者0,top就是把一个8bits信号做同样的随机化,用my_lib在实现单个bit的随机化。我的本意是想随机化的d的每个bit,但是上面的code能实现我的想法吗,这里面有什么隐藏的bug吗?
涉及到的随机化和random stability,有一个博主的文章写的很详细,可移步阅读:
RNG与Random stability_urandom_range_kevindas的博客-CSDN博客
重点内容总结如下:
1. 每个module 或者interface instance的时候都会有一个初始RNG,每个RNG都由相同的default seed产生,所以多次instance之后调用$urandom得到的结果是一样的.(Thread stability)
2. 我们在class里面常用的$urandom_range(),或者std::randomize以及obj.randomize在每次new的时候都会由parent thread随机产生下一个RNG,所以每次new之后再用$urandom随机的结果会不一样。(Object stability)
3. $random的default初始seed是0,并且不受EDA tool给的rand seed影响,但是可以通过$random(seed)来手动改变seed,参数是inout,调用不仅返回rand值,还会生成下一次rand的RNG。
所以上面code的结果c只有两种值:8{a}或者0,因为8次instance对应的my_lib的随机值都是一样的,要想8次随机完全独立不一样,需要把$urandom_range改成$random,不过这样会引入另外一个,$random每次都是从RNG0开始随机,并且随机序列一样,这样就会导致regression的结果都是一样,不受seed控制,需要把随机seed带入,并且在一开始0时刻调用一次$random(rand_seed)来改变随机序列。
所以修改之后的代码应该是这样:
module my_lib(a,b);
input a;
output b;
assign b=($random%2)?a:0;//多次例化随机结果不一样了
endmodule
module top(c,d);
input [7:0] c;
ouput [7:0] d;
c = $urandom();
initial begin
int rseed;
$value$plusargs("ntb_rand_seed=%0d",rseed);//以VCS为例
void'($random(rseed));//改变不同seed的随机序列,多次仿真结果不一样
end
genvar i;
generate
for(i=0;i<8;i++) begin:gen_lib
my_lib my_lib_inst(.a(c[i],.b(d[i])));
end
endgenerate
endmodule
也可以改my_lib,修改如下:
module my_lib(a,b);
input a;
output b;
initial begin
int rseed;
process _process;
_process = process:self;//获取进程
$value$plusargs("ntb_rand_seed=%0d",rseed);//以VCS为例
void'($random(rseed));//改变不同seed的随机序列,多次仿真结果不一样
_process.srandom(rseed);//进程随机
end
assign b=$urandom_range(0,1)?a:0;//多次例化随机结果不一样了
endmodule
module top(c,d);
input [7:0] c;
ouput [7:0] d;
c = $urandom();
genvar i;
generate
for(i=0;i<8;i++) begin:gen_lib
my_lib my_lib_inst(.a(c[i],.b(d[i])));
end
endgenerate
endmodule
几种随机的区别:
$random(seed)—— 系统随机化调用函数,返回32bit有符号数;seed参数可选,并且seed是inout类型,随机之后不仅返回随机数,seed也会更新。但是缺省情况下是从seed=0开始随机
$urandom_range()—— 系统随机化调用函数,返回指定范围内的无符号随机整数;
srandom(seed) —— 对象和进程的随机化播种方法,需手动添加种子seed;