您好,欢迎访问三七文档
Abstract除了看波型圖外,在寫Testbench時還可搭配Verilog本身所帶的一些函數做驗證,如$display()、$strobe()、$monitor()與$fwrite()等,這些函數在遇到blocking與nonblocking時,該如何使用才正確呢?它與Debussy/Verdi的nWave又有什麼關係呢?Introduction使用環境:ModelSimSE6.3e+Debussy5.4v9本文將討論以下主題:1.Verilog的『stratifiedeventqueue』2.blocking/nonblocking與$display()、$strobe()、$monitor()、$fwrite()的執行順序3.Debussy/Verdi的nWave與blocking/nonblocking的關係4.Conclusion先來看一下摘自[1]CliffordE.Cummings2000,NonblockingAssignmentsinVerilogSynthesis,CodingStylesThatKills,SunburstDesign,Inc.這篇paper的一段範例,我稍加修改,另外加上了常用的$fwrite()與Debussy的$fsdbDumpvars()與$fsdbDumpvars()一起測試。nb_schedule1.v/Verilog1modulenb_schedule1;23rega,b;4integerfp;56initialbegin7fp=$fopen(log.txt,w);8a=0;9b=0;10#1;11a=0;12b=1;13a=b;14b=a;1516$monitor(%0dns:\$monitor:a=%bb=%b,$stime,a,b);17$display(%0dns:\$display:a=%bb=%b,$stime,a,b);18$strobe(%0dns:\$strobe:a=%bb=%b\n,$stime,a,b);19$fwrite(fp,%0dns:\$fwrite:a=%bb=%b\n,$stime,a,b);20#0$display(%0dns:#0:a=%bb=%b,$stime,a,b);212223#1$monitor(%0dns:\$monitor:a=%bb=%b,$stime,a,b);24$display(%0dns:\$display:a=%bb=%b,$stime,a,b);25$strobe(%0dns:\$strobe:a=%bb=%b\n,$stime,a,b);26$fwrite(fp,%0dns:\$fwrite:a=%bb=%b\n,$stime,a,b);27#0$display(%0dns:#0:a=%bb=%b,$stime,a,b);282930$fclose(fp);31end3233initialbegin34$fsdbDumpfile(nb_schedule1.fsdb);35$fsdbDumpvars(0,nb_schedule1);36end3738endmodule執行結果#1ns:$display:a=0b=1#1ns:#0:a=0b=1#1ns:$monitor:a=1b=0#1ns:$strobe:a=1b=0##2ns:$display:a=1b=0#2ns:#0:a=1b=0#2ns:$monitor:a=1b=0#2ns:$strobe:a=1b=0文字檔部份1ns:$fwrite:a=0b=12ns:$fwrite:a=1b=0Debussy的nWave假如結果如你預期,恭喜你,那表示你的觀念非常清楚,如果不是,請你繼續往下看,我將會解釋這段範例程式。Verilog的『stratifiedeventqueue』我在(原創)深入探討blocking與nonblocking(SOC)(Verilog)曾經討論過Verilog在Simulator內實際的運行方式,這裡再稍為提一下。在軟體的世界,程式碼基本上是一行一行地執行,也就是再同一個時間點,只有一件事情會發生;但在硬體的世界裡,電路卻可以平行執行,也就是在同一個時間點,有很多事情可以同時發生。我們現在要在一個只能『循序處理』的軟體去『模擬』能『平行處理』的硬體,勢必有些特殊的機制才行。在Simulator內,為了要模擬出硬體的平行處理機制,時間軸是個虛擬的時間軸,另外搭配了5個eventqueue,也就是說,當一個時間點的5個eventqueue內的所有程式碼都執行過後,時間軸才會自動加1,如此就很巧妙的『看起來』好像在同一個時間點作了很多事情,不過事實上對於軟體與CPU來說,依然是同一時間點只發生了一件事情。在IEEEVerilogStandard中定義了這5個EventQueue,依序討論如下:1.ActiveEvents:大部分的Verilog程式碼都在此執行,其中包括以綠色字表示的blockingasignments以及continuousassignments(也就是用assign寫的),至於nonblocking部分,只執行RHS(RightHandSide),也就是只執行nonblocking右測的部分,唯一用紅色表示的是本文所要討論的$display()與$fwrite(),也是屬於ActiveEvents,值的注意的是,在ActiveEvents中的程式碼,若是同一個時間點,且在同一個sequentialblock,程式碼是依序執行,但是IEEEVerilogStandard並不保證在同一個時間點,不同的sequentialblock內的程式碼誰先執行,也就是說若你寫的程式碼都屬於ActiveEvents所執行,但分屬不同的sequentialblock,且彼此互相依賴,就可能出現RaceCondition的情形發生。當在ActiveEvents的程式碼執行完後,會自動移出ActiveEvents。2.InactiveEvents當ActiveEvents執行完後,InactiveEvents的程式碼會依序變成ActiveEvents而執行之。InactiveEvents執行的是blockingassignments且帶#0delay,因為是#0,所以理論上還是屬於同一個時間點,只是執行順序略晚於正常的blockingassignments,這也是為什麼遇到RaceCondition時,常常加上#0就會正常,這就是因為#0是屬於InactiveEvents,執行順序很明顯的在ActiveEvents之後,因此不會有在ActiveEvents內不保證誰先誰後執行,而造成RaceCondition發生。很多人認為#0會在每個時間點的最後執行,這是個錯誤的觀念,事實上,#0只是在InactiveEvents,比NonblockingEvents還要早。3.NonblockingEvents當InactiveEvents執行完後,接著NonblockingEvent的程式碼會依序變成ActiveEvents而執行之。NonblockingEvents執行的是nonblocking的LHS(LeftHandSide)部分,在此我們可以明確地發現,blocking發生在ActiveEvents,而nonblocking雖然在ActiveEvents已經執行了RHS,但真正完成LHS是在NonblockingEvents,也就是blocking會在nonblocking之前先完成。這也是為什麼同一個時間點,nonblocking可以讀到blocking所做的改變,但是blocking卻無法讀到nonblocking的改變,因為blocking已經先執行,必須要等到下一個clkedge才能讀到nonblocking所做的改變。除此之外,還有一個常見的迷思也可在此澄清,我們都知道寫sequentiallogic時要用nonblocking寫,事實上用blocking也是可以寫,只是blocking寫很容易造成RaceCondition,要很小心注意其先後順序,但為什麼用nonblocking寫就不會有RaceCondition呢?理由就在於nonblocking的RHS是在ActiveEvents,而LHS是在NonblockingEvents,儘管彼此互相依賴,但NonblockingEvents很明顯地在ActiveEvents之後,所以執行順序可以明確地確定,不像用blocking寫時,因為在ActiveEvents內執行順序不確定,造成結果不可預期而產生RaceCondition。4.MonitorEvents當NonblockingEvents執行完後,接著MonitorEvents的程式碼會依序變成ActiveEvents而執行之。我們都知道$display()無法觀察nonblocking所改變的結果,必須要使用$strobe()才可以,這是為什麼呢?因為$display()是屬於ActiveEvents,而nonblocking完成於NonblockingEvents,明顯在ActiveEvents之後,所以$display()跟本欄不到nonblocking所造成的改變,必須使用比NonblockingEvents更晚執行的MonitorEvents中的$strobe()才可以觀察到nonblocking所改變的結果。5.VerilogPLIEvents當MonitorEvents執行完後,接著VerilogPLIEvents的程式碼會依序變成ActiveEvents而執行之。VerilogPLI是允許你用C語言去寫一些Simulator的擴充功能,如Debussy/Verdi的$fsdbDumpfile()、$fsdbDumpvars()就是透過VerilogPLI,以前我ㄧ直搞不懂為什麼我用$display()與$fwrite()所dump的值與在Debussy/Verdi的nWave所看到的值不一樣,後來才發現原來$display()與$fwrite()是屬於ActiveEvents,而$fsdbDumpfile()與$fsdbDumpvars是屬於VerilogPLIEvents,比NonblockingEvents晚執行,這也是為什麼Debussy/Verdi可以顯示每個時間點nonblocking的值,而$display()與$fwrite()卻無法dump每個時間點的nonblocking,彼此的結果會差1個clock。blocking/nonblocking與$display()、$strobe()、$monitor()、$fwrite()的執行順序了解VerilogSimulator的『stratifiedeventqueue』之後,為了解釋nb_schedule1為什麼會有這樣的執行結果,我們將所有程式依照其在EventQueue的執行順序重新排列如下圖所示:我們可以發現,儘管nonblocking與$monitor()、$strobe()寫在$display()與$fwrite()前面,但真正在執行時,VerilogSimulator還是會把它放在該放的EventQueue內,因為$display()與$fwrite()是放在ActiveEvents,所以會印出a=0,b=1,接下來是InactiveEvents的#0$display(),也是顯示a=0,b=1,再過來是NonblockingEvents,執行a=b與b=a,最後才是MonitorEvents的$monitor()與$strobe(),因為nonblocking已經執行過,a與b的值已經改變,所以a=1,b=0,接下來因為a與b的值都不再改變,所以印出的值都不會再變。Debussy/Verdi的nWave與blocking/nonblocking的關係在nWave內,1ns時,所顯示的是a=1,b=0,若你是用
本文标题:$dispaly()、$strobe()、$monitor()-、$fwrite()与blockin
链接地址:https://www.777doc.com/doc-1752440 .html