Moore和Mealy状态机
0 状态机概述
状态机由状态寄存器和组合逻辑电路构成,能够根据控制信号按照预先设定的状态进行状态转移,是协调相关信号动作、完成特定操作的控制中心。根据状态机的状态是否收敛又可将状态机划分为:有限状态机(FSM:Finite State Machine)和无限状态机(ISM:Infinite State Machine),一般数字电路设计中提及的状态机一般均指FSM,其基本要素包括:状态、输入和输出。其中各要素的含义如下:
状态(状态变量):在逻辑设计中,使用状态来表示电路的各种工作状态和顺序;
输入:状态机进入每个状态的相关条件;
输出:在特定状态下发生的对应事件;
在FSM中,根据FSM输出的特点,又可将FSM分为Mealy状态机和Moore状态机:
Mealy状态机:此类状态机的输出不但取决于当前的输入还取决于当前的状态;
Moore状态机:此类状态机的输出仅与当前状态有关;
根据上述状机的结构特点,可将状态机的编码结构上分为:一段式、二段式、三段式。
一段式:状态转移、状态的输入与输出均在一个always块中。该方式代码较为冗长,结构不清晰,不利于附加约束,不利于综合工具对设计进行优化,不推荐使用;
二段式:状态转移、状态的输入与输出任意两个在一个always块中。该方式输出一般为组合逻辑,极易产生毛刺等,所以一般情况下需要对输出端进行适当处理;
1 状态编码
在具体设计状态机时,需要根据电路的具体跳转状态进行编码,常用的编码格式如下:
独热码(one-hot code) | 二进制码(binary code) | 格雷码(gray code) |
使用N位状态触发器来对N个状态进行编码,每个状态都有独立的触发器对应,并且任意时刻只有一位触发器为“1” | 用二进制数对电路状态进行编码 | 任意两个相邻的状态只有一位二进制数不同 |
状态比较时仅仅需要比较一位,从一定程度上来说译码较容易,减少毛刺产生的概率; 在表示同样数目的状态时,独热码消耗较多的触发器(但是增加的触发器占用的面积与译码电路省下来的面积相当); 速度快但是较占用资源; | 需要较多的逻辑资源进行译码,译码过程较复杂;易懂;触发器数量与格雷码相同; | 因为相邻两个状态仅有一位不同,所以当出现状态跳转时,触发器翻转较少,产生亚稳态几率较小; 需要较多的逻辑资源进行译码,译码较为复杂;易懂; |
大型设计(ASIC、FPGA可以提供较多的触发器资源) | 小型设计(CPLD提供较多的组合逻辑资源) | 小型设计(CPLD提供较多的组合逻辑资源),多用于异步多时钟域电路 |
【示例】以下为对四个状态进行描述采用不同编码风格的示意图:
2 建议规则
建议规则一:使用parameter声明定义状态机的各状态,不要使用条件编译命令(`deinfe)进行定义,因为条件编译一般是全局定义的,而parameter仅限于特定的模块内部,且不同模块可以使用相同的parameter名,易于维护和修改。这里需要注意编码格式根据设计规模要求进行适当选择,没有固定的编码要求;
建议规则二:当前状态和下一状态的声明建议在parameter之后;
建议规则三:时序进程使用非阻塞赋值;
建议规则四:组合逻辑进程的敏感信号列表中必须包括当前状态和所有该进程的输入;
建议规则五:组合逻辑进程使用阻塞赋值;
建议规则六:在组合逻辑always块开始处,设置下一状态(next state)或默认状态为不定态态或者确定状态(一般为初始态)。初始状态设置为不定态有利于前仿真进行调试,当case语句中的所有状态都没有被涵盖时,将会输出异常。同时这样的设置并不会影响综合结果,综合工具将会优化掉不相关的逻辑,有利于提高综合质量。另外,还可以根据具体设计需要将下一状态设置为某一确定状态,这样状态机在加点或者复位后可以进入确定的逻辑状态;
建议规则七:在输出逻辑部分,模块输出一定要有默认值;
建议规则八:书写状态机时,每个状态单独放在一行,这样编码结构清晰,易于阅读维护;
建议规则九:每个module只有一个状态机,每个状态机仅属于一个module;
3 【示例要求】
功能是检测一个5位二进制序列“10010”。可实现循环检测(检测到10010之后如果后续输入为010,即序列为10010010xxxx,需检测到2次该序列)用Verilog代码实现并给出测试结果。
根据要求得到的IO关系如下表所示:
clk | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
in | 1 | 0 | 0 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 0 | 0 |
out | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
4 Moore FSM
Moore FSM状态机一般由三部分组成:输出逻辑部分,状态跳转部分,状态缓存部分。
输出逻辑部分(output logic):一般为组合逻辑,根据当前状态产生对应的输出.
状态缓存部分(state register):一般为时序逻辑,对当前状态进行同步缓存;
状态跳转部分(next state logic):一般由组合逻辑组成,其输入一般为当前模块的相关输入端口和当前状态,通过case语句产生不同分支的选择,目的是产生一个状态用于状态缓存;
为了描述示例方便,将以下例要求进行说明状态机的各种结构特点。
【机制框图】
示例中的状态机采用三段式FSM,就是将输出逻辑部分、状态跳转部分、状态缓存部分分别描述,具体代码如下:
采用三段式FSM有以下几个特点:
l 可以充分体现Moore FSM的组成结构,结构清晰;
l 状态修改和代码维护较为方便;
同时还需要注意以下几点:
l 输出逻辑部分为组合逻辑,所以always块中的赋值采用阻塞赋值;
l 状态跳转部分为组合逻辑,所以always块中的赋值采用阻塞赋值;
l 状态缓存部分为时序逻辑,所以always块中的赋值采用非阻塞赋值;
l 因为存在状态缓存部分,所以当前状态和下一状态之间相差一个时钟周期;
5 Mealy FSM
Mealy FSM结构与Moore FSM结构类似,只是输出逻辑部分需要增加相关的输入,即输出由当前状态和输入决定。其结构示意图如下:
注:图中小括号为输入,中括号对应为输出。
【源代码】
6 构建FSM一般步骤
根据上述描述和示例,状态机的构建一般分为以下步骤:
l 逻辑抽象获得状态图;
l 状态简化,将等价状态尽可能的合并,重绘状态图;
l 状态编码,参照状态图,根据电路的复杂度和要求采取适当的编码策略进行状态编码;
l 确定状态机结构(三段式、二段式、一段式);
l 根据状态图和结构进行具体程序编写;
在构建过程中一定要注意以下各部分的设计:
进入动作(entry action):进入状态时操作之前确保电路的状态是确定的;
退出动作(exit action):退出时确保电路的状态稳定,输出有效正确;
输入动作(input action):依赖于当前状态和或输入条件,确保状态机跳转时跳转条件的正确性;
7 总结
l 构建不同的FSM需要注意当前状态与下一状态之间的时序和转移关系,否则极易造成输出结果提前、退后或者异常;
l 为了后续电路时序,可在FSM输出级后增加同步处理结构;
l 推荐使用三段式FSM,结构清晰,易于维护和调试;
l Mealy FSM和MooreFSM可以互相转换,但是需要注意输出时序间的关系,因为Mealy FSM与当前输入有关,而输出组合逻辑部分的判断条件一般都要相对于输入推迟一个时钟周期,所以在两者之间转换需要特别注意。
l Mealy FSM和Moore比较如下表:
Mealy FSM | Moore FSM |
输出与当前状态和输入有关 | 输出仅与当前状态有关 |
输入立即反映在当前周期,即响应速度较快 | 输入影响下一状态,通过下一状态输出 |
结构复杂 | 结构简单 |
输出是当前状态和输入的组合逻辑决定的,所以输出需要更多的逻辑资源 | 输出仅由当前状态决定,输出使用的组合逻辑资源较少 |
输出不仅由当前状态决定,还由输入决定,所以输出可以在一个时钟周期完成多次变化,导致结果不稳定,所以对于输入一定要进行同步处理 | 只有当前状态发生变化时输出才会有变化 |