1. 程式人生 > >FPGA學習筆記(七)——FSM(Finite State Machine,有限狀態機)設計

FPGA學習筆記(七)——FSM(Finite State Machine,有限狀態機)設計

fault mil 系統 time 編碼 代碼 ril esc 寫法

  FPGA設計中,最重要的設計思想就是狀態機的設計思想!狀態機的本質就是對具有邏輯順序時序規律的事件的一種描述方法,它有三個要素:狀態、輸入、輸出:狀態也叫做狀態變量(比如可以用電機的不同轉速作為狀態),輸出指在某一個狀態的特定輸出,輸入指狀態機中進入每個狀態的條件。根據狀態機的輸出是否和輸入有關,可分為摩爾(Moore)型狀態機和米勒型(Mealy)狀態機:摩爾型狀態機的輸出只取決於當前狀態,而米勒型狀態機的輸出不僅取決於當前狀態,還與當前輸入有關。通常,我們描述狀態機有三種方法:狀態轉移圖、狀態轉移表、HDL描述,狀態轉移圖直觀,設計用,而HDL語言方便描述,實現時用。

  那麽,如何用HDL描述一個好的狀態機呢?主要有以下四點:安全、穩定性高

速度快面積小設計清晰在描述過程中,我們會引用兩個新的verilog語法:localparam描述參數(等價於parameter)以及用task/endtask將輸出功能塊封裝,增強代碼可讀性;描述狀態機的關鍵是要描述清楚狀態機的三大要素:如何進行狀態轉移?每個狀態的輸出?狀態輸出是否和輸入條件相關?通常有三種寫法,下面通過一個實例說明;

實例.檢測“Hello”序列狀態機

  1、功能:在輸入一串字符中檢測“Hello”序列,檢測到後將led狀態進行翻轉;

  2、根據設計的FSM狀態轉移圖(visio繪制):

  3、一段式描述法:在一個always塊裏既描述狀態轉移,又描述狀態的輸入和輸出;

    verilog代碼如下:

//檢測“Hello”後led狀態翻轉

module check_hello(
    input  clk,         //50M時鐘信號
    input  rst,         //低電平復位
    input  [7:0]asci,   //字符輸入
    output reg  led     //控制led
);
    //狀態寄存器
    reg  [4:0]NS;     //nextstate
    
    //狀態獨熱編碼
    localparam 
        CHECK_H   = 5b0_0001,
        CHECK_e     = 5
b0_0010, CHECK_la = 5b0_0100, CHECK_lb = 5b0_1000, CHECK_o = 5b1_0000; //一段式狀態機 always@(posedge clk,negedge rst) if(!rst)begin NS <= CHECK_H; led <= 1b1; //led熄滅 end else begin case(NS) CHECK_H: begin if(asci == "H") NS <= CHECK_e; else NS <= CHECK_H; end CHECK_e: begin if(asci == "e") NS <= CHECK_la; else NS <= CHECK_H; end CHECK_la: begin if(asci == "l") NS <= CHECK_lb; else NS <= CHECK_H; end CHECK_lb: begin if(asci == "l") NS <= CHECK_o; else NS <= CHECK_H; end CHECK_o: begin if(asci == "o") led <= ~led; else led <= led; NS <= CHECK_H; end default     //排除任意情況,增強FSM安全性 begin NS <= CHECK_H; led <= 1b1; end endcase end endmodule

  testbench測試文件如下:

 `timescale 1ns/1ps
 `define    clk_period 20
 
 module check_hello_tb();
 
        reg  clk;         //50M時鐘信號
        reg  rst;         //低電平復位
        reg  [7:0]asci;   //字符輸入
        wire  led;        //控制led
        
        //例化測試模塊
        check_hello  check_hello_test(
            .clk(clk),         //50M時鐘信號
            .rst(rst),         //低電平復位
            .asci(asci),       //字符輸入
            .led(led)          //控制led
        );
        
        //產生50M時鐘信號
        initial clk = 1;
        always #(`clk_period / 2)clk <= ~clk;
            
        //開始測試
        initial begin
            rst  = 0;          //系統復位
            asci = 3bx;
        #(`clk_period * 2);
            rst = 1;
        #(`clk_period);
            asci = "H";
        #(`clk_period);
            asci = "e";
        #(`clk_period);
            asci = "l";
        #(`clk_period);
            asci = "l";
        #(`clk_period);
            asci = "o";
        #(`clk_period);
            asci = "2";
        #(`clk_period);
            asci = "e";
        #(`clk_period);
            asci = "h";
        #(`clk_period);
            asci = "l";    
        #(`clk_period);
            $stop;
        end 
endmodule

  測試結果如下,可以看到,剛開始輸入數據是任意數據,FSM為CHECK_H狀態,led輸出高電平,保持熄滅;當檢測到Hello序列時,led輸出低電平,狀態翻轉:

技術分享圖片

  狀態轉移圖如下,可以看到按照預定設計執行:

技術分享圖片

  綜合出來的電路圖如下,可以看到FSM實現的重點在於狀態寄存器,耗費資源很少,由綜合報告也可看出:

技術分享圖片

  技術分享圖片

  在一段式描述方法中可以看到,雖然一個alaways塊就可以解決問題,但描述不清晰,不利於維護修改,並且不利用附加約束,不利於綜合其和布局布線器對設計的優化;

  4、兩段式描述法:一個always塊描述狀態轉移,另一個always塊描述狀態判斷轉移條件

  verilog代碼如下:

//檢測“Hello”後led狀態翻轉

module check_hello(
    input  clk,         //50M時鐘信號
    input  rst,         //低電平復位
    input  [7:0]asci,//字符輸入
    output reg led     //控制led
);
    //狀態寄存器
    reg  [4:0]NS;     //nextstate
    reg  [4:0]CS;    //currentstate
    
    //狀態獨熱編碼
    localparam 
        CHECK_H   = 5b0_0001,
        CHECK_e     = 5b0_0010,
        CHECK_la  = 5b0_0100,
        CHECK_lb  = 5b0_1000,
        CHECK_o   = 5b1_0000;
        
    //兩段式狀態機
    //第一個always塊描述狀態轉移
    always@(posedge clk,negedge rst)
        if(!rst)
            CS  <= CHECK_H;
        else
            CS <= NS;        //狀態轉移到下一狀態
            
    //第二個always塊描述狀態輸出以及判斷狀態轉移        
    always@(*)
        case(CS)
            CHECK_H:
                begin
                    led <= 1b1;
                    if(asci == "H")
                        NS <= CHECK_e;
                    else
                        NS <= CHECK_H;
                end
            CHECK_e:
                begin
                    led <= 1b1;
                    if(asci == "e")
                        NS <= CHECK_la;
                    else
                        NS <= CHECK_H;
                end
            CHECK_la:
                begin
                    led <= 1b1;
                    if(asci == "l")
                        NS <= CHECK_lb;
                    else
                        NS <= CHECK_H;
                end
            CHECK_lb:
                begin
                    led <= 1b1;
                    if(asci == "l")
                        NS <= CHECK_o;
                    else
                        NS <= CHECK_H;
                end
            CHECK_o:
                begin
                    if(asci == "o")
                        led <= 1b0;
                    else
                        led <= 1b1;
                    NS <= CHECK_H;
                end
            default 
                begin
                    NS  <= CHECK_H;
                    led <= 1b1;
                end
        endcase
endmodule
            
        
    

    

  

FPGA學習筆記(七)——FSM(Finite State Machine,有限狀態機)設計