一、三段式状态机概述三段式状态机是 FPGA 设计中描述有限状态机FSM的经典方法它将状态机的状态转移、次态逻辑和输出逻辑分别写在三个独立的always块中。相比于一段式、二段式三段式结构具有代码清晰、时序明确、易于维护、避免竞争冒险等优点。重点三个always块各自分工实现时序逻辑与组合逻辑分离。二、三段式状态机的标准写法2.1 模块结构module fsm_example ( input clk, input rst_n, input condition, // 输入条件决定状态转移 output reg out_signal // 输出信号 );2.2 第一段状态寄存器时序逻辑作用当前时钟沿将next_state赋给current_state实现状态寄存。// 第一段状态转移时序 reg [1:0] current_state, next_state; always (posedge clk or negedge rst_n) begin if (!rst_n) current_state IDLE; else current_state next_state; end注意使用非阻塞赋值复位应使状态回到初始状态如IDLE2.3 第二段次态逻辑组合逻辑作用根据current_state和输入条件计算next_state。// 第二段次态计算组合 always (*) begin case (current_state) IDLE : if (condition) next_state WORK; else next_state IDLE; WORK: if (done) next_state STOP; else next_state WORK; STOP: next_state IDLE; default: next_state IDLE; endcase end注意使用阻塞赋值组合逻辑敏感列表写*代表所有输入信号避免综合出锁存器必须写default防止综合出锁存器所有可能状态分支都要明确赋值2.4 第三段输出逻辑时序/组合均可输出逻辑可以有两种风格时序输出推荐可滤除毛刺或组合输出速度快但有毛刺风险。✅ 推荐时序输出与状态寄存器同步// 第三段输出逻辑时序 always (posedge clk or negedge rst_n) begin if (!rst_n) out_signal 1b0; else begin case (current_state) WORK : out_signal 1b1; default: out_signal 1b0; endcase end end组合输出写法不推荐除非对延迟要求极高always (*) begin case (current_state) WORK : out_signal 1b1; default: out_signal 1b0; endcase end重点时序输出能避免组合逻辑产生的毛刺且方便时序约束是 FPGA 工程实践的首选。三、完整代码示例以 Moore 型状态机为例module moore_fsm ( input clk, input rst_n, input start, input done, output reg led ); // 状态编码建议使用 localparam localparam IDLE 2b00; localparam WORK 2b01; localparam STOP 2b10; reg [1:0] current_state, next_state; // ----- 第一段状态寄存器 ----- always (posedge clk or negedge rst_n) begin if (!rst_n) current_state IDLE; else current_state next_state; end // ----- 第二段次态逻辑 ----- always (*) begin case (current_state) IDLE : next_state start ? WORK : IDLE; WORK : next_state done ? STOP : WORK; STOP : next_state IDLE; default: next_state IDLE; endcase end // ----- 第三段输出逻辑时序----- always (posedge clk or negedge rst_n) begin if (!rst_n) led 1b0; else begin case (current_state) WORK : led 1b1; default: led 1b0; endcase end end endmodule四、重要注意事项重点注意点详细说明编码方式状态使用localparam定义推荐独热码one-hot占用触发器多但译码快、无毛刺或格雷码适用于高速异步时钟。避免在代码中写硬编码的数字。复位必须有异步或同步复位使状态机进入确定初始状态。推荐异步复位negedge rst_n注意复位释放需满足恢复时间。第二段组合逻辑必须使用always (*)条件分支必须完整case中加defaultif-else中覆盖所有路径否则综合出锁存器导致功能错误。第三段输出方式强烈推荐时序输出放在时钟always中避免组合输出的毛刺如果输出需要立即响应无延迟可以组合输出但需要手动处理毛刺如加滤波。阻塞 vs 非阻塞时序逻辑状态寄存、时序输出用组合逻辑次态计算、组合输出用。混用会仿真出错。状态转移条件避免在一个状态内同时判断多个复杂条件可分解成多个小状态条件表达式应消除竞争如输入已同步到当前时钟域。综合属性可添加syn_encoding或(* fsm_encoding one_hot *)指导综合器优化。仿真调试建议在 testbench 中打印状态名用$display避免直接看二进制难以调试。五、常见错误及避免方法缺少default现象综合出锁存器状态机可能卡死。解决case语句最后加default: next_state IDLE;次态逻辑中使用非阻塞赋值现象仿真时 next_state 更新慢一拍状态转移出错。解决组合逻辑一律用。输出逻辑使用current_state却放在组合块中现象输出有毛刺导致后级误触发。解决改用时序输出或对组合输出加寄存器。状态编码冲突现象状态机进入无效状态。解决在default分支中让next_state回到安全状态如IDLE或添加状态保护逻辑。跨时钟域处理输入信号如start,done若来自不同时钟域必须先用两级寄存器同步否则亚稳态会导致状态错误。六、进阶技巧提升可靠性状态机“一 hot”写法可以使用(* fsm_encoding one_hot *)让综合器自动生成独热码提高速度和抗干扰能力。三段式 输出寄存器即使需要组合输出也建议在输出后加一级寄存器即第四段彻底消除毛刺。仿真保护在 testbench 中模拟进入非法状态检查状态机是否能自动恢复到有效状态。使用 SystemVerilog可以用enum定义状态更清晰且支持自动编码。七、总结段落功能敏感信号赋值方式关键要点第一段状态寄存时钟/复位非阻塞同步或异步复位第二段次态计算所有输入*阻塞完整分支 default第三段输出逻辑时钟/复位时序输出或*组合输出非阻塞/阻塞优先选时序输出避免毛刺核心原则时序逻辑与组合逻辑严格分离每个always块扮演唯一角色。这样写出的状态机可读性高、易调试、综合结果可靠是工业级 FPGA 设计的最佳实践。