当前位置:   article > 正文

Verilog的随机数系统任务----$random_verilog random

verilog random

目录

        概述

        $random与$random()

        $random(seed)

        常用用法

        总结与参考


概述

        在做仿真的时候,难免会需要一些数据作为输入。有的时候对输入数据没什么要求,随便什么样的数据都行。这种情况下有两种办法:

  • 随便编写一些数据,但数据量一大麻烦不说,还费脑子
  • 使用Verilog提供的随机数生成系统任务$random来帮助生成大量的随机数,一个系统任务统统搞定!

        $random 是Verilog提供的一个随机数生成系统任务,调用该任务后,将会返回一个32bit的integer类型的有符号的值。其调用格式有3种:

  • $random;
  • $random();
  • $random(seed);

$random与$random()

        $random$random()用起来方法和结果都是一样的,可以写一个小TB测试一下:

  1. `timescale 1ns / 1ns
  2. module random_test();
  3. reg [31:0] rand_data; //定义一个32位数据
  4. //10ns产生一个随机数
  5. initial begin
  6. rand_data = 0;
  7. repeat(5) begin
  8. #10 rand_data = $random;
  9. end
  10. #5 $finish;
  11. end
  12. 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]):

  1. `timescale 1ns / 1ns
  2. module random_test();
  3. reg [31:0] rand_data; //定义一个32位数据
  4. //10ns产生一个随机数
  5. initial begin
  6. rand_data = 0;
  7. repeat(10) begin
  8. #10 rand_data = $random%10;
  9. end
  10. #5 $finish;
  11. end
  12. endmodule

                

        其结果如下:

         生成的值都在范围[-9:9]内(注意有几个重复的)。

        此外,如果我们希望只生成正数范围内的随机数,那么可以这么使用:{$random}%b;那么生成的随机数的范围就是   [ 0 : (b - 1 ) ]。

        还是用上面的TB测试下正数范围的随机数生成结果【0:9】的效果。看下仿真结果:

         嗯很好,结果已经全是【0:9】范围内的数了。


$random(seed)

        先别说其他的,直接用modelsim仿真一下下面的模块:生成10次【0:9】范围内的随机数:

  1. `timescale 1ns / 1ns
  2. module random_test();
  3. reg [31:0] rand_data; //定义一个32位数据
  4. //10ns产生一个随机数
  5. initial begin
  6. rand_data = 0;
  7. repeat(10) begin
  8. #10 rand_data = {$random}%10;
  9. end
  10. #5 $finish;
  11. end
  12. endmodule

        把结果记录下来:

仿真结果1

        然后把modelsim关了(甚至可以把电脑重启一下),喝杯卡布奇诺休息5分钟,刷刷哔哩哔哩、摸摸鱼。

        

        然后重新打开modelsim,对上面的模块重新进行仿真,再把结果记录下来:

仿真结果2

        咦?奇怪?怎么两次仿真结果是一样的呢?说好的随机数生成函数呢?这他喵的也不随机啊?

        实际上,$random并不是一个真正意义上的随机数生成函数,如果我们每次仿真调用它的时间一致其实是种子seed一致,那么其生成的随机数就是一致的。

        在上面的仿真中,我们省略了seed种子这一参数,由仿真工具默认生成,而仿真工具生成种子是根据仿真时间来定的。所以在我们每次进行仿真时,其实在同一时刻都是在调用相同的seed,所以仿真结果一致也不奇怪了。

        忘了说,$random中的seed数据类型可以是reg,integer或者time。

        接下来,我们改一下TB,加上seed:

  1. `timescale 1ns / 1ns
  2. module random_test();
  3. reg [31:0] rand_data; //定义一个32位数据
  4. //10ns产生一个随机数
  5. initial begin
  6. rand_data = 0;
  7. repeat(10) begin
  8. #10 rand_data = {$random(1)}%100;
  9. end
  10. #5 $finish;
  11. end
  12. 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,完美覆盖输入数据的全部范围。


总结与参考

  • $random与$random()的用法、结果都是一致的
  • $random%b可以生成范围 [ ( -b+1 ) : (b- 1 ) ]内的随机数
  • {$random}%b可以生成范围 [ 0: (b- 1 ) ]内的随机数

        参考资料1:IEEE Standard for Verilog® Hardware Description Language(IEEE Std 1364™-2005)


推荐阅读
相关标签