$random(seed)是verilog中最簡單的產生隨機數的系統函數。
在調用系統函數$random(seed)時,可以寫成三種樣式:1)$random,2)$random(),3)$random(seed)。下面分別說明:
1)$random
這是最簡單的一種寫法,略去了seed這個傳入參數,$random會使用一個默認的seed(這個默認值為0?)。也正因此,每次進行仿真時,$random產生的隨機數序列都是相同的。
2)$random()
這種寫法和寫法1)的作用是相同的,同樣是沒有給$random傳入seed。
3)$random(seed)
這種寫法與上面兩種不同,給$random傳入了參數seed,因此$random根據seed來產生隨機數。seed不同,產生的隨機數的序列也不同。而且,每執行一次$random(seed)產生一個隨機數,seed也自動更新一次。
下面討論seed的產生。
據我有限的知識,seed有兩種產生方式:4)直接賦值為一個確定數,5)利用系統函數$get_initial_random_seed獲得值。下面分別討論:
4)直接賦值
在一個initial塊中直接將seed變量寫成某值,如下面代碼:
integer seed;
reg [7:0] rand_num;
initial begin seed = 0; end
always @(posedge clk) begin rand_num <= $random(seed); end
在上面代碼中,seed初始值被賦為0(也可以是1或其它數),在第一個時鍾上升沿,rand_num取得的第一個隨機數就是$random(0)產生的,seed也隨即更新;在第二個時鍾上升沿時,rand_num取得第二個隨機數,是$random(更新后的seed)產生的,seed又隨即更新;如此下去。
值得注意的是,如果把seed賦值為0,那么利用$random(seed)產生的隨機數序列和直接執行$random產生的隨機數序列是相同的。這個結論是我根據經驗得出的。
5)seed = $get_initial_random_seed()
如下面代碼:
integer seed;
reg [7:0] rand_num;
initial begin seed = $get_initial_random_seed(); end
always @(posedge clk) begin rand_num <= $random(seed); end
在上面代碼中,利用系統函數得到的seed的值是1,此后seed更新后的值和$random(seed)產生的隨機數序列都和將seed直接賦值成1,利用$random(seed)產生隨機數的情況相同。這也是我根據經驗得出的結論。
我在網上沒有找到關於$get_initial_random_seed的詳細介紹。
下面討論仿真時如何改變seed的初值:
如果seed的初值是確定的,那么不論進行多少次仿真,產生的隨機數的序列總是確定的,就不能覆蓋更多的情況。因此在仿真時,要能夠改變seed的初值。目前我所知道的改變seed的初值有兩種方法:6)修改代碼;7)采用deposit方式。下面分別介紹:
6)修改代碼
這種方式最直接,缺點是每次要修改seed時都需要重新編輯一遍代碼。
比如,第一次仿真時,代碼寫成下面的樣子:
integer seed;
reg [7:0] rand_num;
initial begin seed = 0; end
always @(posedge clk) begin rand_num <= $random(seed); end
而第二次仿真時,想修改seed的初值,就寫成下面的樣子:
integer seed;
reg [7:0] rand_num;
initial begin seed = 1; end
always @(posedge clk) begin rand_num <= $random(seed); end
7)采用deposit的方式
這種方式比較靈活,不必修改代碼,也不必重新編譯,直接修改輸入到仿真軟件的命令即可。
下面是最簡單的一個命令:
deposit top.seed 2
run 125ns
exit
上面命令的意思是,將信號(或變量)seed的初值設成1,然后開始仿真,仿真時間為125ns,然后結束仿真。
deposit是在仿真開始之前起作用的(如果沒有給deposit加上其它時間方面的條件),而且它只是將某個信號的初始值設為某一個數(可以是確定數,也可以是隨機數),此后便不再干預該信號的值。如果仿真開始后有別的條件或語句改變該變量的值,則該變量就變成改變后的值。
如果代碼按下面的樣子寫:
integer seed;
reg [7:0] rand_num;
initial begin seed = 1; end
always @(posedge clk) begin rand_num <= $random(seed); end
我們來看一下,在仿真開始之前deposit將seed賦值為2,然而仿真開始后的0ns時刻,initial塊又將seed賦為1,因此相當於deposit沒有起到預期的作用。我們想要的是,seed的初值為2,$random(2)產生一個隨機數后,seed再由2變成其它的數;而不是$random(1)產生一個隨機數,然后seed又由1變成其它的數。
為了達到我們的預期目的,要把deposit命令改成下面的樣子:
deposit top.seed 2 -after 1ns
run 125ns
exit
在仿真開始的0ns時,initial塊執行,將seed設為1。加上"-after 1ns"后,deposit命令就會在仿真開始后的1ns時起作用,把seed的值改為2,然后作用於第一次$random(seed)的執行,然后seed再更新。
綜上討論,我得出以下結論:
1. 利用$random產生隨機數時最好利用上seed參數,即寫成$random(seed)樣式。
2. 沒有必要利用$get_initial_random_seed()函數給seed賦值,直接寫成一個值即可,像4)一樣。
3. 建議用deposit的方式在仿真時改變seed的初值,使$random(seed)產生不同的隨機數序列