FPGA-状态机架构

状态机架构

状态机的适用场景

计数器结构适用与,状态只会按顺序执行的情况,如1->2->3->4这种情况。当出现1->3->1->4这状态跳转顺序不固定,要处理的输出信号复杂时的情况,就需要使用状态机了。

状态机规则

  1. 使用四段式写法,明德扬其所谓四段式,只是在moore摩尔型(输出与输入无关的类型)三段式的基础上加上了,一段规定状态转移信号的模板。
    具体模板如下,
verilog 复制代码
//以下是FSM的状态机模板

module FSM (

  

    input clk,

  

    input rst_n,

  

    input [3:0] data_in,

  

    output reg [3:0] data_out,

  

    output reg [3:0] data_out_2

  

);

  
  

//------------<状态机参数定义>------------------------------------------

//这里使用独热码编码节省组合逻辑资源

//此外还可以使用格雷码 、二进制码

localparam  IDLE  = 4'b0001,

            s1   = 4'b0010,

            s2   = 4'b0100,

            DONE = 4'b1000;

  

    reg [3:0] cur_state;  // 当前状态

    reg [3:0] next_state; // 下一状态

  
  

    // 第一段,状态的转移,时序逻辑

    always @(posedge clk or negedge rst_n) begin

        if (!rst_n)

            cur_state <= IDLE;

        else

            cur_state <= next_state;

    end

  
  
  

    // 第二段,新状态的生成,组合逻辑

    always @(*) begin

        case (cur_state)

            IDLE: begin

                if(IDLE2s1_start)

                    next_state = s1;

                else

                    next_state = cur_state;

            end

  

            s1: begin

                if (s12s2_start)

                    next_state = s2;

                else

                    next_state = cur_state;

            end

  

            s2: begin

                if (s22DONE_start)

                    next_state = DONE;

                else

                    next_state = cur_state;

            end

  

            DONE:begin

                if(DONE2IDLE_start)

                    next_state = IDLE;

                else

                    next_state = cur_state;

            end

  

            default:

                next_state = IDLE;                

        endcase

    end

  

    //第三段,状态机转移信号的赋值,组合逻辑

    //模板:

    //assign 状态机转移信号 = (cur_state == 当前状态) && (data_in == 当前状态的输入条件);

    assign IDLE2s1_start = (cur_state == IDLE) && (data_in == 4'b0001);

    assign s12s2_start = (cur_state == s1) && (data_in == 4'b0010);

    assign s22DONE_start = (cur_state == s2) && (data_in == 4'b0100);

    assign DONE2IDLE_start = (cur_state == DONE) && (data_in == 4'b1000);

  
  

    // 第四段,各状态的输出逻辑,组合逻辑

    // 对初学者,最好将所有输出分成单独的always块写,这样可以更清楚的看到各个状态的输出

    always @(posedge clk or negedge rst_n) begin

        case (cur_state)

            IDLE:

                data_out = 0;

  

            s1:

                data_out = data_in;

            s2:

                data_out = data_in;

  

            DONE:

                data_out = 0;

  

        endcase

    end

  

    always @(posedge clk or negedge rst_n) begin

        case (cur_state)

            IDLE:

                data_out_2 = 0;

  

            s1:

                data_out_2 = data_in;

  

            s2:

                data_out_2 = data_in;

  

            DONE:

                data_out_2 = 0;

        endcase

    end

  

//对于复杂工程,熟练工程师也可以将所有输出信号写到一个always块中,这样可以更清晰的看到各个状态的输出

//模板:

//always @(*) begin

  

always @(posedge clk or negedge rst_n) begin

    case (cur_state)

        IDLE: begin

            data_out = 0;

            data_out_2 = data_in;

        end

        s1: begin

            data_out = data_in;

            data_out_2 = data_in;

        end

        s2: begin

            data_out = data_in;

            data_out_2 = data_in;

        end

        DONE: begin

            data_out = 0;

            data_out_2 = data_in;

        end

    endcase

end

endmodule
  1. 状态转移信号的命名规则:
verilog 复制代码
(上一个状态名)2(下一个状态名)_start
  1. 用assign赋值状态转移条件时,必须与上当前状态。(跟计数器赋值结束条件时,必须与上+1条件类似)
  2. 状态不变时,要用next_state = cur_state。不要用具体的状态名如next_state=IDLE这种

状态机八步法

  1. 明确功能

    • 分析并明确功能
    • 每个状态机都应该写成一个单独的模块,便于复用和维护
    • 画出该模块框图,明确有哪些输入输出信号
    • 写出该模块的输入输出信号列表,其包括方向,位宽,功能。
  2. 输出分析

    • 明德扬认为应该对状态机的各输出信号,进行逐个的状态分析。即以输出信号为分析基础,这种做法跟普遍的以状态作为分析基础不同。
    • 将不同信号,在不同状态下的输出画图列出
  3. 状态合并

    • 原来的单个输出信号的状态分析,现在将所有的输出信号合并分析,状态能合在一起的就合在一起。
  4. 状态转移

    • 写出状态合并后,各状态的转移信号
  5. 转移条件

    • 将状态转移的条件用明确的信号表示

其表示也可以用更高的抽象级表示如下图,可以方便后续代码的编写。

  1. 完整性检查
    • 将所有的信号进行分析考虑(前面几步,主要分析了状态机信号,除状态机的信号的没有仔细考虑)
  2. 状态机代码
    • 套前面的状态机四段式
  3. 功能代码
    • 将其余的代码补全,主要是状态机转移信号那个部分
相关推荐
仲南音2 天前
Xilinx FPGA——时钟IP核MMCM、PLL
fpga开发
I'm a winner2 天前
基于Xilinx FPGA的LVDS高速串行通信系统(三)--数据训练及握手机制【文末源码】
fpga开发
upper20203 天前
coremark移植坑之-nostartfiles -nostdlib参数
学习·fpga开发·coremark移植·riscv设计
Eloudy3 天前
Vivado 纯命令行构建 FPGA 项目教程
fpga开发
Rambo.xia3 天前
AXI跨时钟域与数据一致性——CDC FIFO深度不够、写后读冒险、多Master仲裁、乱序返回,出了Bug根本查不出来
fpga开发·bug
upper20203 天前
FPGA部署卷积神经网络识别MINST图片
fpga开发·卷积神经网络·minst·minst识别·部署神经网络·神经网络识别图片
你是我的解忧王子3 天前
嵌入式 ADC采样 原始数据分析上层(平均值 波动率 正态分布 线性补偿 系统误差)
fpga开发·数据挖掘·数据分析
9527华安4 天前
FPGA纯verilog代码ISP图像处理培训教程,基于IMX214,提供工程源码+视频教程+FPGA开发板
图像处理·fpga开发·isp·imx214·mipi
千寻xun4 天前
二、实战篇-NVME SSD控制之ZYNQ实现(六)-读写NVME SSD硬盘数据
fpga开发·nvme·nvme ssd
千寻xun5 天前
二、实战篇-NVME SSD控制之ZYNQ实现(三)
fpga开发·nvme ssd·nvme协议