4. 综合与实现:综合策略、时序约束、布局布线、生成比特流

好,咱们进入第四讲。前面我们把工程建好了,代码也写完了,仿真也跑通了。但说实话,那都是在“理想世界”里。现在要动真格的了——把代码变成真正的硬件电路,烧到芯片里去。这一步,我习惯叫它“从代码到硅片”的惊险一跳。

这一章,咱们就聊聊 Vivado 里综合、实现、生成比特流这几个关键步骤。嗯,这里面的坑不少,我当年可没少往里跳。

4.1 综合策略:把 RTL 翻译成门级网表

综合,说白了就是把你的 Verilog/VHDL 代码,翻译成 FPGA 底层能用的基本单元——查找表(LUT)、触发器(FF)、块内存(BRAM)、DSP 切片这些东西。Vivado 的 synth_design 就是干这个活的。

我个人习惯,在综合阶段不会把所有优化选项都开到最大。为什么?因为综合跑得快,方便我快速迭代。你想想看,改一行代码就要等半小时综合,那谁受得了?

我的小技巧: 开发阶段用 -flatten_hierarchy rebuilt 和 -retiming 关闭,跑得飞快。等代码稳定了,再开 -flatten_hierarchy full 和 -retiming auto 做最终综合。

Vivado 提供了几种综合策略,我整理了个表格,方便你对比:

策略名称 特点 适用场景
Default 平衡面积和性能,速度适中 日常开发,快速迭代
AreaOptimized_high 极力压缩 LUT/FF 用量,但可能牺牲时序 资源紧张的芯片,比如小规模 Artix
PerformanceOptimized 优先满足时序,可能多用资源 高速接口、DDR 控制器等高频设计
Flow_RunPhysSynth 综合阶段就做物理综合,考虑布局信息 时序收敛困难时的“杀手锏”

我记得有一次做 10G 以太网项目,默认策略综合后时序总差那么一点点。换成 Flow_RunPhysSynth 后,问题迎刃而解。当然,代价是综合时间翻了一倍。

4.2 时序约束:给芯片定规矩

时序约束,说白了就是告诉 Vivado:“我的时钟跑多快,哪些路径要优先照顾。”没有约束,工具就像没头苍蝇,布出来的线可能根本不能用。

最基本的约束就两个:时钟和输入输出延迟。

# 创建主时钟,200MHz
create_clock -name sys_clk -period 5.000 [get_ports clk]

# 生成时钟,MMCM/PLL 输出
create_generated_clock -name clk_100m -source [get_pins mmcm_inst/CLKIN1] \
  -divide_by 5 -multiply_by 2 [get_pins mmcm_inst/CLKOUT0]

# 输入延迟约束
set_input_delay -clock sys_clk -max 2.0 [get_ports data_in]
set_input_delay -clock sys_clk -min 0.5 [get_ports data_in]

# 输出延迟约束
set_output_delay -clock sys_clk -max 3.0 [get_ports data_out]
set_output_delay -clock sys_clk -min 1.0 [get_ports data_out]
我曾经踩过的坑: 刚入行时,我忘了给异步复位信号加 set_false_path。结果 Vivado 拼命优化那条根本不需要时序检查的路径,浪费了大量布线资源,还导致其他路径时序违例。记住,异步复位、跨时钟域信号、测试逻辑,一定要显式声明 false path 或 multicycle path。

这里有个经验之谈:约束宁多勿少。你漏掉一个关键路径,工具就会“放飞自我”,布出来的线可能让你欲哭无泪。我一般会在综合后先跑一次 report_timing_summary,看看有没有未约束的路径。

4.3 布局布线:把逻辑放到物理位置上

综合完拿到网表,接下来就是布局布线。这一步,Vivado 会把逻辑单元分配到芯片的具体位置,然后用可编程连线把它们连起来。

布局布线的策略选择,直接决定你的设计能不能跑起来。Vivado 提供了几个常用策略:

  • Default:常规策略,适合大多数设计。
  • Explore:尝试多种布局布线方案,选最优的。时间翻倍,但时序改善明显。
  • Congestion_SpreadLogic_high:当芯片内部布线拥堵时,把逻辑打散。我遇到过 BRAM 和 DSP 挤在一起导致布线失败,用这个策略解决了。
  • Performance_ExplorePostRoutePhysOpt:布线后做物理优化,是时序收敛的最后手段。

我个人习惯,第一次实现用 Default 策略。如果时序没过,再看 report_timing_summary 和 report_utilization,分析是时序问题还是拥塞问题,然后对症下药。

核心原则: 布局布线不是一次就能搞定的。我通常要迭代 3-5 轮,每轮调整约束或策略,直到时序收敛。别指望一键搞定,那是不现实的。

4.4 生成比特流:最后的临门一脚

布局布线完成后,Vivado 会生成一个 .dcp 文件(设计检查点)。但要让 FPGA 跑起来,还得生成比特流文件(.bit)。这一步叫 write_bitstream。

生成比特流时,Vivado 会做几件事:

  1. 把配置数据按 FPGA 要求的格式打包。
  2. 插入同步头、CRC 校验等。
  3. 如果你勾选了 bin_file,还会生成 .bin 文件,适合烧写到 SPI Flash 里。

这里有个容易被忽略的点:比特流选项。在 Vivado 的“Settings → Bitstream”里,你可以配置:

  • -g compress:压缩比特流,减小存储空间。我一般都会勾上。
  • -g config_rate:配置速率,默认 33MHz,可以改到 50MHz 甚至 100MHz 加快烧写。
  • -g SPI_buswidth:如果从 SPI Flash 加载,可以设成 2 或 4 位宽,提高加载速度。
# Tcl 命令行生成比特流
write_bitstream -force -file ./output/top.bit

# 同时生成 .bin 文件,用于 SPI Flash
write_bitstream -force -file ./output/top.bin -bin_file
我的习惯: 每次生成比特流后,我都会用 report_route_status 检查一下有没有未布通的线。如果有,说明设计有严重问题,烧进去也跑不起来。

4.5 本章知识体系

下面这张图,把综合到生成比特流的整个流程串起来了。你可以把它当作一个检查清单:

综合与实现流程 综合与实现流程 RTL 代码 综合 (synth_design) 时序约束 综合策略 布局布线 (place_design / route_design) 实现策略 时序分析 生成比特流 烧写 FPGA 提示:每一步都可能需要迭代。时序没过?回去调约束或策略。布线拥塞?换策略或改代码。

嗯,这张图把整个流程串起来了。你可能会问:“如果时序没过怎么办?”别急,下一节我会专门讲时序收敛的技巧。但核心思路就是:先看报告,再调策略,不行改代码。千万别盲目乱试。

总结一下: 综合是把代码变网表,约束是告诉工具你的要求,布局布线是把网表放到芯片上,比特流是最终产物。每一步都有策略可选,选对了事半功倍,选错了事倍功半。多跑几次,多看看报告,慢慢就有感觉了。