3. RTL 综合入门:Yosys 综合流程
综合,说白了就是把我们写的 RTL 代码,翻译成芯片厂给的 standard cells 能认识的门级网表。这一步做不好,后面布局布线全是白搭。我刚开始用 OpenROAD 的时候,总觉得综合就是个黑盒子,脚本一跑就完事。后来吃过亏才明白——综合策略选不对,时序收敛就是做梦。
今天我们就来啃这块硬骨头。我会带着你,把 Yosys 综合的每一步都走一遍。
3.1 Yosys 是什么?
Yosys 是 OpenROAD 流程里的综合引擎。它是个开源工具,但能力一点也不弱。我个人习惯把它看作一个「RTL 到网表的翻译官」——你给它 Verilog,它给你 mapped netlist。
它的工作流程大致分三步:
- 读取设计文件(读 RTL)
- 高层次优化(逻辑化简、资源共享)
- 技术映射(把逻辑映射到标准单元库)
嗯,这里要注意:Yosys 不是直接一股脑把 RTL 变成门级网表的。它中间会做很多「小动作」,比如常量传播、死逻辑消除、状态机编码优化等等。这些优化做得好不好,直接影响最终面积和时序。
3.2 读取设计文件
先看一个最基本的 Yosys Tcl 脚本。我一般习惯把脚本分成几个清晰的段落,方便调试。
# 1. 读取设计文件
read_verilog -sv ./src/top.sv
read_verilog -sv ./src/sub_module_a.v
read_verilog -sv ./src/sub_module_b.v
# 2. 设置顶层模块
hierarchy -top top
# 3. 高层次优化
proc; opt; fsm; opt; memory; opt
# 4. 技术映射
dfflibmap -liberty ./lib/sky130_fd_sc_hd__tt_025C_1v80.lib
abc -liberty ./lib/sky130_fd_sc_hd__tt_025C_1v80.lib -script +strash;scorr;ifraig;retime,{D};strash;dch,-f;map,-M,1,{D}
# 5. 输出网表
write_verilog ./outputs/top_synth.v
write_verilog -noattr ./outputs/top_synth_clean.v
这段脚本里,read_verilog 就是读文件。我遇到过不少新手,文件路径写错或者漏读某个模块,结果综合出来一堆黑盒(blackbox)。
读文件时,有几点经验分享:
- SystemVerilog 支持:加
-sv开关才能读 .sv 文件。不加的话,很多语法会报错。 - 文件顺序:被例化的模块要放在前面读,或者用
-D定义宏来避免依赖问题。 - 黑盒检查:读完后用
hierarchy -check检查有没有未解析的模块。
3.3 标准单元库映射
技术映射(tech mapping)是综合里最核心的一步。Yosys 用 abc 命令调用 ABC 工具来做这件事。
标准单元库长什么样?说白了就是一个 Liberty 格式的文件(.lib)。里面描述了每个 cell 的功能、面积、时序、功耗等信息。Yosys 需要这个文件才能知道「你的设计里有哪些门可以用」。
映射过程可以拆成几个子步骤:
| 步骤 | 命令 | 作用 |
|---|---|---|
| 1. 提取逻辑 | abc -script +strash |
把电路转成 AIG(And-Inverter Graph) |
| 2. 逻辑优化 | scorr; ifraig; retime |
消除冗余、重定时优化 |
| 3. 技术映射 | map -M 1,{D} |
把 AIG 节点映射到标准单元 |
这里 -M 1,{D} 的意思是:面积优先,同时考虑延迟(D)。你可以改成 -M 0,{D} 变成延迟优先。
-M 0,{D} 跑一遍,看看能不能满足时序。如果面积超标,再调成 -M 1,{D} 做面积优化。没有一招鲜吃遍天的策略。
3.4 综合策略选择
综合策略说白了就是「在面积、时序、功耗之间做取舍」。Yosys 给了我们几个旋钮可以拧:
- 面积优先:
map -M 1,逻辑共享多,但路径可能变长。 - 时序优先:
map -M 0,用更大的 cell 来驱动长线,面积会涨。 - 功耗优先:配合
dfflibmap选择低功耗触发器,但速度会慢。
你想想看,实际项目里很少有「既要又要」的情况。我做过一个 MCU 项目,面积预算卡得很死,我就用了面积优先策略,结果时序差了 0.3ns。后来在布局布线阶段用插 buffer 的方式修回来的——但那是后话了。
下面这张图,是我自己总结的 Yosys 综合流程,你可以对照着看:
3.5 综合后的检查清单
综合跑完,别急着往下走。我每次都会做这几件事:
- 检查黑盒:
hierarchy -check看有没有未解析的模块。 - 检查面积:Yosys 会打印 cell 数量,跟预期对比一下。
- 检查连线:用
stat命令看网表统计信息。 - 检查扇出:高扇出网络(比如时钟、复位)在综合阶段就要标记出来。
stat 确认面积不为零。
3.6 实战小贴士
最后分享几个我在项目中积累的实用技巧:
- 增量综合:如果只改了某个子模块,可以用
read_verilog -sv -D SYNTHESIS配合hierarchy -top只综合改动的部分,节省时间。 - 保留中间结果:在
abc之前加write_verilog ./outputs/pre_abc.v,方便对比映射前后的逻辑变化。 - 多库支持:如果工艺库有多个 PVT corner,可以分别综合,然后选最差 corner 的网表做时序分析。
- 脚本化:把综合脚本写成 Makefile 或 Python 脚本,每次改参数不用手敲命令。
嗯,综合这一步说难不难,说简单也不简单。关键是要理解 Yosys 每一步在做什么,以及怎么根据设计需求调整策略。你把这章的内容吃透了,后面的布局布线就会顺畅很多。