状态机模板
1、一段式状态机
1.1 一段式状态机模板代码
module fsm_one_segment (
input clk,
input rst_n,
input [输入信号],
output reg [输出信号]
);
parameter [1:0]
IDLE = 2'b00,
STATE1 = 2'b01,
STATE2 = 2'b10;
reg [1:0] current_state;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
current_state <= IDLE;
[输出信号] <= 默认值;
end else begin
case (current_state)
IDLE: begin
[输出信号] <= 值1;
if (转移条件) begin
current_state <= STATE1;
end
end
STATE1: begin
[输出信号] <= 值2;
if (条件1) begin
current_state <= STATE2;
end
end
default: begin
current_state <= IDLE;
[输出信号] <= 默认值;
end
endcase
end
end
endmodule
1.2 一段式状态机结构特点说明
- 特点:所有逻辑在一个时序块中完成,代码结构简单,代码量小。
- 缺点:代码可读性差,易产生锁存器,不推荐复杂设计。
2、二段式状态机
2.1 二段式状态机模板代码
module fsm_two_segment (
input clk,
input rst_n,
input [输入信号],
output reg [输出信号]
);
// ================== 状态定义 ==================
parameter [1:0]
IDLE = 2'b00,
STATE1 = 2'b01,
STATE2 = 2'b10;
reg [1:0] current_state;
reg [1:0] next_state;
// ============== 状态寄存器(第一段)==============
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
current_state <= IDLE;
end else begin
current_state <= next_state;
end
end
// ============== 状态转移+输出逻辑(第二段)==============
always @(*) begin
// 默认值和状态转移初始化
next_state = current_state;
[输出信号] = 默认值;
case (current_state)
IDLE: begin
[输出信号] = 值1; // 输出逻辑
if (转移条件) begin
next_state = STATE1;
end
end
STATE1: begin
[输出信号] = 值2;
if (条件1) begin
next_state = STATE2;
end else if (条件2) begin
next_state = IDLE;
end
end
default: begin
next_state = IDLE;
[输出信号] = 默认值;
end
endcase
end
endmodule
2.2 二段式状态机结构特点说明
特点:将状态转移逻辑与输出逻辑合并(输出在时序逻辑中)
优点:规避组合逻辑输出的毛刺,代码结构更简洁
3、三段式状态机
3.1 三段式状态机模板代码
module fsm_three_segment (
input clk, // 时钟
input rst_n, // 异步复位(低有效)
input [输入信号声明],
output reg [输出信号声明]
);
// ========================= 状态定义 =========================
// 建议使用独热码(one-hot)或二进制编码
parameter [STATE_WIDTH-1:0]
IDLE = 0,
STATE1 = 1,
STATE2 = 2;
reg [STATE_WIDTH-1:0] current_state;
reg [STATE_WIDTH-1:0] next_state;
// ===================== 状态寄存器(第一段)=====================
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
current_state <= IDLE; // 复位初始状态
end else begin
current_state <= next_state; // 状态更新
end
end
// ===================== 状态转移逻辑(第二段)=====================
always @(*) begin
// 默认保持当前状态
next_state = current_state;
case (current_state)
IDLE: begin
if (触发条件) begin
next_state = STATE1;
end
end
STATE1: begin
if (状态转移条件1) begin
next_state = STATE2;
end else if (状态转移条件2) begin
next_state = IDLE;
end
end
STATE2: begin
if (状态转移条件) begin
next_state = IDLE;
end
end
default: next_state = IDLE; // 避免锁存
endcase
end
// ===================== 输出逻辑(第三段)=====================
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
// 复位输出初始化
[输出信号] <= 默认值;
end else begin
case (current_state)
IDLE: begin
// 状态对应输出
[输出信号] <= 值1;
end
STATE1: begin
[输出信号] <= 值2;
end
STATE2: begin
[输出信号] <= 值3;
end
default: [输出信号] <= 默认值;
endcase
end
end
endmodule
3.2 三段式结构特点说明
- 特点:逻辑分层明确,代码简洁且符合同步设计规范。
- 优点:规避毛刺问题,综合优化友好,模块化设计,易扩展性好。
4、总结区分
一段式:所有逻辑混在一个 always 块中,代码臃肿且难以维护。易因条件覆盖不全产生锁存器,但其代码量少易于构建使用,简单状态逻辑可以使用。
两段式(组合输出型):两段式一般将状态转移和输出逻辑合并,或者将状态寄存器和转移逻辑分开,输出逻辑为组合电路,其可能产生毛刺,需额外同步电路处理,状态转移和输出逻辑混合,代码可读性降低。
三段式:三段式状态机通常分为三个部分,状态寄存器(时序)、状态转移逻辑(组合)和输出逻辑(时序或组合),输出逻辑用时序电路,直接规避毛刺问题,逻辑分层明确,代码简洁且符合同步设计规范。
4.1 三种架构对比表
类型 | 代码结构 | 毛刺风险 | 可维护性 | 推荐场景 |
---|---|---|---|---|
三段式 | 状态寄存 + 转移 + 输出 | 时序/组合 | 低 | 高 |
两段式 | 状态寄存 + (转移+输出) | 时序或组合 | 中 | 中 |
一段式 | 单时序块完成所有逻辑 | 时序 | 低 | 低 |
4.2 设计建议
- 推荐使用 parameter 定义状态(而非 define)
- FPGA 建议使用独热码(one-hot),ASIC 建议用二进制编码
- 每个状态对应独立的输出逻辑
- 所有条件分支必须覆盖所有可能性
- 必须包含 default 处理未定义状态
- 建议对状态机做容错处理(例如添加看门狗)