1. 程式人生 > >有限狀態機(FSM)的設計

有限狀態機(FSM)的設計

有限狀態機(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
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 
endmodule            
View 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 
endmodule    
View Code

有限狀態機的介紹就先到此,前段時間沒時間更新,以後儘量多更新。