(原創) 多工器MUX coding style整理 (SOC) (Verilog) (Quartus II)

Abstract
本文整理出幾種常見的多工器mux可合成的coding style,並深入探討其合成的結果。

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

(同一種coding style在不同synthesizer下會有不同的認知,甚至相同synthesizer不同版本也會不同,本文僅討論Quartus II 8.1下的實驗結果)。

各種coding style的RTL Viewer比較

1.使用case
mux_case.v / Verilog
 

1 /*
2 (C) OOMusou 2010 http://oomusou.cnblogs.com
3
4 Filename : mux_case.v
5 Simulator : NC-Verilog 5.4 + Debussy 5.4 v9 + Quartus II 8.1
6 Description : mux by case
7 Release : Aug.30,2010 1.0
8  */
9
10  module mux_case (
11 a_i,
12 b_i,
13 c_i,
14 d_i,
15 sel_i,
16 q_o
17 );
18
19  input a_i;
20  input b_i;
21  input c_i;
22  input d_i;
23  input [1:0] sel_i;
24  output q_o;
25
26  reg q_o;
27
28  always@(a_i or b_i or c_i or d_i or sel_i) begin
29 case (sel_i)
30 2'b00 : q_o = a_i;
31   2'b01 : q_o = b_i;
32   2'b10 : q_o = c_i;
33   default : q_o = d_i;
34 endcase
35  end
36
37  endmodule 

30行 

case (sel_i)
2'b00 : q_o = a_i;
2'b01 : q_o = b_i;
2'b10 : q_o = c_i;
default : q_o = d_i;
endcase

既然心理想的是mux,用case來窮舉自然最一目暸然, 根據[3]Altera所推薦coding style,當使用case時,Quartus II會使用parallel mux來實現。

mux_1_00

Testbench
mux_case_tb.v / Verilog

1 /*
2 (C) OOMusou 2010 http://oomusou.cnblogs.com
3
4 Filename : mux_case_tb.v
5 Simulator : NC-Verilog 5.4 & Debussy 5.4 v9 + Quartus II 8.1
6 Description : mux by case testbench
7 Release : Aug.30,2010 1.0
8  */
9
10 `timescale 1 ns/1 ns
11 `include "mux_case.v"
12
13  module mux_case_tb;
14
15  reg a_i, b_i, c_i, d_i;
16  reg [1:0] sel_i;
17  wire q_o;
18
19  initial begin
20 fork
21 #0 a_i = 1'b0;
22   b_i = 1'b1;
23   c_i = 1'b0;
24   d_i = 1'b1;
25   sel_i = 2'b00;
26  
27 #10 sel_i = 2'b01;
28   #20 sel_i = 2'b10;
29   #30 sel_i = 2'b11;
30   #40 sel_i = 2'b00;
31   #50 $finish;
32 join
33  end
34
35  initial begin
36 $fsdbDumpfile("mux_case.fsdb");
37 $fsdbDumpvars(0, mux_case_tb);
38  end
39
40 mux_case u_mux_case (
41 .a_i (a_i),
42 .b_i (b_i),
43 .c_i (c_i),
44 .d_i (d_i),
45 .sel_i(sel_i),
46 .q_o (q_o)
47 );
48
49  endmodule

Simulation結果

mux_1_01 

2.使用if else if
mux_if_else_if.v / Verilog 

