(原創) 深入探討blocking與nonblocking (SOC) (Verilog)
Abstract
Verilog雖然是個(gè)語(yǔ)法簡(jiǎn)單的語(yǔ)言,但是blocking與nonblocking卻是大家學(xué)習(xí)Verilog時(shí)永遠(yuǎn)的痛,即時(shí)是很資深的IC Designer,也未必完全搞清楚兩者的差異,本文試著以simulator與synthesizer的角度去探討之。
Introduction
使用環(huán)境:NC-Verilog 5.4 + Debussy 5.4 v9 + Quartus II 7.2
軟體的語(yǔ)言都是一行一行依序執(zhí)行,這與Verilog的blocking觀念一樣,但偏偏Verilog還有個(gè)nonblocking,而且在寫(xiě)同步電路時(shí),還一定得用nonblocking寫(xiě),到底blocking與nonblocking有什麼不同呢?我在(筆記)如何使用blocking與nonblocking assignment? (SOC) (Verilog)這篇討論過(guò)幾個(gè)簡(jiǎn)單的原則,基本上只要依照這幾個(gè)原則去寫(xiě)RTL,就能保證simulation的與synthesis的結(jié)果一致,但當(dāng)時(shí)我並沒(méi)有討論其原因,只是將規(guī)則背下來(lái)而已。
在正式討論之前,請(qǐng)各位先做個(gè)小測(cè)驗(yàn),考驗(yàn)?zāi)挠^念是否正確:
blocking.v / Verilog?
1?/*?2?(C) OOMusou 2010 http://oomusou.cnblogs.com
3?
4?Filename??? : blocking.v
5?Simulator?? : NC-Verilog 5.4
6?Description : blocking assignment in always block
7?Release???? : Jul/30/2010 1.0
8?*/
9?
10?module blocking (
11?? clk,
12?? rst_n,
13?? a_i,
14?? b_i,
15?? a_o,
16?? b_o
17?);
18?
19?input clk;
20?input rst_n;
21?input a_i;
22?input b_i;
23?output a_o;
24?output b_o;
25?
26?reg a;
27?reg b;
28?
29?assign a_o = a;
30?assign b_o = b;
31?
32?always@(posedge clk or?negedge rst_n) begin
33?? if (~rst_n) begin
34???? a = a_i;
35???? b = b_i;
36?? end
37?? else?begin
38???? a = b;
39???? b = a;
40?? end
41?end
42?
43?endmodule
blocking_tb.v / Verilog?
1?/*?2?(C) OOMusou 2010 http://oomusou.cnblogs.com
3?
4?Filename??? : blocking_tb.v
5?Simulator?? : NC-Verilog 5.4
6?Description : testbench of blocking assignment in always block
7?Release???? : Jul/30/2010 1.0
8?*/
9?
10?`include?"blocking.v"
11?
12?module blocking_tb;
13?
14?reg clk;
15?reg rst_n;
16?reg a_i;
17?reg b_i;
18?wire a_o;
19?wire b_o;
20?
21?initial?begin
22?? clk =?1'b0;
23?? rst_n =?1'b0;
24?? a_i =?1'b1;
25?? b_i =?1'b0;
26?? #5;
27?? rst_n =?1'b1;
28?? #100;
29?? $finish;
30?end
31?
32?always #10 clk =?~clk;
33?
34?initial?begin
35?? $fsdbDumpfile("blocking.fsdb");
36?? $fsdbDumpvars(0, blocking_tb);
37?end
38?
39?blocking blocking_0 (
40?? .clk(clk),
41?? .rst_n(rst_n),
42?? .a_i(a_i),
43?? .b_i(b_i),
44?? .a_o(a_o),
45?? .b_o(b_o)
46?);
47?
48?endmodule
nonblocking.v / Verilog?
1?/*?2?(C) OOMusou 2010 http://oomusou.cnblogs.com
3?
4?Filename??? : nonblocking.v
5?Simulator?? : NC-Verilog 5.4
6?Description : nonblocking assignment in always block
7?Release???? : Jul/30/2010 1.0
8?*/
9?
10?module nonblocking (
11?? clk,
12?? rst_n,
13?? a_i,
14?? b_i,
15?? a_o,
16?? b_o
17?);
18?
19?input clk;
20?input rst_n;
21?input a_i;
22?input b_i;
23?output a_o;
24?output b_o;
25?
26?reg a;
27?reg b;
28?
29?assign a_o = a;
30?assign b_o = b;
31?
32?always@(posedge clk or?negedge rst_n) begin
33?? if (~rst_n) begin
34???? a <= a_i;
35???? b <= b_i;
36?? end
37?? else?begin
38???? a <= b;
39???? b <= a;
40?? end
41?end
42?
43?endmodule
nonblocking_tb.v / Verilog?
1?/*?2?(C) OOMusou 2010 http://oomusou.cnblogs.com
3?
4?Filename??? : nonblocking_tb.v
5?Simulator?? : NC-Verilog 5.4
6?Description : testbench of nonblocking assignment in always block
7?Release???? : Jul/30/2010 1.0
8?*/
9?
10?`include?"nonblocking.v"
11?
12?module nonblocking_tb;
13?
14?reg clk;
15?reg rst_n;
16?reg a_i;
17?reg b_i;
18?wire a_o;
19?wire b_o;
20?
21?initial?begin
22?? clk =?1'b0;
23?? rst_n =?1'b0;
24?? a_i =?1'b1;
25?? b_i =?1'b0;
26?? #5;
27?? rst_n =?1'b1;
28?? #100;
29?? $finish;
30?end
31?
32?always #10 clk =?~clk;
33?
34?initial?begin
35?? $fsdbDumpfile("nonblocking.fsdb");
36?? $fsdbDumpvars(0, nonblocking_tb);
37?end
38?
39?nonblocking nonblocking_0 (
40?? .clk(clk),
41?? .rst_n(rst_n),
42?? .a_i(a_i),
43?? .b_i(b_i),
44?? .a_o(a_o),
45?? .b_o(b_o)
46?);
47?
48?endmodule
以上為完整的RTL與testbench,其實(shí)真正的差異只有以下兩部份,其他部分完全一樣:
1.在always block使用blocking
always@(posedge clk or?negedge rst_n) begin? if (~rst_n) begin
??? a = a_i;
??? b = b_i;
? end
? else?begin
??? a = b;
??? b = a;
? end
end
2.在always block使用nonblocking?
always@(posedge clk or?negedge rst_n) begin? if (~rst_n) begin
??? a <= a_i;
??? b <= b_i;
? end
? else?begin
??? a <= b;
??? b <= a;
? end
end
請(qǐng)先把你自己當(dāng)成simulator,實(shí)際模擬一下結(jié)果為何。
以下為使用NC-Verilog + Debussy所模擬的結(jié)果:
blocking.v
?
nonblocking.v
你所預(yù)期的結(jié)果與simulator一樣嗎?
以Simulator角度探討blocking與nonblocking
blocking
always@(posedge clk or?negedge rst_n) begin? if (~rst_n) begin
??? a = a_i;
??? b = b_i;
? end
? else?begin
??? a = b;
??? b = a;
? end
end
先討論較好理解的blocking,所謂的blocking,就是一行程式執(zhí)行完才能執(zhí)行下一行,所以在clk rising edge時(shí),先將b的值給a,然後再將a的值給a,也就是說(shuō),在clk rising edge之後,a = b = 0,這與C的觀念一樣。
nonblocking
always@(posedge clk or?negedge rst_n) begin? if (~rst_n) begin
??? a <= a_i;
??? b <= b_i;
? end
? else?begin
??? a <= b;
??? b <= a;
? end
end
再來(lái)討論nonblocking,在clk rising edge時(shí),a <= b,b <= a,這到底要怎麼理解呢?這必須牽涉到simulator的event queue如何處理這些event。
在討論evnet之前,先解釋兩個(gè)專(zhuān)有名詞,RHS與LHS。
RHS:在 =? 或 <= 右邊的運(yùn)算式或變數(shù)
LHS:在 = 或 <= 左邊的運(yùn)算式或變數(shù)
由於電腦軟體本身是依序執(zhí)行(也就是如C一樣程式一行一行的執(zhí)行),但硬體電路卻可併行執(zhí)行,simulator是軟體寫(xiě)的,卻要能夠模擬出硬體電路的的並行執(zhí)行,也就是如在5 ns時(shí),同時(shí)有很多信號(hào)被處理,所以才有event queue的概念,將同一個(gè)time step要處理的信號(hào)放在一個(gè)event queue,simulator再依序處理,處理完後再處理下一個(gè)time step,這樣就能使依序執(zhí)行的simulator可以模擬出並行執(zhí)行的硬體電路。
在IEEE Verilog standard定義了以下的event queue讓simulator廠商實(shí)作,至於該如何實(shí)作是各廠商的商業(yè)機(jī)密。
?
絕大部分的event都會(huì)放在Active Events queue內(nèi),包括blocking assignments、blocking的RHS、continuous assignments、$display()..等,也就是說(shuō)當(dāng)某個(gè)time step到達(dá)時(shí),會(huì)執(zhí)行Active Events queue的event,但Verilog IEEE standard並沒(méi)有保證在Active Events queue內(nèi)event的執(zhí)行順序(所以一些不良的coding style可能會(huì)造成race condition,這又是另外一個(gè)Verilog很惱人的issue,再另闢專(zhuān)文討論),值得注意的是nonblocking的RHS是放在Active Events queue,但沒(méi)有包含nonblocking的LHS。
在IEEE standard有定義演算法介紹其他Event queue如何加進(jìn)Active Events,在這就不多談,這裡的重點(diǎn)是有一個(gè)Nonblocking Events queue專(zhuān)門(mén)放nonblocking的LHS,會(huì)在適當(dāng)?shù)臅r(shí)機(jī)加入Active Events queue執(zhí)行。
所以由此可知,由於RHS of nonblocking放在Active Events,所以會(huì)先執(zhí)行,之後等在Nonblocking Events queue的LHS of nonblocking進(jìn)入Active Events queue後再執(zhí)行。
因此整個(gè)nonblocking可視為兩個(gè)步驟的行為:
1.在clk rising edge的一開(kāi)始執(zhí)行RHS。
2.在clk rising edge快結(jié)束時(shí)執(zhí)行LHS。
所以在 a <= b, b <= a時(shí),clk rising edge一開(kāi)始先執(zhí)行RHS,也就是a = 1,b = 0,然後再執(zhí)行LHS,因此a = 0,b = 1,因此nonblocking不會(huì)如blocking因?yàn)閍已經(jīng)更新了,因而改變了b的值。可以發(fā)現(xiàn),blocking會(huì)因?yàn)槌淌降淖珜?xiě)順序而有不同的值,但nonblocking卻不會(huì)因?yàn)槌淌降淖珜?xiě)順序而有影響,原因是nonblocking的執(zhí)行是2個(gè)步驟,而blocking的執(zhí)行是1個(gè)步驟。
以Synthesizer角度探討blocking與nonblocking
寫(xiě)Verilog最擔(dān)心的是simulation時(shí)正常,但synthesis後卻不是你要的,因此我們實(shí)際在Quartus II跑看看,看看經(jīng)過(guò)P&R之後,是否與NC-Verilog的結(jié)果一樣,並使用RTL Viewer看看Quartus II如何synthesis。
blocking.v
?
nonblocking.v
?
除了加上delay外,基本上波形與NC-Verilog所模擬的一樣。
blocking.v
?
雖然在code中宣告了2個(gè)reg,但synthesizer只會(huì)合成出1個(gè)register,也就是a = b, b = a只delay了1個(gè)clk。
nonblocking.v
?
會(huì)合成出2個(gè)register,符合我們的預(yù)期,也就是 a <= b, b <= a會(huì)delay 2個(gè)clk。
完整程式碼下載
blocking.7z (NC-Verilog + Debussy)
blocking_quartus_ii.7z (Quartus II)
nonblocking.7z (NC-Verilog + Debussy)
nonblocking_quartus_ii.7z (Quartus II)
Conclusion
本文試著用最淺顯易懂的方式解釋blocking與nonblocking的差異,並從simulator與synthesizer的角度同時(shí)去思考,若想得知更完整的資訊,可參考Reference的paper與書(shū)籍。
See Also
(筆記)如何使用blocking與nonblocking assignment? (SOC) (Verilog)
(筆記) Cliff Cummings的paper大全 (SOC) (Verilog)
Reference
Clifford E. Cummings 2000, Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kills, Sunburst Design, Inc.
夏宇文 2008, Verilog數(shù)字系統(tǒng)設(shè)計(jì)教程, 北京航空航天大學(xué)出版社
總結(jié)
以上是生活随笔為你收集整理的(原創) 深入探討blocking與nonblocking (SOC) (Verilog)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Java中反射的三种常用方式
- 下一篇: linux中Daemon守护进程编程