Abstract
FSM在數位電路中非常重要,藉由FSM,可以讓數位電路也能循序地執行起演算法。本文將詳細討論各種FSM coding style的優缺點,並歸納出推薦的coding style。

Introduction
使用環境:Debussy 5.4 v9 + ModelSim SE 6.3e + Quartus II 8.1

本文將討論以下主題:

1.Moore FSM的架構

2.Moore FSM各種coding style比較

3.Mealy FSM架構

4.Mealy FSM各種coding style比較

5.實務上推薦的coding style

6.Conclusion

若要讓數位電路也能循序地執行演算法,最簡單的方式可以使用D-FF產生counter,根據counter的值去決定要執行不同的程式碼,如此也能達到使數位電路循序執行演算法的目的,不過這種方式僅適用於很簡單的演算法,在一般規模的演算法若使用counter方式,程式碼將不容易維護,所以實務上會使用FSM方式來實現演算法。

其實FSM方式也是利用counter來實現,所謂的counter,並不是只有counter = counter + 1才算是counter,FSM的state register就是廣義的counter,只是這種counter不是一直加1而已,而是有自己的遞增規則。FSM只是提供了一種較為高階與較容易維護的方式來實現演算法。

Moore FSM架構

有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP

一般在寫FSM時,會以Moore FSM為主,所以先討論Moore。由上圖可知,Moore FSM內部由3個block所構成:Next state logic,State register與Output logic。

Next state logic:純粹的組合邏輯,以整個module的input與目前的state為輸入,目的在產生下一個state值存入state register。

State register:由D-FF所構成,將Next state logic所產生的state存入register。

Output logic:純粹的組合邏輯,根據目前的state產生整個module的output。

所以可以發現,整個Moore FSM事實上是由2塊的組合邏輯與1塊D-FF所構成,我們常聽到所謂的一段式、二段式與三段式FSM,事實上就是由這3個block排列組合而成。

Moore FSM各種coding style比較

有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP

為了要實際比較各種coding style,在此舉一個簡單的例子,若input w_i為連續2個clk為high,則output會在下1個clk產生周期為1 T的high pulse,timing diagram如上圖所示。

有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP

因此設計了Moore FSM,state diagram如上圖所示,接下來要做的就是用各種coding style來實現這個Moore FSM。

1.使用3個always (三段式)

有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP

simple_fsm_moore_3_always_best.v / Verilog

有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP
 1 /* 
2 (C) OOMusou 2011 http://oomusou.cnblogs.com
3
4 Filename : simple_fsm_moore_3_always_best.v
5 Synthesizer : Quartus II 8.1
6 Description : 3 always block for moore fsm (BEST)
7 Release : Jun.05,2011 1.0
8 */
9
10 module simple_fsm (
11 clk,
12 rst_n,
13 w_i,
14 z_o
15 );
16
17 input clk;
18 input rst_n;
19 input w_i;
20 output z_o;
21
22 parameter IDLE = 2'b00;
23 parameter S0 = 2'b01;
24 parameter S1 = 2'b10;
25
26 reg [1:0] curr_state;
27 reg [1:0] next_state;
28 reg z_o;
29
30 // state reg
31 always@(posedge clk or negedge rst_n)
32 if (~rst_n) curr_state <= IDLE;
33 else curr_state <= next_state;
34
35 // next state logic
36 always@(*)
37 case (curr_state)
38 IDLE : if (w_i) next_state = S0;
39 else next_state = IDLE;
40 S0 : if (w_i) next_state = S1;
41 else next_state = IDLE;
42 S1 : if (w_i) next_state = S1;
43 else next_state = IDLE;
44 default : next_state = IDLE;
45 endcase
46
47 // output logic
48 always@(*)
49 case (curr_state)
50 IDLE : z_o = 1'b0;
51 S0 : z_o = 1'b0;
52 S1 : z_o = 1'b1;
53 default : z_o = 1'b0;
54 endcase
55
56 endmodule
有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP

35行

有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP
// next state logic    
always@(*)
case (curr_state)
IDLE : if (w_i) next_state = S0;
else next_state = IDLE;
S0 : if (w_i) next_state = S1;
else next_state = IDLE;
S1 : if (w_i) next_state = S1;
else next_state = IDLE;
default : next_state = IDLE;
endcase
有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP

使用1個always描述next state logic,因為是純粹組合邏輯,所以使用blocking。

根據Moore FSM架構圖所示,next state logic的結果與input與目前state有關,所以先用case對目前state做一次大分類,然後每個state再根據input做if判斷。

30行

// state reg
always@(posedge clk or negedge rst_n)
if (~rst_n) curr_state <= IDLE;
else curr_state <= next_state;

使用1個always描述state register,因為是D-FF且含clk,所以使用nonblocking。

由於state register區塊並不包含任何邏輯,所以不會因為不同FSM而有不同寫法,不同FSM只會改變next state logic與output logic的寫法。

47行

有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP
// output logic
always@(*)
case (curr_state)
IDLE : z_o = 1'b0;
S0 : z_o = 1'b0;
S1 : z_o = 1'b1;
default : z_o = 1'b0;
endcase
有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP

使用1個always描述output logic,因為是純粹組合邏輯,所以使用blocking。

根據Moore FSM架構圖所示,output logic的結果只與目前state有關,所以只需用case對state做一次分類即可。

使用3個always寫法有幾個優點:

1.可忠實地反映出原本的Moore FSM硬體架構
2.可輕易地將state diagram改用Verilog表示
3.將Next state logic與output logic分開,可降低code的複雜度,便於日後維護

3個always是一個推薦的寫法。

Testbench

simple_fsm_tb.v / Verilog

