有限状态机(FSM)是数字逻辑设计的核心模式,用于描述具有有限个状态、并依据特定输入条件进行状态转移的系统。在FPGA设计中,FSM的编码风格直接决定了设计的可读性、可维护性、时序性能以及最终的综合实现结果。本指南将系统性地对比业界广泛采用的“三段式”与“二段式”FSM编码风格,提供从快速上手到深入原理的完整实践路径,并明确各自的适用场景与边界条件。
快速概览
三段式FSM将逻辑清晰地划分为状态寄存器、次态逻辑和输出逻辑三个部分,结构规整,时序路径明确。二段式FSM则将状态寄存器与次态逻辑(有时包含输出逻辑)合并,代码更紧凑,但对时序收敛要求更高。对于绝大多数FPGA设计,推荐优先采用三段式风格。
前置条件与环境
- 硬件平台:支持任意主流FPGA开发板(如Xilinx Artix-7系列或Intel Cyclone IV系列)。
- 软件工具:Vivado(Xilinx)或 Quartus Prime(Intel)任一版本,用于综合、实现与仿真。
- 设计语言:Verilog HDL 或 VHDL,本指南以Verilog为例进行说明。
- 基础知识:熟悉同步数字电路设计概念、时钟与复位、基本的HDL语法。
目标与验收标准
完成本指南的实践后,您将能够:
- 理解三段式与二段式FSM的代码结构与核心差异。
- 独立使用两种风格实现功能相同的状态机模块。
- 通过综合报告,对比分析两种风格在时序性能(最大时钟频率)和资源消耗(LUTs、FFs)上的差异。
- 根据设计需求,合理选择并应用合适的FSM编码风格。
实施步骤
步骤一:工程结构与模块定义
为公平对比,我们为两种风格创建接口完全一致的顶层模块。以一个简单的“序列检测器”(检测输入序列“1101”)为例,定义模块接口如下:
module seq_detector_3style (
input wire clk,
input wire rst_n,
input wire data_in,
output reg det_out
);
// 三段式FSM实现将放置于此
endmodule
module seq_detector_2style (
input wire clk,
input wire rst_n,
input wire data_in,
output reg det_out
);
// 二段式FSM实现将放置于此
endmodule步骤二:三段式FSM实现
三段式风格是推荐的FPGA FSM编码范式,它将逻辑清晰地划分为三个部分,严格遵循同步设计原则。
- 第一段:状态寄存器(时序逻辑)
使用同步时序逻辑描述当前状态的存储与更新。这是所有FSM的“记忆”单元。 - 第二段:次态逻辑(组合逻辑)
使用纯组合逻辑,根据当前状态和输入条件,计算出下一个时钟周期应跳转到的状态(次态)。 - 第三段:输出逻辑(组合或时序)
根据当前状态(摩尔型输出)或当前状态与输入(米利型输出)产生输出信号。为消除毛刺和提高时序,通常建议对输出进行寄存器打拍(即用时序逻辑实现)。
核心机制分析:这种分离使得综合工具能清晰识别时序路径的起点(寄存器)和终点(寄存器)。状态转移路径(当前状态 → 次态逻辑 → 状态寄存器)构成一条标准时序路径,便于工具优化以满足时钟约束。输出路径若同样经过寄存器,则输出稳定,无组合逻辑毛刺。
// 三段式示例片段(状态定义与第一段)
parameter S_IDLE = 3'd0, S1 = 3'd1, S11 = 3'd2, S110 = 3'd3, S1101 = 3'd4;
reg [2:0] current_state, next_state;
// 第一段:状态寄存器
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
current_state <= S_IDLE;
else
current_state <= next_state;
end
// 第二段:次态逻辑(组合)
always @(*) begin
next_state = current_state; // 默认保持当前状态
case (current_state)
S_IDLE: next_state = (data_in == 1‘b1) ? S1 : S_IDLE;
S1: next_state = (data_in == 1‘b1) ? S11 : S_IDLE;
// ... 其他状态转移
default: next_state = S_IDLE;
endcase
end
// 第三段:输出逻辑(时序,寄存输出)
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
det_out <= 1'b0;
else begin
case (current_state)
S1101: det_out <= 1'b1;
default: det_out <= 1'b0;
endcase
end
end步骤三:二段式FSM实现
二段式风格将上述的第一段(状态寄存器)与第二段(次态逻辑)或第三段(输出逻辑)进行合并,代码行数可能减少,但结构混合。
- 第一段:合并的时序逻辑
通常在一个always @(posedge clk)块中,既完成状态寄存器的更新,又可能根据某些条件直接产生寄存型的输出。次态计算所需的组合逻辑有时会内嵌在此过程中。 - 第二段:组合逻辑
描述剩余的状态转移条件或输出逻辑。有时,整个状态转移和输出都放在组合逻辑块中,而时序块仅负责寄存。
核心机制与风险:二段式风格模糊了纯组合的次态计算路径。如果次态逻辑复杂且被置于时序块中通过if-else语句实现,其关键路径可能始于上一个寄存器,经过复杂的多级选择器,再进入当前的状态寄存器,这条路径可能变得冗长,限制fmax。逻辑的混合也降低了代码的可读性和可维护性。
// 二段式示例片段(一种常见变体)
reg [2:0] state;
// 第一段:时序逻辑,包含状态转移判断
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
state <= S_IDLE;
det_out <= 1'b0;
end else begin
case (state) // 状态转移逻辑内嵌在时序块中
S_IDLE: begin
det_out <= 1'b0;
if (data_in) state <= S1;
end
S1: begin
det_out <= 1'b0;
if (data_in) state <= S11; else state <= S_IDLE;
end
// ... 其他状态,输出可能随状态直接赋值
S1101: begin
det_out <= 1'b1; // 输出可能产生毛刺,因为依赖于异步的state变化?
state <= S_IDLE; // 检测到后回到空闲
end
default: state <= S_IDLE;
endcase
end
end
// 第二段可能为空,或包含一些额外的组合输出逻辑




