看板 Electronics 關於我們 聯絡資訊
最近在翻Synopsys VCS的user guide的時候,忽然看到一個有意思的東西[1], 是關於使用nonblocking assignment解決race condition的問題。 我之前一直都沒注意到這個特性,只是有點半懂的照別人說的 "寫sequential circuit用nonblocking assignment", 現在才知道nonblocking assignment還有解決race condition的問題。 後來我又翻了一分文件: http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf 這分文件是之前我在板上跟板友們討論關於 blocking與nonblocking assignment的使用時機 (文章代碼: #19uVW10a),ksmrt0123大當時提供的一篇paper。 裡面有描述為何sequential circuit要用nonblocking assignment。 其實這分文件已經提到這的race condition現象。 我本來用SystemVerilog Scheduling Algorithm去推論, 後來發現與這篇paper也是用Scheduling去解釋的 (原來這paper早就討論過這問題,只是我當時沒仔細看XD)。 以下就詳述為何sequential circuit使用blocking assignment所遇到的race問題 (這解釋也適用Verilg): 在SystemVerilog中,一個assignment(不管是blocking、nonblocking、continuous) 可分成兩個步驟。一個是等號右手邊的evaluation,另一個是更新等號左手邊的 值的update。 在SystemVerilog的排程演算法中,一個時間點是一個time slot。 一個time slot可區分不同的region, 在此會提到其中兩個regions,active events 與nonblocking assignment events regions。 active events region是simulator正在執行的events。 SysterVerilog standard在這region中的events沒有限定它們的執行順序, 所以它其有非決定性(nodeterminism)。 Nonblocking assignment (NBA) events region則存放著 在active events region執行過的nonblocking assignment statements 所產生的更新(update) events。也就是如果在執行一個NBA,它不會立即更新值, 而會等到simulator的排程器執行到NBA events region,才會執行那些更新敘述。 另外要強調的是在一個time slot中,排程器會較先去active events region執行 裡面的events。等到active events region所有的events都執行完, 才會去剩下的regions(如NBA events region)執行未執行的events。 而剩下的regions仍可能產生新的events到active events region。 詳細的time slot flow,可以參考[3]。 Blocking assignments,與nonblocking assignments最大的不同 就在於它在active events region執行過後是直接update左手端的變數, 而不像nonblocking assignments是在NBA events region才作update。 由於active events region,的非決定性(nodeterminism), 會造成race發生的可能。一個例子就是shift registers的race[1]: module test(out,in,clk); input in,clk; output out; wire a; dff dff0(a,in,clk); dff dff1(out,a,clk); endmodule module dff(q,d,clk); output q; input d,clk; reg q; always @(posedge clk) q = d; // race! endmodule 這個例子"q = d;"使用blocking assignment。 dff0與dff1的always(以下簡稱always0與always1)都對posedge clk敏感(sensitive)。 當posedge clk一出現,always0與always1會產生了evaluation events。 也就是會計算它們的sequential blocks(begin-end), IEEE 1800-2009有說這樣的events,它們的執行順序是任意的[2]。 所以若always0較先執行,此時/test/dff1/d(也就是/test/a或/test/dff0/q) 已經是新的值,接著再執行always1,會造成/test/dff0/q與/test/dff0/q同值的情形, 這就不是shift registers的行為(behavior); 反之若always1先執行,always0後執行,這就是shift registers的行為。 那麼要如何解決這個nondeterminism問題呢?一個作法是把兩個flip-flop同寫在 一個sequential block(不要與sequential circuit搞混,兩者沒絕對的關係)。 因為sequential block有順序性,所以我們可以在 /test/dff0/q被寫入新值時,先把舊值寫給/test/dff1/q。改寫如下: module test(out,in,clk); input in,clk; output out; wire a; reg q0, q1; always @(posedge clk) begin q1 = q0; q0 = in; end assign out = q1; endmodule (Xilinx ISE確實合出shift registers, 所以我之前文章曾說blocking assignment不能model shift registers是不正確的。) 但這種方法較不建議使用,這對模組化有困難, 因為一定要把所有訊號寫在一個sequential block內。 另外一種解決這問題的方法是使用nonblocking assignment(NBA), 改寫如下: module test(out,in,clk); input in,clk; output out; wire a; dff dff0(a,in,clk); dff dff1(out,a,clk); endmodule module dff(q,d,clk); output q; input d,clk; reg q; always @(posedge clk) q <= d; endmodule 使用NBA,如果遇到always0先執行先執行會怎樣? 首先右手端會進行evaulation,但因NBA所以update要到NBA events region才會執行。 所以always0執行完後,並沒有update /test/dff0/q。 接著會去執行always1,這時/test/dff1的"q <= d"的d所讀到的值 仍是舊的/test/dff0/q,這值也不會立即更新,它會延遲到NBA events region。 再來NBA events region的兩個update event執行後,/test/dff0/q與/test/dff1/q所 更新的值是在前面active events region時所算的, 不是在NBA region算的(否則仍會有race問題)。 所以/test/dff1/q最後是更新成舊的/test/dff0/q,/test/dff0/q更新成/test/in; 若反過來,always1較always0先執行,仍然會得到一樣的結果。 也就是不管always1與always0的執行順序,結果都是shift registers的行為。 sequential block與NBA都可以用來解決race的問題。但NBA的好處是code可以更模組化。 要不然用sequential block解race,本來可以寫成模組的東西就變得不能寫成模組, 這就犧牲了模組化的好處。這篇文章只舉個簡單的shift registers,若是更大的電路 而不能模組化,那就很難維護了。 所以這就是為什麼有coding style叫我們寫sequential circuit要用NBA, 不要用blocking assignment的緣故。 [1] Synopsys, "VCS/VCSi User Guide Version C-2009.06," p.p. 3-5, June 2009. [2] IEEE, "IEEE 1800-2009," p.p. 23, Dec 2009. [3] IEEE, "IEEE 1800-2009," p.p. 28, Dec 2009. -- 信佛的人要知道:佛絕不會說謊。但請把握時光。 法滅盡經: http://www.cbeta.org/result/normal/T12/0396_001.htm 共勉之。 -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 140.115.221.79 ※ 編輯: zxvc 來自: 140.115.221.79 (08/24 19:46)
ViewMoon:sunburst 上的 paper 是好物,在我初學時獲益良多深受啟發 08/24 20:48
ViewMoon:q <= d 最好寫成 q <= #1 d; 一是為了 waveform 易 check 08/24 20:50
ViewMoon:另外它也反映 gate level simulation 時, clock edge 的 08/24 20:51
ViewMoon:相位超前 q transition point 的事實 08/24 20:52
ViewMoon:還有一個原因是, 我遇過加或不加 #1, 導致 simulation 08/24 20:53
ViewMoon:result 不同, 原因可能是 dff0/dff1 clock 不同, 但這兩 08/24 20:55
ViewMoon:個 clock 是同一 clock group, 加 #1 比較不會遇到 08/24 20:56
ViewMoon:simulator 牌子不同而不同的結果 08/24 20:57
Acme:呵呵,想當初;我也曾在這版上,說加#dly的好處...理由同上... 08/24 21:42
Acme:不過被說一定沒啥design經驗..後來就索性把文刪了 08/24 21:44
HenryLai:1 08/25 00:39
genghiskii:#1 在合成時會自動消失 08/25 21:57
colinshih:acme 那家公司, 說一下笑笑好嗎? 08/28 07:14
sepcher:基本功推一個 08/29 00:43
Acme:小公司,不足掛齒...不敢讓colinshih笑了.. 08/30 00:02
sneak: 另外它也反映 gate https://muxiv.com 08/13 19:02
sneak: 個 clock 是同一 https://daxiv.com 09/17 22:57
sneak: 還有一個原因是, 我遇 https://muxiv.com 11/11 15:55
sneak: q <= d 最好寫成 https://noxiv.com 01/04 22:12