4. 综合优化与层次化设计:深入 yosys 脚本
综合这一步,说白了就是把 RTL 代码翻译成门级网表。但翻译谁都会,难的是怎么翻得又小又快。我刚开始用 yosys 时,总觉得它就是个黑盒子,脚本跑完就完事。后来吃过几次亏才明白——综合脚本写得好不好,直接决定了后端后面是顺风顺水还是步步惊心。
4.1 yosys 综合脚本的基本骨架
先搭个最常用的脚本框架。我个人习惯把脚本分成三段:读入、优化、输出。
# 1. 读入设计
read_verilog -sv top.v
read_verilog -sv sub_module_a.v
read_verilog -sv sub_module_b.v
# 2. 高层次综合与展平
hierarchy -check -top top
proc
flatten
# 3. 逻辑优化
opt -fast -full
techmap
abc -lut 4 -dress
# 4. 输出网表
write_verilog synth_out.v
write_json synth_out.json
这里有个细节:hierarchy -check 会检查模块引用是否完整。如果某个子模块没读到,它会报错退出。嗯,这其实是好事——早发现早解决,总比跑到后面才发现缺模块强。
4.2 面积优化 vs 时序优化
优化这步,很多人上来就调 abc 的参数。但我想说,先搞清楚你要优化什么。
| 优化目标 | 关键命令 | 适用场景 |
|---|---|---|
| 面积优先 | abc -lut 4 -g 2,3,4 |
成本敏感、芯片面积紧张 |
| 时序优先 | abc -lut 4 -dress -D 500 |
高速设计、关键路径紧张 |
| 平衡模式 | abc -lut 4 -dress |
大多数通用场景 |
-g 2,3,4 是限制 ABC 只能使用 2/3/4 输入的 LUT,面积会小,但路径级数可能变多。-D 500 是给 ABC 一个时序约束(单位 ps),它会尽量把路径优化到 500ps 以内。
我的经验: 别一上来就上
-D 参数。先跑一遍不带时序约束的综合,看看默认的时序余量。如果 slack 是负的,再逐步收紧 -D 值。我曾经有个项目,上来就设 -D 300,结果 ABC 优化了 40 分钟还没跑完……后来改成 -D 500,5 分钟搞定,时序还过了。
4.3 层次化模块与黑盒处理
真实项目里,很少有单模块的。大部分都是层次化设计——顶层套子模块,子模块再套子模块。这时候 yosys 怎么处理?
我一般用两种策略:
- 展平(flatten):把所有层次打散,变成一个平面网表。优点是优化更充分,缺点是网表巨大,调试困难。
- 保留层次(-noflatten):保持模块边界。适合大型设计,或者某些模块需要单独约束。
举个例子,假设顶层 top 调用了 pll 和 memory 两个硬宏:
read_verilog top.v
read_verilog pll_behavioral.v
read_verilog memory_behavioral.v
hierarchy -check -top top
# 把 pll 和 memory 标记为黑盒
blackbox pll
blackbox memory
# 只综合顶层逻辑
proc
flatten
opt -fast -full
techmap
abc -lut 4 -dress
# 输出时保留黑盒端口
write_verilog -blackboxes synth_out.v
注意: 黑盒模块必须提供行为级模型(behavioral model),否则 yosys 无法推断端口连接。我曾经犯过这个错——把 memory 直接设成黑盒,但没给行为模型,结果综合出来的网表端口全悬空了。查了三天才找到原因。
4.4 综合优化的核心流程
下面这张图是我自己总结的 yosys 综合优化流程,每次做新项目都会对着过一遍:
4.5 综合脚本的调试技巧
写脚本最怕什么?跑完了发现结果不对。我分享几个调试技巧:
- 用
show看电路图:show top会弹出图形化视图,快速检查逻辑结构是否合理。 - 用
stat看统计信息:stat -top top会输出 cell 数量、面积估算、逻辑深度。每次优化前后对比一下,心里有数。 - 用
select定位问题:比如select t:$_AND_可以选出所有 AND 门,检查是否有多余的逻辑。
避坑指南: 我曾经在综合一个 8 位加法器时,发现面积比预期大了 3 倍。用
show 一看,原来 yosys 把加法器展开成了全加器阵列,没有调用工艺库里的 CLA 加法器。后来加了 techmap -map adder_map.lib 才解决。所以——别忘了映射到工艺库的专用单元。
4.6 综合脚本的完整示例
最后给一个我常用的综合脚本模板,适用于中等规模(10万门左右)的层次化设计:
# ============================================
# yosys 综合脚本 - 层次化设计
# 适用工艺:28nm
# ============================================
# 读入设计文件
read_verilog -sv ./rtl/top.sv
read_verilog -sv ./rtl/cpu_core.sv
read_verilog -sv ./rtl/cache_controller.sv
read_verilog -sv ./rtl/ahb_bus.sv
# 读入工艺库
read_liberty -lib ./lib/slow.lib
# 层次检查
hierarchy -check -top top
# 标记黑盒(硬宏)
blackbox pll_inst
blackbox sram_inst
# 展平逻辑部分
proc
flatten
# 优化
opt -fast -full
techmap -map ./lib/techmap.lib
abc -lut 4 -dress -D 800
# 统计
stat -top top
# 输出
write_verilog -blackboxes ./output/top_synth.v
write_sdc ./output/top_synth.sdc
这个脚本我用了好几个项目,基本没出过大问题。当然,具体参数要根据你的工艺和设计规模微调。比如 7nm 工艺,-D 值可能要设到 200 以下;如果是 180nm,1000 以上都正常。
嗯,综合优化这块就先聊到这儿。记住一句话:脚本是死的,设计是活的。多跑几次,多对比,慢慢就能找到最适合你项目的参数组合。