FPGA线上课程平台|最全栈的FPGA学习平台|FPGA工程师认证培训
登录
首页-技术文章/快讯-技术分享-正文

Verilog中有限状态机编码方式在2026年综合工具下的性能对比

FPGA小白FPGA小白
技术分享
9小时前
0
0
8

Quick Start

  • 准备Vivado 2024.2(或更高版本)工程,目标器件选xc7a35ticsg324-1L(Artix-7)。
  • 创建三个Verilog模块:fsm_onehot.v(独热码)、fsm_binary.v(二进制码)、fsm_gray.v(格雷码),实现相同状态机(8状态,条件转移)。
  • 编写顶层测试文件,例化三个FSM并驱动相同输入序列。
  • 运行行为仿真,确认三个FSM输出一致(状态转换正确)。
  • 运行综合(synth_design),查看综合后资源报告(LUT、FF)与最大频率(Fmax)。
  • 对比资源与Fmax:独热码通常LUT多但Fmax高;二进制码LUT少但Fmax低;格雷码居中。
  • 运行实现(place_design、route_design),检查时序收敛情况。
  • 记录结果至表格,完成对比。

前置条件与环境

项目推荐值说明替代方案
器件/板卡xc7a35ticsg324-1L (Artix-7)典型中低端FPGA,资源有限,对比明显xc7k325t (Kintex-7) 或 xczu9eg (Zynq UltraScale+)
EDA版本Vivado 2024.22026年主流版本,综合策略成熟Vivado 2025.x 或 Quartus Prime Pro 24.x
仿真器Vivado Simulator (xsim)内置于Vivado,方便快捷ModelSim/QuestaSim 2024.2
时钟100 MHz(周期10 ns)典型系统时钟,便于时序分析50 MHz 或 200 MHz
复位异步复位,高有效与Xilinx原语匹配同步复位(需额外逻辑)
接口依赖无外部接口纯内部逻辑对比可添加UART/GPIO输出状态
约束文件create_clock -period 10.000 [get_ports clk]必须指定时钟约束多时钟域需额外约束

目标与验收标准

  • 功能点:三个FSM在相同输入序列下状态输出一致(仿真通过)。
  • 性能指标:记录综合后LUT/FF使用数、最大频率(Fmax,以Vivado报告为准)。
  • 资源对比:独热码LUT数应比二进制码多30%~80%,FF数相近。
  • 时序对比:独热码Fmax应比二进制码高10%~30%(因组合逻辑级数少)。
  • 验收方式:Vivado综合后报告(utilization_synth.rpt 和 timing_summary.rpt)中的具体数值。

实施步骤

1. 工程结构与RTL设计

  • 创建Vivado工程,添加三个Verilog源文件:fsm_onehot.v, fsm_binary.v, fsm_gray.v。
  • 每个模块实现一个8状态(S0~S7)的状态机,状态转移条件相同:输入din为0时进入下一状态,为1时回到S0。
  • 输出dout为当前状态值(独热码输出8位,二进制/格雷码输出3位,需统一位宽以便对比)。
  • 使用always块描述状态寄存器和次态逻辑,组合逻辑输出。
// fsm_onehot.v
module fsm_onehot (
    input clk,
    input rst_n,
    input din,
    output reg [7:0] dout
);

parameter [7:0] S0 = 8'b0000_0001;
parameter [7:0] S1 = 8'b0000_0010;
parameter [7:0] S2 = 8'b0000_0100;
parameter [7:0] S3 = 8'b0000_1000;
parameter [7:0] S4 = 8'b0001_0000;
parameter [7:0] S5 = 8'b0010_0000;
parameter [7:0] S6 = 8'b0100_0000;
parameter [7:0] S7 = 8'b1000_0000;

reg [7:0] state, next_state;

always @(posedge clk or negedge rst_n) begin
    if (!rst_n)
        state <= S0;
    else
        state <= next_state;
end

always @(*) begin
    case (state)
        S0: next_state = din ? S0 : S1;
        S1: next_state = din ? S0 : S2;
        S2: next_state = din ? S0 : S3;
        S3: next_state = din ? S0 : S4;
        S4: next_state = din ? S0 : S5;
        S5: next_state = din ? S0 : S6;
        S6: next_state = din ? S0 : S7;
        S7: next_state = din ? S0 : S0;
        default: next_state = S0;
    endcase
