本节摘要:状态机是时序设计的"大脑",由状态寄存器、次态逻辑、输出逻辑三件套组成。本节用同一需求(检测串行序列)分别实现 Moore 与 Mealy 两种状态机,对照状态数、输出时序与抗扰能力的差异,建立两种结构的选型手感。
状态机的需求表达就是一张状态图。以检测串行流中的序列 1-0-1-1 为例,先画 Moore 版:状态记录"当前已匹配到目标序列的第几位"。上电在空闲态 S0;收到 1 进 S1(匹配了一位);S1 收 0 进 S2;S2 收 1 进 S3;S3 再收 1 进 S4(匹配完成,输出检测脉冲);任何状态收到不符位都退回合适的状态。输出只在 S4 拉高——Moore 的输出只由状态决定。
注意 S3 收 0 回 S1 而不是 S0——因为尾部的 1 可以当新序列的开头,这种"重叠匹配"的细节只有在画图时才会暴露,这正是"先画图"的价值。
VHDL 写状态机的标准姿势是枚举类型 + 双进程:
library ieee; use ieee.std_logic_1164.all; entity seq_det_moore is port ( clk, rst : in std_logic; ser_in : in std_logic; hit : out std_logic ); end entity seq_det_moore; architecture rtl of seq_det_moore is type state_t is (S0, S1, S2, S3, S4); -- 状态用枚举,可读且免编码烦恼 signal state : state_t := S0; begin -- 进程一:次态逻辑 + 状态寄存器(单进程写法,紧凑) process (clk) begin if rising_edge(clk) then if rst = '1' then state <= S0; else case state is when S0 => if ser_in = '1' then state <= S1; end if; when S1 => if ser_in = '0' then state <= S2; end if; when S2 => if ser_in = '1' then state <= S3; else state <= S0; end if; when S3 => if ser_in = '1' then state <= S4; else state <= S1; end if; when S4 => if ser_in = '1' then state <= S1; else state <= S0; end if; when others => state <= S0; end case; end if; end if; end process; -- 输出逻辑:纯组合,只看状态 hit <= '1' when state = S4 else '0'; end architecture rtl;
状态用 type state_t is (...) 枚举声明,综合器自动分配编码(通常顺序二进制)。要显式控制编码(比如格雷码防毛刺、独热码省译码逻辑),可以加 encoding 属性或改用常量向量定义状态——初学阶段交给工具即可。
Mealy 机把输入也纳入输出条件:检测到 S3 状态且当前输入为 1,即可立刻宣布命中,不必专门设 S4。状态图少一个节点,输出提前一拍:
architecture rtl of seq_det_mealy is type state_t is (S0, S1, S2, S3); -- 少了 S4 signal state : state_t := S0; begin process (clk) begin if rising_edge(clk) then if rst = '1' then state <= S0; else case state is when S0 => if ser_in = '1' then state <= S1; end if; when S1 => if ser_in = '0' then state <= S2; end if; when S2 => if ser_in = '1' then state <= S3; else state <= S0; end if; when S3 => if ser_in = '1' then state <= S3; -- 命中且尾部可重叠 else state <= S1; end if; when others => state <= S0; end case; end if; end if; end process; -- 输出逻辑:状态与输入共同决定 hit <= '1' when state = S3 and ser_in = '1' else '0'; end architecture rtl;
Mealy 版 S3 收 1 停留在 S3——序列 1-0-1-1-1-1 连续命中,状态不必绕行,输出在输入有效的同一拍拉高。

给两版状态机喂同一串激励:1、0、1、1、0、1、0、1、1、1。对照波形找三处差异。差异一:状态数,Mealy 比 Moore 少一个状态,触发器占用更省。差异二:命中时刻,在序列第二次出现处,Mealy 的 hit 与最后一位输入同拍拉高,Moore 的 hit 晚一拍(要先跳进 S4)。差异三:毛刺敏感,Mealy 的 hit 是组合输出,输入在时钟间抖动会直接在 hit 上抖出毛刺;Moore 的 hit 从寄存器出发,天生干净。把 hit 定义成寄存器输出(在时钟进程里赋值)可以给 Mealy 补上这一拍延迟,代价是又变回"慢一拍"——工程上常见的折中是 Mealy 逻辑 + 输出打一拍。
| 对比项 | Moore | Mealy |
|---|---|---|
| 输出依赖 | 仅当前状态 | 状态与当前输入 |
| 状态数量 | 通常多一个"完成态" | 更省 |
| 输出时延 | 对齐时钟沿、慢一拍 | 与输入同拍 |
| 抗输入毛刺 | 强 | 弱,必要时输出寄存 |
| 典型场景 | 显示驱动、总线仲裁 | 协议解析、快速响应 |
⚠️ 常见坑:状态机的 when others 漏写,或复位只复位了状态寄存器、忘了输出寄存器——前者在状态编码出现非法值时(例如上电亚稳态)整机卡死,后者复位后输出乱跳一拍。case 永远兜底,复位永远成套。
💡 关键直觉:状态机三件套——"记住现在(寄存器)、算出下一步(次态逻辑)、决定说什么(输出逻辑)"。画图时先写清每个状态"收到什么、去哪里、说什么",代码只是把这张表抄进去。