Verilog 状态机综合后毛刺的仿真与消除实战指南(2026年Q2)

FPGA小白
文章2026-06-11
80 0 0 0

Quick Start

  1. 准备环境:安装 Vivado 2025.2 或更高版本,确保支持 SystemVerilog 与综合后仿真。
  2. 创建工程:新建 RTL 工程,选择器件 xc7a35tcsg324-1(Artix-7 系列)。
  3. 编写状态机 RTL:使用三段式状态机编码,状态编码采用 Gray 码或 One-hot 码。
  4. 添加约束:创建 XDC 文件,约束时钟周期为 10 ns(100 MHz),并设置 false_path 或 multicycle 路径(如适用)。
  5. 运行综合:执行 synthesis,观察综合报告中的状态机推断情况。
  6. 运行综合后仿真:使用 Vivado Simulator 运行综合后时序仿真(post-synth timing simulation)。
  7. 观察毛刺:在波形中检查状态机输出信号是否存在毛刺(glitch),尤其是组合逻辑输出。
  8. 消除毛刺:修改 RTL,将输出改为寄存器输出,或插入同步寄存器链;重新综合并仿真验证。
  9. 验收:毛刺消失,输出波形干净,满足时序约束。

前置条件与环境

项目推荐值说明替代方案
器件/板卡Xilinx Artix-7 xc7a35tcsg324-1典型 FPGA,支持综合后仿真其他 7 系列或 UltraScale 器件
EDA 版本Vivado 2025.2支持 SystemVerilog 与高级综合后仿真Vivado 2024.x 或 Quartus Prime 24.x
仿真器Vivado Simulator (xsim)内建,支持 SDF 反标ModelSim/QuestaSim 2024.3
时钟/复位100 MHz 时钟,异步低电平复位典型系统时钟,复位用于初始化状态机50 MHz 或 200 MHz 时钟
接口依赖无外部接口,纯内部状态机便于聚焦毛刺问题可添加 GPIO 输出观察
约束文件XDC 文件:时钟周期 10 ns,输入延迟 2 ns必须约束时钟以进行时序仿真SDC 格式(Quartus)

目标与验收标准

  • 功能点:状态机正确完成状态跳转,输出符合预期逻辑。
  • 性能指标:综合后时序仿真中,所有输出信号无毛刺(glitch)持续时间超过 100 ps。
  • 资源/Fmax:综合后 Fmax ≥ 100 MHz,资源占用在合理范围(LUT ≤ 50,FF ≤ 30)。
  • 验收方式:在 Vivado 波形窗口中,放大观察输出信号跳变沿,无多余脉冲;日志中无 setup/hold 违例。

实施步骤

工程结构与 RTL 编写

  • 创建工程目录:src/(RTL 文件)、sim/(仿真脚本)、constr/(约束文件)。
  • 编写状态机 RTL:使用三段式结构(状态寄存器、次态组合逻辑、输出组合逻辑)。
  • 状态编码:使用 Gray 码(如 2’b00, 2’b01, 2’b11, 2’b10)以减少相邻跳变时的毛刺风险。
  • 输出策略:所有输出信号采用寄存器输出(在时钟沿赋值),避免组合逻辑直接驱动输出。
// fsm_gray.v - 三段式状态机,Gray 编码,寄存器输出
module fsm_gray (
    input wire clk,
    input wire rst_n,
    input wire start,
    output reg [1:0] state_out // 寄存器输出
);

// 状态编码(Gray)
localparam [1:0] IDLE = 2'b00,
                 S1   = 2'b01,
                 S2   = 2'b11,
                 S3   = 2'b10;

reg [1:0] state_reg, state_next;

// 状态寄存器
always @(posedge clk or negedge rst_n) begin
    if (!rst_n)
        state_reg <= IDLE;
    else
        state_reg <= state_next;
end

// 次态逻辑
always @(*) begin
    state_next = state_reg; // 默认保持
    case (state_reg)
        IDLE: if (start) state_next = S1;
        S1:   state_next = S2;
        S2:   state_next = S3;
        S3:   state_next = IDLE;
        default: state_next = IDLE;
    endcase
end

// 寄存器输出
always @(posedge clk or negedge rst_n) begin
    if (!rst_n)
        state_out <= IDLE;
    else
        state_out <= state_reg;
end

endmodule

