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 coding style整理 (SOC) (Verilog) (Quartus II)

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 coding style整理 (SOC) (Verilog) (Quartus II) 

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 coding style整理 (SOC) (Verilog) (Quartus II)

這篇博文會卡這麼久,除了工作了只能用下班時間寫博文以外,對於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 coding style整理 (SOC) (Verilog) (Quartus II) 

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 coding style整理 (SOC) (Verilog) (Quartus II)

 

前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 coding style整理 (SOC) (Verilog) (Quartus II)

我個人的認知也是頃向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 coding style整理 (SOC) (Verilog) (Quartus II)

由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 coding style整理 (SOC) (Verilog) (Quartus II)

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 coding style整理 (SOC) (Verilog) (Quartus II)

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

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

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 coding style整理 (SOC) (Verilog) (Quartus II)

這告訴我們,若寫出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 coding style整理 (SOC) (Verilog) (Quartus II)

但這是要付出代價的,動用了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 coding style整理 (SOC) (Verilog) (Quartus II)

夠慘吧,不知道在合什麼,而且還有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 coding style整理 (SOC) (Verilog) (Quartus II) 

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

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

難怪很多人說,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 coding style整理 (SOC) (Verilog) (Quartus II)

以下是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 coding style整理 (SOC) (Verilog) (Quartus II)

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

 

原來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, 全華科技圖書股份有限公司

全文完。

相关文章:

  • 2021-07-21
  • 2021-07-21
  • 2021-06-25
  • 2022-03-04
  • 2021-12-22
  • 2021-08-23
  • 2021-12-24
  • 2021-06-21
猜你喜欢
  • 2021-10-16
  • 2022-01-13
  • 2022-01-04
  • 2022-02-24
  • 2021-09-01
  • 2021-11-11
  • 2021-06-25
相关资源
相似解决方案