3. 综合入门:Yosys 与 OpenROAD 的集成、逻辑综合基本概念、综合策略与脚本编写、综合后的检查
逻辑综合,说白了就是把我们写的 RTL 代码(Verilog/VHDL)翻译成门级网表的过程。你想想看,我们写的是行为级的描述,比如 assign c = a & b;,但芯片里真正干活的是与门、或门、触发器这些标准单元。综合工具就是干这个翻译活的。
在 OpenROAD 流程里,Yosys 是负责综合的引擎。我个人习惯把 Yosys 看作一个“翻译官”——它把 RTL 翻译成网表,同时还要考虑面积、时序和功耗。嗯,这里要注意,Yosys 本身是个开源工具,功能很强大,但和商业工具(比如 Synopsys DC)比,有些高级优化策略需要我们自己手动调。
3.1 Yosys 与 OpenROAD 的集成方式
OpenROAD 把 Yosys 作为综合步骤内嵌在流程里。你不需要单独启动 Yosys,而是通过 OpenROAD 的 Tcl 脚本来调用它。我刚开始用的时候也困惑过——到底怎么把这两个工具串起来?其实很简单。
核心集成流程:
- OpenROAD 启动后,加载设计文件(Verilog RTL)
- 调用
yosys命令,执行综合脚本 - Yosys 输出门级网表(.v 格式)
- OpenROAD 读取网表,继续后续的布局布线
下面是一个典型的集成调用示例。我在项目中通常把综合脚本单独写成一个文件,然后在 OpenROAD 里用 source 命令加载。
# 在 OpenROAD 的 Tcl 脚本中调用 Yosys
yosys -import
# 读取 RTL 文件
read_verilog ./rtl/top.v
read_verilog ./rtl/sub_module.v
# 设置顶层模块
synth -top top
# 映射到标准单元库
dfflibmap -liberty ./lib/sky130_fd_sc_hd__tt_025C_1v80.lib
abc -liberty ./lib/sky130_fd_sc_hd__tt_025C_1v80.lib
# 输出网表
write_verilog ./results/synth_netlist.v
我的经验: 记得在综合前先检查 RTL 有没有语法错误。我曾经有一次忘了检查,结果 Yosys 报了一堆莫名其妙的错误,排查了半天才发现是 RTL 里有个未声明的 wire。
3.2 逻辑综合的基本概念
综合不是简单的翻译,它涉及几个关键概念。我把它整理成一张表,方便你对照理解。
| 概念 | 说明 | 我的理解 |
|---|---|---|
| RTL 综合 | 将行为级代码转为结构级网表 | 就像把建筑设计图转成施工图 |
| 逻辑优化 | 简化布尔表达式,减少门数 | 去掉冗余逻辑,让电路更精简 |
| 技术映射 | 将逻辑门映射到标准单元库 | 选择具体的门电路实现 |
| 时序约束 | 设定时钟频率、输入输出延迟 | 告诉工具“你得跑多快” |
| 面积优化 | 在满足时序的前提下减小面积 | 能省则省,但别牺牲性能 |
为什么会需要这些概念?因为综合工具不是万能的。你给它一个复杂的 RTL,它可能优化得不够好。这时候就需要你手动干预——比如调整综合策略、添加约束。
3.3 综合策略与脚本编写
综合策略说白了就是“怎么让工具听你的话”。我总结了三种常用策略,你在项目中可以根据需求选择。
- 面积优先策略: 适合低成本设计。工具会尽量用最小的门来实现功能,但时序可能变差。
- 时序优先策略: 适合高性能设计。工具会使用更快的门(但面积更大),确保满足时钟频率。
- 平衡策略: 在面积和时序之间取折中。我个人最常用这种,因为大多数项目不需要极致优化。
下面是一个完整的综合脚本示例。我习惯把脚本分成几个部分:读入、约束、综合、输出。
# ========== 综合脚本:synth.tcl ==========
# 1. 读入 RTL
read_verilog ./rtl/top.v
read_verilog ./rtl/alu.v
read_verilog ./rtl/ctrl.v
# 2. 设置顶层
synth -top top
# 3. 时序约束(手动设置时钟)
create_clock -name clk -period 10 [get_ports clk]
set_input_delay -clock clk 2 [all_inputs]
set_output_delay -clock clk 2 [all_outputs]
# 4. 综合策略:时序优先
# 使用 abc 命令进行逻辑优化
abc -liberty ./lib/sky130_fd_sc_hd__tt_025C_1v80.lib \
-constr ./constraints/clk_constraint.sdc
# 5. 输出网表和报告
write_verilog ./results/synth_netlist.v
write_sdf ./results/synth_delays.sdf
stat -liberty ./lib/sky130_fd_sc_hd__tt_025C_1v80.lib
避坑指南: 我曾经在综合时忘了设置时钟约束,结果 Yosys 默认把时钟周期设成了 1ns。流片回来后芯片根本跑不到那么快,只能降频使用。所以,时钟约束一定要写对!
3.4 综合后的检查
综合完不是就完事了。你得检查网表对不对、时序满不满足、有没有警告。我一般会做以下几步检查。
3.4.1 网表正确性检查
用 stat 命令查看综合结果。重点关注面积、门数、触发器数量。
# 在 Yosys 中查看统计信息
stat -liberty ./lib/sky130_fd_sc_hd__tt_025C_1v80.lib
# 输出示例:
# === Design statistics ===
# Number of wires: 1234
# Number of wire bits: 5678
# Number of public wires: 100
# Number of public wire bits: 500
# Number of cells: 200
# $_AND_ 50
# $_OR_ 30
# $_DFF_P_ 120
3.4.2 时序检查
综合后的时序报告能告诉你最差路径的延迟。如果 slack 是负数,说明时序不满足,需要优化。
# 生成时序报告
report_timing -max_paths 10
# 输出示例:
# Path 1: slack = -0.5 ns (VIOLATED)
# Startpoint: reg_a/Q
# Endpoint: reg_b/D
# Delay: 10.5 ns
# Required: 10.0 ns
检查清单:
- 网表里有没有未连接的引脚?
- 时钟网络有没有被优化掉?
- 所有触发器都有复位信号吗?
- 面积是否在预期范围内?
- 最差路径的 slack 是否为正?
3.4.3 常见问题与解决
我遇到过不少综合后的问题,这里列几个典型的。
| 问题 | 原因 | 解决方法 |
|---|---|---|
| 面积过大 | 综合策略太激进,用了太多大驱动单元 | 改用面积优先策略,或手动约束最大扇出 |
| 时序违例 | 关键路径太长,或者时钟约束太紧 | 优化 RTL 代码,或放宽时钟周期 |
| 网表有悬空引脚 | RTL 中某些信号未连接 | 检查 RTL,补全连接 |
| 综合报错 | 语法错误或库文件不匹配 | 检查 RTL 语法,确认库文件路径正确 |
我的习惯: 综合后我会用 show 命令查看电路图。虽然 Yosys 的图形界面比较简陋,但能直观看到逻辑结构,有时候能发现 RTL 里隐藏的问题。
3.5 综合流程知识图谱
下面这张图总结了综合的核心流程。你可以把它当作一个快速参考。
这张图把整个流程串起来了。你从 RTL 开始,经过 Yosys 综合、优化映射,最后得到网表。别忘了做综合后检查——这一步能帮你提前发现问题,避免后面布局布线时踩坑。
最后提醒: 综合后的网表不是最终版。你还要经过布局、时钟树综合、布线等步骤。但综合这一步如果没做好,后面再怎么优化也救不回来。所以,花时间把综合脚本写扎实,值!