状态机设计

目录

一、状态机概述

1、什么是状态机

2、FSM分类

3、通用状态机建模规范

二、状态机代码实例

1、可乐机

1.1一段式

(1)一段式Moore型

(2)一段式Mealy型 

1.2二段式       

(1)二段式Moore型

(2)二段式Mealy型

  1.3三段式

(1)三段式Moore型

(2)三段式Mealy型     

2、序列检测器


一、状态机概述

1、什么是状态机

        状态机是有限状态机(FSM)的简称,是现实事物运行规则抽象而成的一个数学模型。状态机的本质就是对具有逻辑顺序或时序规律事件的一种描述方法,所有具有逻辑顺序和时序规律的事情都适合用状态机描述。

        FSM顾名思义,状态数目是有限的,状态的数目可以用表示状态的位数确定,采用n位二进制编码的状态机的状态数目最多是2^{n}种。

        同步FSM在数字系统种应用广泛,其特点是具有有限个状态,且状态的转移由时钟驱动。

2、FSM分类

        FSM有两种基本类型:Mealy状态机和Moore状态机。他们的区别在于:Mealy状态机的下一级状态和输出取决于当前状态和当前输入;Moore状态机的下一状态取决于当前状态和当前输入,但是输出只取决于当前状态。这两类FSM的下一状态和输出都是由组合逻辑电路形成的。

3、通用状态机建模规范

        分为一段式、两段式与三段式状态机,可以根据状态机always块数目对状态机进行初步区分,具体区分还是要判断状态机是否按照具体的建模规则描述。

        一段式:将状态的同步转移、状态输出与状态的输入条件都写在同一个always模块里面。

        不建议使用,原因在于:(1)这种描述方法不符合将时序逻辑与组合逻辑分开描述的Coding Style;(2)所有功能都在同一Always块中,在描述状态转移的同时需要考虑状态输出,代码比较冗余,可读性较差。(3)不利于维护修改,不利于综合器和布局布线器对设计进行优化。

        两段式:使用两个always 模块,其中一个always 模块采用同步时序的方式描述状态转移,而另一个模块采用组合逻辑的方式判断状态转移条件,描述状态转移规律。

        两段式状态机符合将时序逻辑与组合逻辑分开描述的Coding Style,利于工具进行综合与布局布线,但也有缺点:其输出一般采用组合逻辑描述,而组合逻辑输出易产生毛刺等不稳定因素。解决方式是可以在两段式输出之后插入一个额外的寄存器,进行寄存器打拍操作来有效的消除毛刺带来的问题。这种解决方式会使得输出延迟一个时钟,具体问题具体分析

        三段式:使用3个always模块,一个always 模块采用同步时序的方式描述状态转移,一个采用组合逻辑的方式判断状态转移条件,描述状态转移规律,第三个always 模块使用同步时序电路描述每个状态的输出。

        第三个进程采用下一状态决定电路输出,是为了保证三段式状态机输出时延与两段式相等。在没有时延要求的情况下,建议使用当前状态决定电路输出,提高状态机的稳定性。

        其实选择使用现态还是次态作为第三段的输出判断,本质上是决定使用Moore型和Mealy型的问题,当选择Moore型时,输出仅和状态有关,所以采用次态来决定输出,可以使得输出严格与状态在时序上具有理论的一致性,选择Mealy型时,本身就是基于现态和输入决定输出,所以使用现态决定输出,会更加符合思维上的认知。但是在真实的HDL设计中没有这么明确的要求,设计者需要根据时延的需求完成自己的设计,但是要注意考虑到避免用一个输入同时去作为次态和输出的决定条件。推荐还是使用现态+输入的方式作为第三段输出的判决条件。

二、状态机代码实例

