赞
踩
目录
在做仿真的时候,难免会需要一些数据作为输入。有的时候对输入数据没什么要求,随便什么样的数据都行。这种情况下有两种办法:
$random 是Verilog提供的一个随机数生成系统任务,调用该任务后,将会返回一个32bit的integer类型的有符号的值。其调用格式有3种:
$random与$random()用起来方法和结果都是一样的,可以写一个小TB测试一下:
- `timescale 1ns / 1ns
-
- module random_test();
-
- reg [31:0] rand_data; //定义一个32位数据
-
- //每10ns产生一个随机数
- initial begin
- rand_data = 0;
- repeat(5) begin
- #10 rand_data = $random;
- end
- #5 $finish;
- end
-
- endmodule
上面的TB文件要做的事很简单:每隔10ns生成一个随机数,重复5次。其结果如下:
可以看到生成了5个32bit 的随机数,有整数也有负数。
接下来我们把上面的TB中的系统任务 $random替换成$random()的,其他不变,再看看仿真结果:
和之前的结果是一致的,这说明$random替换成$random()其实用起来效果是一样的,所以我们一般都用$random。
$random的返回值是一个32位的整数,但是有时不见得需要这么大的数。如果希望随机数的值能固定在某个范围,那么可以这么使用:$random%b;那么生成的随机数的范围就是 [ ( -b+1 ) : (b- 1 ) ]。 这其实就是对b取余,那可不就是把范围给框住了嘛!
同样的,用上面的TB测试一下,同时多生成几个随机数方便对比(除数用10,生成范围[-9:9]):
- `timescale 1ns / 1ns
-
- module random_test();
-
- reg [31:0] rand_data; //定义一个32位数据
-
- //每10ns产生一个随机数
- initial begin
- rand_data = 0;
- repeat(10) begin
- #10 rand_data = $random%10;
- end
- #5 $finish;
- end
-
- endmodule
其结果如下:
生成的值都在范围[-9:9]内(注意有几个重复的)。
此外,如果我们希望只生成正数范围内的随机数,那么可以这么使用:{$random}%b;那么生成的随机数的范围就是 [ 0 : (b - 1 ) ]。
还是用上面的TB测试下正数范围的随机数生成结果【0:9】的效果。看下仿真结果:
嗯很好,结果已经全是【0:9】范围内的数了。
先别说其他的,直接用modelsim仿真一下下面的模块:生成10次【0:9】范围内的随机数:
- `timescale 1ns / 1ns
-
- module random_test();
-
- reg [31:0] rand_data; //定义一个32位数据
-
- //每10ns产生一个随机数
- initial begin
- rand_data = 0;
- repeat(10) begin
- #10 rand_data = {$random}%10;
- end
- #5 $finish;
- end
-
- endmodule
把结果记录下来:
然后把modelsim关了(甚至可以把电脑重启一下),喝杯卡布奇诺休息5分钟,刷刷哔哩哔哩、摸摸鱼。
然后重新打开modelsim,对上面的模块重新进行仿真,再把结果记录下来:
咦?奇怪?怎么两次仿真结果是一样的呢?说好的随机数生成函数呢?这他喵的也不随机啊?
实际上,$random并不是一个真正意义上的随机数生成函数,如果我们每次仿真调用它的时间一致其实是种子seed一致,那么其生成的随机数就是一致的。
在上面的仿真中,我们省略了seed种子这一参数,由仿真工具默认生成,而仿真工具生成种子是根据仿真时间来定的。所以在我们每次进行仿真时,其实在同一时刻都是在调用相同的seed,所以仿真结果一致也不奇怪了。
忘了说,$random中的seed数据类型可以是reg,integer或者time。
接下来,我们改一下TB,加上seed:
- `timescale 1ns / 1ns
-
- module random_test();
-
- reg [31:0] rand_data; //定义一个32位数据
-
- //每10ns产生一个随机数
- initial begin
- rand_data = 0;
- repeat(10) begin
- #10 rand_data = {$random(1)}%100;
- end
- #5 $finish;
- end
-
- endmodule
第1次我们用 1作为seed,看看结果:
由于每次都使用1作为seed,所以10次生成的随机数都是68(0是初始值,不是随机生成的)。
把seed改成10,结果如下:
由于每次都使用10作为seed,所以10次生成的随机数都是48(0是初始值,不是随机生成的)。
所以,如果您希望每次仿真都有最好的随机性,那么最好都每次都改一下seed。
平常的仿真中调用随机数生成函数的常用用法是:
输入 data_in,位宽【a-1:0】,即位宽a,其值范围2^a,Verilog语法即2**a; //2**a表示2的a次方。
所以如果需要模拟data_in的随机输入,通常这样调用:data_in = {$random}%(2**a);
比如:
input [3:0] data_in; //其值范围为2进制0000~1111(即十进制0-15),
data_in = {$random}%(2**4); //即data_in = {$random}%16),生成的随机数范围为0-15,完美覆盖输入数据的全部范围。
参考资料1:IEEE Standard for Verilog® Hardware Description Language(IEEE Std 1364™-2005)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。