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,分析是时序问题还是拥塞问题,然后对症下药。
4.4 生成比特流:最后的临门一脚
布局布线完成后,Vivado 会生成一个 .dcp 文件(设计检查点)。但要让 FPGA 跑起来,还得生成比特流文件(.bit)。这一步叫 write_bitstream。
生成比特流时,Vivado 会做几件事:
- 把配置数据按 FPGA 要求的格式打包。
- 插入同步头、CRC 校验等。
- 如果你勾选了
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 本章知识体系
下面这张图,把综合到生成比特流的整个流程串起来了。你可以把它当作一个检查清单:
嗯,这张图把整个流程串起来了。你可能会问:“如果时序没过怎么办?”别急,下一节我会专门讲时序收敛的技巧。但核心思路就是:先看报告,再调策略,不行改代码。千万别盲目乱试。