1、可乐机

        每次只能投入 1 枚 1 元硬币,且每瓶可乐卖 3 元钱,即投入 3 个硬币就可以让可乐机出可乐,如果投币不够 3 元想放弃投币需要按复位键,否则之前投入的钱不能退回。

        输入信号:

                clk:系统时钟

                rst_n:低电平有效的复位信号

                money:投币结果,高电平为投币1元,低电平为未投币

        输出信号:

                cola:低电平为无可乐输出,高电平为有可乐输出

        下面给出状态转移图,由于FSM可以分为Moore和Mealy型,所以可以给出的状态转移图也有2种,这两种在绘制的时候会稍有不同,一般数电的课程会明确其规范性,但是还是经常会出现混淆的情况:

        

1.1一段式

(1)一段式Moore型
//一段式FSM示例
//采用的是Moore型的FSM
//--------------------<模块及端口定义>---------------------
module cola_FSM(
    input clk,             //时钟输入
    input rst_n,           //复位信号
    input money,           //是否投币输入
 
    output reg cola);      //是否有可乐输出

//--------------------<状态机参数定义>---------------------
//独热码编码的优点是每次状态跳转只有两个bit位发生跳变,动态功耗较低。同时独热码编码译码电路比较简单。缺点是用的寄存器位宽比二进制编码会大一点。
parameter IDLE  = 4'b0001;
parameter ONE   = 4'b0010;
parameter TWO   = 4'b0100;
parameter THREE = 4'b1000;

//--------------------<一段式状态定义>---------------------
reg [3:0] state; // 状态定义

//---------------------<一段式状态机>---------------------
always@(posedge clk or negedge rst_n)begin
    if(!rst_n) begin 
        state <= IDLE;
        cola <= 1'b0;
    end
    else case (state)
        IDLE: begin
            cola <= 1'b0;
            state <= money ? ONE : IDLE;  
        end
        ONE : begin 
            cola <= 1'b0;
            state <= money ? TWO : ONE ;
        end
        TWO : begin 
            cola <= 1'b0;
            state <= money ? THREE : TWO ;
        end
        THREE:begin 
            cola <= 1'b0;
            state <= money ? ONE : IDLE;
        end
        default:begin 
            cola <= 1'b0;
            state <= money ? ONE : IDLE;
        end
    endcase
end
endmodule 
(2)一段式Mealy型 
//一段式FSM示例
//采用的是Mealy型的FSM
//--------------------<模块及端口定义>---------------------
module cola_FSM(
    input clk,             //时钟输入
    input rst_n,           //复位信号
    input money,           //是否投币输入
 
    output reg cola);      //是否有可乐输出

//--------------------<状态机参数定义>---------------------
//独热码编码的优点是每次状态跳转只有两个bit位发生跳变,动态功耗较低。同时独热码编码译码电路比较简单。缺点是用的寄存器位宽比二进制编码会大一点。
parameter IDLE  = 3'b001;
parameter ONE   = 3'b010;
parameter TWO   = 3'b100;

//--------------------<一段式状态定义>---------------------
reg [2:0] state; // 状态定义

//---------------------<一段式状态机>---------------------
always@(posedge clk or negedge rst_n)begin
    if(!rst_n) begin 
        state <= IDLE;
        cola <= 1'b0;
    end
    else case (state)
        IDLE: begin
            cola <= 1'b0;
            state <= money ? ONE : IDLE;  
        end
        ONE : begin 
            cola <= 1'b0;
            state <= money ? TWO : ONE ;
        end
        TWO : begin 
            cola <= money ? 1'b1 : 1'b0;
            state <= money ? IDLE : TWO ;
        end
        default:begin 
            cola <= 1'b0;
            state <= money ? ONE : IDLE;
        end
    endcase
end
endmodule 

1.2二段式       

(1)二段式Moore型
//二段式FSM示例
//采用的是Moore型的FSM
//--------------------<模块及端口定义>---------------------
module cola_FSM(
    input clk,             //时钟输入
    input rst_n,           //复位信号
    input money,           //是否投币输入
 
    output reg cola);      //是否有可乐输出

