1. 程式人生 > >FPGA 狀態機設計

FPGA 狀態機設計

數字系統有兩大類有限狀態機(Finite State Machine,FSM):Moore狀態機和Mealy狀態機。

Moore狀態機

  其最大特點是輸出只由當前狀態確定,與輸入無關。Moore狀態機的狀態圖中的每一個狀態都包含一個輸出訊號。這是一個典型的Moore狀態機的狀態跳轉圖,x、y、z是輸入,a、b、c是輸出。

Mealy狀態機

  它的輸出不僅與當前狀態有關係,而且與它的輸入也有關係,因而在狀態圖中每條轉移邊需要包含輸入和輸出的資訊。

狀態編碼

  數字邏輯系統狀態機設計中常見的編碼方式有:二進位制碼(Binary碼)、格雷碼(Gray碼)、獨熱碼(One-hot碼)以及二一十進位制碼(BCD碼)。

  格雷碼的特點:相鄰的兩個碼組之間僅有一位不同。

普通二進位制碼與格雷碼之間可以相互轉換。

  二進位制碼轉換為格雷碼:從最右邊一位起,一次與左邊一位“異或”,作為對應格雷碼該位的值,最左邊的一位不變(相當於最左邊是0)。

  格雷碼轉換為二進位制碼:從左邊第二位起,將每一位與左邊一位解碼後的值“異或”,作為該解碼後的值(最左邊的一位依然不變)。

  獨熱碼又分為獨熱1碼和獨熱0碼,是一種特殊的二進位制編碼方式。當任何一種狀態有且僅有一個1時,就是獨熱1碼,相反任何一種狀態有且僅有一個0時,就是獨熱0碼。

狀態機的描述

  狀態機有三種描述方式:一段式狀態機、兩段式狀態機、三段式狀態機。下面就用一個小例子來看看三種方式是如何實現的。

  (各種圖片,各種坑爹啊 - -!)

一段式狀態機

  當把整個狀態機解除安裝一個always模組中,並且這個模組既包含狀態轉移,又含有組合邏輯輸入/輸出時,稱為一段式狀態機。不推薦採用這種狀態機,因為從程式碼風格方面來講,一般都會要求把組合邏輯和時序邏輯分開;從程式碼維護和升級來說,組合邏輯和書序邏輯混合在一起不利於程式碼維護和修改,也不利於約束。

複製程式碼
 1 //一段式狀態機來實現:在非同步復位訊號的控制下,一段式狀態機進入IDLE
2 //狀態,q_sig4被複位,一旦sig1或者sig2有效,狀態機進入WAIT狀態,如果
3 //sig1和sig2同時有效,那麼狀態機進入DONE狀態,
4 //如果sig4還有效,那麼q_sig4置位,同時狀態機進入IDLE狀態。
5
6 module one_seg_fsm(clk,reset,sig1,sig2,sig3,q_sig4,q_sm_state);
7 //資料宣告部分 8 input clk,reset,sig1,sig2,sig3;
9
10 output reg q_sig4;
11 output reg [1:0] q_sm_state;
12
13 //引數宣告14 parameter IDLE = 2'b00;15 parameter WAIT = 2'b01;16 parameter DONE = 2'b10;17
18 //狀態跳轉邏輯程式設計19 always @(posedge clk or posedge reset)
20 begin
21 if(reset)
22 begin
23 q_sig4 <= 0;
24 q_sm_state <= IDLE;
25 end
26 else
27 begin
28 case(q_sm_state)
29 IDLE: begin
30 if(sig1 || sig2)
31 begin
32 q_sm_state <= WAIT;
33 q_sig4 <= 1'b0;34 end
35 else
36 begin
37 q_sm_state <= IDLE;
38 q_sig4 <= 1'b0;39 end
40 end
41 WAIT: begin
42 if(sig2 && sig3)
43 begin
44 q_sm_state <= DONE;
45 q_sig4 <= 1'b0;46 end
47 else
48 begin
49 q_sm_state <= WAIT;
50 q_sig4 <= 1'b0;51 end
52 end
53
54 DONE:begin
55 if(sig3)
56 begin
57 q_sm_state <= IDLE;
58 q_sig4 <= 1'b1;59 end
60 else
61 begin
62 q_sm_state <= DONE;
63 q_sig4 <= 1'b0;64 end
65 end
66
67 default: begin
68 q_sm_state <= IDLE;
69 q_sig4 <= 0;
70 end
71 endcase
72 end
73 end
74 endmodule
複製程式碼

兩段式狀態機

  所謂的兩段式狀態機就是採用一個always語句來實現時序邏輯,另外一個always語句來實現組合邏輯,提高了程式碼的可讀性,易於維護。不同於一段式狀態機的是,它需要定義兩個狀態----現態和次態,然後通過現態和次態的轉換來實現時序邏輯。

