1、對於信號幾種賦值方式的區別:
1 logic [15:0] frame_n; 2 3 rtr_io.cb.frame_n <= 1;//port0=1,port1~15=0 4 5 //如果想對所有的信號賦值,用下面這種方法 6 rtr_io.cb.frame_n <= '1;//port0~15=1 7 8 //如果只想對信號的某一位單獨賦值,用下面這種賦值方法 9 rtr_io.cb.frame_n[5] <= 1'b0;
2、隨機數方法和函數
$urandom_range()
語法:$urandom_range(int unsigned maxval,int unsigned minval = 0);
功能:返回一個在maxval和minval之間的無符號整數
Example:
1 val = $urandom_range(7,0); 2 //等價於 3 val = $urandom_range(7);//如果minval沒有指定,默認為0 4 5 //如果mixval比minval小,參數列表會自動反向 6 val = $urandom_range(0,7);//等價於上面兩個例子
$urandom()
語法:$urandom[(int seed)];
功能:產生偽隨機數,每次調用時返回一個32位的無符號偽隨機數;
For example:
1 bit [61:1] addr; 2 bit [3:0] number; 3 4 addr[32:1] = $urandom(254);//初始化生成器,獲得一個32位的隨機數 5 addr = {$urandom,$urandom};//64位隨機數 6 number = $urandom & 15;//4位隨機數
在lab2中,使用隨機數來產生地址和payload隊列的值:
1 task gen(); 2 sa = $urandom; 3 da = $urandom; 4 payload.delete();//clear previous data 5 repeat($urandom_range[4,2]) 6 payload.push_back($urandom); 7 endtask:gen
3、更新仿真時間
Pay particular attention to how you advance the clock. If in one
subroutine you advance the clock upon exiting the subroutine, then
in another subroutine you advance the clock upon entering the
subroutine, erroneous timing may result.
更新仿真時間的方式,@(在tb參數列表中例化的interface名 + clocking名):
For example:
1 @(rtr_io.cb);//單次更新時鍾 2 3 repeat(10) @(rtr_io.cb);//更新10次時鍾
在lab2中的時鍾更新:
Example 1:
1 initial begin 2 $vcdpluson; 3 run_for_n_packets = 21; 4 reset(); 5 repeat(run_for_n_packets) begin 6 gen(); 7 send(); 8 end 9 repeat(10) @(rtr_io.cb);//更新10個時鍾周期的仿真時間,這樣做可以保證輸出的數據能被觀察到 10 end
Example 2:
1 task send_addrs(); 2 rtr_io.cb.frame_n[sa] <= 1'b0; 3 for(int i=0;i<4;i++) begin 4 rtr_io.cb.din[sa] <= da[i];//i'th bit of da 5 @(rtr_io.cb); 6 end 7 endtask:send_addrs
Example 3:
1 task send_payload(); 2 foreach(payload[index]) begin 3 for(int i=0;i<8;i++) begin 4 rtr_io.cb.din[sa] <= payload[index][i]; 5 rtr_io.cb.valid[sa] <= 1'b0; 6 //payload初始值為空,不停的裝入數據,在裝滿第七位時,需要將其拉高 7 rtr_io.cb.frame_n[sa] <= ((i == 7) && (index == (payload.size()-1))); 8 @(rtr_io.cb);//更新仿真時間 9 end 10 end 11 rtr_io.cb.valid_n[sa] <= 1'b1;//最后將valid_n拉高; 12 endtask:send_payload
4、看門狗,防止deadlock的產生:
在lab3中,get_payload需要等到frameo_n的下降沿到來以后,進而進行下一步操作,
如果直接寫@(negedge rtr_io.frameo_n[sa])來等待時鍾邊沿的到來,存在一種潛在的可能,
就是如果代碼出錯,可能程序永遠等不到下降沿。
For example:
1 for(i = 0; i < run_for_n_packets;i++) 2 gen(); 3 fork 4 begin 5 send(); 6 recv(); 7 end 8 join
說明:send()和recv()兩個任務本來是並行執行的,但是由於編程時,錯誤的將其放在了
begin...end內,變成了順序操作。此時如果使用@(negedge rtr_io.frameo_n[sa])來檢測一個新的從dut輸出的數據包,
仿真將會死循環。
為了有效的避免這種情況的產生,可以加入看門狗機定時器,防止子程序超時:
1 fork 2 begin:wd_timer_fork 3 fork:frameo_wd_timer 4 @(negedge rtr_io.cb.frameo_n[sa]); 5 begin 6 repeat(1000) @(rtr_io.cb); 7 $display("\n%m\n[ERROR]%t Frame signal time out!\n",$realtime); 8 $finish; 9 end 10 join_any:frameo_wd_timer 11 disable fork 12 end:wd_timer_fork 13 join
說明:在上面代碼中,fork...join中的代碼是並行執行的。
也即@(negedge rtr_io.frameo_n[sa])和其下面begin...end塊中的內容是並行執行的。
fork...join_any中,只要其中任何一個子程序執行,即可跳出此模塊執行后續代碼,
因此,如果代碼出錯一直等不到 frameo_n信號下降沿的到來,時鍾更新1000次后,看門狗
計數器超時,報錯,此時即跳出了此模塊,不會進入死循環的情況。
擴展閱讀:
fork...join_none模塊中,任何線程都不用執行就可以執行下面的代碼。
disable fork——停止多個線程,包括從當前線程衍生出來的線程。
使用時為了防止停止過多的線程,應該使用fork...join將目標代碼圍起來限制disable fork的
作用范圍,如上述例子中只停止fork...join中的進程。
For another example:
1 initial begin 2 check_trans(tr0); //線程0 3 //創建一個線程來限制disable fork的作用范圍 4 fork //線程1 5 begin 6 check_trans(tr1); //線程2 7 fork //線程3 8 check_trans(tr2); //線程4 9 join 10 //停止線程1-4,單獨保留線程0 11 #(TIME_OUT/2) disable fork; 12 end 13 join 14 end 15 16 17
5、lab3中出現的打印選項
%m —— display hierarchical name
%p —— display an assignment pattern
Example:
1 function bit compare(ref string message); 2 ... 3 message = "Payload Content Mismatch:\n" 4 message = {message,$sformatf("Packet Sent: %p\nPkt Received: %p",payload,pkt2cmp_payload)}; 5 return(0); 6 ... 7 endfunction:compare 8 9 task check(); 10 string name; 11 static int pkts_checked = 0; 12 if(!compare(message)) begin 13 $display("\n%m\n[ERROR]%t Packet #%0d %s\n",$realtime,pkts_checked,message); 14 $finish; 15 end 16 $display("[NOTE]%t Packet #%0d %s",$realtime,pkts_checked,message);//[NOTE]137350.0ns Packet #38 Successfully Compared! 17 endtask:check
說明:上面的例子中,如果check()調用compare()函數時,若剛好函數中的那部分代碼被執行,即發送的代碼與回讀內容不一致,則返回0;
成都市check()調用compare(),執行if條件成立的語句,即$display("\n%m\n[ERROR]%t Packet #%0d %s\n",$realtime,pkts_checked,message);
就會打印出如下的信息:
1 router_test_top.t.check //%m 打印出的信息,即出現問題地方名字的層次結構 2 [ERROR]141650.0ns Packet #39 Payload Content Mismatch: 3 Packet Send: '{'h3a, 'hc7, 'hbd, 'h84} //%p打印出的信息,即顯示一個賦值形式 4 Pkt Received: '{'hxx, 'hxx, 'hxx, 'hxx}
6、仿真控制系統任務:$finish $stop $exit
$stop ——終止仿真
$finish ——退出仿真器,將控制返回給主操作系統
$exit —— wait for all program blocks to complete,and then make an imlicit call to $finish
注:$stop和$finish有可選的參數0,1,2,決定什么類型的診斷信息被打印:
0 —— printing nothing
1 —— printing simulation time and location
2 —— printing simulation time,location and statistics about the memory and Central Process Unit(CPU) time used in simulation