ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

FPGA_状态机工作原理

FPGA_状态机工作原理 FPGA_状态机介绍和工作原理状态机工作原理Mealy 状态机模型Moore 状态机模型Moore 与 Mealy 详细对比状态机描述方式三段式的核心优势状态编码方式三段式状态机详解与7分频实例状态参数定义独热码完整的三段式状态机代码第三段输出使用 curr_st 还是 next_st总结工程实践要点状态机工作原理状态机全称是有限状态机Finite State Machine简称FSM是表示有限个状态以及在这些状态之间的转移和动作等行为的数学模型。作为数字系统设计的核心组件状态机被广泛应用于控制逻辑、通信协议处理、接口时序控制等场景。状态机分为摩尔Moore型有限状态机与米利Mealy型有限状态机。摩尔状态机输出是只由输入确定的有限状态机不直接依赖于当前状态。米利有限状态机的输出不止与其输入有关还于它的当前状态相关这也是与摩尔有限状态机的不同之处。Mealy 状态机组合逻辑的输出不仅取决于当前状态还取决于输入状态。Moore 状态机组合逻辑的输出只取决于当前状态。Mealy 状态机模型Moore 状态机模型Moore 与 Mealy 详细对比对比维度Moore 状态机Mealy 状态机输出依赖仅依赖当前状态依赖当前状态和输入信号数学表达Output f(Current_State)Output f(Current_State, Input)响应速度较慢需等待状态更新后的时钟沿较快输入变化后立即反映状态数量通常需要更多状态状态数量相对较少毛刺风险低输出与状态同步较高输入毛刺可能传递到输出时序复杂度较低便于时序约束较高需关注输入到输出的组合路径状态转移图标注输出标注在状态节点内部输出标注在状态转移弧上input/output适用场景高可靠性设计、时钟分频、计数器等快速响应、状态数受限的场景FPGA设计建议在大多数FPGA应用中推荐优先使用 Moore 状态机因为同步设计更符合FPGA的架构特点输出寄存器化后时序更容易满足代码可读性和可维护性也更好。状态机描述方式状态机的Verilog描述可分为一段式、两段式以及三段式。一段式整个状态机写到一个 always 模块里面。在该模块中既描述状态转移又描述状态的输入和输出。结构简单但不利于维护和综合优化。两段式用两个 always 模块来描述状态机。其中一个 always 模块采用同步时序描述状态转移另一个模块采用组合逻辑判断状态转移条件描述状态转移规律及其输出。逻辑较清晰但输出仍为组合逻辑存在毛刺风险。三段式推荐在两个 always 模块描述方法基础上使用三个 always 模块一个 always 模块采用同步时序描述状态转移一个 always 采用组合逻辑判断状态转移条件描述状态转移规律另一个 always 模块描述状态输出可以用组合电路输出也可以时序电路输出。实际应用中三段式状态机使用最多因为三段式状态机将组合逻辑和时序分开有利于综合器分析优化以及程序的维护并且三段式状态机将状态转移与状态输出分开使代码看上去更加清晰易懂提高了代码的可读性推荐大家使用三段式状态机本文也着重讲解三段式。三段式的核心优势逻辑清晰便于维护状态转移、转移条件、输出逻辑完全分离修改某一部分不影响其他模块避免锁存器风险组合逻辑中使用完整的case语句和default分支综合器不会推断出锁存器综合器友好结构规范综合工具能更好地进行逻辑优化和时序分析毛刺过滤输出采用时序电路寄存器输出可有效滤去组合逻辑产生的毛刺三段式状态机的基本格式是第一个 always 语句实现同步状态跳转第二个 always 语句采用组合逻辑判断状态转移条件第三个 always 语句描述状态输出可以用组合电路输出也可以时序电路输出。状态编码方式在开始编写状态机代码之前一般先画出状态跳转图这样在编写代码时思路会比较清晰。在定义状态参数时还需要选择合适的编码方式。常见的状态编码方式有三种编码方式优点缺点适用场景二进制编码资源占用最少使用 ceil(log2(N)) 位即可表示N个状态状态跳转时多位同时变化易产生毛刺状态数少于5个格雷码相邻状态仅1位变化减少毛刺和功耗译码逻辑较复杂编码不直观状态数50个以上独热码仅1位为1状态比较只需1位判断速度快译码简单占用寄存器较多N个状态需N位5~50个状态的FPGA设计最常用在FPGA设计中由于寄存器触发器资源相对丰富独热码是最常用的编码方式其状态比较逻辑简单有利于提高工作频率。在CPLD中因组合逻辑资源丰富则多使用格雷码。三段式状态机详解与7分频实例下面以一个7分频为例对于分频等较简单的功能可以不使用状态机这里只是演示状态机编写的方法状态跳转图如下图所示状态参数定义独热码状态跳转图画完之后接下来通过 parameter 来定义各个不同状态的参数parameter S0 7b0000001; //独热码定义方式 parameter S1 7b0000010; parameter S2 7b0000100; parameter S3 7b0001000; parameter S4 7b0010000; parameter S5 7b0100000; parameter S6 7b1000000;这里是使用独热码的方式来定义状态机。接下来还需要定义两个7位的寄存器一个用来表示当前状态另一个用来表示下一个状态reg [6:0] curr_st ; //当前状态 reg [6:0] next_st ; //下一个状态完整的三段式状态机代码接下来就可以使用三个 always 语句来开始编写状态机的代码。第一个 always 采用同步时序描述状态转移第二个 always 采用组合逻辑判断状态转移条件第三个 always 是描述状态输出。一个完整的三段式状态机的例子如下代码所示module divider7_fsm ( //系统时钟与复位 input sys_clk , input sys_rst_n , //输出时钟 output reg clk_divide_7 ); //parameter define parameter S0 7b0000001; //独热码定义方式 parameter S1 7b0000010; parameter S2 7b0000100; parameter S3 7b0001000; parameter S4 7b0010000; parameter S5 7b0100000; parameter S6 7b1000000; //reg define reg [6:0] curr_st ; //当前状态 reg [6:0] next_st ; //下一个状态 //***************************************************** //** main code //***************************************************** //状态机的第一段采用同步时序描述状态转移 always (posedge sys_clk or negedge sys_rst_n) begin if (!sys_rst_n) curr_st S0; else curr_st next_st; end //状态机的第二段采用组合逻辑判断状态转移条件 always (*) begin case (curr_st) S0: next_st S1; S1: next_st S2; S2: next_st S3; S3: next_st S4; S4: next_st S5; S5: next_st S6; S6: next_st S0; default: next_st S0; endcase end //状态机的第三段描述状态输出这里采用时序电路输出 always (posedge sys_clk or negedge sys_rst_n) begin if (!sys_rst_n) clk_divide_7 1b0; else if ((curr_st S0) | (curr_st S1) | (curr_st S2) | (curr_st S3)) clk_divide_7 1b0; else if ((curr_st S4) | (curr_st S5) | (curr_st S6)) clk_divide_7 1b1; else ; end endmodule第三段输出使用 curr_st 还是 next_st这是一个常见的工程疑问。在上述代码中第三段使用的是curr_st原因如下使用curr_st输出与当前状态同步在时钟上升沿更新输出稳定可靠属于标准的Moore型输出。这是默认推荐的选择适用于绝大多数通用控制场景。使用next_st输出会提前一个时钟周期变化即输出与状态跳转对齐适用于预取数据、提前握手、低延迟响应等特殊高性能需求但需确保后续逻辑能正确处理提前生效的信号且验证复杂度较高。工程建议除非有明确的提前响应需求否则第三段一律使用curr_st。无论何种类型基于curr_st的输出比基于next_st的输出延迟一个时钟周期但时序更加稳定可控。总结从代码中可以看出输出的分频时钟 clk_divide_7 只与当前状态curr_st有关而与输入状态无关所以属于摩尔型状态机。状态机的第一段对应摩尔状态机模型的状态寄存器用来记忆状态机当前所处的状态状态机的第二段对应摩尔状态机模型产生下一状态的组合逻辑 F状态机的第三段对应摩尔状态机产生输出的组合逻辑 G因为采用时序电路输出有很大的优势所以这里第三段状态机是由时序电路输出的。状态机时序电路输出模型采用这种描述方法虽然代码结构复杂了一些但是这样做的好处是可以有效地滤去组合逻辑输出的毛刺同时也可以更好的进行时序计算与约束另外对于总线形式的输出信号来说容易使总线数据对齐减小总线数据间的偏移从而降低接收端数据采样出错的频率。工程实践要点要点说明default 分支第二段 case 语句必须添加 default 分支将非法状态引导回初始状态防止状态机因干扰进入死锁寄存器输出在航天、医疗、工业控制等高可靠性领域状态机输出必须采用时序电路寄存器输出避免毛刺导致误触发复位设计状态机必须有异步或同步复位确保上电后进入确定的初始状态状态命名使用有意义的参数名如 S_IDLE、S_READ、S_WRITE提高代码可读性仿真验证编写测试平台时需覆盖正常跳转、非法状态注入、复位等场景
返回列表