有限狀態機(FSM)的設計
阿新 • • 發佈:2018-12-05
有限狀態機(FSM)的設計_zhangxianhe
有限狀態機(FSM)是一種常見的電路,由時序電路和組合電路組成。
設計有限狀態機的第一步是確定採用Moore 狀態機還是採用Mealy 狀態機。
Mealy 型:狀態的轉變不僅和當前狀態有關,而且跟各輸入訊號有關;
Moore 型:狀態的轉變只和當前狀態有關。
從實現電路功能來講,任何一種都可以實現同樣的功能。
但他們的輸出時序不同,所以,在選擇使用哪種狀態機時要根據具體情況而定,在此,把他們的主要區別介紹一下:
1. Moore 狀態機:在時鐘脈衝的有限個門延時之後,輸出達到穩定。輸出會在一個完整的時鐘週期內
保持穩定值,即使在該時鐘內輸入訊號變化了,輸出訊號也不會變化。輸入對輸出的影響要到下一個時鐘
週期才能反映出來。把輸入和輸出分開,是Moore 狀態機的重要特徵。
2. Mealy 狀態機:由於輸出直接受輸入影響,而輸入可以在時鐘週期的任一時刻變化,這就使得輸出狀
態比Moore 狀態機的輸出狀態提前一個週期到達。輸入訊號的噪聲可能會出現在輸出訊號上。
3. 對同一電路,使用Moore 狀態機設計可能會比使用Mealy 狀態機多出一些狀態。
根據他們的特徵和要設計的電路的具體情況,就可以確定使用那種狀態機來實現功能。一旦確定狀態機,
接下來就要構造狀態轉換圖。現在還沒有一個成熟的系統化狀態圖構造演算法,所以,對於實現同一功能,可以構造出不同的狀態轉換圖。
但一定要遵循結構化設計。在構造電路的狀態轉換圖時,使用互補原則可以幫助我們檢查設計過程中是否出現了錯誤。
互補原則是指離開狀態圖節點的所有支路的條件必須是互補的。同一節點的任何2 個或多個支路的條件不能同時為真。
同時為真是我們設計不允許的。在檢查無冗餘狀態和錯誤條件後,就可以開始用verilog HDL 來設計電路了。 在設計的過程中要注意以下方面:
1. full_case spec:所謂 Full Case 是指:FSM 的所有編碼向量都可以與case 結構的某個分支或default 預設情況匹配起來。
如果一個FSM 的狀態編碼是8bit,則對應的256 個狀態編碼都可以與 case 的某個分支或者 default對映起來。
定義完全狀態,即使有的狀態可能在電路中不會出現。目的是避免綜合出不希望的Latch,因為Latch可能會帶來:a. 額外的延時;b. 非同步Timing 問題 ①沒有采用full-case
確保不同時出現多種狀態 ①沒采用parallel-case
4. 推薦在模組劃分時,把狀態機設計分離出來,便於使用綜合根據對狀態機優化。
5. 在條件表示式或附值語句中,要注意向量的寬度適配。否則,前模擬和後模擬不一致,RTL 級的功能驗證很難找出問題所在。 狀態機設計的其他技巧
1.FSM編碼
Binary(二進位制編碼)、gray-code(格雷碼)編碼使用最少的觸發器,較多的組合邏輯,而one-hot(獨熱碼)編碼反之。
one-hot 編碼的最大優勢在於狀態比較時僅僅需要比較一個bit,一定程度上從而簡化了比較邏輯,減少了毛刺產生的概率。
FPGA 更多地提供觸發器資源,所以FPGA 多使用one-hot 編碼。
另一方面,對於小型設計使用gray-code 和binary 編碼更有效,而大型狀態機使用one-hot 更高效。
2.FSM 初始化狀態
大多數FPGA 有GSR(Global Set/Reset)訊號,當FPGA 加電後,GSR 訊號拉高,對所有的暫存器、RAM 等單元置位/復位,
這時配置於FPGA 的邏輯並未生效,所以不能保證正確地進入初始化狀態。
所以使用GSR 企圖進入FPGA 的初始化狀態,常常會產生種種不必要的麻煩。
一般的方法是採用非同步復位訊號,當然也可以使用同步復位,但是要注意同步復位邏輯的設計。
解決這個問題的另一種方法是將預設的初始狀態的編碼設為全零,這樣GSR 復位後,狀態機自動進入初始狀態。
3.FSM 狀態編碼定義
Verilog HDL描述狀態機時必須由parameter分配好狀態。
4.FSM 輸出
如果使用 2 段式FSM 描述Mealy 狀態機,輸出邏輯可以用"?語句"描述,或者使用case 語句判斷轉移條件與輸入訊號即可
5.阻塞和非阻塞賦值
為了避免不必要的競爭冒險,不論是做兩段式還是三段式 FSM 描述時,
必須遵循時序邏輯always 模組使用非阻塞賦值"<=",即當前狀態向下一狀態時序轉移,和寄存FSM 輸出等時序always 模組中都要使用非阻塞賦值;
而組合邏輯always 模組使用阻塞賦值"=",即狀態轉移條件判斷,組合邏輯輸出等always 模組中都要使用阻塞賦值。
6.FSM 的預設狀態
完整的狀態機應該包含一個預設(default)狀態,當轉移條件不滿足,或者狀態發生了突變時,要能保證邏輯不會陷入"死迴圈"。
這是對狀態機健壯性的一個重要要求,也就是常說的要具備"自恢復"功能。 組合邏輯和時序邏輯分開用不同的程序
組合邏輯包括狀態譯碼和輸出,時序邏輯則是狀態暫存器的切換,
必須包括對所有狀態都處理,不能出現無法處理的狀態,使狀態機失控 Mealy狀態機的例子如下:
有限狀態機(FSM)是一種常見的電路,由時序電路和組合電路組成。
設計有限狀態機的第一步是確定採用Moore 狀態機還是採用Mealy 狀態機。
Mealy 型:狀態的轉變不僅和當前狀態有關,而且跟各輸入訊號有關;
Moore 型:狀態的轉變只和當前狀態有關。
從實現電路功能來講,任何一種都可以實現同樣的功能。
但他們的輸出時序不同,所以,在選擇使用哪種狀態機時要根據具體情況而定,在此,把他們的主要區別介紹一下:
1. Moore 狀態機:在時鐘脈衝的有限個門延時之後,輸出達到穩定。輸出會在一個完整的時鐘週期內
保持穩定值,即使在該時鐘內輸入訊號變化了,輸出訊號也不會變化。輸入對輸出的影響要到下一個時鐘
週期才能反映出來。把輸入和輸出分開,是Moore 狀態機的重要特徵。
2. Mealy 狀態機:由於輸出直接受輸入影響,而輸入可以在時鐘週期的任一時刻變化,這就使得輸出狀
態比Moore 狀態機的輸出狀態提前一個週期到達。輸入訊號的噪聲可能會出現在輸出訊號上。
3. 對同一電路,使用Moore 狀態機設計可能會比使用Mealy 狀態機多出一些狀態。
根據他們的特徵和要設計的電路的具體情況,就可以確定使用那種狀態機來實現功能。一旦確定狀態機,
接下來就要構造狀態轉換圖。現在還沒有一個成熟的系統化狀態圖構造演算法,所以,對於實現同一功能,可以構造出不同的狀態轉換圖。
但一定要遵循結構化設計。在構造電路的狀態轉換圖時,使用互補原則可以幫助我們檢查設計過程中是否出現了錯誤。
互補原則是指離開狀態圖節點的所有支路的條件必須是互補的。同一節點的任何2 個或多個支路的條件不能同時為真。
同時為真是我們設計不允許的。在檢查無冗餘狀態和錯誤條件後,就可以開始用verilog HDL 來設計電路了。 在設計的過程中要注意以下方面:
1. full_case spec:所謂 Full Case 是指:FSM 的所有編碼向量都可以與case 結構的某個分支或default 預設情況匹配起來。
如果一個FSM 的狀態編碼是8bit,則對應的256 個狀態編碼都可以與 case 的某個分支或者 default對映起來。
定義完全狀態,即使有的狀態可能在電路中不會出現。目的是避免綜合出不希望的Latch,因為Latch可能會帶來:a. 額外的延時;b. 非同步Timing 問題 ①沒有采用full-case
always@(CurrentState)begin case(CurrentState) ST0 : NextState = ST1; ST1 : NextState = ST2; ST2 : NextState = ST0; endcase end
②採用full-case
always @(CurrentState)begin case(CurrentState) //synthesis full_case ST0 : NextState = ST1; ST1 : NextState= ST2; ST2 : NextState = ST0; default : NextState = ST0; endcase end
2. parallel_case spec:所謂 Parallel Case 是指:在case 結構中,每個case 的判斷條件表示式,
有且僅有唯一的case 語句的分支與之對應,即兩者關係是一一對應關係。確保不同時出現多種狀態 ①沒采用parallel-case
case({En3, En2, En1})3'b??1 : Out = In1; 3'b?1? : Out = In2; 3'b1?? : Out = In3; endcase
②採用parallel-case
case({En3, En2, En1}) //synthesis parallel_case 3'b??1 : Out = In1; 3'b?1? : Out = In2; 3'b1?? : Out = In3; endcase
3. 禁止使用casex
casex 在綜合時,認為Z,X 為Dont cares,會導致前模擬和後模擬不一致。如果電路中出現X,一定要分析是否會傳遞。4. 推薦在模組劃分時,把狀態機設計分離出來,便於使用綜合根據對狀態機優化。
5. 在條件表示式或附值語句中,要注意向量的寬度適配。否則,前模擬和後模擬不一致,RTL 級的功能驗證很難找出問題所在。 狀態機設計的其他技巧
1.FSM編碼
Binary(二進位制編碼)、gray-code(格雷碼)編碼使用最少的觸發器,較多的組合邏輯,而one-hot(獨熱碼)編碼反之。
one-hot 編碼的最大優勢在於狀態比較時僅僅需要比較一個bit,一定程度上從而簡化了比較邏輯,減少了毛刺產生的概率。
FPGA 更多地提供觸發器資源,所以FPGA 多使用one-hot 編碼。
另一方面,對於小型設計使用gray-code 和binary 編碼更有效,而大型狀態機使用one-hot 更高效。
2.FSM 初始化狀態
大多數FPGA 有GSR(Global Set/Reset)訊號,當FPGA 加電後,GSR 訊號拉高,對所有的暫存器、RAM 等單元置位/復位,
這時配置於FPGA 的邏輯並未生效,所以不能保證正確地進入初始化狀態。
所以使用GSR 企圖進入FPGA 的初始化狀態,常常會產生種種不必要的麻煩。
一般的方法是採用非同步復位訊號,當然也可以使用同步復位,但是要注意同步復位邏輯的設計。
解決這個問題的另一種方法是將預設的初始狀態的編碼設為全零,這樣GSR 復位後,狀態機自動進入初始狀態。
3.FSM 狀態編碼定義
Verilog HDL描述狀態機時必須由parameter分配好狀態。
4.FSM 輸出
如果使用 2 段式FSM 描述Mealy 狀態機,輸出邏輯可以用"?語句"描述,或者使用case 語句判斷轉移條件與輸入訊號即可
5.阻塞和非阻塞賦值
為了避免不必要的競爭冒險,不論是做兩段式還是三段式 FSM 描述時,
必須遵循時序邏輯always 模組使用非阻塞賦值"<=",即當前狀態向下一狀態時序轉移,和寄存FSM 輸出等時序always 模組中都要使用非阻塞賦值;
而組合邏輯always 模組使用阻塞賦值"=",即狀態轉移條件判斷,組合邏輯輸出等always 模組中都要使用阻塞賦值。
6.FSM 的預設狀態
完整的狀態機應該包含一個預設(default)狀態,當轉移條件不滿足,或者狀態發生了突變時,要能保證邏輯不會陷入"死迴圈"。
這是對狀態機健壯性的一個重要要求,也就是常說的要具備"自恢復"功能。 組合邏輯和時序邏輯分開用不同的程序
組合邏輯包括狀態譯碼和輸出,時序邏輯則是狀態暫存器的切換,
必須包括對所有狀態都處理,不能出現無法處理的狀態,使狀態機失控 Mealy狀態機的例子如下:
module FSM(Clk, Rst_,In1,In2,Out1); input Clk; //system Clock input Rst_; //async Reset, active low input In1,In2; //FSM input signals output Out1; //FSM output signals //define output signals type reg Out1; // Declare the symbolic names for states Parameter S0=0,S1=1; // Declare current state and next state variables reg CurrentState; reg NextState; always@(posedge Clk or negedge Rst_)begin if (!Rst_)begin CurrentState=S0; end else begin CurrentState=NextState; end end always @(In1 or In2 or CurrentState)begin // output and state vector decode (combinational) case (CurrentState) S0:begin NextState <= S1; Out1 <= 1'b0; end S1:begin if (In1)begin NextState <= S0; Out1 <= In2; end else begin NextState <= S1; Out1 <= !In2; end endcase end endmodule
下圖是一個狀態機的狀態轉換圖,在Verilog HDL 中我們可以用如下方法設計該狀態機。
例:One-hot編碼(FPGA 多使用one-hot 編碼)
module ONE_HOT_FSM (Clock, Rst_, A, B, C, D, E,Single, Multi, Contig); input Clock; //system Clock input Rst_; //async Reset, active low input A, B, C, D, E; //FSM input signals output Single, Multi, Contig; //FSM output signals //define output signals type reg Single; reg Multi; reg Contig; // Declare the symbolic names for states parameter [6:0] // enum STATE_TYPE one-hot S1 = 7'b0000001, S2 = 7'b0000010, S3 = 7'b0000100, S4 = 7'b0001000, S5 = 7'b0010000, S6 = 7'b0100000, S7 = 7'b1000000; parameter U_DLY = 1; // Declare current state and next state variables reg [2:0] CurrentState; reg [2:0] NextState; //CurrentState assignment, sequential logic always @ (posedge Clock or posedge Reset)begin if (!Rst_)begin CurrentState <= S1; end else begin CurrentState <= #U_DLY NextState; end end //combinational logic always @ (CurrentState or A or B or C or D or E)begin case(CurrentState) S1:begin Multi = 1'b0; Contig = 1'b0; Single = 1'b0; if(A&~B&C)begin NextState=S2; end else if(A&B&~C)begin NextState=S4; end else begin NextState=S1; end end S2:begin Multi = 1'b1; Contig = 1'b0; Single = 1'b0; if(!D)begin NextState=S3; end else begin NextState=S4; end end S3:begin Multi = 1'b0; Contig = 1'b1; Single = 1'b0; if(A|D)begin NextState=S4; end else begin NextState=S3; end end S4:begin Multi = 1'b1; Contig = 1'b1; Single = 1'b0; if(A&B&~C)begin NextState=S5; end else begin NextState=S4; end end S5:begin Multi = 1'b1; Contig = 1'b0; Single = 1'b0; NextState=S6; end S6:begin Multi = 1'b0; Contig = 1'b1; Single = 1'b1; if(!E)begin NextState=S7; end else begin NextState=S6; end S7:begin Multi = 1'b0; Contig = 1'b1; Single = 1'b1; if(E)begin NextState=S1; end else begin NextState=S7; end end endcase end endmoduleView Code
例2:Binary 編碼(小型設計使用gray-code 和binary 編碼更有效,而大型狀態機使用one-hot 更高效。)
module binary (Clock, Reset, A, B, C, D, E,Single, Multi, Contig); input Clock; //system Clock input Rst_; //async Reset, active low input A, B, C, D, E; //FSM input signals output Single, Multi, Contig; //FSM output signals //define output signals type reg Single; reg Multi; reg Contig; // Declare the symbolic names for states parameter [2:0] // enum STATE_TYPE binary S1 = 3'b001, S2 = 3'b010, S3 = 3'b011, S4 = 3'b100, S5 = 3'b101, S6 = 3'b110, S7 = 3'b111; parameter U_DLY = 1; // Declare current state and next state variables reg [2:0] CurrentState; reg [2:0] NextState; //CurrentState assignment, sequential logic always @ (posedge Clock or posedge Reset)begin if (!Rst_)begin CurrentState <= S1; end else begin CurrentState <= #U_DLY NextState; end end //combinational logic always @ (CurrentState or A or B or C or D or E)begin case(CurrentState) S1:begin Multi = 1'b0; Contig = 1'b0; Single = 1'b0; if(A&~B&C)begin NextState=S2; end else if(A&B&~C)begin NextState=S4; end else begin NextState=S1; end end S2:begin Multi = 1'b1; Contig = 1'b0; Single = 1'b0; if(!D)begin NextState=S3; end else begin NextState=S4; end end S3:begin Multi = 1'b0; Contig = 1'b1; Single = 1'b0; if(A|D)begin NextState=S4; end else begin NextState=S3; end end S4:begin Multi = 1'b1; Contig = 1'b1; Single = 1'b0; if(A&B&~C)begin NextState=S5; end else begin NextState=S4; end end S5: begin Multi = 1'b1; Contig = 1'b0; Single = 1'b0; NextState=S6; end S6: begin Multi = 1'b0; Contig = 1'b1; Single = 1'b1; if(!E) begin NextState=S7; end else begin NextState=S6; end S7:begin Multi = 1'b0; Contig = 1'b1; Single = 1'b1; if(E)begin NextState=S1; end else begin NextState=S7; end end endcase end endmoduleView Code
有限狀態機的介紹就先到此,前段時間沒時間更新,以後儘量多更新。