end

always @(posedge clk or negedge rst_n) begin
    if (!rst_n)
        dout <= 8'b0;
    else
        dout <= state;
end

endmodule

逐行说明(fsm_onehot.v)

  • 第1~6行:模块端口声明,clk和rst_n为时钟和复位,din为输入,dout为8位输出。
  • 第8~15行:用parameter定义8个独热码状态,每个状态只有1位为1,其余为0。独热码编码方式。
  • 第17行:声明state(当前状态)和next_state(次态)寄存器,均为8位。
  • 第19~23行:时序逻辑,在时钟上升沿或复位下降沿更新state。复位时进入S0。
  • 第25~36行:组合逻辑,根据当前state和din计算next_state。case语句覆盖所有状态,default处理未定义状态。
  • 第38~43行:输出寄存器dout,在时钟沿更新为当前state。此处dout直接输出状态编码。
// fsm_binary.v
module fsm_binary (
    input clk,
    input rst_n,
    input din,
    output reg [7:0] dout
);

parameter [2:0] S0 = 3'd0, S1 = 3'd1, S2 = 3'd2, S3 = 3'd3,
                S4 = 3'd4, S5 = 3'd5, S6 = 3'd6, S7 = 3'd7;

reg [2:0] state, next_state;

always @(posedge clk or negedge rst_n) begin
    if (!rst_n)
        state <= S0;
    else
        state <= next_state;
end

always @(*) begin
    case (state)
        S0: next_state = din ? S0 : S1;
        S1: next_state = din ? S0 : S2;
        S2: next_state = din ? S0 : S3;
        S3: next_state = din ? S0 : S4;
        S4: next_state = din ? S0 : S5;
        S5: next_state = din ? S0 : S6;
        S6: next_state = din ? S0 : S7;
        S7: next_state = din ? S0 : S0;
        default: next_state = S0;
    endcase
end

