FPGA 开发中 Vivado 时序收敛:从约束编写到增量编译的完整策略
Vivado 跑 STA,网表、IP、SDC 齐了,WNS 却还在 -0.3 ns 反复横跳——多半不是器件慢,是约束不准 + 策略瞎选 + 增量乱用,工具被带偏了。下面这套流程按 UG949 UltraFAST 方法论走,从 SDC 写到 impl_1 策略再到增量复用,一轮能把 100 MHz 设计压到正 slack。
一、约束编写:按"钟→I/O→CDC→例外"顺序,别倒着来
打开 Timing Constraints Wizard(Tools → Timing → Constraints Wizard),让它帮你扫缺失项,但主体约束建议手写,分阶段管:
# ===== 基线约束(初期就必须有)=====
create_clock -period 10.000 -name sys_clk [get_ports sys_clk_p]
# MMCM/PLL 输出必须用 generated,别再 create_clock 一刀砍
create_generated_clock -name clk_100m -source [get_pins clk_wiz/CLKIN1] \
-divide_by 1 [get_pins clk_wiz/clk_out1]
# I/O delay 带 -max/-min,否则只有 setup 没 hold
set_input_delay -clock sys_clk -max 2.5 [get_ports {data_in[*]}]
set_input_delay -clock sys_clk -min 1.0 [get_ports {data_in[*]}]
set_output_delay -clock sys_clk -max 2.0 [get_ports {data_out[*]}]
CDC 别偷懒用 false_path 一刀砍,异步组用 set_clock_groups -asynchronous,FIFO 指针再补 set_multicycle_path 或 set_max_delay 保相对关系;伪路径只给"真无关"的(如调试探针、JTAG 旁路)。
高扇出信号(global_rst_n、enable 之类)XDC 里先锁扇出,比让工具在 place 阶段自己复制稳:
```tcl
set_property MAX_FANOUT 50 [get_cells u_rst_sync/*]
```
二、实现策略:先诊断再换,别盲开 Explore
看到 WNS 为负就 Performance_Explore + AggressiveExplore 全开,是新手经典操作——你还没搞清瓶颈是逻辑级深、扇出大还是拥塞,工具已经在无效方向上烧了 40 分钟。
正确节奏:
1. report_design_analysis 看关键路径的 Logic Levels 和 Congestion;
2. 逻辑级 > 15 → RTL 插流水,或综合勾 -retiming 让工具挪寄存器;
3. 扇出爆 → MAX_FANOUT + 手动复制;
4. 拥塞红区 → floorplan 划 Pblock,把大 RAM/DSP 捆一块。
工具策略在 impl_1 上切:
set_property STRATEGY Performance_Explore [get_runs impl_1] # 首轮试
set_property STRATEGY Performance_Retiming [get_runs impl_1] # 逻辑级深
set_property PHYS_OPT_DIRECTIVE AggressiveExploreHold [get_runs impl_1] # hold 违例
report_qor_suggestions 跑一遍,Vivado 会给你针对本设计的 directive 清单,比盲试快。
三、增量编译:复用对了提速,复用错了崩时序
日常改几行 RTL 或动一个 AXI 从机,全量重跑 40 分钟太亏——read_checkpoint -incremental 拿上一轮 routed.dcp 当参考,未动部分物理位置锁住,只重布变动逻辑:
# 在 impl_1 的 pre-opt Tcl 钩子里
read_checkpoint -incremental ./checkpoints/top_routed_prev.dcp
但有两个硬条件:
• Cell reuse > 80% 才进真增量,低于这值工具会退成全量,白配;
• 逻辑利用率 > 90% 时别用增量——锁定的拥塞区会把布线器逼死,WNS 比全量还糟,这时要么更新 reference checkpoint,要么回全量重编一版干净基线。
稳定模块(时钟基础设施、PHY 包装、DMA 子系统)走 OOC(Out-of-Context),顶层实现时直接复用,既降 runtime 又避免被顶层策略拖着重跑。
四、收尾校验
report_timing_summary 盯三件事:WNS/TNS 正负、Clock Skew 是否 < 150 ps、Unsatisfied Requirement 里有没有"Unconstrained"路径——有就回 XDC 补。check_timing 扫漏约束,report_methodology 扫 UG949 违规,两轮 clean 再签核。
Vivado 时序收敛的真谛:约束按顺序写、STRATEGY 先诊断再换、增量编译看 reuse 率、OOC 把稳定块剥出去。这套跑通,100 MHz → 150 MHz 的 uplift 往往不是靠换器件,是靠把工具从"盲猜"拉到"按你的意图干活"。