有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP
1 /* 
2 (C) OOMusou 2011 http://oomusou.cnblogs.com

4 Filename : simple_fsm_tb.v
5 Simulator : ModelSim SE 6.3e + Debussy 5.4 v9
6 Description : testbench for FSM
7 Release : Jun.05,2011 1.0
8  */

10  module simple_fsm_tb;
11 
12  reg clk = 1'b1;
13  reg rst_n = 1'b1;
14  reg w_i = 1'b0;
15  wire z_o;
16 
17  // clk
18  always #10 clk = ~clk;
19 
20  event after_rst;
21 
22  // rst_n
23  initial begin
24   #6; // 6ns
25   rst_n = 1'b0;
26   #30; // 36ns
27   rst_n = 1'b1;
28   ->after_rst; 
29  end
30 
31  // w_i
32  initial begin
33   @(after_rst);
34   repeat(2)@(posedge clk); // 60ns
35   w_i <= 1'b1;
36   @(posedge clk); // 80 ns
37   w_i <= 1'b0;
38   @(posedge clk); // 100 ns
39   w_i <= 1'b1;
40   repeat(2)@(posedge clk); // 140 ns
41   w_i <= 1'b0;
42   @(posedge clk); // 160 ns
43   w_i <= 1'b1;
44   repeat(3)@(posedge clk); // 220 ns
45   w_i <= 1'b0;
46 end
47 
48 initial begin
49   $fsdbDumpfile("simple_fsm.fsdb");
50   $fsdbDumpvars(0, simple_fsm_tb);
51 end
52 
53 simple_fsm u_simple_fsm (
54   .clk (clk),
55   .rst_n (rst_n),
56   .w_i (w_i),
57   .z_o (z_o)
58 );
59 
60 endmodule
有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP

執行結果

有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP

2.使用2個always (二段式)

由於要使用2個always去描述3個block,根據排列組合原理,C3取2,共有3種可能,我們一個一個討論。

2.1 state register與next state logic合一

有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP

simple_fsm_moore_2_always_0_cs_ns_good.v / Verilog

有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP
 1 /* 
2 (C) OOMusou 2011 http://oomusou.cnblogs.com
3
4 Filename : simple_fsm_moore_2_always_0_cs_ns_good.v
5 Synthesizer : Quartus II 8.1
6 Description : 2 always block for moore fsm (GOOD)
7 Release : Jun.05,2011 1.0
8 */
9
10 module simple_fsm (
11 clk,
12 rst_n,
13 w_i,
14 z_o
15 );
16
17 input clk;
18 input rst_n;
19 input w_i;
20 output z_o;
21
22 parameter IDLE = 2'b00;
23 parameter S0 = 2'b01;
24 parameter S1 = 2'b10;
25
26 reg [1:0] curr_state;
27 reg z_o;
28
29 // state reg + next state logic
30 always@(posedge clk or negedge rst_n)
31 if (~rst_n) curr_state <= IDLE;
32 else
33 case (curr_state)
34 IDLE : if (w_i) curr_state <= S0;
35 else curr_state <= IDLE;
36 S0 : if (w_i) curr_state <= S1;
37 else curr_state <= IDLE;
38 S1 : if (w_i) curr_state <= S1;
39 else curr_state <= IDLE;
40 default : curr_state <= IDLE;
41 endcase
42
43 // output logic
44 always@(*)
45 case (curr_state)
46 IDLE : z_o = 1'b0;
47 S0 : z_o = 1'b0;
48 S1 : z_o = 1'b1;
49 default : z_o = 1'b0;
50 endcase
51
52 endmodule
有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP

29行

有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP
// state reg + next state logic
always@(posedge clk or negedge rst_n)
if (~rst_n) curr_state <= IDLE;
else
case (curr_state)
IDLE : if (w_i) curr_state <= S0;
else curr_state <= IDLE;
S0 : if (w_i) curr_state <= S1;
else curr_state <= IDLE;
S1 : if (w_i) curr_state <= S1;
else curr_state <= IDLE;
default : curr_state <= IDLE;
endcase
有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP

將state register與next state logic合起來用1個always去描述,雖然next state logic是純粹的組合邏輯,為了遷就於帶clk的state register,且要用一個always描述,就必須改用nonblocking。

由於state register與next state logic合一,所以可以少宣告next_state reg,不過這並不會影響合成結果,只是可以少打幾個字而已。

因為next state logic由input與state所構成,所以先用case對state做一次大分類,然後每個state再根據input做if判斷。

43行

有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP
// output logic
always@(*)
case (curr_state)
IDLE : z_o = 1'b0;
S0 : z_o = 1'b0;
S1 : z_o = 1'b1;
default : z_o = 1'b0;
endcase
有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP

使用1個always描述output logic,因為是純粹組合邏輯,所以使用blocking。

根據Moore FSM架構圖所示,output logic的結果只與目前state有關,所以只需用case對state做一次分類即可。

使用2個always (state register與next state logic合一)寫法有幾個優點:

1.程式碼較3個always寫法精簡
2.可輕易地將state diagram改用Verilog表示
3.因為state register原本程式碼就不多,將next state logic與state register合一後,next state logic仍與output logic分開,因此不會增加code的複雜度,便於日後維護

2個always (state register與next state logic合一)也是一個推薦的寫法。

接下來要討論的都是不推薦的寫法,主要目的是了解為什麼不推薦的原因。

2.2 state register與output logic合一

有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP

simple_fsm_moore_2_always_1_cs_ol_ng.v / Verilog

