002:verilog有限狀態機代碼總結——讀懂狀態機思想

前言 兩週前公司任務讓我配置一個時序接口,搞了很久怎麼搞都出問題,涉及到四塊芯片,高速,32個通道同時傳輸,種種問題加上我能力不足越搞心態越崩,原來本身仍是這麼的菜,芯片官網給了一個評估代碼,其中串轉並的部分使用狀態機的方法描述,拿起語法書,邊搞項目邊複習一下基礎吧,今天總結下狀態機,文中部份內容來自《輕鬆成爲設計高手》和《通訊ic》改編總結,最後也給出了我寫的幾個例子,相信花時間看一遍應該會清楚很多,知識內容我儘可能簡化說重點,只講三段式寫法。

 

一.文字歸納

1.狀態機適合描述有前後順序有邏輯規律的事情。好比本文最後的紅綠燈,飲料機的題目。異步

2.存儲器加上組合電路能夠描述任何複雜的電路功能,但常常會有輸入相同而歷史輸入不一樣致使的輸出不一樣的狀況,在數字邏輯中引入fsm,fsm將任意模型簡化爲:將要輸出的結果是當前狀態以及當前輸入的組合。ide

3.有限狀態機設計4大部分 :狀態機編碼 狀態機復位 狀態機條件轉換 狀態機的輸出。函數

4.採用gary碼減小相鄰狀態瞬變的次數,採用one_hot碼能夠減小組合邏輯的使用。編碼

5.狀態機復位:設計

同步復位: 指復位要與分頻後的時鐘信號同步,觸發信號僅爲分頻後的時鐘信號。blog

異步復位: 指復位與分頻後的時鐘信號都參與觸發。接口

歸根結底是觸發復位函數的敏感列表中是否把復位鍵信號做爲觸發信號。進程

6.狀態機的跳轉:狀態機核心部分控制狀態機在狀態間的切換從而決定輸出的狀況。input

7. moore只和當前狀態有關,mealy型輸出與輸入有關(不只與當前狀態有關)。同步

二.三段式寫法舉例

三段式:

一:always模塊採用同步時序描述狀態轉移。

二:always模塊採用組合邏輯判斷狀態轉移條件,描述狀態轉移規律。

三:always模塊描述每一個狀態的輸出。(這裏應該是能夠使用同步時序寄存或者說用組合邏輯,使用同步時序的話應該能夠減小毛刺)

例1:

 

 

 

module fsm(

    input clk,

    input rst_n,

    input in1,

    input in2,

    input in3,

    output reg out1,

    output reg out2,

    output reg out3

);

    reg [3:0]state;

    reg next_state;

    parameter state0 = 4'b0001,state1 = 4'b0010,state2 = 4'b0100,state3 = 4'b1000;

   

//第一段 更新狀態寄存器

    if(!rst_n)

        state <= state0;

    else

        state <= next_state;   

   

//第二段 組合邏輯電路用於狀態轉移規律

//根據當前狀態和輸入確認下一個週期的狀態

always@(state or in1 or in2 or in3)

    case(state)

        state0:if(in1)

            next_state <= state1;

            else

            next_state <= state0;

           

        state1: next_state <= state2;

       

        state2: if(in2)

            next_state <= state3;

            else

            next_state <= state0;

           

        state3: if(in3)

            next_state <= state0;

            else

            next_state <= state3;

           

        default:

            next_state <= state0;

    endcase

       

//第三段 利用狀態寄存器輸出控制結果

    always@(state)

    begin //先產生默認值 後邊再改寫 防止寄存器產生

    {out1,out2,out3} = 3'b000;

    case(state)

        state1:{out1,out2,out3} = 3'b100;

        state2:{out1,out2,out3} = 3'b110;

        state3:{out1,out2,out3} = 3'b111;  

    endcase

    end

    endmodule

 

 

 

例2:

 

圖畫的潦草了一點…

//功能簡介:初始狀態s0下輸出3'b001,若是收到start信號爲1,進入s1;若是start爲0,保持。s1輸出一個週期的3'b010再到s2狀態,s2輸出3’b100等待step2爲1轉移到s3,不然維持。state3和state2相似。

 

 

 

module fsm(

    input clk,

    input rst_n,

    input start,

    input step2,

    input step3,

    output reg [2:0]fsm_out

);

 

localparam state0 = 2'b00;

localparam state1 = 2'b01;

localparam state2 = 2'b11;

localparam state3 = 2'b10;

 

//標準三段式 每一個週期開始時更新當前狀態

reg [1:0] state;

reg [1:0]next_state;

 

always@(posedge clk or negedge rst_n)

if(!rst_n)

    state <= state0;

else

    state <= next_state;

 

//根據當前狀態和輸入確認下一個週期的狀態

always@(state or start or step2 or step3)

begin

    case(state)

        state0:

begin

        if(start)

            next_state <= state1;

        else

            next_state <= state0;

        end

       

        state1:

begin

            next_state <= state2;

        end

       

        state2:

begin

        if(step2)

            next_state <= state3;

        else

            next_state <= state2;

        end

           

        state3:

begin

        if(step3)

            next_state <= state0;

        else

            next_state <= state3;

        end

       

        default: next_state <= state0;

    endcase

end

 

 

//該進程定義fsm的輸出

    always@(state)

        case(state)

        state0:fsm_out = 3'b001;

        state1:fsm_out = 3'b010;

        state2:fsm_out = 3'b100;

        state3:fsm_out = 3'b111;

        default:fsm_out = 3'b001;//default能夠避免鎖存器

        endcase

   

