---
title: Verilog中有限状态机编码方式在2026年综合工具下的性能对比
url: "https://www.fpgalearn.com/48161.html"
kind: article
id: 48161
excerpt: Quick Start准备Vivado 2024.2（或更高版本）工程，目标器件选xc7a35ticsg324-1L（Artix-7）。创建三个Verilog模…
published_at: 2026-06-02
author: FPGA小白
tags: FSM, Verilog, 有限状态机
word_count: 3400
source: "https://www.fpgalearn.com"
---

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

> 标签：FSM、Verilog、有限状态机
> Quick Start准备Vivado 2024.2（或更高版本）工程，目标器件选xc7a35ticsg324-1L（Artix-7）。创建三个Verilog模…

> Quick Start准备Vivado 2024.2（或更高版本）工程，目标器件选xc7a35ticsg324-1L（Artix-7）。创建三个Verilog模…

## Quick Start
1. 准备Vivado 2024.2（或更高版本）工程，目标器件选xc7a35ticsg324-1L（Artix-7）。
1. 创建三个Verilog模块：fsm_onehot.v（独热码）、fsm_binary.v（二进制码）、fsm_gray.v（格雷码），实现相同状态机（8状态，条件转移）。
1. 编写顶层测试文件，例化三个FSM并驱动相同输入序列。
1. 运行行为仿真，确认三个FSM输出一致（状态转换正确）。
1. 运行综合（synth_design），查看综合后资源报告（LUT、FF）与最大频率（Fmax）。
1. 对比资源与Fmax：独热码通常LUT多但Fmax高；二进制码LUT少但Fmax低；格雷码居中。
1. 运行实现（place_design、route_design），检查时序收敛情况。
1. 记录结果至表格，完成对比。
## 前置条件与环境
| 项目 | 推荐值 | 说明 | 替代方案 |
| --- | --- | --- | --- |
| 器件/板卡 | xc7a35ticsg324-1L (Artix-7) | 典型中低端FPGA，资源有限，对比明显 | xc7k325t (Kintex-7) 或 xczu9eg (Zynq UltraScale+) |
| EDA版本 | Vivado 2024.2 | 2026年主流版本，综合策略成熟 | 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) |
| --- | --- | --- | --- | --- |
| 独热码 | 24 | 16 | 285 | 0.023 |
| 二进制码 | 14 | 11 | 210 | 0.045 |
| 格雷码 | 15 | 11 | 225 | 0.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) – 语言参考手册。