//--------------------<状态机参数定义>---------------------
//独热码编码的优点是每次状态跳转只有两个bit位发生跳变,动态功耗较低。同时独热码编码译码电路比较简单。缺点是用的寄存器位宽比二进制编码会大一点。
parameter IDLE  = 4'b0001;
parameter ONE   = 4'b0010;
parameter TWO   = 4'b0100;
parameter THREE = 4'b1000;

//--------------------<二段式状态定义>---------------------
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@(*)begin
    case (state)
        IDLE: begin
            cola = 1'b0;
            next_state = money ? ONE : IDLE;  
        end
        ONE : begin 
            cola = 1'b0;
            next_state = money ? TWO : ONE ;
        end
        TWO : begin 
            cola = 1'b0;
            next_state = money ? THREE : TWO ;
        end
        THREE:begin 
            cola = 1'b1;
            next_state = money ? ONE : IDLE;
        end
        default:begin 
            cola = 1'b0;
            next_state = money ? ONE : IDLE;
        end
    endcase
end
endmodule 
(2)二段式Mealy型
//二段式FSM示例
//采用的是Mealy型的FSM
//--------------------<模块及端口定义>---------------------
module cola_FSM(
    input clk,             //时钟输入
    input rst_n,           //复位信号
    input money,           //是否投币输入
 
    output reg cola);      //是否有可乐输出

//--------------------<状态机参数定义>---------------------
//独热码编码的优点是每次状态跳转只有两个bit位发生跳变,动态功耗较低。同时独热码编码译码电路比较简单。缺点是用的寄存器位宽比二进制编码会大一点。
parameter IDLE  = 3'b001;
parameter ONE   = 3'b010;
parameter TWO   = 3'b100;

//--------------------<二段式状态定义>---------------------
reg [2:0] state;         // 当前状态定义
reg [2:0] next_state;    // 下一状态定义

//---------------------<二段式状态机>---------------------
//同步时序描述状态转移
always@(posedge clk or negedge rst_n)begin 
    if(!rst_n) state <= IDLE;
    else       state <= next_state; 
end

//组合逻辑描述状态转移条件,并给出输出
always@(*)begin
    case (state)
        IDLE: begin
            cola = 1'b0;
            next_state = money ? ONE : IDLE;  
        end
        ONE : begin 
            cola = 1'b0;
            next_state = money ? TWO : ONE ;
        end
        TWO : begin 
            cola = money ? 1'b1 : 1'b0;
            next_state = money ? IDLE : TWO ;
        end
        default:begin 
            cola = 1'b0;
            next_state = money ? ONE : IDLE;
        end
    endcase
end
endmodule 

  1.3三段式

(1)三段式Moore型
//三段式FSM示例
//采用的是Moore型的FSM
//--------------------<模块及端口定义>---------------------
module cola_FSM(
    input clk,             //时钟输入
    input rst_n,           //复位信号
    input money,           //是否投币输入
 
    output reg cola);      //是否有可乐输出

//--------------------<状态机参数定义>---------------------
//独热码编码的优点是每次状态跳转只有两个bit位发生跳变,动态功耗较低。同时独热码编码译码电路比较简单。缺点是用的寄存器位宽比二进制编码会大一点。
parameter IDLE  = 4'b0001;
parameter ONE   = 4'b0010;
parameter TWO   = 4'b0100;
parameter THREE = 4'b1000;

//--------------------<三段式状态定义>---------------------
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@(*)begin
    case (state)
        IDLE: begin
            next_state = money ? ONE : IDLE;  
        end
        ONE : begin 
            next_state = money ? TWO : ONE ;
        end
        TWO : begin 
            next_state = money ? THREE : TWO ;
        end
        THREE:begin 
            next_state = money ? ONE : IDLE;
        end
        default:begin 
            next_state = money ? ONE : IDLE;
        end
    endcase
end

//同步时序逻辑描述输出
always@(posedge clk or negedge rst_n)begin
    if(!rst_n) 
        cola <= 1'b0;
    else 
        cola <= (state == THREE) ? 1'b1 : 1'b0;