endmodule

 

 

例3:

 

 

 

 

//輸入信號clk,復位rst_n,共四個狀態idel,s1,s2,error

//ns 下一個狀態 cs 當前狀態

module state(

    input clk;

    input rst_n;

    input i1,i2;

    output reg o1,o2,err

);

 

reg [2:0]ns,cs;

 

parameter[2:0]//one hot

    IDLE = 3'b000,

    S1  = 3'b001,

    S2  = 3'b010,

    ERROR= 3'b100;

 

always@(posedge clk or negedge rst_n)

    if(!rst_n)

        cs <= IDLE;

    else

        cs <= ns;

   

always@(rst_n or cs or i1 or i2)

    begin

        ns = 3'bx;

        case(cs)

            IDLE:

                begin

                    if(!i1)         ns <= IDLE;

                    if(i1&&i2)      ns <= S1;

                    if(i1&&!i2)     ns <= ERROR;

                end

               

            S1:

                begin

                    if(!i1)         ns <= S1;

                    if(!i1&&i2)     ns <= ERROR;

                    if(i1&&i2)      ns <= S2;

                end

               

            S2:

                begin

                    if(i2)          ns <= S2;

                    if(!i1&&!i2)    ns <= ERROR;

                    if(i1&&!i2)     ns <= IDLE;

                end

 

            ERROR:

                begin

                    if(i1)          ns <= ERROR;

                    if(!i1)         ns <= IDLE;

                end

        endcase

           

    end

   

always@(posedge clk or negedge rst_n)

    if(!rst_n)

        {o1,o2,err} <= 3'b000;

    else

        begin

            {o1,o2,err} <= 3'b000;

            case(ns)

            IDLE:       {o1,o2,err} <= 3'b000,

            S1:        {o1,o2,err} <= 3'b100,

            S2:        {o1,o2,err} <= 3'b010,

            ERROR:      {o1,o2,err} <= 3'b111;

            endcase

        end

       

    endmodule

 

三.實際問題

例1:一個簡單的紅綠燈問題

module rgy

(

  input        clk,

  input        rst_n,

 

  input    [2:0]cnt,

 

  output reg   LED_R_1,

  output reg   LED_G_1,

  output reg   LED_Y_1,

         

  output reg   LED_R_2,

  output reg   LED_G_2,

  output reg   LED_Y_2  

);

 

parameter IDLE = 0, WE_GO = 1,WE_WAIT = 2,NS_GO = 3,NS_WAIT = 4;   

 

reg[3:0] state;

reg[3:0] next_state;

 

always@(posedge clk or negedge rst_n)

begin

if(!rst_n)

    state <= IDLE;

else

    state <= next_state;

end

 

always@(state or cnt or rst_n)

begin

    case(state)

   

       IDLE:begin

                next_state = WE_GO;  

            end

           

      WE_GO:begin

              if(cnt == 3)

                next_state = WE_WAIT;

              else

                next_state = WE_GO;

            end

    WE_WAIT:begin

              if(cnt == 0)

                next_state = NS_GO;

              else

                next_state = WE_WAIT;

            end

    NS_GO:begin

              if(cnt == 3)

                next_state = NS_WAIT;

              else

                next_state = NS_GO;

            end

    NS_WAIT:begin

              if(cnt == 0)

                next_state = WE_GO;

              else

                next_state = NS_WAIT;

            end                 

    endcase

end

 

 

always@(posedge clk or negedge rst_n)  //WE東西方向

begin

 if(!rst_n)

  begin

    LED_R_1 <= 1;

    LED_G_1 <= 0;

    LED_Y_1 <= 0;

  end

 else case(next_state)

       IDLE:begin

              LED_R_1 <= 1;//紅

              LED_G_1 <= 0;//綠

              LED_Y_1 <= 0;//黃

            end

      WE_GO:begin

              LED_R_1 <= 0;

              LED_G_1 <= 1;

              LED_Y_1 <= 0;

            end

    WE_WAIT:begin

              LED_R_1 <= 0;

              LED_G_1 <= 0;

              LED_Y_1 <= 1;

            end

    NS_GO:begin

              LED_R_1 <= 1;

              LED_G_1 <= 0;

              LED_Y_1 <= 0;

            end

    NS_WAIT:begin

              LED_R_1 <= 1;

              LED_G_1 <= 0;

              LED_Y_1 <= 0;

            end   

  endcase          

end

 

always@(posedge clk or negedge rst_n)  //NS

begin

 if(!rst_n)

   begin

    LED_R_2 <= 1;

    LED_G_2 <= 0;

    LED_Y_2 <= 0;

   end

 else case(next_state)

       IDLE:begin

              LED_R_2 <= 1;

              LED_G_2 <= 0;

              LED_Y_2 <= 0;  

            end

      WE_GO:begin

              LED_R_2 <= 1;

              LED_G_2 <= 0;

              LED_Y_2 <= 0;

            end

    WE_WAIT:begin

              LED_R_2 <= 1;

              LED_G_2 <= 0;

              LED_Y_2 <= 0;

            end

    NS_GO:begin

              LED_R_2 <= 0;

              LED_G_2 <= 1;

              LED_Y_2 <= 0;

            end

    NS_WAIT:begin

              LED_R_2 <= 0;

              LED_G_2 <= 0;

              LED_Y_2 <= 1;

            end 

   endcase          

end

endmodule

有點晚了 後邊我會把 飲料機的題目從新開一帖子,飲料機內容比較多而且板級驗證複習一下按鍵消抖的模塊。

相關文章
相關標籤/搜索