逐行说明

  1. 第 1 行:注释,说明文件功能:三段式状态机,Gray 编码,寄存器输出。
  2. 第 2 行:模块声明,模块名为 fsm_gray。
  3. 第 3 行:输入端口 clk,类型 wire,用于驱动状态机时钟。
  4. 第 4 行:输入端口 rst_n,类型 wire,异步低电平复位。
  5. 第 5 行:输入端口 start,类型 wire,启动信号。
  6. 第 6 行:输出端口 state_out,类型 reg [1:0],寄存器输出,用于观察状态。
  7. 第 7 行:模块声明结束。
  8. 第 9 行:注释,说明状态编码采用 Gray 码。
  9. 第 10-13 行:使用 localparam 定义四个状态:IDLE (2’b00)、S1 (2’b01)、S2 (2’b11)、S3 (2’b10),相邻状态间仅一位变化。
  10. 第 15 行:声明 state_reg 和 state_next,均为 reg [1:0],分别用于当前状态寄存器和次态组合逻辑。
  11. 第 17 行:注释,开始状态寄存器逻辑。
  12. 第 18 行:always 块,敏感列表为 posedge clk 或 negedge rst_n,实现异步复位。
  13. 第 19 行:条件判断,若 rst_n 为低电平(复位有效),则执行复位。
  14. 第 20 行:复位时,state_reg 赋值为 IDLE(2’b00)。
  15. 第 21 行:否则(复位无效),执行正常赋值。
  16. 第 22 行:时钟上升沿时,state_reg 更新为 state_next。
  17. 第 23 行:状态寄存器 always 块结束。
  18. 第 25 行:注释,开始次态组合逻辑。
  19. 第 26 行:always 块,敏感列表为 *(所有信号),组合逻辑。
  20. 第 27 行:默认将 state_next 赋值为 state_reg,避免锁存器。
  21. 第 28 行:case 语句,根据 state_reg 决定次态。
  22. 第 29 行:当状态为 IDLE 时,若 start 为高,则次态为 S1,否则保持。
  23. 第 30 行:当状态为 S1 时,次态无条件为 S2。
  24. 第 31 行:当状态为 S2 时,次态无条件为 S3。
  25. 第 32 行:当状态为 S3 时,次态无条件为 IDLE。
  26. 第 33 行:default 分支,覆盖未定义状态,次态为 IDLE,增强安全性。
  27. 第 34 行:case 结束。
  28. 第 35 行:次态逻辑 always 块结束。
  29. 第 37 行:注释,开始寄存器输出逻辑。
  30. 第 38 行:always 块,敏感列表为 posedge clk 或 negedge rst_n,实现同步输出。
  31. 第 39 行:条件判断,若复位有效,则执行复位。
  32. 第 40 行:复位时,state_out 赋值为 IDLE(2’b00)。
  33. 第 41 行:否则(复位无效),执行正常赋值。
  34. 第 42 行:时钟上升沿时,state_out 更新为 state_reg,实现寄存器输出。
  35. 第 43 行:输出 always 块结束。
  36. 第 45 行:endmodule,模块定义结束。

仿真脚本与运行

  • 编写 testbench(如 tb_fsm_gray.v),实例化 fsm_gray,提供时钟和复位激励。
  • 在 Vivado 中设置综合后仿真:Tools → Simulation → Run Post-Synthesis Timing Simulation。
  • 观察波形:放大输出信号跳变沿,检查是否存在多余脉冲(毛刺)。

毛刺消除机制分析

原因分析:组合逻辑输出毛刺的根本原因是路径延迟不匹配。在状态机中,次态组合逻辑的输出直接驱动外部信号时,由于不同路径的延迟差异,会导致短暂的错误电平(毛刺)。Gray 编码虽能减少相邻状态跳变时的位变化数量,但无法消除组合逻辑固有的延迟竞争。

落地路径:将输出改为寄存器输出(即在时钟沿赋值),利用触发器的同步特性,将组合逻辑的毛刺“屏蔽”在时钟采样窗口之外。具体做法是:在状态机中增加一个寄存器输出级,如上述 RTL 中的 state_out,在时钟上升沿锁存 state_reg 的值。

风险边界:寄存器输出会增加一个时钟周期的延迟,对于需要即时响应的应用(如高速握手协议),需评估是否可接受。此外,若输出信号本身需要组合逻辑快速反馈(如用于下一级组合逻辑的输入),则寄存器输出可能破坏时序关系,此时应改用双寄存器同步链或调整设计架构。

验证结果

  • 运行综合后时序仿真,在波形窗口中放大输出信号 state_out 的跳变沿,确认无多余脉冲。
  • 检查 Vivado 日志,无 setup/hold 违例报告。
  • 资源报告:LUT 占用 ≤ 50,FF 占用 ≤ 30,Fmax ≥ 100 MHz。

排障指南

  • 毛刺仍存在:检查输出是否为寄存器输出;确认仿真模式为时序仿真(post-synth timing),而非功能仿真。
  • 时序违例:检查时钟约束是否正确,尝试降低时钟频率或调整综合策略(如 -retiming)。
  • 状态机推断失败:查看综合报告中的 FSM 部分,确认状态编码是否被正确识别;避免在 case 中使用 unique 或 priority 关键字导致误判。

扩展实践

  • 尝试 One-hot 编码(如 4’b0001, 4’b0010, 4’b0100, 4’b1000),观察资源占用与毛刺情况。
  • 在输出端添加双寄存器同步链(两个级联的 D 触发器),进一步降低亚稳态风险。
  • 使用 Vivado 的 report_glitch 命令(如适用)自动检测毛刺。

参考文档

  • Xilinx UG901: Vivado Design Suite User Guide: Synthesis
  • Xilinx UG900: Vivado Design Suite User Guide: Logic Simulation
  • IEEE Std 1364-2005: Verilog Hardware Description Language

附录:完整 RTL 与 Testbench 示例

完整项目文件(包括 testbench 和 XDC 约束)可从配套资源获取,或参考以下模板自行构建。

分类
技术分享
标签
Verilog毛刺状态机
浏览 80收藏 0赞 0评论 0
分享:

相关推荐

同频道 · 相近分类

暂无相关推荐

作者

FPGA小白查看主页

同分类阅读

文章

延伸阅读与实操

  • 文章 + 课程联动深度文章常对应体系课章节,可一键选课。
  • 学习产出可参考笔记与作业案例在学习产出广场持续更新。

探索全站