---
title: FPGA时序分析中Setup与Hold Violation的根因定位与修复实战指南
url: "https://www.fpgalearn.com/50073.html"
kind: article
id: 50073
excerpt: Quick Start打开Vivado 2025.2（或对应版本），创建新工程，选择器件xc7a35ticsg324-1L（Artix-7典型型号）。添加一个简…
published_at: 2026-06-09
author: FPGA小白
tags: fpga, setup, 时序分析
word_count: 5369
source: "https://www.fpgalearn.com"
---

# FPGA时序分析中Setup与Hold Violation的根因定位与修复实战指南

> 标签：fpga、setup、时序分析
> Quick Start打开Vivado 2025.2（或对应版本），创建新工程，选择器件xc7a35ticsg324-1L（Artix-7典型型号）。添加一个简…

> Quick Start打开Vivado 2025.2（或对应版本），创建新工程，选择器件xc7a35ticsg324-1L（Artix-7典型型号）。添加一个简…

## Quick Start
1. 打开Vivado 2025.2（或对应版本），创建新工程，选择器件xc7a35ticsg324-1L（Artix-7典型型号）。
1. 添加一个简单的计数器RTL文件（clk_div.v），时钟频率设为100MHz，复位为高有效。
1. 运行综合（Synthesis），确保无语法错误。
1. 打开综合后的时序报告（Report Timing Summary），确认setup slack为正值。
1. 故意在代码中插入一个组合逻辑链（例如串联20个加法器），重新综合。
1. 再次查看时序报告，观察setup violation（slack为负值）。
1. 双击violation路径，在Schematic视图中高亮显示关键路径。
1. 通过流水线（插入寄存器）修复该路径，重新综合并验证slack变为正值。
**预期结果**：在8步内，亲手制造并修复一个setup violation，理解根因定位的基本流程。
## 前置条件与环境
| 项目 | 推荐值 | 说明 | 替代方案 |
| --- | --- | --- | --- |
| 器件/板卡 | Xilinx Artix-7 XC7A35T | 入门级FPGA，时序分析机制典型 | Kintex-7 / Zynq-7000 / Intel Cyclone V |
| EDA版本 | Vivado 2025.2 | 支持最新时序引擎与报告格式 | Vivado 2024.x / Quartus Prime Pro 24.x |
| 仿真器 | Vivado Simulator | 用于功能验证，非时序分析必需 | ModelSim / Questa / VCS |
| 时钟/复位 | 100MHz 单端时钟，高有效异步复位 | 典型约束设置 | 差分时钟 / 低有效复位（需调整约束） |
| 接口依赖 | 无外部接口 | 纯内部逻辑测试 | 可扩展至AXI / DDR接口（需额外约束） |
| 约束文件 | create_clock -period 10.000 [get_ports clk] | 定义主时钟周期10ns | set_input_delay / set_output_delay（外部接口） |
## 目标与验收标准
1. **功能点**：能独立定位setup/hold violation的根因（组合逻辑过长、扇出过大、跨时钟域未同步等）。
1. **性能指标**：修复后Fmax提升至少20%（示例：从80MHz提升至100MHz以上），hold slack ≥ 0。
1. **资源/Fmax**：修复后LUT/FF增加不超过20%（流水线带来的合理开销）。
1. **验收方式**：Vivado Timing Summary报告显示所有setup/hold slack ≥ 0；关键路径Schematic中无长组合链；仿真波形功能正确。
## 实施步骤
### 工程结构与关键模块
```
// clk_div.v - 带长组合链的计数器
module clk_div (
    input wire clk,
    input wire rst_n,
    output reg [7:0] count
);

wire [7:0] sum;
assign sum = count + 8'd1; // 简单加法

always @(posedge clk or negedge rst_n) begin
    if (!rst_n)
        count <= 8'd0;
    else
        count <= sum;
end

endmodule
```
### 逐行说明
1. **第1行**：注释，说明文件名和模块功能——带长组合链的计数器。
1. **第2行**：模块定义开始，命名为clk_div。
1. **第3行**：声明输入端口clk（时钟）。
1. **第4行**：声明输入端口rst_n（低有效异步复位）。
1. **第5行**：声明输出端口count，8位宽，寄存器类型。
1. **第6行**：模块端口声明结束。
1. **第8行**：声明内部连线sum，8位宽。
1. **第9行**：连续赋值语句，sum等于count加1（简单加法）。
1. **第11行**：always块开始，敏感列表为时钟上升沿或复位下降沿。
1. **第12行**：条件判断，若rst_n为低（复位有效），则执行下一行。
1. **第13行**：将count赋值为0（复位操作）。
1. **第14行**：else分支，复位无效时执行。
1. **第15行**：将sum的值赋给count（正常计数）。
1. **第17行**：endmodule，模块定义结束。
### 步骤1：制造Setup Violation
在clk_div.v中，将简单加法替换为长组合逻辑链，例如串联20个8位加法器，以增加路径延迟。修改后的代码片段如下：
```
// 长组合链示例（20级加法器）
wire [7:0] sum_chain [19:0];
assign sum_chain[0] = count + 8'd1;
genvar i;
generate
    for (i = 1; i < 20; i = i + 1) begin : adder_chain
        assign sum_chain[i] = sum_chain[i-1] + 8'd1;
    end
endgenerate
assign sum = sum_chain[19];
```
### 逐行说明
1. **第1行**：注释，说明为长组合链示例（20级加法器）。
1. **第2行**：声明一个包含20个8位连线的数组sum_chain，索引0到19。
1. **第3行**：将count加1的结果赋给sum_chain[0]（第一级）。
1. **第4行**：声明生成变量i，用于循环。
1. **第5行**：generate块开始，循环从i=1到i<20。
1. **第6行**：为每个i生成一个块，命名为adder_chain。
1. **第7行**：将上一级结果加1后赋给当前级，形成链式依赖。
1. **第8行**：endgenerate，生成块结束。
1. **第9行**：将最后一级sum_chain[19]赋给sum，作为最终结果。
重新综合后，打开时序报告，应观察到setup slack为负值，表明violation已成功制造。
### 步骤2：定位根因
在Vivado中，通过以下操作定位violation根因：
1. 运行综合后，点击“Report Timing Summary”，查看setup路径列表。
1. 找到slack最负的路径（通常为WNS，最差负slack），双击打开路径详情。
1. 在“Path Properties”中，查看数据路径延迟（data path delay）是否远大于时钟周期（10ns）。
1. 点击“Schematic”按钮，高亮显示该路径，观察是否包含长组合逻辑链（如多个加法器串联）。
1. 记录路径中组合逻辑的级数（LUT级联数量），确认根因为组合逻辑过长。
### 步骤3：修复Setup Violation
采用流水线技术，在组合链中插入寄存器以缩短每级路径延迟。修改后的代码片段如下：
```
// 流水线修复：在每级加法器后插入寄存器
reg [7:0] sum_pipe [19:0];
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        sum_pipe[0] <= 8'd0;
    end else begin
        sum_pipe[0] <= count + 8'd1;
    end
end
genvar i;
generate
    for (i = 1; i < 20; i = i + 1) begin : pipe_stage
        always @(posedge clk or negedge rst_n) begin
            if (!rst_n)
                sum_pipe[i] <= 8'd0;
            else
                sum_pipe[i] <= sum_pipe[i-1] + 8'd1;
        end
    end
endgenerate
assign sum = sum_pipe[19];
```
### 逐行说明
1. **第1行**：注释，说明为流水线修复方案。
1. **第2行**：声明寄存器数组sum_pipe，包含20个8位寄存器。
1. **第3行**：always块开始，敏感列表为时钟上升沿或复位下降沿。
1. **第4行**：条件判断，若复位有效，则执行下一行。
1. **第5行**：将sum_pipe[0]复位为0。
1. **第6行**：else分支，复位无效时执行。
1. **第7行**：将count加1的结果赋值给sum_pipe[0]（第一级流水线）。
1. **第8行**：always块结束。
1. **第9行**：声明生成变量i。
1. **第10行**：generate块开始，循环从i=1到i<20。
1. **第11行**：为每个i生成一个块，命名为pipe_stage。
1. **第12行**：每个流水线级的always块开始。
1. **第13行**：复位判断。
1. **第14行**：复位时赋0。
1. **第15行**：else分支。
1. **第16行**：将上一级结果加1后赋值给当前级（流水线运算）。
1. **第17行**：always块结束。
1. **第18行**：endgenerate，生成块结束。
1. **第19行**：将最后一级sum_pipe[19]赋给sum。
重新综合并运行时序分析，确认setup slack变为正值。注意：流水线增加了20个8位寄存器（约160个FF），资源开销在预期范围内。
### 步骤4：Hold Violation的定位与修复
Hold violation通常由数据路径过快（延迟过小）导致，常见于时钟偏斜或短路径。定位方法：
1. 在时序报告中切换到“Hold”标签页，查看hold slack是否为负值。
1. 双击负slack路径，查看数据路径延迟是否小于时钟偏斜（clock skew）加上保持时间。
1. 常见根因：时钟网络延迟差异大（如跨时钟域）、短路径未加缓冲（如直接连线）。
修复方法：
1. 在短路径中插入缓冲器（如LUT或延迟单元），增加数据路径延迟。
1. 调整时钟约束（如set_clock_uncertainty）以平衡偏斜。
1. 若为跨时钟域问题，使用双触发器同步器或FIFO。
验证：重新运行时序分析，确认hold slack ≥ 0。
## 验证结果
完成修复后，执行以下验证步骤：
1. 运行Vivado Timing Summary，检查所有setup和hold slack是否均≥0。
1. 在Schematic中确认关键路径无长组合链（流水线已打断）。
1. 运行功能仿真，验证计数器输出波形正确（每10个时钟周期递增一次）。
1. 记录修复前后Fmax对比：修复前约80MHz，修复后应达100MHz以上。
1. 检查资源利用率报告，确认LUT/FF增加不超过20%。
## 排障指南
1. **问题**：修复后setup slack仍为负。
**原因**：流水线级数不足或时钟约束过紧。
**解决**：增加流水线级数，或放宽时钟周期（如改为12ns）。
1. **问题**：hold slack为负。
**原因**：数据路径延迟过小。
**解决**：在短路径中插入LUT或延迟单元，或调整时钟偏斜约束。
1. **问题**：资源增加超过20%。
**原因**：流水线寄存器过多或未共享。
**解决**：优化流水线级数，或使用资源共享技术。
1. **问题**：仿真功能错误。
**原因**：流水线引入额外延迟周期。
**解决**：调整仿真期望值，考虑流水线延迟（本例中延迟20个时钟周期）。
## 扩展实践
1. **跨时钟域（CDC）**：使用双触发器同步器处理异步信号，避免setup/hold violation。
1. **多周期路径**：对于非关键路径，使用set_multicycle_path约束放宽时序要求。
1. **时钟门控**：使用时钟使能信号（clock enable）降低功耗，同时避免hold violation。
1. **高级工具**：尝试Vivado的“Report QoR Assessment”自动分析时序瓶颈。
## 参考资源
1. Xilinx UG906: Vivado Design Suite User Guide – Design Analysis and Closure Techniques.
1. Xilinx UG949: UltraFast Design Methodology Guide for the Vivado Design Suite.
1. IEEE Std 1364-2001: Verilog Hardware Description Language (用于RTL语法参考).
## 附录：时序分析关键术语
| 术语 | 定义 | 典型值（本例） |
| --- | --- | --- |
| Setup Slack | 数据到达时间与建立时间要求的差值，≥0表示满足 | 修复前：-2.5ns；修复后：+1.2ns |
| Hold Slack | 数据保持时间与保持时间要求的差值，≥0表示满足 | 修复前：+0.3ns；修复后：+0.5ns |
| WNS | 最差负slack（Worst Negative Slack），所有路径中最差的setup slack | 修复前：-2.5ns；修复后：+1.2ns |
| TNS | 总负slack（Total Negative Slack），所有负slack路径之和 | 修复前：-15.0ns；修复后：0ns |
| Fmax | 最大工作频率，由最差setup slack决定 | 修复前：80MHz；修复后：100MHz |
