3、设计输入:理解 LEF/DEF 格式。准备你的第一个设计文件。用 OpenROAD 读取设计。
好,我们正式开始动手了。前面两章我们把 OpenROAD 装好、跑通了 hello-world,但说实话,那只是个空壳子。真正的芯片设计,你得先搞清楚输入文件长什么样。
这一章,我们就来啃 LEF 和 DEF 这两个格式。别怕,它们没那么玄乎。说白了,LEF 是告诉你「库里有啥零件」,DEF 是告诉你「这些零件怎么摆、怎么连」。我当年刚入行时,对着这两个文件看了三天才搞明白谁是谁……嗯,今天争取让你三十分钟就理清楚。
3.1 LEF 和 DEF 到底在描述什么?
先打个比方。你要盖一栋楼:
- LEF(Library Exchange Format) —— 相当于建材目录。里面写着每种砖头、每根钢筋的尺寸、引脚位置、不能走线的区域( obstruction )。它不关心你这栋楼具体长啥样,只告诉你「我有这些标准件」。
- DEF(Design Exchange Format) —— 相当于施工图纸。它说:哪块砖放在哪个坐标,哪根线连到哪个引脚,电源网络怎么走。它不关心砖头内部长啥样,只关心位置和连接关系。
在 OpenROAD 流程里,这两兄弟缺一不可。LEF 提供物理库信息,DEF 提供设计实例化信息。你想想看,没有 LEF,工具不知道每个单元多大;没有 DEF,工具不知道你要放什么。所以第一步,就是让 OpenROAD 把这两个文件吃进去。
核心概念速记:
- LEF = 库视图(技术 + 宏单元)
- DEF = 设计视图(实例 + 连线 + 布局)
- OpenROAD 读 LEF 在前,读 DEF 在后
3.2 LEF 文件结构速览
LEF 文件分两大部分:技术 LEF 和 单元 LEF。技术 LEF 定义工艺信息,比如金属层数、最小线宽、通孔规则。单元 LEF 定义每个标准单元或宏单元的物理轮廓和引脚位置。
我截一段真实的 LEF 片段给你看,别被吓到,我们只关注关键字段:
MACRO AND2X1
CLASS CORE ;
ORIGIN 0 0 ;
SIZE 0.56 BY 2.72 ;
PIN A
DIRECTION INPUT ;
PORT
LAYER M1 ;
RECT 0.14 1.22 0.28 1.50 ;
END
END A
PIN Y
DIRECTION OUTPUT ;
PORT
LAYER M1 ;
RECT 0.28 1.22 0.42 1.50 ;
END
END Y
OBS
LAYER M1 ;
RECT 0 0 0.56 2.72 ;
END
END AND2X1
看到没?一个 AND2X1 单元,宽 0.56 微米,高 2.72 微米。两个引脚 A 和 Y,都在 M1 层上,坐标范围清清楚楚。OBS 区域告诉工具:这整个矩形内部,其他单元不能占用。
我在项目中遇到过最坑的事,就是某个第三方 IP 的 LEF 里 OBS 画错了,导致 APR 时工具死活绕不开那个区域。后来手动查 LEF 才发现,OBS 比实际芯片大了 10 倍……所以,拿到 LEF 后,我建议你先用文本编辑器扫一眼 OBS 和 PIN 的坐标,心里有个底。
3.3 DEF 文件结构速览
DEF 描述的是你的具体设计。它包含:
- DIEAREA —— 芯片的边界
- COMPONENTS —— 所有实例化的单元
- PINS —— 芯片的顶层端口
- NETS —— 互连关系
- SPECIALNETS —— 电源/地网络
一个简单的 DEF 片段长这样:
DESIGN top ;
UNITS DISTANCE MICRONS 1000 ;
DIEAREA ( 0 0 ) ( 100 100 ) ;
COMPONENTS 3 ;
- u1 AND2X1 + PLACED ( 10 20 ) N ;
- u2 INVX1 + PLACED ( 30 40 ) N ;
- u3 DFFX1 + PLACED ( 50 60 ) N ;
END COMPONENTS
PINS 2 ;
- clk + NET clk + DIRECTION INPUT + USE SIGNAL
+ LAYER M1 ( 0 0 ) ( 5 5 ) + PLACED ( 0 50 ) N ;
- out + NET out + DIRECTION OUTPUT + USE SIGNAL
+ LAYER M1 ( 0 0 ) ( 5 5 ) + PLACED ( 100 50 ) N ;
END PINS
NETS 3 ;
- net1 ( u1 Y ) ( u2 A ) ;
- net2 ( u2 Y ) ( u3 D ) ;
- net3 ( clk ) ( u3 CK ) ;
END NETS
END DESIGN
这个设计只有 3 个单元、2 个端口、3 条网线。当然真实设计不会这么简单,但结构一模一样。DEF 的 COMPONENTS 段里,+ PLACED 表示已经摆好了位置;如果是 + UNPLACED,那就是还没布局,等着工具去摆。
小技巧: 刚开始学的时候,你可以用 grep 命令快速统计 DEF 里的单元数量:grep -c "PLACED\|UNPLACED" your.design.def。这样一眼就知道设计规模有多大。
3.4 准备你的第一个设计文件
我们不用真实的大设计,那太复杂了。我准备了一个极简的「计数器」设计,只有 5 个标准单元。你跟着我做:
- 创建一个工作目录,比如
~/openroad_lab/ch03 - 下载或复制 Nangate 45nm 的 LEF 文件(技术 LEF + 单元 LEF)
- 用文本编辑器写一个简单的 DEF 文件,包含 5 个单元和它们的连线
这里我直接给你一个能用的 DEF 模板。你把它保存为 counter.def:
DESIGN counter ;
UNITS DISTANCE MICRONS 1000 ;
DIEAREA ( 0 0 ) ( 50 50 ) ;
COMPONENTS 5 ;
- u0 DFFX1 + UNPLACED ;
- u1 DFFX1 + UNPLACED ;
- u2 AND2X1 + UNPLACED ;
- u3 INVX1 + UNPLACED ;
- u4 BUFX2 + UNPLACED ;
END COMPONENTS
PINS 3 ;
- clk + NET clk + DIRECTION INPUT + USE SIGNAL
+ LAYER M1 ( 0 0 ) ( 2 2 ) + PLACED ( 0 25 ) N ;
- rst + NET rst + DIRECTION INPUT + USE SIGNAL
+ LAYER M1 ( 0 0 ) ( 2 2 ) + PLACED ( 0 30 ) N ;
- count_out + NET count_out + DIRECTION OUTPUT + USE SIGNAL
+ LAYER M1 ( 0 0 ) ( 2 2 ) + PLACED ( 50 25 ) N ;
END PINS
NETS 4 ;
- clk_net ( clk ) ( u0 CK ) ( u1 CK ) ;
- rst_net ( rst ) ( u0 R ) ( u1 R ) ;
- q0_to_d1 ( u0 Q ) ( u1 D ) ;
- count_net ( u1 Q ) ( u2 A ) ( u3 A ) ( u4 A ) ;
END NETS
END DESIGN
注意,这里所有单元都是 UNPLACED,因为我们还没做布局。端口 clk 和 rst 放在了芯片左边界,count_out 放在右边界。网表连接也很简单:两个 DFF 级联,输出经过一些组合逻辑到端口。
警告: 你的 LEF 文件里必须有 DFFX1、AND2X1、INVX1、BUFX2 这四个单元的定义,否则 OpenROAD 读 DEF 时会报错说找不到单元。我建议你直接用 Nangate 45nm 的开放库,它包含这些基本单元。
3.5 用 OpenROAD 读取设计
文件准备好了,现在让 OpenROAD 把它们读进来。启动 OpenROAD 后,在 Tcl 命令行里依次执行:
# 第一步:读入技术 LEF(工艺信息)
read_lef /path/to/Nangate45/NangateOpenCellLibrary.lef
# 第二步:读入单元 LEF(标准单元物理信息)
# 注意:如果技术 LEF 和单元 LEF 是分开的,需要分别读
# 这里假设它们已经合并到一个文件里了
# 第三步:读入 DEF 设计文件
read_def counter.def
# 第四步:检查读入结果
report_components
report_nets
report_pins
如果一切顺利,你会看到类似这样的输出:
Components: 5
u0 (DFFX1)
u1 (DFFX1)
u2 (AND2X1)
u3 (INVX1)
u4 (BUFX2)
Nets: 4
clk_net (3 pins)
rst_net (3 pins)
q0_to_d1 (2 pins)
count_net (4 pins)
Pins: 3
clk (INPUT)
rst (INPUT)
count_out (OUTPUT)
看到这个,就说明你的设计已经被 OpenROAD 成功加载了。所有单元、网线、端口都在内存里了,随时可以开始布局布线。
我记得第一次成功读入自己的 DEF 时,那种感觉就像……嗯,就像你拼好了一个乐高模型的第一个零件。虽然还只是个骨架,但至少证明你的「图纸」没画错。
3.6 常见问题与避坑
读文件时最容易遇到这几个问题,我帮你列出来:
| 错误信息 | 原因 | 解决办法 |
|---|---|---|
Can't find macro 'XXX' |
DEF 里引用了 LEF 中没有的单元 | 检查 LEF 文件是否包含该宏单元,或 DEF 里单元名拼写是否正确 |
LEF pin layer not found |
DEF 中引用的金属层在 LEF 技术文件中未定义 | 确保技术 LEF 包含了所有用到的金属层定义 |
DEF units mismatch |
DEF 和 LEF 的单位不一致 | 检查 DEF 头部 UNITS DISTANCE MICRONS 的值,通常为 1000 或 2000 |
Read DEF failed: syntax error |
DEF 文件格式有误,比如少写了分号或括号不匹配 | 用文本编辑器检查 DEF 语法,特别注意 END 和分号 |
我的习惯: 每次写 DEF 后,我都会先用 defcheck 工具(OpenROAD 自带)做一次语法检查:defcheck counter.def。它能帮你提前发现 90% 的格式问题,省得在 OpenROAD 里报错再回头改。
3.7 本章知识结构图
下面这张图帮你把 LEF、DEF 和 OpenROAD 的关系理清楚:
从这张图可以看得很清楚:LEF 提供「零件手册」,DEF 提供「装配图」,OpenROAD 把两者合并后,你的设计才真正在工具里「活」起来。后续的 floorplan、placement、routing,全都建立在这个基础上。
3.8 本章小结
这一章我们做了三件事:
- 理解了 LEF 和 DEF 各自描述什么,以及它们的关系
- 亲手写了一个极简的 DEF 文件,包含 5 个单元和 4 条网线
- 用 OpenROAD 的
read_lef和read_def命令成功加载了设计
说实话,LEF/DEF 的细节远不止这些,但作为入门,你掌握到这个程度已经够了。后面几章我们会在这个小设计上一步步做布局、布线、时序分析。到时候你会发现,今天花时间搞懂这两个格式,值。