(原創) 深入探討blocking與nonblocking (SOC) (Verilog)

Abstract
Verilog雖然是個語法簡單的語言,但是blocking與nonblocking卻是大家學習Verilog時永遠的痛,即時是很資深的IC Designer,也未必完全搞清楚兩者的差異,本文試著以simulator與synthesizer的角度去探討之。

Introduction
使用環境:NC-Verilog 5.4 + Debussy 5.4 v9 + Quartus II 7.2

軟體的語言都是一行一行依序執行,這與Verilog的blocking觀念一樣,但偏偏Verilog還有個nonblocking,而且在寫同步電路時,還一定得用nonblocking寫,到底blocking與nonblocking有什麼不同呢?我在(筆記)如何使用blocking與nonblocking assignment? (SOC) (Verilog)這篇討論過幾個簡單的原則,基本上只要依照這幾個原則去寫RTL,就能保證simulation的與synthesis的結果一致,但當時我並沒有討論其原因,只是將規則背下來而已。

在正式討論之前,請各位先做個小測驗,考驗您的觀念是否正確:

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,其實真正的差異只有以下兩部份,其他部分完全一樣:

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

請先把你自己當成simulator,實際模擬一下結果為何。

以下為使用NC-Verilog + Debussy所模擬的結果:

blocking.v

 nonblocking00

nonblocking.v

nonblocking01

你所預期的結果與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,就是一行程式執行完才能執行下一行,所以在clk rising edge時,先將b的值給a,然後再將a的值給a,也就是說,在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

再來討論nonblocking,在clk rising edge時,a <= b,b <= a,這到底要怎麼理解呢?這必須牽涉到simulator的event queue如何處理這些event。

在討論evnet之前,先解釋兩個專有名詞,RHS與LHS。

RHS:在 =  或 <= 右邊的運算式或變數

LHS:在 = 或 <= 左邊的運算式或變數

由於電腦軟體本身是依序執行(也就是如C一樣程式一行一行的執行),但硬體電路卻可併行執行,simulator是軟體寫的,卻要能夠模擬出硬體電路的的並行執行,也就是如在5 ns時,同時有很多信號被處理,所以才有event queue的概念,將同一個time step要處理的信號放在一個event queue,simulator再依序處理,處理完後再處理下一個time step,這樣就能使依序執行的simulator可以模擬出並行執行的硬體電路。

在IEEE Verilog standard定義了以下的event queue讓simulator廠商實作,至於該如何實作是各廠商的商業機密。

  nonblocking06

絕大部分的event都會放在Active Events queue內,包括blocking assignments、blocking的RHS、continuous assignments、$display()..等,也就是說當某個time step到達時,會執行Active Events queue的event,但Verilog IEEE standard並沒有保證在Active Events queue內event的執行順序(所以一些不良的coding style可能會造成race condition,這又是另外一個Verilog很惱人的issue,再另闢專文討論),值得注意的是nonblocking的RHS是放在Active Events queue,但沒有包含nonblocking的LHS。

在IEEE standard有定義演算法介紹其他Event queue如何加進Active Events,在這就不多談,這裡的重點是有一個Nonblocking Events queue專門放nonblocking的LHS,會在適當的時機加入Active Events queue執行。

所以由此可知,由於RHS of nonblocking放在Active Events,所以會先執行,之後等在Nonblocking Events queue的LHS of nonblocking進入Active Events queue後再執行。

因此整個nonblocking可視為兩個步驟的行為:

1.在clk rising edge的一開始執行RHS。

2.在clk rising edge快結束時執行LHS。

所以在 a <= b, b <= a時,clk rising edge一開始先執行RHS,也就是a = 1,b = 0,然後再執行LHS,因此a = 0,b = 1,因此nonblocking不會如blocking因為a已經更新了,因而改變了b的值。可以發現,blocking會因為程式的撰寫順序而有不同的值,但nonblocking卻不會因為程式的撰寫順序而有影響,原因是nonblocking的執行是2個步驟,而blocking的執行是1個步驟

以Synthesizer角度探討blocking與nonblocking

寫Verilog最擔心的是simulation時正常,但synthesis後卻不是你要的,因此我們實際在Quartus II跑看看,看看經過P&R之後,是否與NC-Verilog的結果一樣,並使用RTL Viewer看看Quartus II如何synthesis。

blocking.v

 nonblocking02

nonblocking.v

 nonblocking03

除了加上delay外,基本上波形與NC-Verilog所模擬的一樣。

blocking.v

 nonblocking04

雖然在code中宣告了2個reg,但synthesizer只會合成出1個register,也就是a = b, b = a只delay了1個clk。

nonblocking.v

 nonblocking05

會合成出2個register,符合我們的預期,也就是 a <= b, b <= a會delay 2個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的角度同時去思考,若想得知更完整的資訊,可參考Reference的paper與書籍。

See Also
(筆記)如何使用blocking與nonblocking assignment? (SOC) (Verilog)
(筆記) Cliff Cummings的paper大全 (SOC) (Verilog)

(筆記) $dispaly()、$strobe()、$monitor() 、$fwrite()與blocking / nonblocking的關係 (SOC) (Verilog) (Debussy) (Verdi)

Reference
Clifford E. Cummings 2000, Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kills, Sunburst Design, Inc.
夏宇文 2008, Verilog數字系統設計教程, 北京航空航天大學出版社

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值