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

有点晚了 后边我会把 饮料机的题目从新开一帖子,饮料机内容比较多而且板级验证复习一下按键消抖的模块。

相关文章
相关标签/搜索