3. 设计输入与准备:RTL 设计文件、Liberty 库文件、LEF/DEF 文件、SDC 约束文件,构建项目目录结构

好了,咱们正式开始动手。在做任何后端工作之前,有一件事必须搞定——设计输入文件的准备与项目目录的搭建。

这步看着简单,但我见过太多新手甚至老手在这上面翻车。文件放错位置、库版本不对、约束文件缺胳膊少腿……等到跑流程到一半报错,回头排查才发现是输入文件的问题,那叫一个痛苦。

我个人习惯,在项目启动的第一天,先把目录结构搭好,把所有输入文件归位。这就像做饭前先把菜洗好切好,后面炒起来才顺手。

3.1 我们需要哪些输入文件?

OpenROAD 的输入,说白了就是五样东西。我列个表,你对照着准备:

文件类型 扩展名 作用 来源
RTL 设计文件 .v / .sv 描述电路功能逻辑 前端设计团队
Liberty 库文件 .lib 标准单元时序与功耗信息 工艺厂商 / PDK
LEF 文件 .lef 标准单元物理尺寸与引脚位置 工艺厂商 / PDK
DEF 文件 .def 初始布局或顶层互连信息 前端 / 顶层集成
SDC 约束文件 .sdc 时序、面积、功耗约束 前端设计团队
小提示: 我建议你拿到文件后,第一时间用 file 命令或文本编辑器打开看一眼。有时候前端给过来的 .v 文件其实是加密过的,或者 .lib 文件是旧版本的。看一眼,省得后面白跑。

3.2 RTL 设计文件

RTL 文件是芯片的「源代码」。OpenROAD 支持 Verilog 和 SystemVerilog。这里有个坑——OpenROAD 的 Yosys 综合器对 SystemVerilog 的支持有限。如果你用了复杂的 SV 语法(比如 interface、class),可能会报错。

我曾经接手过一个项目,前端给了满篇的 SV 语法,结果 Yosys 直接罢工。最后只能让前端把 RTL 改成纯 Verilog-2001 可综合子集。所以,保险起见,建议用 Verilog-2001 风格。

文件组织上,我习惯把所有 RTL 源文件放在 rtl/ 目录下,并维护一个 filelist.f 文件,列出所有源文件的路径。这样在综合时直接引用 filelist 就行,不用在命令行里写一长串。

# rtl/filelist.f 示例
./rtl/top.v
./rtl/cpu/core.v
./rtl/cpu/alu.v
./rtl/mem/ram.v
./rtl/mem/rom.v
./rtl/periph/uart.v
./rtl/periph/spi.v

3.3 Liberty 库文件

Liberty 文件(.lib)是标准单元的「时序身份证」。里面记录了每个单元的延迟、功耗、建立时间、保持时间等参数。OpenROAD 在综合和时序分析时都要用到它。

这里要注意:Liberty 文件有不同的工作条件版本。通常工艺厂商会提供多个 corner 的 .lib 文件:

  • 典型条件(typical):用于常规分析
  • 最差条件(worst):用于 setup 检查
  • 最好条件(best):用于 hold 检查

我个人习惯,在项目目录下建一个 lib/ 文件夹,里面按 corner 再分子目录:

lib/
├── typical/
│   └── sky130_fd_sc_hd__tt_025C_1v80.lib
├── worst/
│   └── sky130_fd_sc_hd__ss_100C_1v60.lib
└── best/
    └── sky130_fd_sc_hd__ff_125C_1v95.lib
注意: 有些工艺厂商提供的 .lib 文件是压缩包(.lib.gz),OpenROAD 可以直接读取 gz 格式,不需要解压。但如果你要手动查看内容,记得先解压。

3.4 LEF 与 DEF 文件

LEF 文件描述的是标准单元的物理信息——每个单元占多大面积、引脚在什么位置、有哪些布线阻挡层。DEF 文件则描述的是芯片的布局信息——单元放在哪里、模块之间的连接关系。

对于 OpenROAD 流程:

  • LEF 文件:综合和布局布线阶段都需要。通常包含技术 LEF(描述金属层、通孔规则)和单元 LEF(描述标准单元)。
  • DEF 文件:如果你是从前端拿到一个初始布局,或者要做顶层集成,就需要读入 DEF。如果是纯平摊设计,可以从零开始,不需要初始 DEF。

我建议把 LEF 文件放在 lef/ 目录,DEF 文件放在 def/ 目录。如果项目有多个 DEF 版本(比如 floorplan 阶段、placement 阶段),可以加时间戳或版本号区分。

lef/
├── sky130_fd_sc_hd__tech.lef
└── sky130_fd_sc_hd__cells.lef

def/
├── top_floorplan_v1.def
└── top_floorplan_v2.def

3.5 SDC 约束文件

