状态机一段式、两段式、三段式怎么选?
更新时间:2026-09-21。问题驱动短答页。C 语言裸机状态机对照见 C 状态机,组合/时序规则见 阻塞与非阻塞赋值。
一句话回答
它们是 FSM 的三种 RTL 组织方式:一段式用一个 always 块包办状态寄存器、次态逻辑和输出;两段式拆成「时序块更新现态 + 组合块算次态和输出」;三段式进一步把输出也放到独立时序块,得到无毛刺的同步 Moore 输出。工程上默认推荐三段式。
三种写法骨架
一段式(简单小 FSM 可接受,但易混时序组合、难维护):
verilog
always @(posedge clk)
case (state)
S_A: if (go) begin state <= S_B; out <= 1; end
...
endcase两段式(时序状态 + 组合次态/输出):
verilog
always @(posedge clk or posedge rst)
if (rst) state <= S_A; else state <= next;
always @(*)
case (state)
S_A: begin next = go ? S_B : S_A; out = ...; end
endcase三段式(次态组合、状态时序、输出时序三者分离):
verilog
// 1) 次态组合逻辑
always @(*) begin next = state; case(state) ... endcase end
// 2) 状态寄存器
always @(posedge clk or posedge rst)
if (rst) state <= S_A; else state <= next;
// 3) 同步输出(Moore),避免组合毛刺
always @(posedge clk) out <= (state == S_B);Moore vs Mealy
- Moore:输出只取决于当前状态,三段式同步输出最干净。
- Mealy:输出还取决于输入,响应快一拍但输出随输入变化、易有毛刺,必要时也对输出打一拍。
怎么选
| 维度 | 一段式 | 两段式 | 三段式 |
|---|---|---|---|
| 可读性 | 差 | 中 | 好、职责清晰 |
| 组合毛刺 | 少(输出是寄存器) | 可能有 | 同步输出无毛刺 |
| 面积/时序 | 一般 | 一般 | 多用输出寄存器,更利于收敛 |
| 适用 | 极简 FSM | 一般 | 中大型/主流推荐 |
状态编码:二进制/格雷码省寄存器(状态多、时序紧凑),独热码 one-hot 每个状态一个触发器、译码简单、组合逻辑浅,是 FPGA 的常用选择。
常见坑
- 组合块里忘了给
next赋默认值:推断出锁存器,务必先next = state。 - 组合输出直接驱动敏感控制信号:毛刺风险,用三段式同步输出。
- 状态没用
default覆盖全部编码:进入未定义态跑飞,建议 default 回到 IDLE。 - 复位只清部分状态:保证回到确定初始态。
- Mealy 输出当 Moore 用:输入抖动会直接反映到输出。
总结
一段式把状态寄存、次态和输出写进一个时序块,适合极简 FSM;两段式拆成时序状态寄存器加组合次态/输出,结构清晰但组合输出可能有毛刺;三段式在此基础上把输出也同步寄存,得到只依赖状态、无毛刺的 Moore 输出,是中大型状态机的主流推荐,写法上务必给 next 默认值、用 default 覆盖非法态、复位回到确定状态,并在 FPGA 上优先用独热码以减小组合逻辑深度。