Quick Start(快速上手)
- 准备环境:安装 Vivado 2020.1+ 或 Quartus Prime 18.0+,确保工具链支持 Verilog-2001 标准。
- 创建工程:新建空白工程,目标器件选择 Xilinx Artix-7 (xc7a35t) 或等效 FPGA。
- 编写 RTL 代码:将下文“关键模块”中的三段式状态机代码复制保存为
fsm_three_stage.v。 - 编写 Testbench:将下文“验证代码”中的仿真文件复制保存为
tb_fsm.v。 - 运行行为仿真:在 Vivado 中将
tb_fsm设为仿真顶层,运行 1 µs 仿真。 - 观察波形:确认
state信号按IDLE → S1 → S2 → S1 → …循环,out在 S2 状态拉高。 - 综合与实现:运行 Synthesis 和 Implementation,检查无 Latch 推断警告。
- 查看资源报告:确认仅使用寄存器 + LUT,无额外锁存器。
前置条件与环境
| 项目 | 推荐值 | 说明 | 替代方案 |
|---|---|---|---|
| 器件/板卡 | Xilinx Artix-7 (xc7a35t) | 通用逻辑资源,适合教学 | Cyclone IV / Lattice iCE40 |
| EDA 版本 | Vivado 2021.1 | 支持 Verilog-2001 全特性 | Quartus Prime 20.1 / ModelSim |
| 仿真器 | Vivado Simulator | 内置于 Vivado,无需额外安装 | ModelSim / Verilator |
| 时钟/复位 | 100 MHz 时钟,同步高有效复位 | 复位同步化,避免异步复位问题 | 异步复位(需额外 CDC 处理) |
| 接口依赖 | 无外部接口 | 纯内部状态机演示 | 可扩展为 AXI-Stream 输入 |
| 约束文件 | 无需时序约束(仿真阶段) | 综合后需添加时钟周期约束 | SDC: create_clock -period 10 [get_ports clk] |
目标与验收标准
- 功能点:三段式状态机实现
IDLE → S1 → S2 → S1 → …循环,在 S2 状态输出高电平。 - 性能指标:无组合逻辑反馈环路,无锁存器推断;寄存器输出无毛刺。
- 资源验收:综合报告显示无 Latch,寄存器数量 = 状态编码位宽 + 输出位宽。
- 波形验收:仿真波形中
state与out在时钟上升沿同步变化,无异步跳变。 - 日志验收:综合与实现无 Critical Warning,无 Latch 推断。
实施步骤
工程结构
工程目录下包含以下文件:
rtl/fsm_three_stage.v(设计文件)sim/tb_fsm.v(仿真文件)constr/timing.xdc(约束文件)
顶层模块名 fsm_three_stage,端口列表:clk、rst_n、in、out。
关键模块:三段式状态机 RTL
module fsm_three_stage (
input wire clk,
input wire rst_n,
input wire in,
output reg out
);
// 状态编码(独热码,易于综合)
localparam IDLE = 3'b001,
S1 = 3'b010,
S2 = 3'b100;
reg [2:0] state, next_state;
// 第一段:状态寄存器(时序逻辑)
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
state <= IDLE;
else
state <= next_state;
end
// 第二段:次态逻辑(组合逻辑)
always @(*) begin
next_state = state; // 默认保持当前状态
case (state)
IDLE: if (in) next_state = S1;
S1: next_state = S2;
S2: next_state = S1;
default: next_state = IDLE;
endcase
end
// 第三段:输出逻辑(时序逻辑,寄存器输出)
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
out <= 1'b0;
else begin
case (next_state) // 使用次态判断,避免组合毛刺
S2: out <= 1'b1;
default: out <= 1'b0;
endcase
end
end
endmodule机制分析:三段式结构将状态机拆分为三个独立 always 块:第一段(时序逻辑)负责状态寄存,第二段(组合逻辑)计算次态,第三段(时序逻辑)生成输出。这种分离设计的关键优势在于:输出直接由寄存器驱动,避免了组合逻辑输出常见的毛刺问题。同时,次态逻辑与输出逻辑解耦,便于独立修改状态转移条件或输出策略,而不影响状态寄存器的时序闭合。
验证代码:Testbench
`timescale 1ns / 1ps
module tb_fsm;
reg clk, rst_n, in;
wire out;
fsm_three_stage uut (
.clk (clk),
.rst_n (rst_n),
.in (in),
.out (out)
);
// 时钟生成:100 MHz
always #5 clk = ~clk;
initial begin
// 初始化
clk = 0;
rst_n = 0;
in = 0;
// 复位释放
#20 rst_n = 1;
// 触发 IDLE → S1
#10 in = 1;
#10 in = 0;
// 观察自动循环
#100;
$finish;
end
endmodule约束文件(可选,综合阶段使用)
create_clock -period 10.000 -name sys_clk [get_ports clk]验证结果
运行仿真后,波形应呈现以下行为:
- 复位期间
state为IDLE,out为低电平。 - 复位释放后第一个时钟上升沿,
state保持IDLE。 - 当
in拉高一个周期后,state在下一个时钟沿跳变为S1。 - 随后每个时钟沿
state在S1和S2之间交替,out在S2状态期间为高电平。 out信号与时钟上升沿对齐,无组合毛刺。
综合后资源报告应显示:无 Latch 推断,寄存器数量 = 3(状态位宽)+ 1(输出位宽)= 4 个,LUT 数量约 4~6 个。
排障指南
- 综合报告出现 Latch 推断:检查第二段(次态逻辑)是否遗漏了
default分支,或第三段(输出逻辑)中case未覆盖所有状态。确保组合逻辑中所有分支都有赋值。 - 仿真波形中
out出现毛刺:确认输出逻辑使用的是next_state而非state,且输出为寄存器类型(reg)。若使用组合逻辑输出,需在第三段改用assign并添加同步寄存器。 - 状态机无法从 IDLE 跳转:检查
in信号是否在正确时钟沿被采样,建议在 Testbench 中让in在时钟上升沿之后变化(如#1延迟),避免建立时间违规。 - 综合后资源异常增多:检查状态编码是否为独热码,若使用二进制编码,寄存器数量可减少但组合逻辑会增加。独热码适合状态数 ≤ 16 的场景。
扩展与进阶
本指南的三段式结构可扩展至以下场景:
- 复杂状态机:增加状态数量(如 8~16 个),保持三段式结构不变,只需修改
localparam和case分支。 - 多输出控制:在第三段中增加多个输出寄存器,每个输出独立控制,互不干扰。
- Mealy 型输出:若输出依赖输入信号,可在第三段中组合
next_state和in进行判断,但需注意组合路径延迟。 - 流水线状态机:在状态寄存器后添加一级流水线寄存器,用于高速设计中降低扇出。
风险边界:三段式结构并非万能。当状态数超过 32 时,独热码的寄存器开销过大,建议改用格雷码或二进制编码。此外,输出逻辑若使用 next_state 判断,在状态跳转频繁的场景下可能引入一个周期的输出延迟,需根据应用权衡。
参考与延伸阅读
- Clifford E. Cummings, “State Machine Coding Styles for Synthesis”, SNUG 2002.
- Xilinx UG901, “Vivado Design Suite User Guide: Synthesis”.
- Intel Quartus Prime Handbook, “Recommended HDL Coding Styles”.
附录:完整文件清单
rtl/fsm_three_stage.v:三段式状态机 RTL 代码(见上文)sim/tb_fsm.v:Testbench 代码(见上文)constr/timing.xdc:时序约束文件(见上文)