always @(posedge clk or negedge rst_n) begin
    if (!rst_n)
        dout <= 8'b0;
    else
        dout <= {5'b0, state};  // 扩展为8位输出
end

endmodule

逐行说明(fsm_binary.v)

  • 第1~6行:模块端口声明,与独热码模块相同。
  • 第8~9行:用parameter定义8个二进制编码状态,每个状态用3位二进制数表示。二进制码编码方式。
  • 第11行:state和next_state声明为3位,比独热码节省5个FF。
  • 第13~17行:时序逻辑,更新state。
  • 第19~30行:组合逻辑,与独热码相同,但case的比较对象是3位二进制数。
  • 第32~37行:输出dout,将3位state扩展为8位(高位补0),以便与独热码模块输出位宽一致。
// fsm_gray.v
module fsm_gray (
    input clk,
    input rst_n,
    input din,
    output reg [7:0] dout
);

parameter [2:0] S0 = 3'b000, S1 = 3'b001, S2 = 3'b011, S3 = 3'b010,
                S4 = 3'b110, S5 = 3'b111, S6 = 3'b101, S7 = 3'b100;

reg [2:0] state, next_state;

always @(posedge clk or negedge rst_n) begin
    if (!rst_n)
        state <= S0;
    else
        state <= next_state;
end

always @(*) begin
    case (state)
        S0: next_state = din ? S0 : S1;
        S1: next_state = din ? S0 : S2;
        S2: next_state = din ? S0 : S3;
        S3: next_state = din ? S0 : S4;
        S4: next_state = din ? S0 : S5;
        S5: next_state = din ? S0 : S6;
        S6: next_state = din ? S0 : S7;
        S7: next_state = din ? S0 : S0;
        default: next_state = S0;
    endcase
end

always @(posedge clk or negedge rst_n) begin
    if (!rst_n)
        dout <= 8'b0;
    else
        dout <= {5'b0, state};
end

endmodule

逐行说明(fsm_gray.v)

  • 第1~6行:模块端口声明。
  • 第8~9行:用parameter定义8个格雷码状态,相邻状态只有1位不同。格雷码编码方式。
  • 第11行:state和next_state为3位。
  • 第13~17行:时序逻辑。
  • 第19~30行:组合逻辑,case语句比较格雷码值。
  • 第32~37行:输出扩展为8位。

2. 仿真验证

  • 编写testbench,例化三个模块,驱动相同时钟、复位和din序列(如:din先为0连续8个周期,再为1一个周期,重复)。
  • 运行仿真,观察dout波形:独热码输出应为8位,二进制/格雷码输出应为3位扩展后的值。
  • 确认状态转换正确:例如,din=0时,状态从S0→S1→...→S7→S0循环;din=1时,状态回到S0。

3. 综合与实现

  • 在Vivado中分别将三个模块设为顶层(或使用综合选项中的“flatten_hierarchy”为none以保持模块边界)。
  • 运行综合,打开综合后报告,记录每个模块的LUT、FF使用数和WNS(最差负时序裕量)。
  • 运行实现,检查时序是否收敛。

常见坑与排查

  • 坑1:综合工具自动优化状态机编码。Vivado默认会尝试将状态机优化为二进制码,导致对比失效。需在综合设置中关闭FSM优化:在Vivado Tcl控制台运行 set_property STEPS.SYNTH_DESIGN.ARGS.FSM_EXTRACTION off [get_runs synth_1]
  • 坑2:输出位宽不一致导致对比困难。确保三个模块输出位宽一致(如都扩展为8位),否则资源对比不公平。
  • 坑3:复位状态不一致。确保所有模块复位后都进入S0,且S0编码在所有编码方式中对应最低值(独热码为0x01,二进制为0,格雷码为000)。

原理与设计说明

为什么独热码Fmax更高? 独热码每个状态只有1位为1,次态逻辑只需比较该位是否为1(或使用与门),组合逻辑级数少。例如,从S0到S1的转移只需判断state[0]和din,无需多级译码。二进制码需将3位state与常数比较,产生3位比较器,组合逻辑深度更大,导致路径延迟增加,Fmax降低。

为什么独热码LUT更多? 独热码使用8位寄存器(FF),而二进制/格雷码仅3位。次态逻辑中,独热码的case语句会综合出8选1多路器,每个输入需一个LUT;二进制码的case语句综合出3位比较器,LUT更少。但独热码的译码逻辑更简单,因此LUT多但Fmax高。

格雷码的优势:格雷码相邻状态仅1位变化,在跨时钟域或异步信号同步时能减少亚稳态风险。但在同一时钟域内,其性能与二进制码接近,Fmax略高于二进制码(因译码逻辑略简单)。

Trade-off总结

编码方式FF使用LUT使用Fmax适用场景
独热码高(N个状态需N个FF)较高高速设计、状态数少(<16)
二进制码低(log2(N)个FF)资源受限、状态数多(>16)
格雷码跨时钟域、低功耗(减少翻转)

验证与结果

以下为在Vivado 2024.2、xc7a35ticsg324-1L器件下,关闭FSM优化后的综合结果(示例值,实际以工程为准):

编码方式LUT数FF数Fmax (MHz)WNS (ns)
独热码24162850.023
二进制码14112100.045
格雷码15112250.038

测量条件:时钟约束100 MHz,综合策略为Vivado默认,关闭FSM优化。Fmax由Vivado时序报告中的最大频率给出(基于WNS计算)。

故障排查(Troubleshooting)

  • 现象:综合后三个模块资源相同 → 原因:Vivado自动优化了FSM编码。检查点:确认FSM_EXTRACTION已关闭。修复:在Tcl中运行 set_property STEPS.SYNTH_DESIGN.ARGS.FSM_EXTRACTION off [get_runs synth_1] 后重新综合。
  • 现象:仿真中状态不按预期转移 → 原因:复位信号极性错误。检查点:确认rst_n为低有效,且testbench中复位时序正确。修复:调整testbench复位序列。
  • 现象:时序不收敛(WNS为负) → 原因:时钟频率过高或组合逻辑路径过长。检查点:查看关键路径报告,定位最长路径。修复:降低时钟频率或优化状态机逻辑(如使用独热码)。
  • 现象:独热码LUT数异常高 → 原因:状态数过多(如超过16),独热码FF数线性增长,导致LUT也增加。检查点:评估状态数是否适合独热码。修复:改用二进制码或格雷码。
  • 现象:格雷码Fmax低于预期 → 原因:综合工具未识别格雷码序列,仍按二进制优化。检查点:查看综合报告中的状态编码。修复:手动指定状态编码(使用syn_encoding属性)。
  • 现象:输出dout出现毛刺 → 原因:组合逻辑输出未寄存。检查点:确认dout是否在always块中时序赋值。修复:将dout改为寄存器输出(如代码中所示)。
  • 现象:资源对比时FF数相同 → 原因:输出扩展逻辑引入了额外FF。检查点:确认输出寄存器是否独立于状态寄存器。修复:将输出dout直接赋值为state(不额外寄存),但需注意时序。
  • 现象:Vivado报告中的Fmax为0 → 原因:未添加时钟约束。检查点:确认XDC文件中包含create_clock。修复:添加约束。

扩展与下一步

  • 参数化状态机:使用parameter定义状态数,通过generate语句自动选择编码方式,提高代码复用性。
  • 带宽提升:在高速设计中,可结合流水线技术,在状态机前/后插入寄存器,进一步提高Fmax。
  • 跨平台对比:在Quartus Prime或ISE中重复实验,对比不同综合工具对编码方式的优化差异。
  • 加入断言:在testbench中使用SVA(SystemVerilog Assertions)检查状态转换的合法性,如“状态不能非法跳转”。
  • 形式验证:使用OneSpin或Vivado Formal验证状态机等价性,确保不同编码方式的功能一致。
  • 低功耗优化:格雷码在状态翻转时仅1位变化,可降低动态功耗。可测量实际功耗对比。

参考与信息来源

  • Xilinx UG901 (Vivado Design Suite User Guide: Synthesis) – 关于FSM编码和综合属性。
  • Clifford E. Cummings, "State Machine Coding Styles for Synthesis" (SNUG 2002) – 经典论文。
  • Vivado 2024.2 在线帮助文档 – FSM_EXTRACTION属性说明。
  • IEEE Std 1364-2005 (Verilog HDL) – 语言参考手册。
标签:
本文原创,作者:FPGA小白,其版权均为FPGA线上课程平台|最全栈的FPGA学习平台|FPGA工程师认证培训所有。
如需转载,请注明出处:https://z.shaonianxue.cn/48161.html
分享:
FPGA时序约束中create_clock与generated_clock的2026年最佳实践
FPGA时序约束中create_clock与generated_clock的2026年最佳实践上一篇
相关文章
总数:1.24K

2026年FPGA行业趋势深度解析:边缘AI、国产EDA与汽车功能安全新挑战

2026年,FPGA行业在AI大模型边缘部署、国产EDA工具链、汽车功能安全以及数据中心推理加速等多个维度迎来新一轮变革。成电国芯FPGA云课堂…
二牛学FPGA二牛学FPGA
技术分享
1个月前
0
0
62
0

FPGA毕业设计选题指南:从数字钟到AI加速器的实践路径

QuickStart:三步锁定你的FPGA毕设方向第一步:评估自身基础。如果你已掌握Verilog基础,并能熟练使用Vivado或Quartu…
二牛学FPGA二牛学FPGA
技术分享
1个月前
0
0
58
0

FPGA入门实践:4位加法器的设计、仿真与上板验证

QuickStart:10分钟跑通第一个加法器下载并安装Vivado或QuartusPrimeLite(免费版),安装时勾选对应器件…
FPGA小白FPGA小白
技术分享
1个月前
0
0
51
0

动手玩转FPGA:用OV5640摄像头打造实时边缘检测系统

嘿,想不想亲手用FPGA做一个能“看见”边缘的视觉系统?在自动驾驶、安防监控这些酷炫的应用里,实时找出图像的轮廓(也就是边缘检测)可是基本功。而…
FPGA小白FPGA小白
技术分享
1个月前
0
0
167
1

基于状态机的交通灯控制系统设计与实现指南

QuickStart(快速上手)本指南将引导您从零开始,在FPGA上实现一个基于有限状态机(FSM)的交通灯控制系统。您将完成从代码编写、仿真…
二牛学FPGA二牛学FPGA
技术分享
1个月前
0
0
57
0

FPGA学习路径中从入门到项目实战的2026年高效路线图

QuickStart:最短路径跑通第一个FPGA工程本路线图的核心是“先跑通、再理解”。以下6步可在3小时内完成从安装到看到LED闪烁的全过程…
FPGA小白FPGA小白
技术分享
10小时前
0
0
10
0
评论表单游客 您好,欢迎参与讨论。
加载中…
评论列表
总数:0
FPGA线上课程平台|最全栈的FPGA学习平台|FPGA工程师认证培训
没有相关内容