有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP
 1 /* 
2 (C) OOMusou 2011 http://oomusou.cnblogs.com
3
4 Filename : simple_fsm_moore_2_always_1_cs_ol_ng.v
5 Synthesizer : Quartus II 8.1
6 Description : 2 always block for moore fsm (NO GOOD)
7 Release : Jun.05,2011 1.0
8 */
9
10 module simple_fsm (
11 clk,
12 rst_n,
13 w_i,
14 z_o
15 );
16
17 input clk;
18 input rst_n;
19 input w_i;
20 output z_o;
21
22 parameter IDLE = 2'b00;
23 parameter S0 = 2'b01;
24 parameter S1 = 2'b10;
25
26 reg [1:0] curr_state;
27 reg [1:0] next_state;
28 reg z_o;
29
30 // state reg + output logic
31 always@(posedge clk or negedge rst_n)
32 if (~rst_n) {curr_state, z_o} <= {IDLE, 1'b0};
33 else begin
34 curr_state <= next_state;
35
36 case (next_state)
37 IDLE : z_o <= 1'b0;
38 S0 : z_o <= 1'b0;
39 S1 : z_o <= 1'b1;
40 default : z_o <= 1'b0;
41 endcase
42 end
43
44 // next state logic
45 always@(*)
46 case (curr_state)
47 IDLE : if (w_i) next_state = S0;
48 else next_state = IDLE;
49 S0 : if (w_i) next_state = S1;
50 else next_state = IDLE;
51 S1 : if (w_i) next_state = S1;
52 else next_state = IDLE;
53 default : next_state = IDLE;
54 endcase
55
56 endmodule
有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP

30行

有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP
// state reg + output logic
always@(posedge clk or negedge rst_n)
if (~rst_n) {curr_state, z_o} <= {IDLE, 1'b0};
else begin
curr_state <= next_state; case (next_state)
IDLE : z_o <= 1'b0;
S0 : z_o <= 1'b0;
S1 : z_o <= 1'b1;
default : z_o <= 1'b0;
endcase
有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP

將state register與output logic合起來用1個always去描述,雖然output logic是純粹的組合邏輯,為了遷就於帶clk的state register,且要用一個always描述,就必須改用nonblocking。

因為output logic只與state有關,所以只用case對state做一次分類即可。

這種寫法最大的問題是:output logic必須用next_state去判斷!!

依照Moore FSM的架構圖得知,output logic只與目前state有關,之前的幾種FSM寫法,output logic也是由目前state去判斷,為什麼這種寫法要靠next_state去判斷呢?

主要原因是根據Moore FSM的定義,output logic只與目前state有關,且是個純粹的組合邏輯,但目前強迫將state register與output logic放在同一個always,迫使output logic必須使用nonblocking的方式呈現,也就是若output logic仍然使用目前state去做判斷,則output logic會多delay 1個clk,為了讓output logic結果正常,只好提前1個clk做判斷,也就是提前到next_state去做判斷

所以當我們從state diagram換成Verilog表示時,若使用2個always,且是state register與output logic合一時,必須很小心要使用next_state去做output logic判斷,因為這個地方很不直覺,很容易出錯,所以不推薦這種寫法

44行

有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP
// next state logic    
always@(*)
case (curr_state)
IDLE : if (w_i) next_state = S0;
else next_state = IDLE;
S0 : if (w_i) next_state = S1;
else next_state = IDLE;
S1 : if (w_i) next_state = S1;
else next_state = IDLE;
default : next_state = IDLE;
endcase
有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP

使用1個always描述next state logic,因為是純粹組合邏輯,所以使用blocking。

根據Moore FSM架構圖所示,next state logic的結果與input與目前state有關,所以先用case對目前state做一次大分類,然後每個state再根據input做if判斷。

使用2個always (state register與output logic合一)寫法的缺點:

當使用1個always去描述state register與output logic時,output logic必須使用next_state做判斷,而非用目前state判斷,由於寫法不直覺,一不小心很容易弄錯

不推薦2個always (state register與output logic合一)寫法。

或許你會說,在實務上卻常看到state register與output logic合一的寫法,為什麼不會出問題?那是因為儘管是用Moore FSM,我們為了timing更好,常會在output時多敲一個D-FF,讓Output Logic的組合邏輯不要與其他module的input的組合邏輯合併,避免造成critical path,假如是這種需求,state register與output logic合一後,可以直接判斷curr_state,不用提早一個clk判斷next_state。

2.3 next state logic與output logic合一

有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP

simple_fsm_moore_2_always_2_ns_ol_ng.v / Verilog

有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP
 1 /* 
2 (C) OOMusou 2011 http://oomusou.cnblogs.com
3
4 Filename : simple_fsm_moore_2_always_2_ns_ol_ng.v
5 Synthesizer : Quartus II 8.1
6 Description : 2 always block for moore fsm (NO GOOD)
7 Release : Jun.05,2011 1.0
8 */
9
10 module simple_fsm (
11 clk,
12 rst_n,
13 w_i,
14 z_o
15 );
16
17 input clk;
18 input rst_n;
19 input w_i;
20 output z_o;
21
22 parameter IDLE = 2'b00;
23 parameter S0 = 2'b01;
24 parameter S1 = 2'b10;
25
26 reg [1:0] curr_state;
27 reg [1:0] next_state;
28 reg z_o;
29
30 // state reg
31 always@(posedge clk or negedge rst_n)
32 if (~rst_n) curr_state <= IDLE;
33 else curr_state <= next_state;
34
35 // next state logic + output logic
36 always@(*)
37 case (curr_state)
38 IDLE : if (w_i) {next_state, z_o} = {S0 , 1'b0};
39 else {next_state, z_o} = {IDLE, 1'b0};
40 S0 : if (w_i) {next_state, z_o} = {S1 , 1'b0};
41 else {next_state, z_o} = {IDLE, 1'b0};
42 S1 : if (w_i) {next_state, z_o} = {S1 , 1'b1}; // always output 1'b1
43 else {next_state, z_o} = {IDLE, 1'b1}; // always output 1'b1
44 default : {next_state, z_o} = {IDLE, 1'b0};
45 endcase
46
47 endmodule
有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP

30行

// state reg
always@(posedge clk or negedge rst_n)
if (~rst_n) curr_state <= IDLE;
else curr_state <= next_state;

使用1個always描述state register,因為是D-FF且含clk,所以使用nonblocking。

由於state register區塊並不包含任何邏輯,所以不會因為不同FSM而有不同寫法,不同FSM只會改變next state logic與output logic的寫法。

35行

有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP
// next state logic + output logic 
always@(*)
case (curr_state)
IDLE : if (w_i) {next_state, z_o} = {S0 , 1'b0};
else {next_state, z_o} = {IDLE, 1'b0};
S0 : if (w_i) {next_state, z_o} = {S1 , 1'b0};
else {next_state, z_o} = {IDLE, 1'b0};
S1 : if (w_i) {next_state, z_o} = {S1 , 1'b1}; // always output 1'b1
else {next_state, z_o} = {IDLE, 1'b1}; // always output 1'b1
default : {next_state, z_o} = {IDLE, 1'b0};
endcase
有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP

將next state logic與output logic使用同一個always去描述,由於next state logic與output logic都是純粹的組合邏輯,所以使用blocking描述沒有問題。

由於next state logic與input與目前state有關,但output logic卻只與目前state有關,因為都是先用目前state做case判斷,然後再對input做if判斷,所以會出現output兩次都出現1的情形,起因於output logic只與目前state有關,與input無關,固任何input都會出現1。

使用2個always (next state logic與output logic合一)寫法的缺點:

1.將next state logic與output logic合一只會增加code的複雜度,日後維護會更加困難
2.很類似Mealy FSM寫法,容易讓人誤以為是Mealy FSM

不推薦2個always (next state logic與output logic合一)寫法。

3.使用1個always (一段式)

有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP

simple_fsm_moore_1_always_ng.v / Verilog

有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP
 1 /* 
2 (C) OOMusou 2011 http://oomusou.cnblogs.com
3
4 Filename : simple_fsm_moore_1_always_ng.v
5 Synthesizer : Quartus II 8.1
6 Description : 1 always block for moore fsm (NO GOOD)
7 Release : Jun.05,2011 1.0
8 */
9
10 module simple_fsm (
11 clk,
12 rst_n,
13 w_i,
14 z_o
15 );
16
17 input clk;
18 input rst_n;
19 input w_i;
20 output z_o;
21
22 parameter IDLE = 2'b00;
23 parameter S0 = 2'b01;
24 parameter S1 = 2'b10;
25
26 reg [1:0] curr_state;
27 reg z_o;
28
29 always@(posedge clk or negedge rst_n)
30 if (~rst_n) {curr_state, z_o} <= {IDLE, 1'b0};
31 else
32 case (curr_state)
33 IDLE : if (w_i) {curr_state, z_o} <= {S0, 1'b0};
34 else {curr_state, z_o} <= {IDLE, 1'b0};
35 S0 : if (w_i) {curr_state, z_o} <= {S1, 1'b1}; //?
36 else {curr_state, z_o} <= {IDLE, 1'b0};
37 S1 : if (w_i) {curr_state, z_o} <= {S1, 1'b1};
38 else {curr_state, z_o} <= {IDLE, 1'b0}; //?
39 default : {curr_state, z_o} <= {IDLE, 1'b0};
40 endcase
41
42 endmodule
有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP

29行

有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP
always@(posedge clk or negedge rst_n)
if (~rst_n) {curr_state, z_o} <= {IDLE, 1'b0};
else
case (curr_state)
IDLE : if (w_i) {curr_state, z_o} <= {S0, 1'b0};
else {curr_state, z_o} <= {IDLE, 1'b0};
S0 : if (w_i) {curr_state, z_o} <= {S1, 1'b1}; //?
else {curr_state, z_o} <= {IDLE, 1'b0};
S1 : if (w_i) {curr_state, z_o} <= {S1, 1'b1};
else {curr_state, z_o} <= {IDLE, 1'b0}; //?
default : {curr_state, z_o} <= {IDLE, 1'b0};
endcase
有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP

使用1個always同時描述next state logic、state register與output logic,雖然next state logic與output logic是純粹的組合邏輯,但為了遷就於帶clk的state register,所以必須使用nonblocking。

根據之前的經驗,由於Moore FSM的output logic只與目前state state有關,且是純粹的組合邏輯,若硬要與state register用同一個always去描述,判斷上會出現一些問題,需提早1個clk用next state判斷(在state register與output logic合一時曾經遇過)。

在1個always內,連next_state也省了,所以在35行

S0 : if (w_i) {curr_state, z_o} <= {S1, 1'b1};

當目前state為S0且輸入為1'b1時,output必須提前為1,因為這是在nonblocking內!!

37行

S1 : if (w_i) {curr_state, z_o} <= {S1, 1'b1};

同理,在目前state為S1且輸入為1'b1時,output也必須提前為1,也因為這是在nonblocking內!!

使用1個always寫法的缺點:

1.因為使用nonblocking去描述output logic,所以要提早1個clk判斷,要特別小心處理,一不小心很容易弄錯
2.1個always內同時包含next state logic與output logic,會增加code的複雜度,日後維護更加困難

不推薦1個always寫法。

Mealy FSM架構

有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP

談完了Moore FSM,接下來談Mealy FSM,與Moore FSM的差別只在於Moore FSM的output logic只由目前state決定,但是Mealy FSM可由目前state與input共同決定。

Mealy FSM各種coding style比較

有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP

將之前的例子用Mealy FSM重新改寫,原本在Moore FSM下,若input w_i為連續2個clk為high,則output會在下1個clk產生週期為1 T的high pulse,若改用Mealy FSM,則output會提早1個clk出現,如上圖所示。

有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP

原本Moore FSM需要3個state,若改用Mealy FSM後,會只剩下2個state,接下來要用各種coding style來實現Mealy FSM。

1.使用3個always (三段式)

有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP

simple_fsm_mealy_3_always_best.v / Verilog

有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP
 1 /* 
2 (C) OOMusou 2011 http://oomusou.cnblogs.com
3
4 Filename : simple_fsm_mealy_3_always_best.v
5 Synthesizer : Quartus II 8.1
6 Description : 3 always block for mealy fsm (BEST)
7 Release : Jun.05,2011 1.0
8 */
9
10 module simple_fsm (
11 clk,
12 rst_n,
13 w_i,
14 z_o
15 );
16
17 input clk;
18 input rst_n;
19 input w_i;
20 output z_o;
21
22 parameter IDLE = 2'b00;
23 parameter S0 = 2'b01;
24
25 reg [1:0] curr_state;
26 reg [1:0] next_state;
27 reg z;
28 reg z_o;
29
30 // state reg
31 always@(posedge clk or negedge rst_n)
32 if (~rst_n) curr_state <= IDLE;
33 else curr_state <= next_state;
34
35 // next state logic
36 always@(*)
37 case (curr_state)
38 IDLE : if (w_i) next_state = S0;
39 else next_state = IDLE;
40 S0 : if (w_i) next_state = S0;
41 else next_state = IDLE;
42 default : next_state = IDLE;
43 endcase
44
45 // output logic
46 always@(*)
47 case (curr_state)
48 IDLE : if (w_i) z = 1'b0;
49 else z = 1'b0;
50 S0 : if (w_i) z = 1'b1;
51 else z = 1'b0;
52 default : z = 1'b0;
53 endcase
54
55 // mealy output to delay 1 clk for moore
56 always@(posedge clk or negedge rst_n)
57 if (~rst_n) z_o <= 1'b0;
58 else z_o <= z;
59
60 endmodule
有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP

30行

// state reg
always@(posedge clk or negedge rst_n)
if (~rst_n) curr_state <= IDLE;
else curr_state <= next_state;

使用1個always描述state register。

35行

有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP
// next state logic    
always@(*)
case (curr_state)
IDLE : if (w_i) next_state = S0;
else next_state = IDLE;
S0 : if (w_i) next_state = S0;
else next_state = IDLE;
default : next_state = IDLE;
endcase
有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP

使用1個always描述next state logic。

45行

有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP
// output logic
always@(*)
case (curr_state)
IDLE : if (w_i) z = 1'b0;
else z = 1'b0;
S0 : if (w_i) z = 1'b1;
else z = 1'b0;
default : z = 1'b0;
endcase
有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP

使用1個always描述output logic。

以上3個always寫法與Moore FSM的3個always並無差異,基本上只要state diagram畫的出來,就能等效地用Verilog描述出來。

55行

// mealy output to delay 1 clk for moore  
always@(posedge clk or negedge rst_n)
if (~rst_n) z_o <= 1'b0;
else z_o <= z;

之前提到使用Mealy FSM會少Moore FSM 1個state,且output會早Moore FSM 1個clk,所以最後特別將output在敲一級delay 1個clk,這樣Mealy FSM就會完全與Moore FSM一樣。

使用3個always寫法有幾個優點:

1.可忠實地反映出原本的Mealy FSM硬體架構
2.可輕易地將state diagram改用Verilog表示
3.將Next state logic與output logic分開,可降低code的複雜度,便於日後維護

3個always是一個推薦的寫法。

2.使用2個always (兩段式)

由於要使用2個always去描述3個block,根據排列組合原理,C3取2,共有3種可能,我們一個一個討論。

2.1 state register與next state logic合一

有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP

simple_fsm_mealy_2_always_0_cs_ns_good.v / Verilog

有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP
 1 /* 
2 (C) OOMusou 2011 http://oomusou.cnblogs.com
3
4 Filename : simple_fsm_mealy_2_always_0_cs_ns_good.v
5 Synthesizer : Quartus II 8.1
6 Description : 2 always block for mealy fsm (GOOD)
7 Release : Jun.05,2011 1.0
8 */
9
10 module simple_fsm (
11 clk,
12 rst_n,
13 w_i,
14 z_o
15 );
16
17 input clk;
18 input rst_n;
19 input w_i;
20 output z_o;
21
22 parameter IDLE = 2'b00;
23 parameter S0 = 2'b01;
24
25 reg [1:0] curr_state;
26 reg z;
27 reg z_o;
28
29 // state reg + next state logic
30 always@(posedge clk or negedge rst_n)
31 if (~rst_n) curr_state <= IDLE;
32 else
33 case (curr_state)
34 IDLE : if (w_i) curr_state <= S0;
35 else curr_state <= IDLE;
36 S0 : if (w_i) curr_state <= S0;
37 else curr_state <= IDLE;
38 default : curr_state <= IDLE;
39 endcase
40
41 // output logic
42 always@(*)
43 case (curr_state)
44 IDLE : if (w_i) z = 1'b0;
45 else z = 1'b0;
46 S0 : if (w_i) z = 1'b1;
47 else z = 1'b0;
48 default : z = 1'b0;
49 endcase
50
51 // mealy output to delay 1 clk for moore
52 always@(posedge clk or negedge rst_n)
53 if (~rst_n) z_o <= 1'b0;
54 else z_o <= z;
55
56 endmodule
有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP

29行

有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP
// state reg + next state logic
always@(posedge clk or negedge rst_n)
if (~rst_n) curr_state <= IDLE;
else
case (curr_state)
IDLE : if (w_i) curr_state <= S0;
else curr_state <= IDLE;
S0 : if (w_i) curr_state <= S0;
else curr_state <= IDLE;
default : curr_state <= IDLE;
endcase
有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP

使用1個always同時描述state register與next state logic。

41行

有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP
// output logic
always@(*)
case (curr_state)
IDLE : if (w_i) z = 1'b0;
else z = 1'b0;
S0 : if (w_i) z = 1'b1;
else z = 1'b0;
default : z = 1'b0;
endcase
有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP

使用1個always描述output logic。

以上2個always寫法(state register與next state logic合一)與Moore FSM的2個always寫法(state register與next state logic合一)並無差異,基本上只要state diagram畫的出來,就能等效地用Verilog描述出來。

51行

// mealy output to delay 1 clk for moore  
always@(posedge clk or negedge rst_n)
if (~rst_n) z_o <= 1'b0;
else z_o <= z;

之前提到使用Mealy FSM會少Moore FSM 1個state,且output會早Moore FSM 1個clk,所以最後特別將output在敲一級delay 1個clk,這樣Mealy FSM就會完全與Moore FSM一樣。

使用2個always (state register與next state logic合一)寫法有幾個優點:

1.程式碼較3個always寫法精簡
2.可輕易地將state diagram改用Verilog表示
3.因為state register原本程式碼就不多,將next state logic與state register合一後,next state logic仍與output logic分開,因此不會增加code的複雜度,便於日後維護

2個always (state register與next state logic合一)也是一個推薦的寫法。

接下來要討論的都是不推薦的寫法,主要目的是了解為什麼不推薦的原因。

2.2 state register與output logic合一

有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP

雖然理論上可以用1個always同時描述state register與output logic,但實際上做不到,因為Mealy FSM的output logic是目前state與input的純粹組合邏輯,與state register合一後,就必須使用nonblocking描述,之前Moore FSM還可以提前一個state去做判斷,但Mealy FSM還有input,該如何提前1個clk去判斷input呢?

2個always (state register與output logic合一)無法描述Mealy FSM。

2.3 next state logic與output logic合一

有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP

simple_fsm_mealy_2_always_2_ns_ol_ng.v / Verilog

有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP
 1 /* 
2 (C) OOMusou 2011 http://oomusou.cnblogs.com
3
4 Filename : simple_fsm_mealy_2_always_2_ns_ol_ng.v
5 Synthesizer : Quartus II 8.1
6 Description : 2 always block for mealy fsm (NO GOOD)
7 Release : Jun.05,2011 1.0
8 */
9
10 module simple_fsm (
11 clk,
12 rst_n,
13 w_i,
14 z_o
15 );
16
17 input clk;
18 input rst_n;
19 input w_i;
20 output z_o;
21
22 parameter IDLE = 2'b00;
23 parameter S0 = 2'b01;
24
25 reg [1:0] curr_state;
26 reg [1:0] next_state;
27 reg z;
28 reg z_o;
29
30 // state reg
31 always@(posedge clk or negedge rst_n)
32 if (~rst_n) curr_state <= IDLE;
33 else curr_state <= next_state;
34
35 // next state logic + output logic
36 always@(*)
37 case (curr_state)
38 IDLE : if (w_i) {next_state, z} = {S0 , 1'b0};
39 else {next_state, z} = {IDLE, 1'b0};
40 S0 : if (w_i) {next_state, z} = {S0 , 1'b1};
41 else {next_state, z} = {IDLE, 1'b0};
42 default : {next_state, z} = {IDLE, 1'b0};
43 endcase
44
45 // mealy output to delay 1 clk for moore
46 always@(posedge clk or negedge rst_n)
47 if (~rst_n) z_o <= 1'b0;
48 else z_o <= z;
49
50 endmodule
有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP

30行

// state reg
always@(posedge clk or negedge rst_n)
if (~rst_n) curr_state <= IDLE;
else curr_state <= next_state;

使用1個always描述state register。

35行

有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP
// next state logic + output logic   
always@(*)
case (curr_state)
IDLE : if (w_i) {next_state, z} = {S0 , 1'b0};
else {next_state, z} = {IDLE, 1'b0};
S0 : if (w_i) {next_state, z} = {S0 , 1'b1};
else {next_state, z} = {IDLE, 1'b0};
default : {next_state, z} = {IDLE, 1'b0};
endcase
有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP

使用1個always同時描述next state logic與output logic,因為兩者都是純粹的組合邏輯,所以使用blocking。

45行

// mealy output to delay 1 clk for moore  
always@(posedge clk or negedge rst_n)
if (~rst_n) z_o <= 1'b0;
else z_o <= z;

之前提到使用Mealy FSM會少Moore FSM 1個state,且output會早Moore FSM 1個clk,所以最後特別將output在敲一級delay 1個clk,這樣Mealy FSM就會完全與Moore FSM一樣。

使用2個always (next state logic與output logic合一)寫法的缺點:

將next state logic與output logic合一只會增加code的複雜度,日後維護會更加困難

不推薦2個always (next state logic與output logic合一)寫法。

3.使用1個always (一段式)

有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP

理論上存在使用1個always同時描述next state logic、state register與output logic,但實際上做不到,理由與2個always (state register與output logic合一)的理由一樣,1個always必須使用nonblocking描述,而Mealy FSM的output logic是目前state與input的組合邏輯,我們無法提前1個clk去判斷input,所以無法使用1個always去描述。

1個always 無法描述Mealy FSM。

只要output logic使用nonblocking去描述,就無法實現Mealy FSM output。

實務上推薦的coding style

如之前所述,實務上為了timing更好,常在Moore FSM的output logic再多敲一級,以下為推薦的coding style:

有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP

1.使用2個always (兩段式)

有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP

simple_fsm_moore_2_always_0_cs_ns_good_pratical.v / Verilog

有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP
 1 /* 
2 (C) OOMusou 2011 http://oomusou.cnblogs.com
3
4 Filename : simple_fsm_moore_2_always_0_cs_ns_good.v
5 Synthesizer : Quartus II 8.1
6 Description : 2 always block for moore fsm (GOOD)
7 Release : Jun.05,2011 1.0
8 */
9
10 module simple_fsm (
11 clk,
12 rst_n,
13 w_i,
14 z_o
15 );
16
17 input clk;
18 input rst_n;
19 input w_i;
20 output z_o;
21
22 parameter IDLE = 2'b00;
23 parameter S0 = 2'b01;
24 parameter S1 = 2'b10;
25
26 reg [1:0] curr_state;
27 reg z_o;
28
29 // state reg + next state logic
30 always@(posedge clk or negedge rst_n)
31 if (~rst_n) curr_state <= IDLE;
32 else
33 case (curr_state)
34 IDLE : if (w_i) curr_state <= S0;
35 else curr_state <= IDLE;
36 S0 : if (w_i) curr_state <= S1;
37 else curr_state <= IDLE;
38 S1 : if (w_i) curr_state <= S1;
39 else curr_state <= IDLE;
40 default : curr_state <= IDLE;
41 endcase
42
43 // output logic
44 always@(posedge clk or negedge rst_n)
45 if (~rst_n)
46 z_o <= 1'b0;
47 else
48 case (curr_state)
49 IDLE : z_o <= 1'b0;
50 S0 : z_o <= 1'b0;
51 S1 : z_o <= 1'b1;
52 default : z_o <= 1'b0;
53 endcase
54
55 endmodule
有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP

29行

有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP
// state reg + next state logic
always@(posedge clk or negedge rst_n)
if (~rst_n) curr_state <= IDLE;
else
case (curr_state)
IDLE : if (w_i) curr_state <= S0;
else curr_state <= IDLE;
S0 : if (w_i) curr_state <= S1;
else curr_state <= IDLE;
S1 : if (w_i) curr_state <= S1;
else curr_state <= IDLE;
default : curr_state <= IDLE;
endcase
有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP

使用2個always,且state register與next state logic合一,只要判斷curr_state即可,不用擔心是否要提早1個clk判斷。

43行

有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP
// output logic
always@(posedge clk or negedge rst_n)
if (~rst_n)
z_o <= 1'b0;
else
case (curr_state)
IDLE : z_o <= 1'b0;
S0 : z_o <= 1'b0;
S1 : z_o <= 1'b1;
default : z_o <= 1'b0;
endcase
有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP

output logic也敲clk,只要判斷curr_state即可,不用擔心是否要提早1個clk判斷。

2.使用3個always (三段式)

有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP

simple_fsm_moore_3_always_practical.v / Verilog

有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP
 1 /* 
2 (C) OOMusou 2011 http://oomusou.cnblogs.com
3
4 Filename : simple_fsm_moore_3_always_practical.v
5 Synthesizer : Quartus II 8.1
6 Description : 3 always block for moore fsm (BEST)
7 Release : Jun.05,2011 1.0
8 */
9
10 module simple_fsm (
11 clk,
12 rst_n,
13 w_i,
14 z_o
15 );
16
17 input clk;
18 input rst_n;
19 input w_i;
20 output z_o;
21
22 parameter IDLE = 2'b00;
23 parameter S0 = 2'b01;
24 parameter S1 = 2'b10;
25
26 reg [1:0] curr_state;
27 reg [1:0] next_state;
28 reg z_o;
29
30 // state reg
31 always@(posedge clk or negedge rst_n)
32 if (~rst_n) curr_state <= IDLE;
33 else curr_state <= next_state;
34
35 // next state logic
36 always@(*)
37 case (curr_state)
38 IDLE : if (w_i) next_state = S0;
39 else next_state = IDLE;
40 S0 : if (w_i) next_state = S1;
41 else next_state = IDLE;
42 S1 : if (w_i) next_state = S1;
43 else next_state = IDLE;
44 default : next_state = IDLE;
45 endcase
46
47 // output logic
48 always@(posedge clk or negedge rst_n)
49 if (~rst_n) z_o <= 1'b0;
50 else
51 case (curr_state)
52 IDLE : z_o <= 1'b0;
53 S0 : z_o <= 1'b0;
54 S1 : z_o <= 1'b1;
55 default : z_o <= 1'b0;
56 endcase
57
58 endmodule
有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP

30行

// state reg
always@(posedge clk or negedge rst_n)
if (~rst_n) curr_state <= IDLE;
else curr_state <= next_state;

使用1個always描述state register。

35行

有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP
// next state logic    
always@(*)
case (curr_state)
IDLE : if (w_i) next_state = S0;
else next_state = IDLE;
S0 : if (w_i) next_state = S1;
else next_state = IDLE;
S1 : if (w_i) next_state = S1;
else next_state = IDLE;
default : next_state = IDLE;
endcase
有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP

使用1個always描述next state logic,為純粹組合邏輯,所以使用blocking。

47行

有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP
// output logic
always@(posedge clk or negedge rst_n)
if (~rst_n) z_o <= 1'b0;
else
case (curr_state)
IDLE : z_o <= 1'b0;
S0 : z_o <= 1'b0;
S1 : z_o <= 1'b1;
default : z_o <= 1'b0;
endcase
有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP

使用1個always描述output logic,因為output logic也敲clk,只要判斷curr_state即可,不用擔心是否要提早1個clk判斷。

看到這裡,或許你會問:『為了timing好,多敲一級會多delay一個clk,若我output logic提前1個clk用next_state判斷,不就既可有較好的timing,也不會多delay一個clk?』

有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP

1.使用3個always (三段式)

有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP

simple_fsm_moore_3_always_practical2.v / Verilog

有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP
 1 /* 
2 (C) OOMusou 2011 http://oomusou.cnblogs.com
3
4 Filename : simple_fsm_moore_3_always_practical2.v
5 Synthesizer : Quartus II 8.1
6 Description : 3 always block for moore fsm (BEST)
7 Release : Jun.05,2011 1.0
8 */
9
10 module simple_fsm (
11 clk,
12 rst_n,
13 w_i,
14 z_o
15 );
16
17 input clk;
18 input rst_n;
19 input w_i;
20 output z_o;
21
22 parameter IDLE = 2'b00;
23 parameter S0 = 2'b01;
24 parameter S1 = 2'b10;
25
26 reg [1:0] curr_state;
27 reg [1:0] next_state;
28 reg z_o;
29
30 // state reg
31 always@(posedge clk or negedge rst_n)
32 if (~rst_n) curr_state <= IDLE;
33 else curr_state <= next_state;
34
35 // next state logic
36 always@(*)
37 case (curr_state)
38 IDLE : if (w_i) next_state = S0;
39 else next_state = IDLE;
40 S0 : if (w_i) next_state = S1;
41 else next_state = IDLE;
42 S1 : if (w_i) next_state = S1;
43 else next_state = IDLE;
44 default : next_state = IDLE;
45 endcase
46
47 // output logic
48 always@(posedge clk or negedge rst_n)
49 if (~rst_n) z_o <= 1'b0;
50 else
51 case (next_state)
52 IDLE : z_o <= 1'b0;
53 S0 : z_o <= 1'b0;
54 S1 : z_o <= 1'b1;
55 default : z_o <= 1'b0;
56 endcase
57
58 endmodule
有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP

47行

有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP
// output logic
always@(posedge clk or negedge rst_n)
if (~rst_n) z_o <= 1'b0;
else
case (next_state)
IDLE : z_o <= 1'b0;
S0 : z_o <= 1'b0;
S1 : z_o <= 1'b1;
default : z_o <= 1'b0;
endcase
有限狀態機FSM coding style整理 (SOC) (Verilog)-LMLPHP

使用1個always去描述output logic,重點是,使用next_state去判斷,因此可以提早一個clk,這樣無論是在Simulator或者經過Synthesizer合成後的結果都會一樣,而且既可在output敲過D flip-flop,也不會多delay一個clk。

不過這種寫法也不是沒有缺點,由於next_state本身是一個純粹的組合邏輯,拿來當output logic的判斷,timing會稍微差一點,很可能critical path就出現在這裡,前一個例子的output logic用的是curr_state,是一個D flip-flop,沒有組合邏輯,所以timing比較好。

另外一個缺點是output logic必須判斷next_state,很容易出錯,觀念必須非常清楚。

完整程式碼下載
simple_fsm_moore_3_always_best.7z (Moore FSM 3 always)
simple_fsm_moore_2_always_0_cs_ns_good.7z (Moore FSM 2 always [state register + next state logic合一])
simple_fsm_moore_2_always_1_cs_ol_ng.7z (Moore FSM 2 always [state register + output logic合一])
simple_fsm_moore_2_always_2_ns_ol_ng.7z (Moore FSM 2 always [next state + output logic合一])
simple_fsm_moore_1_always_ng.7z (Moore FSM 1 always)
simple_fsm_mealy_3_always_best.7z (Mealy FSM 3 always)
simple_fsm_mealy_2_always_0_cs_ns_good.7z (Mealy FSM 2 always [state register + next state logic合一])
simple_fsm_mealy_2_always_2_ns_ol_ng.7z (Mealy FSM 2 always [next state logic + output logic合一])
simple_fsm_moore_2_always_0_cs_ns_good_practical.7z (Moore FSM 2 always [state register + next state logic合一] with better timing)
simple_fsm_moore_3_always_practical.7z (Moore FSM 3 always with better timing)
simple_fsm_moore_3_always_practical2.7z (Moore FSM 3 always with better timing and no delay 1 clk)

Conclusion
1.3個always與2個always (state register與next state logic合一)是兩種推薦的寫法,而且這兩種寫法無論要描述Moore FSM或者Mealy FSM都沒問題,其他寫法都不推薦,個人是比較喜歡2個always寫法(state register + next state logic),因為這種寫法最精簡,各種需求都可描述,也不用擔心是否要提前一個clk判斷,最為直覺不易錯。

2.實務上不會特別拘泥使用Moore或者Mealy,只要符合需求即可,一般會以Moore FSM為正宗。

3.實務上為了timing更好,會在Moore FSM的output logic多敲一級。

4.Mealy會比Moore少1個state,且output會比Moore早1個clk。

5.Moore與Mealy之間可以互換,只要在Mealy的output多敲一級即可。

Reference
[1] Douglas J. Smith, HDL Chip Design, A practical guide for designing, synthesizing and simulating ASICs and FPGAs using VHDL or Verilog

[2] Stephen Brown 2005, Zvonko Vranesic, Fundamentals of Digital Logic with VHDL Design, McGraw-Hill

全文完。

转载自:http://www.cnblogs.com/oomusou/archive/2011/06/05/fsm_coding_style.html

05-06 23:56