前言 两周前公司任务让我配置一个时序接口,搞了好久怎么搞都出问题,涉及到四块芯片,高速,32个通道同时传输,种种问题加上我能力不足越搞心态越崩,原来自己还是这么的菜,芯片官网给了一个评估代码,其中串转并的部分使用状态机的方法描述,拿起语法书,边搞项目边复习一下基础吧,今天总结下状态机,文中部分内容来自《轻松成为设计高手》和《通信ic》改编总结,最后也给出了我写的几个例子,相信花时间看一遍应该会清楚不少,知识内容我尽量简化说重点,只讲三段式写法。

 

一.文字概括

1.状态机适合描述有先后顺序有逻辑规律的事情。比如本文最后的红绿灯,饮料机的题目。

2.存储器加上组合电路可以描述任何复杂的电路功能,但经常会有输入相同而历史输入不同导致的输出不同的情况,在数字逻辑中引入fsm,fsm将任意模型简化为:将要输出的结果是当前状态以及当前输入的组合。

3.有限状态机设计4大部分 :状态机编码 状态机复位 状态机条件转换 状态机的输出。

4.采用gary码减少相邻状态瞬变的次数,采用one_hot码可以减少组合逻辑的使用。

5.状态机复位:

同步复位: 指复位要与分频后的时钟信号同步,触发信号仅为分频后的时钟信号。

异步复位: 指复位与分频后的时钟信号都参与触发。

归根结底是触发复位函数的敏感列表中是否把复位键信号作为触发信号。

6.状态机的跳转:状态机核心部分控制状态机在状态间的切换从而决定输出的情况。

7. moore只和当前状态有关,mealy型输出与输入有关(不仅与当前状态有关)。

二.三段式写法举例

三段式:

一:always模块采用同步时序描述状态转移。

二:always模块采用组合逻辑判断状态转移条件,描述状态转移规律。

三:always模块描述每个状态的输出。(这里应该是可以使用同步时序寄存或者说用组合逻辑,使用同步时序的话应该可以减少毛刺)

例1:

编译原理python有限状态机 有限状态机的verilog描述_编译原理python有限状态机

 

 

 

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类似。

 

编译原理python有限状态机 有限状态机的verilog描述_状态机_02

 

 

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:

编译原理python有限状态机 有限状态机的verilog描述_编译原理python有限状态机_03

 

 

 

 

//输入信号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

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