複製程式碼
 1 //本例主要採用兩段式狀態機:在非同步復位訊號的控制下,一段式狀態機進入IDLE
2 //狀態,q_sig4被複位,一旦sig1或者sig2有效,狀態機進入WAIT狀態,如果sig1和sig2同時有效,那麼
3 //狀態機進入DONE狀態,如果sig4還有效,那麼q_sig4置位,同時狀態機進入IDLE狀態。 4
5 module two_seg_fsm(clk,reset,sig1,sig2,sig3,q_sig4);
6 //資料宣告部分 7 input clk,reset,sig1,sig2,sig3;
8
9 output reg q_sig4;
10
11 reg [1:0] current_state, next_state;
12
13 //引數宣告14 parameter IDLE = 2'b00;15 parameter WAIT = 2'b01;16 parameter DONE = 2'b10;17
18 //狀態跳轉程式設計19 always @(posedge clk or posedge reset)
20 if(reset)
21 current_state <= IDLE;
22 else
23 current_state <= next_state;
24
25 //狀態邏輯輸出26 always @(current_state or sig1 or sig2 or sig3)
27 begin
28 case(current_state)
29 IDLE: begin
30 if(sig1 || sig2)
31 begin
32 next_state = WAIT;
33 q_sig4 = 1'b0;34 end
35 else
36 begin
37 next_state = IDLE;
38 q_sig4 = 1'b0;39 end
40 end
41 WAIT: begin
42 if(sig2 && sig3)
43 begin
44 next_state = DONE;
45 q_sig4 = 1'b0;46 end
47 else
48 begin
49 next_state = WAIT;
50 q_sig4 = 1'b0;51 end
52 end
53
54 DONE:begin
55 if(sig3)
56 begin
57 next_state = IDLE;
58 q_sig4 = 1'b1;59 end
60 else
61 begin
62 next_state = DONE;
63 q_sig4 = 1'b0;64 end
65 end
66
67 default: begin
68 next_state = IDLE;
69 q_sig4 = 0;
70 end
71 endcase
72
73 end
74 endmodule
複製程式碼

三段式狀態機

  三段式狀態機與兩段式狀態機的區別:兩段式直接採用組合邏輯輸出,而三段式則通過在組合邏輯後再增加一級暫存器來實現時序邏輯輸出。這樣做的好處是可以有效地濾去租個邏輯輸出的毛刺,同時可以有效地進行時序計算與約束,另外對於匯流排形式的輸出訊號來說,容易使匯流排資料對其,從而減小匯流排資料間的偏移,減小接收端資料取樣出錯的頻率。

  三段式狀態機的基本格式是:第一個always語句實現同步狀態跳轉;第二個always語句實現組合邏輯;第三個always語句實現同步輸出。

複製程式碼
 1 //本例主要採用三段式狀態機:在非同步復位訊號的控制下,一段式狀態機進入IDLE
2 //狀態,q_sig4被複位,一旦sig1或者sig2有效,狀態機進入WAIT狀態,如果sig1和sig2同時有效,那麼
3 //狀態機進入DONE狀態,如果sig4還有效,那麼q_sig4置位,同時狀態機進入IDLE狀態。 4
5 module three_seg_fsm(clk,reset,sig1,sig2,sig3,q_sig4);
6 //資料宣告部分 7 input clk,reset,sig1,sig2,sig3;
8
9 output reg q_sig4;
10
11 reg [1:0] current_state, next_state;
12
13 //引數宣告14 parameter IDLE = 2'b00;15 parameter WAIT = 2'b01;16 parameter DONE = 2'b10;17
18 //狀態跳轉程式設計19 always @(posedge clk or posedge reset)
20 if(reset)
21 current_state <= IDLE;
22 else
23 current_state <= next_state;
24
25 //狀態跳轉輸出26 always @(current_state or sig1 or sig2 or sig3)
27 begin
28 case(current_state)
29 IDLE: begin
30 if(sig1 || sig2)
31 begin
32 next_state = WAIT;
33 end
34 else
35 begin
36 next_state = IDLE;
37 end
38 end
39 WAIT: begin
40 if(sig2 && sig3)
41 begin
42 next_state = DONE;
43 end
44 else
45 begin
46 next_state = WAIT;
47 end
48 end
49
50 DONE:begin
51 if(sig3)
52 begin
53 next_state = IDLE;
54 end
55 else
56 begin
57 next_state = DONE;
58 end
59 end
60
61 default: begin
62 next_state = IDLE;
63 end
64 endcase
65 end
66
67 //邏輯輸出68 always @(posedge clk or posedge reset)
69 if(reset)
70 q_sig4 <= 1'b0;71 else
72 begin
73 case(next_state)
74 IDLE,
75 WAIT: q_sig4 <= 1'b0;76 DONE: q_sig4 <= 1'b1;77 default: q_sig4 <= 1'b0;78 endcase
79 end
80
81 endmodule