end
endmodule 
(2)三段式Mealy型     
//三段式FSM示例
//采用的是Mealy型的FSM
//--------------------<模块及端口定义>---------------------
module cola_FSM(
    input clk,             //时钟输入
    input rst_n,           //复位信号
    input money,           //是否投币输入
 
    output reg cola);      //是否有可乐输出

//--------------------<状态机参数定义>---------------------
//独热码编码的优点是每次状态跳转只有两个bit位发生跳变,动态功耗较低。同时独热码编码译码电路比较简单。缺点是用的寄存器位宽比二进制编码会大一点。
parameter IDLE  = 3'b001;
parameter ONE   = 3'b010;
parameter TWO   = 3'b100;


//--------------------<三段式状态定义>---------------------
reg [2:0] state;         // 当前状态定义
reg [2:0] next_state;    // 次态定义

//---------------------<三段式状态机>---------------------
//同步时序描述状态转移
always@(posedge clk or negedge rst_n)begin 
    if(!rst_n) state <= IDLE;
    else       state <= next_state; 
end

//组合逻辑描述状态转移条件
always@(*)begin
    case (state)
        IDLE: begin
            next_state = money ? ONE : IDLE;  
        end
        ONE : begin 
            next_state = money ? TWO : ONE ;
        end
        TWO : begin 
            next_state = money ? IDLE : TWO ;
        end
        default:begin 
            next_state = money ? ONE : IDLE;
        end
    endcase
end

//同步时序逻辑描述输出
always@(posedge clk or negedge rst_n)begin
    if(!rst_n) 
        cola <= 1'b0;
    else 
        cola <= ((state == TWO) && money) ? 1'b1 : 1'b0;
end
endmodule 

2、序列检测器

        序列检测器是学习状态机设计中非常经典的一个问题,虽然可以使用移位寄存器的方式实现(甚至使用移位寄存器的方式更加简单),但是这里作为状态机的熟悉和练习,还是使用状态机的方式进行一个实现。

        使用三段式状态机设计一个序列检测器,当检测到序列“101110”时,输出结果为1,否则输出为0。

        由于我们一般推荐使用三段式的状态机,所以后面的内容将都采用三段式进行描述。

        首先照例给出状态转移图,由于本人习惯性设计Mealy型状态机,所以后续的设计都将采用Mealy型,Moore型可以根据上述给出可乐机部分给出的示例自行设计实现。        

         根据状态转移图,我们就可以给出HDL代码:

//-------------------------------<模块及输入输出定义>-------------------------
module top(
    input  clk,
    input  rst_n,
    input  data_in,

    output reg data_out); 

//------------------------------<状态参数定义>-------------------------------
    parameter s1 = 6'b000001;
    parameter s2 = 6'b000010;
    parameter s3 = 6'b000100;
    parameter s4 = 6'b001000;
    parameter s5 = 6'b010000;
    parameter s6 = 6'b100000;

//-----------------------------<现态与次态定义>------------------------------
    reg [5:0]state;
    reg [5:0]next_state;

//-----------------------------<三段式状态机设计(Mealy型)>-----------------
//同步时序逻辑描述状态转移
    always@(posedge clk or negedge rst_n)
    begin 
        if(!rst_n)
            state <= s1;
        else 
            state <= next_state;
    end

//组合逻辑描述状态转移条件
    always@(*)
    begin 
        case(state)
            s1: 
                next_state = data_in ? s2 : s1;
            s2: 
                next_state = data_in ? s2 : s3;
            s3:
                next_state = data_in ? s4 : s1;            
            s4:
                next_state = data_in ? s5 : s3;
            s5:
                next_state = data_in ? s6 : s3;
            s6:
                next_state = data_in ? s2 : s3;
            default : 
                next_state = s1;
        endcase
    end     
   
   //同步时序逻辑实现输出
    always@(posedge clk or negedge rst_n)begin 
        if(!rst_n) 
            data_out <= 1'b0;
        else 
            data_out <= ((state == s6) && (!data_in)) ? 1'b1: 1'b0;
    end
endmodule

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

apple_ttt

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值