SDC 文件是后端流程的「指挥棒」。它告诉工具:时钟频率是多少、哪些路径是假的、哪些信号需要特别处理。

一个典型的 SDC 文件长这样:

# 创建时钟
create_clock -name clk -period 10.0 [get_ports clk]

# 设置输入延迟
set_input_delay -clock clk -max 2.0 [get_ports data_in]
set_input_delay -clock clk -min 1.0 [get_ports data_in]

# 设置输出延迟
set_output_delay -clock clk -max 3.0 [get_ports data_out]
set_output_delay -clock clk -min 1.5 [get_ports data_out]

# 设置伪路径
set_false_path -from [get_clocks rst_n]

# 设置最大扇出
set_max_fanout 20 [current_design]

这里有个经验:SDC 文件的质量直接决定后端流程的成败。我见过太多项目因为 SDC 里漏了某个时钟约束,导致综合出来的网表时序完全不对。

避坑指南: 拿到 SDC 后,先用 read_sdc 命令加载,然后用 report_checks 看看工具是否成功解析了所有约束。我曾经遇到过一个 SDC 文件里用了 get_pins 但实际设计中根本没有那个 pin 名,结果工具默默忽略了这个约束,导致后面时序分析全错。

3.6 构建项目目录结构

好了,文件都介绍完了。现在咱们来搭目录结构。我有一套自己用了多年的模板,分享给你:

project_name/
├── rtl/                    # RTL 源文件
│   ├── filelist.f          # 文件列表
│   ├── top.v
│   ├── cpu/
│   └── mem/
├── lib/                    # Liberty 库文件
│   ├── typical/
│   ├── worst/
│   └── best/
├── lef/                    # LEF 文件
├── def/                    # DEF 文件
├── sdc/                    # SDC 约束文件
│   └── top.sdc
├── scripts/                # Tcl 脚本
│   ├── synth.tcl
│   ├── floorplan.tcl
│   ├── place.tcl
│   ├── cts.tcl
│   ├── route.tcl
│   └── sta.tcl
├── output/                 # 输出文件
│   ├── netlist/
│   ├── layout/
│   └── reports/
└── README.md               # 项目说明

这个结构的好处是:

  • 输入输出分离:源文件在 rtl/、lib/ 等目录,生成的文件在 output/,不会混在一起
  • 脚本独立:所有 Tcl 脚本放在 scripts/,方便管理和版本控制
  • 层次清晰:每个阶段都有对应的脚本,想重跑哪一步直接执行对应的 .tcl 文件
我的习惯: 在项目根目录放一个 Makefile,把每个步骤封装成 make target。比如 make synth 执行综合,make place 执行布局。这样团队里其他人也能快速上手。

3.7 知识结构总览

下面这张图总结了本章的核心内容——设计输入文件的类型、作用以及它们在 OpenROAD 流程中的位置:

OpenROAD 设计输入文件体系 设计输入文件 RTL 文件 (.v / .sv) Liberty 库 (.lib) LEF 文件 (.lef) DEF 文件 (.def) SDC 约束 (.sdc) 各文件在流程中的角色: • RTL → Yosys 综合,生成门级网表 • Liberty → OpenSTA 时序分析,OpenROAD 优化 • LEF/DEF → 布局布线阶段,定义物理尺寸与位置 • SDC → 贯穿全流程,指导综合、布局、布线、时序优化 推荐项目目录结构: project/ ├── rtl/ # RTL 源文件 + filelist.f ├── lib/ # Liberty 库(按 corner 分目录) ├── lef/ + def/ # 物理库与布局文件 ├── sdc/ + scripts/ + output/ + README.md

3.8 文件准备检查清单

最后,我整理了一份检查清单。每次开始新项目,我都会对着这个清单过一遍:

  1. RTL 文件:是否所有模块都在?是否有语法错误?(用 verilator --lint-only 快速检查)
  2. Liberty 文件:corner 是否齐全?版本是否与 LEF 匹配?
  3. LEF 文件:技术 LEF 和单元 LEF 是否都有?是否有缺失的 macro?
  4. DEF 文件(如果有):坐标是否合理?是否有重叠的单元?
  5. SDC 文件:时钟定义是否完整?是否有未定义的端口?
  6. 目录结构:是否按规范搭建?脚本路径是否与目录一致?
血的教训: 我曾经因为 .lib 文件和 .lef 文件版本不匹配(一个来自 PDK v1.0,一个来自 PDK v1.1),导致标准单元的时序和物理信息对不上,布局布线后出现大量 DRC 违例。最后花了整整两天排查。所以,所有文件必须来自同一套 PDK 版本,这是铁律。

好了,输入文件准备就绪,目录结构也搭好了。下一步,咱们就可以开始真正的 OpenROAD 流程了——从综合开始,一步步把 RTL 变成 GDSII。