• fpga状态机详解


    什么是状态机:状态机通过不同的状态迁移来完成特定的逻辑操作

    状态机的分类:Moore型状态机和Mealy型状态机

    1. Moore型:状态机的变化只与当前的状态有关
    2. Mealy型:状态机的变化不仅与当前的状态有关,还与输入有关

    如何创建状态机:状态机的创建可以分为一段式,两段式和三段式

    1. 一段式:主要是讲所有的状态变化以及导致的输出变化都写在了一个always快中。

    2. 两段式:将一些复位信号,clk信号单独写在一个always快中,其他的状态变化,输出值得变化写在一个always快中。

    3. 三段式:将一些复位信号,clk信号单独写在一个always快中,其他的状态迁移变化写在一个always快中,对应状态的输出值得变化写在一个always快中。

    举个例子:从循环输入的字母中做连续检测,当连续检测到“hello”时,将led灯进行状态的翻转,继续进行下一次的检测。
    这里写图片描述

    1. 一段式的编写方式:
    module  hello(
    input clk,//系统时钟信号  50mHz
    input rst_n,//系统复位信号,低电平有效
    input [7:0] data,//连续输入的字母
    output reg led//led灯
    );
    
    //设置需要改变的状态
    parameter    checkh  = 5'b0000_1,
                 checke  = 5'b0001_0,
                 checkla = 5'b0010_0,
                 checklb = 5'b0100_0,
                 checko = 5'b1000_0;
    
    reg [4:0]state;
    
    always @(posedge clk or negedge rst_n)
        if(!rst_n)
            begin
                led <= 1'b0;
                state <= checkh;
            end
        else 
            begin
                case (state)
                    checkh:
                        if(data == "h") state <= checke;
                        else  state <= checkh;
                    checke:
                        if(data == "e") state <= checkla;
                        else  state <= checkh;
                    checkla:
                        if(data == "l") state <= checklb;
                        else  state <= checkh;
                    checklb:
                        if(data == "l") state <= checko;
                        else  state <= checkh;
                    checko:
                        if(data == "o")
                            begin
                            led <= ~led;
                            state <= checkh;
                            end
                        else  state <= checkh;
                    default:state <= checkh;
                endcase
            end
    
    endmodule

     

    1. 两段式的编写方式:
    module  hello(
    input clk,
    input rst_n,
    input [7:0] data,
    output reg led
    );
    
    
    parameter checkh  = 5'b0000_1,
                 checke  = 5'b0001_0,
                 checkla = 5'b0010_0,
                 checklb = 5'b0100_0,
                 checko = 5'b1000_0;
    
    reg [4:0] cstate;
    reg [4:0] nstate;
    
    always @(posedge clk or negedge rst_n)
    if(!rst_n)
            begin
                cstate <= checkh;
            end
    else 
                cstate <= nstate;
    
    
    always @(cstate or data)
                case (cstate)
                    checkh:
                        if(data == "h") nstate <= checke;
                        else  nstate <= checkh;
                    checke:
                        if(data == "e") nstate <= checkla;
                        else  nstate <= checkh;
                    checkla:
                        if(data == "l") nstate <= checklb;
                        else  nstate <= checkh;
                    checklb:
                        if(data == "l") nstate <= checko;
                        else  nstate <= checkh;
                    checko:
                        if(data == "o")
                            begin
                            led <= ~led;
                            nstate <= checkh;
                            end
                        else  nstate <= checkh;
                    default:nstate <= checkh;
                endcase
    
    endmodule

     

    1. 三段式的编写方式:
    module  hello(
    input clk,
    input rst_n,
    input [7:0] data,
    output reg led
    );
    
    
    parameter checkh  = 5'b0000_1,
                 checke  = 5'b0001_0,
                 checkla = 5'b0010_0,
                 checklb = 5'b0100_0,
                 checko = 5'b1000_0;
    
    reg [4:0] cstate;
    reg [4:0] nstate;
    
        //复位信号,clk的处理(主要是对初始状态进行赋值操作)
    always @(posedge clk or negedge rst_n)
    if(!rst_n)
            begin
                cstate <= checkh;
            end
    else 
                cstate <= nstate;
    
        //状态迁移的处理
    always @(cstate or data)
                case (cstate)
                    checkh:
                        if(data == "h") nstate <= checke;
                        else  nstate <= checkh;
                    checke:
                        if(data == "e") nstate <= checkla;
                        else  nstate <= checkh;
                    checkla:
                        if(data == "l") nstate <= checklb;
                        else  nstate <= checkh;
                    checklb:
                        if(data == "l") nstate <= checko;
                        else  nstate <= checkh;
                    checko:
                        if(data == "o")
                            begin
                            nstate <= checkh;
                            end
                        else  nstate <= checkh;
                    default:nstate <= checkh;
                endcase
    
        //输出数据的处理
    always @(posedge clk or negedge rst_n)
    if(!rst_n)
            begin
                led <= 1'b1;
            end
    else 
            case (cstate)   
                    checko:
                        if(data == "o")
                        led <= ~led;
                    default;
                endcase
    
    endmodule

     

    注意

    1. 一般的状态机是使用Always语句和case语句组合来实现的
    2. 不可以根据Always快的个数来判断他是属于几段的状态机
    3. 一般情况下不建议使用一段式状态机,建议使用二和三段式状态机,二段式状态机使用时序逻辑处理状态变化,组合逻辑处理输入输出的变化,结构比较清晰,但容易产生毛刺
    4. 三段式从输入到输出会比一、两段式状态机延时一个时钟周期
  • 相关阅读:
    C#中ToString格式大全
    mysql事务
    Mac eclipse 启动卡住
    Mac 安装zkdash
    Mac 安装SecureCRT
    java多线程、并发系列之 (synchronized)同步与加锁机制
    jvm 年轻代
    查看日志技巧
    which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
    tomcat限制内存
  • 原文地址:https://www.cnblogs.com/wanghuaijun/p/8284697.html
Copyright © 2020-2023  润新知