1 /*
2 (C) OOMusou 2010 http://oomusou.cnblogs.com
3
4 Filename : mux_if_else_if.v
5 Simulator : NC-Verilog 5.4 + Debussy 5.4 v9 + Quartus II 8.1
6 Description : mux by if else if
7 Release : Aug.30,2010 1.0
8  */
9
10  module mux_if_else_if (
11 a_i,
12 b_i,
13 c_i,
14 d_i,
15 sel_i,
16 q_o
17 );
18
19  input a_i, b_i, c_i, d_i;
20  input [1:0] sel_i;
21  output q_o;
22
23  reg q_o;
24
25  always@(sel_i or a_i or b_i or c_i or d_i) begin
26 if (sel_i == 2'b00)
27   q_o = a_i;
28 else if (sel_i == 2'b01)
29   q_o = b_i;
30 else if (sel_i == 2'b10)
31   q_o = c_i;
32 else
33 q_o = d_i;
34  end
35
36  endmodule

26行

if (sel_i == 2'b00)
q_o = a_i;
else if (sel_i == 2'b01)
q_o = b_i;
else if (sel_i == 2'b10)
q_o = c_i;
else
q_o
= d_i;

使用if else if來描述mux也是常見的coding style, 根據[3]Altera所推薦coding style,當使用if else if時,會使用priority mux來實現。

mux_1_03

這篇博文會卡這麼久,除了工作了只能用下班時間寫博文以外,對於if else if是否會有priority,我ㄧ直很不確定,因為各種所查到的資料講法都不一樣,在[3] Quartus II 8.1 Handbook Volumn 1, Chapter 1:Recommended HDL Coding Styles與[4] 特權同學的深入淺出玩轉FPGA的p.19中,都認為if else if會有priority,由RTL Viewer看來也是如此, 但在[5] Guide to HDL Coding Style for Synthesis p.1-7與[6] 劉福奇, 劉波 2010, Verilog HDL應用程序設計實例精講, 電子工業出版社的p.217,都認為if else if與case意義相同無priority,所以看起來if else if的認知與synthesizer有強烈的關係,我個人是傾向Altera所建議的coding style:case代表parallel mux,if else if代表priority mux

testbench與simulation結果與使用case都一樣,所以省略。

3.使用?:
mux_ternary.v / Verilog
 

1 /*
2 (C) OOMusou 2010 http://oomusou.cnblogs.com
3
4 Filename : mux_ternary.v
5 Simulator : NC-Verilog 5.4 + Debussy 5.4 v9 + Quartus II 8.1
6 Description : mux by ?:
7 Release : Aug.30,2010 1.0
8  */
9
10 `timescale 1 ns/1 ns
11
12  module mux_ternary (
13 a_i,
14 b_i,
15 c_i,
16 d_i,
17 sel_i,
18 q_o
19 );
20
21  input a_i, b_i, c_i, d_i;
22  input [1:0] sel_i;
23  output q_o;
24
25  assign q_o = (sel_i == 2'b00) ? a_i :
26   (sel_i == 2'b01) ? b_i :
27   (sel_i == 2'b10) ? c_i :
28   d_i;
29
30  endmodule

25行

assign q_o = (sel_i == 2'b00) ? a_i :
(sel_i == 2'b01) ? b_i :
(sel_i == 2'b10) ? c_i :
d_i;

有些人的coding style是always只給sequential logic,若純combinational logic則用?:表示,為了與always做區隔,這種寫法其實跟if else if完全一樣,在Quartus II的RTL Viewer也完全一樣,都是使用priority mux實現。

mux_1_03 

4:使用步林運算式
mux_assign.v / Verilog

1 /*
2 (C) OOMusou 2010 http://oomusou.cnblogs.com
3
4 Filename : mux_assign.v
5 Simulator : NC-Verilog 5.4 + Debussy 5.4 v9 + Quartus II 8.1
6 Description : mux by assign
7 Release : Sep.22,2010 1.0
8  */
9
10  module mux_assign (
11 a_i,
12 b_i,
13 c_i,
14 d_i,
15 sel_i,
16 q_o
17 );
18
19  input a_i;
20  input b_i;
21 input c_i;
22 input d_i;
23 input [1:0] sel_i;
24 output q_o;
25
26 assign q_o = (~sel_i[1] & ~sel_i[0] & a_i) |
27 (~sel_i[1] & sel_i[0] & b_i) |
28 ( sel_i[1] & ~sel_i[0] & c_i) |
29 ( sel_i[1] & sel_i[0] & d_i);
30
31 endmodule

這是最基本的作法,只要剛開始學邏輯設計就會這招,雖然很低階,但很多時候這種方式這種方式卻是最實用的,而且也不花俏,Synthesizer一定看的懂。

mux_1_00

 

前4種都是正統推薦的寫法,後面要講的都是不推薦的寫法,主要是讓我們知道這樣為什麼不好,並不是鼓勵大家這樣寫。

5.使用multiple if
mux_multi_if.v / Verilog  

1 /*
2 (C) OOMusou 2010 http://oomusou.cnblogs.com
3
4 Filename : mux_mult_if.v
5 Simulator : NC-Verilog 5.4 + Debussy 5.4 v9 + Quartus II 8.1
6 Description : mux by mutiple if
7 Release : Sep.1,2010 1.0
8  */
9
10 `timescale 1 ns/1 ns
11
12  module mux_multi_if (
13 a_i,
14 b_i,
15 c_i,
16 d_i,
17 sel_i,
18 q_o
19 );
20
21  input a_i, b_i, c_i, d_i;
22  input [1:0] sel_i;
23  output q_o;
24
25  reg q_o;
26
27  always@(sel_i or a_i or b_i or c_i or d_i) begin
28 q_o = 1'bx;
29  
30 if (sel_i == 2'b00)
31   q_o = a_i;
32
33 if (sel_i == 2'b01)
34   q_o = b_i;
35
36 if (sel_i == 2'b10)
37   q_o = c_i;
38
39 if (sel_i == 2'b11)
40   q_o = d_i;
41  end
42
43  endmodule

這種寫法比較少見,但偶而還是會看到有人會用multi if來寫,若以C與simulation的角度來看,這種寫法邏輯絕對正確,但若以synthesizer的角度來看,由於每個if都沒有else,在[3] Altera所建議的coding style中,沒有else的就暗示有latch,儘管multi if將所有的條件都列出而不該有latch,但這種寫法會增加synthesizer的判斷難度而造成誤判,所以較不推薦這種寫法。

28行

q_o = 1'bx;

還特別將q_o加一個default值為don't care(unknown對synthesizer為don't care),若不加這個don't care,RTL Viewer會多合出1個latch,稍後會解釋。

30行

if (sel_i == 2'b00)
q_o = a_i;

if (sel_i == 2'b01)
q_o = b_i;

if (sel_i == 2'b10)
q_o = c_i;

if (sel_i == 2'b11)
q_o = d_i;

使用multi if列出所有條件。

至於這樣代表什麼電路呢?在[3] Altera所建議的coding style並沒有明確的講是什麼電路,在[4] 特權同學的深入淺出玩轉FPGA的p.27,認為multi if跟case一樣,會合成出parallel mux,在其他的書大都認為multi if合成出priority mux,在Quartus II的RTL Viewer看到的也是priority mux。

mux_1_03

我個人的認知也是頃向priority mux。

回到之前的問題,若沒加上q_o = 1'bx 會如何呢?

reg q_o;

always@(sel_i or a_i or b_i or c_i or d_i) begin
if (sel_i == 2'b00)
q_o = a_i;

if (sel_i == 2'b01)
q_o = b_i;

if (sel_i == 2'b10)
q_o = c_i;

if (sel_i == 2'b11)
q_o = d_i;
end

對pre sim來說,這樣也完全正確,但對Quartus II來說,已經提出了warning

Warning (10240): Verilog HDL Always Construct warning at mux_multi_if.v(27): inferring latch(es) for variable "q_o", which holds its previous value in one or more paths through the always construct

Warning: LATCH primitive
"q_o$latch" is permanently enabled

 mux_1_04

由RTL Viewer觀察,也真的多出了latch,並且從原本3個比較器變成4個comparator,因為你動用了4個if,所以合出4個comparator似乎也是合理。

除此之外,或許你會問:『在RTL用unknown不太好吧,RTL應該只有0或1,unknown會讓synthesizer認為don't care,可能0或1,而造成pre-sim與post-sim結果不一樣。』

在絕大部分狀況下,RTL都不該用unknown,應該給default值0或者1,但這裡比較特別,因為後面的if是full case,也就是列出了所有狀況,會自動蓋掉default的unknown,而unknown只希望告訴synthesizer default就是don't care,要synthesizer不用去合成出latch,而且也因為後面的if是full case,並不會造成pre-sim與post-sim結果不同。

若將default改成0,結果會怎樣呢?

reg q_o;

always@
(sel_i or a_i or b_i or c_i or d_i) begin
q_o
= 1'b0;

if (sel_i == 2'b00)
q_o
= a_i;

if (sel_i == 2'b01)
q_o
= b_i;

if (sel_i == 2'b10)
q_o
= c_i;

if (sel_i == 2'b11)
q_o
= d_i;
end

Quartus II不再會有產生latch的警告,不過RTL Viewer卻不是很理想。

mux_1_05

Quartus II使用了4個mux與4個comparator與4個mux,雖然已經沒有latch,但還是沒有使用q_o = 1'bx的結果好。

由此可知,使用multi if的寫法,真的造成synthesizer很大的負擔,在這麼簡單的程式中,就已經搞成這樣,很難想像在真的project中,那種複雜的程式結果會怎樣,所以不建議使用multi if寫法。

6.使用2層nested if
mux_nested_if.v / Verilog 

1 /*
2 (C) OOMusou 2010 http://oomusou.cnblogs.com
3
4 Filename : mux_nested_if_2.v
5 Simulator : NC-Verilog 5.4 + Debussy 5.4 v9 + Quartus II 8.1
6 Description : mux by 2 nested if
7 Release : Aug.30,2010 1.0
8 */
9
10 module mux_nested_if_2 (
11 a_i,
12 b_i,
13 c_i,
14 d_i,
15 sel_i,
16 q_o
17 );
18
19 input a_i;
20 input b_i;
21 input c_i;
22 input d_i;
23 input [1:0] sel_i;
24 output q_o;
25
26 reg q_o;
27
28 always@(a_i or b_i or c_i or d_i or sel_i) begin
29 if (~sel_i[1])
30 if (~sel_i[0])
31 q_o = a_i;
32 else
33 q_o = b_i;
34 else
35 if (~sel_i[0])
36 q_o = c_i;
37 else
38 q_o = d_i;
39 end
40
41 endmodule

29行

if (~sel_i[1])
if (~sel_i[0])
q_o
= a_i;
else
q_o
= b_i;
else
if (~sel_i[0])
q_o
= c_i;
else
q_o
= d_i;

根據每個bit而使用nested if來描述mux,在[1] Douglas J. Smith, HDL Chip Design, A practical guide for designing, synthesizing and simulating ASICs and FPGAs using VHDL or Verilog的p.138出現這種寫法,在實務上,我發現有軟體背景的人寫RTL比較容易出現這種寫法,因為在C中,nested if相當自然,但硬體背景的人不太會寫nested if,因為知道巢狀寫的越深,則電路延遲就越大,因此巢狀延伸的層數不宜太多,以免電路跑不快[2],也就是fmax會較差,因為可能產生critical path。

若依照原本的程式,應該合成出以下的電路。

mux_1_06

不過現在synthesizer都很聰明,對於巢狀if通常都會看的懂,自動會用parallel mux去實現。

mux_1_07

Quartus II在這裡有點搞笑,已經用parallel mux去實現了,但最後又多了一個mux,而且0與1還接同一個out0,擺明了這個mux根本無用,我是不懂為什麼Quartus II會這樣子合成,不知道Quartus II新版本會不會有改進(後來我裝了最新的Quartus II 10.0後,結果還是一樣沒變)。

在此我們看到了nested if雖然也能代表mux,但卻必須強烈依賴synthesizer的合成功力,與其如此,還不如coder自己在code就能掌握要合成什麼電路,所以也不太建議使用巢狀if來寫mux。

7.使用3層nested if
mux_nested_if_3.v / Verilog
 

1 /*
2 (C) OOMusou 2010 http://oomusou.cnblogs.com
3
4 Filename : mux_nested_if_3.v
5 Simulator : NC-Verilog 5.4 + Debussy 5.4 v9 + Quartus II 8.1
6 Description : mux by 3 nested if
7 Release : Sep.1,2010 1.0
8 */
9
10 module mux_nested_if_3 (
11 a_i,
12 b_i,
13 c_i,
14 d_i,
15 sel_i,
16 q_o
17 );
18
19 input a_i;
20 input b_i;
21 input c_i;
22 input d_i;
23 input [1:0] sel_i;
24 output q_o;
25
26 reg q_o;
27
28 always@(a_i or b_i or c_i or d_i or sel_i) begin
29 if (sel_i == 2'b00)
30 q_o = a_i;
31 else begin
32 if (sel_i == 2'b01)
33 q_o = b_i;
34 else begin
35 if (sel_i == 2'b10)
36 q_o = c_i;
37 else
38 q_o = d_i;
39 end
40 end
41 end
42
43 endmodule

32行

if (sel_i == 2'b00)
q_o = a_i;
else begin
if (sel_i == 2'b01)
q_o = b_i;
else begin
if (sel_i == 2'b10)
q_o = c_i;
else
q_o
= d_i;
end
end

使用了3層nested if,初學者很容易寫出這種code,先不討論Verilog,若以C的觀點,表面上雖然是3層if,若仔細的去思考,其實它的意義與使用if else if是相同的。

if (sel_i == 2'b00)
q_o = a_i;
else if (sel_i == 2'b01)
q_o = b_i;
else if (sel_i == 2'b10)
q_o = c_i;
else
q_o
= d_i;

所以這種是假的3層nested if,Quartus II在合成時,與第2種方法:使用if else if的結果完全一樣。

mux_1_03

這告訴我們,若寫出3層以上的nested if時,可以冷靜思考真的需要嗎?是不是其實一層的if esle if就可以實現了,雖然可能不會影響最後合成結果,但最少code的可讀性更高。

8.使用case(1)
mux_case_1.v / Verilog
 

1 /*
2 (C) OOMusou 2010 http://oomusou.cnblogs.com
3
4 Filename : mux_case_1.v
5 Simulator : NC-Verilog 5.4 + Debussy 5.4 v9 + Quartus II 8.1
6 Description : mux by case_1
7 Release : Sep.1,2010 1.0
8 */
9
10 module mux_case_1 (
11 a_i,
12 b_i,
13 c_i,
14 d_i,
15 sel_i,
16 q_o
17 );
18
19 input a_i;
20 input b_i;
21 input c_i;
22 input d_i;
23 input [1:0] sel_i;
24 output q_o;
25
26 reg q_o;
27
28 always@(a_i or b_i or c_i or d_i or sel_i) begin
29 case (1) // synthesis parallel_case full_case
30 (sel_i == 2'b00) : q_o = a_i;
31 (sel_i == 2'b01) : q_o = b_i;
32 (sel_i == 2'b10) : q_o = c_i;
33 (sel_i == 2'b11) : q_o = d_i;
34 endcase
35 end
36
37 endmodule

29行

case (1) // synthesis parallel_case full_case
(sel_i == 2'b00) : q_o = a_i;
(sel_i == 2'b01) : q_o = b_i;
(sel_i == 2'b10) : q_o = c_i;
(sel_i == 2'b11) : q_o = d_i;
endcase

首先我必須承認這是很變態的寫法,不值得學習, 但當成Verilog語法的學習倒可以,順便知道這樣為什麼不好。

先看合成結果,會使用1個parallel mux與4個comparator,這與預期符合,雖然不像第一種寫法直接用case這麼漂亮,但最少已經用了parallel mux,且沒有priority,而且4個compartor也在預期當中。

mux_1_10

但這是要付出代價的,動用了parallel_case與full_case 2個synthesis directive!!

之所以會這樣寫,主要是因為Verilog提供了一個大部分語言(包括VHDL、C/C++、C#、Java、JavaScript、VB..)所沒有的神奇功能,目前僅在VB.NET看到過有這種寫法,在case item竟然可以擺運算式,若你在C這樣寫,會給你『case expression not constant』的錯誤訊息,VHDL也規定case item必須是常數,這導致Verilog的case可以寫出"case if true"的coding style,也就是在case中寫if else if的感覺。

由於case expression形同虛設,主要都在case item判斷,所以case expression只要給1就行。

但case (1)的問題來了,synthesizer無法藉由case expression與case item來判斷是否為full case,所以當Quartus II遇到你用case (1)寫法時,會出下以下warning。

Warning (10763): Verilog HDL warning at mux_case_1.v(29): case statement has overlapping case item expressions with non-constant or don't care bits - unable to check case statement for completeness

所以這時候就該適時使用 // synthesis full_case 來告訴Quartus II:『我這個case是full的!!』 。一般來說,// synthesis full_case 被誤用都是因為本來不是full case硬使用 // synthesis full_case 而造成pre-sim與post-sim結果不一樣,我們這個例子因為肯定是full case,所以不會造成pre-sim與post-sim不同。

除此之外,case (1)因為是"case if true",所以synthesizer很容易當成if else if的方式認知,而合成出具有priority的電路,所以case (1)寫法時,通常會搭配 // synthesis parallel_case,這也是為什麼這個例子要同時使用full_case與parallel_case。

若沒加上//synthesis full_case parallel_case會怎樣呢?

case (1)
(sel_i
== 2'b00) : q_o = a_i;
(sel_i == 2'b01) : q_o = b_i;
(sel_i == 2'b10) : q_o = c_i;
(sel_i == 2'b11) : q_o = d_i;
endcase

 mux_1_11

夠慘吧,不知道在合什麼,而且還有latch。

結論還是不贊成這樣寫,通常case (1)都不是好coding style [7],除非用在one-hot encoding時 [7],以後會有專文討論。這裡只是順便用來展示Verilog case (1)這種獨門絕技,並且適時搭配// synthesis full_case // synthesis parallel_case

以上是我目前所知能合成出mux的8種coding style,若你還知道其他寫法,請告訴我。其中前4種為推荐的寫法,後4種並不推薦。

各種coding style的Technology Map Viewer比較

若去比較以上7種寫法的所佔用資源的狀況,會有驚人的發現,雖然7種寫法的RTL Viewer不一樣,但最後mapping的結果卻完全一樣,僅佔2個LE。

mux_1_12 

再打開Technology Map Viewer一看,7種寫法也完全一樣,都只佔用了2個LE,而且是完全利用2個LE(這也是為什麼我舉4對1 mux為例的意義,稍後要講的Restructure Multiplexer選項就是利用4對1 mux能完全利用2個LE的優點來減少LE的使用),也就是說,無論你code怎麼寫,最後在FPGA都是一樣的,最後都是用parallel mux實現

mux_1_13 

難怪很多人說,RTL Viwer只能參考用,畢竟這只是Quartus II初步對你code認知的結果,要到mapping之後,才能完全確定Quartus II是如何實現,因為Cyclone系列一個LE的LUT是基於4 input,所以一個1個4x1 mux加上sel_i[1:0]一共6個input,就要動用2個LE,若是Stratix系列,一個LE的LUT是基於6 input,就只需1個LE就能搞定。

Quartus II對mux的優化選項

Quartus II另外提供了對mux的優化選項,以Quartus II 8.1來說,在Assignments –> Settings –> Analysis & Synthesis Settings的Restructure Multiplexers。

 mux_1_15

以下是Tcl的方式:(on/off/auto可自己更改)

set_global_assignment -name mux_restructure on

首先簡單的談這個選項的意義,因為FPGA是基於4 input LUT(以Cyclone為例), 若你寫了很多的if,基本上每個if都會是一個2對1的mux,對1個LE來說,只用了3個input,另外1個input就空著沒用,等下一個2對1的mux需要時,又是另外開一個LE,這樣就造成了LE的浪費,若使用了Restruecture Multiplexer後,Quartus II會在truth table結果不變的前提下,重新將2對1的mux組合成4對1的mux,由上面的例子可知,4對1的mux剛好2個LE用滿,沒有浪費,這樣LE的利用率就越高,就可越節省LE的使用,當然代價就是需要另外用control logic去做轉換,combinational logic gate delay會較大,Fmax會較差。在[7] Multiplexer Restructuring for FPGA Implementation Cost Reduction中,有對Restruecture Multiplexer演算法詳細的描述,以下引兩張該paper的圖解釋。

mux_1_16

mux_1_17

 

原來2對1 mux tree被restructure成4對1 mux並帶一些control logic,因為4對1 max可以完全利用2個4 input LUT的LE,如此可大大增加LE的使用率,而節省LE的使用。當然這只是最初步的解釋,詳細還是請參考[7] Multiplexer Restructuring for FPGA Implementation Cost Reduction,這是Altera原廠的paper。

根據[3] Quartus II 8.1 Handbook Volume 1, Section III Synthesis, Chapter 8, Quartus II Synthesis Options : Restructure Multiplexers的解釋,這個設定可以有三種選項:

On : 永遠執行mux restructure來減少LE,但有可能使Fmax變差(因為多了control logic後,gate delay較大,所以Fmax會較差)。

Off:永遠不執行mux restructure。

Auto:(default) 當Optimization Technique選Speed、Balance或者Area時,會自動執行mux restructure,尤其當選擇speed時,會選擇性的restructure mux,已達成speed的需求,並且也能減少LE的使用率。

完整程式碼下載
mux_case.7z (使用case)
mux_if_else_if.7z (使用if else if)
mux_ternary.7z (使用?:)
mux_assign.7z (使用步林運算式)
mux_multi_if.7z (使用multi if)
mux_nested_if_2.7z (使用2層nested if)
mux_nested_if_3.7z (使用3層nested if)
mux_case_1.7z (使用 case (1))

Conclusion
1.Verilog是HDL,寫法要保守

之前的博文我就已經多次強調過,Verilog是HDL,是硬體描述語言,而不是硬體程式語言,所以絕對不能像寫C一樣,寫C只要語法對,邏輯對,C compiler就看的懂,你也不用去考慮C compiler會編譯成什麼組合語言,更不能像C++一樣,一味的追求語法華麗,而產生出像template或STL, boost那種看起來很爽的寫法,寫Verilog時,自己一定要能清楚掌握你想要合成出什麼樣的硬體,然後用synthesizer能看的懂得寫法去寫,而不是只求Verilog語法邏輯正確,或者語法簡潔華麗,卻不知道synthesizer最後會合成出什麼硬體。其實好的RTL都很樸實,就是always block,if else if描述條件,case描述FSM,偶爾搭配?:,大概就這4種寫法就打死一切了,並沒有用什麼高級的寫法。樸實的寫法除了讓synthesizer看的懂外,在ASIC開發時,最後總逃不過ECO,若連你自己都不知道code會合成出什麼硬體,要怎麼去做ECO呢?

2.多層if時,考慮重新思考

初學者由於受C語言影響,很容易寫出多層nested if的程式,由以上的經驗可發現,2層與3層的if都可以化簡成if else if或者case,所以真的寫出多層if時,可以重新考慮是否有化簡的可能,畢竟恐龍級的nested if並不好閱讀。

3.在FPGA,RTL Viewer並不是最後的結果,Technology Map Viewer才是最後結果

由於FPGA的工藝是採用4 input LUT的LE,與ASIC不一樣,所以不能光看RTL Viewer就斷定合成的結果,而必須看過經過mapping後的Technology Map Viewer才能真正確定是如何在FPGA實現。雖然以上7個coding style在Altera FPGA結果都一樣,但也不代表RTL我們可以亂寫,雖然synthesizer的優化演算法一直在進步,但身為coder卻不能完全去依賴synthesizer的優化能力,而是應該培養好的coding style習慣,而不是在測試synthesizer的極限。基本上mux所建議的coding style就是case、if else if與?:,其他寫法都不建議。好的coding style除了有助於synthesizer合成外,對日後維護也是很有幫助。

Reference
[1] Douglas J. Smith, HDL Chip Design, A practical guide for designing, synthesizing and simulating ASICs and FPGAs using VHDL or Verilog
[2] 鄭羽伸 2006, Verilog數位電路設計範例寶典基礎篇, 儒林圖書出版社
[3] Quartus II 8.1 Handbook Volume 1, Chapter 6:Recommended HDL Coding Styles
[4] 特權同學 2010, 深入淺出玩轉FPGA, 北京航空航天大學出版社
[5] 1999, Guide to HDL Conding Style for Synthesis
[6] 劉福奇, 劉波 2010, Verilog HDL應用程序設計實例精講, 電子工業出版社
[7] Cliff Cummings 1999, "full_case parallel_case", the Evil Twins of Verilog Synthesis, Sunburst Design
[8] Paul Metzgen, Dominic Nancekievill 2005, Multiplexer Restructuring for FPGA Implementation Cost Reduction, Altera European Technology Center
[9] 廖裕評, 陸瑞強 2006, 系統晶片設計 使用Quartus II, 全華科技圖書股份有限公司

全文完。

posted on 2010-09-05 10:07  真 OO无双  阅读(61533)  评论(6编辑  收藏  举报

导航