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 脚本来调用它。我刚开始用的时候也困惑过——到底怎么把这两个工具串起来?其实很简单。

核心集成流程:

  1. OpenROAD 启动后,加载设计文件(Verilog RTL)
  2. 调用 yosys 命令,执行综合脚本
  3. Yosys 输出门级网表(.v 格式)
  4. 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 综合引擎 逻辑优化 + 技术映射 门级网表输出 综合后检查(时序/面积/网表) 关键输入 Verilog RTL 标准单元库 (.lib) 时序约束 (.sdc) 关键输出 门级网表 (.v) SDF 延迟文件 综合报告

这张图把整个流程串起来了。你从 RTL 开始,经过 Yosys 综合、优化映射,最后得到网表。别忘了做综合后检查——这一步能帮你提前发现问题,避免后面布局布线时踩坑。

最后提醒: 综合后的网表不是最终版。你还要经过布局、时钟树综合、布线等步骤。但综合这一步如果没做好,后面再怎么优化也救不回来。所以,花时间把综合脚本写扎实,值!