☰
LEF/DEF物理设计文件解析:从5.8手册语法到自动检查脚本
2026/10/14 1:46:12 网站建设 项目流程

简介:LEF/DEF 5.8语言参考是Cadence官方发布的EDA领域重要规范文档,面向数字IC后端设计工程师、物理验证人员和EDA工具开发者。文档系统阐述了LEF(库交换格式)与DEF(设计交换格式)的定义,前者覆盖工艺技术层定义、单元模型、间距规则及宏模型,后者描述模块布局、网络连接、约束设置与物理分区,帮助读者建立从工艺库到物理实现的数据交互体系。资源包以单个PDF文件形式提供,大小仅2.48MB,便于离线查阅;内容包含Preface、What’s New等章节,完整呈现LEF/DEF 5.8语法结构及2017年5月产品版本特性,并附有版权与权限说明,适合个人学习参考。已有2171人学习该文档,是数字IC物理设计入门与进阶的重要参考资料;除了掌握语法规则外,读者还能结合设计流程理解EDA工具链中数据交换的关键细节,为布局规划、布线验证等环节提供扎实理论支撑。

1. 一本 PDF 手册解决了物理设计里的什么“翻译”问题

lefdefref-5.8.pdf 是很多后端工程师桌面上躺着却很少被翻开的参考文档。它定义的是 LEF 与 DEF 这两种物理设计交换格式的完整语法:一个是库交换格式,描述工艺层、标准单元几何与 Pin;一个是设计交换格式,描述一颗芯片里实例怎么摆放、网络怎么连接。当一个 LEF 里的 pin 坐标始终跟版图对不上,或者 DEF 里的 net 少了一条线,翻手册比开 GUI 更快定位根因。这篇笔记面向要读懂、编写、校验 LEF/DEF 文件的从业者,把 5.8 版里最常用的对象、语法和踩坑点串一遍。新手可以照着示例文件把最小单元跑通,熟手可以直接跳到后面几节的边界参数和排查记录。

2. LEF 和 DEF 的分工,以及 5.8 手册怎么组织这些内容

2.1 LEF 管“长什么样”,DEF 管“摆在哪”

LEF 是 Library Exchange Format 的缩写,它描述的是工艺库和单元库的物理属性。一个 LEF 文件里会看到 LAYER、SITE、MACRO、PIN、OBS、VIA 这些关键字。以 LAYER 为例,里面定义了金属层的名字、类型(ROUTING 还是 CUT)、布线方向(HORIZONTAL / VERTICAL)、最小宽度、间距、Pitch。这些参数不是摆设,后续布线器能走几条线、过孔怎么阵列,全由它们决定。如果 LEF 里的 spacing 比真实工艺大,工具会在密度不高的地方也绕远,无端增加面积。

DEF 是 Design Exchange Format,它记录某个具体设计实例的状态。DIEAREA 给出芯片整体边界,COMPONENT 列出每个子模块或标准单元放在哪个坐标、什么朝向,NET 记录各 Pin 之间的连接关系,ROUTING 则存放已经走好的线段。可以这么理解:LEF 是“零件目录”,DEF 是“装配说明书”。同一个 LEF 可以服务几十个 DEF,因为库属性是共用的;换一颗芯片只是换一个新 DEF。

我在实际调试时,经常遇到布局文件里某个单元位置和 LEF 的 SITE 不匹配。这时候我会同时打开两份文件:DEF 里查 component 的放置坐标与方向,LEF 里查这个 macro 的 ORIGIN 和 SIZE,两边的坐标系都以 DIEAREA 左下角为原点。大多数错位问题都出在坐标基准不一致,这个后面会细说。

2.2 5.8 手册里最值得先读的四个章节

拿到 lefdefref-5.8.pdf 这样的参考手册,不建议从头当小说看。常见的手册结构会把语法说明、关键字约定和每种对象的完整定义分成几个大块。我一般会先读四部分:语法表示法、单位与精度、LEF 的 MACRO 定义、DEF 的 COMPONENT 与 NET。语法表示法说明如何看那些带尖括号和问号的“公式”,比如pin <name> [layer ...]。单位与精度部分决定了你写的数字是纳米还是微米,是 1000 倍误差还是 1 倍误差。

MACRO 定义是我翻得最勤的一段,因为标准单元或 IP 的形状、Pin 位置、禁止布线区全在这里。手册里会给出每个语句的允许范围,比如CLASS CORE还是CLASS BLOCK,哪些语句可选,哪些必须出现。同样,DEF 的 COMPONENT 章节会写清楚component语句怎么与 LEF 里的 macro 名称关联,以及PLACED与FIXED状态的差别。很多新人会在 COMPONENT 里把PLACED和FIXED混写,导致后续布线时工具把固定单元移走。

最后必须看示例样例。5.8 版手册里通常附有简化的 LEF 和 DEF 完整文件,哪怕只有几十行,也比一段段孤立语法更容易理解对象间引用。我的习惯是把样例文件保存下来,先跑通解析,再一点点改成自己项目的格式,出了问题能确定是“改坏的地方”还是“原来就不支持”。

2.3 手册中反复出现的 BNF 式语法,怎么读

在我常用的 5.8 版手册里,每种对象的定义都会用类似 BNF 的形式给出。比如 MACRO 的定义里会出现MACRO macroName [CLASS ...] [ORIGIN ...] [SIZE ...] ;。读这种语法时,方括号代表可选,竖线代表“或”,省略号代表可重复。我第一次读时习惯在关键词之间画连线,把可选项展开,形成一棵“语法树”。这样写自定义脚本时,能清楚知道每一行从哪里开始、到哪里结束。

还有一个容易被忽略的点:手册里所有语句末尾的分号是语法的一部分,不是排版装饰。我见过很多手写 LEF 的人漏掉分号,导致整段解析失败,报错指向下一行。所以读语法规则时,我会特意把分号也当成 token。另外,注释符号在 LEF/DEF 里是#,整行注释,不支持行内注释。如果你想在一段描述后面加说明,只能在下一行从#开始。这些细节在手册的“Notation”部分都会写,但一般人都跳过了。

3. 照着 5.8 手册写一个最小 LEF:关键语法与参数怎么定

3.1 LAYER / SITE / MACRO 三段式

先给一个能通过解析器检查的最小 LEF 文件。这个文件定义了一个 M1 金属层、一个 CORE 放置单元和一个 inverter 宏单元,共三个部分。实际工艺库里会有几十层金属和上百个 macro,但语法骨架是一样的。

VERSION 5.8 ; BUSBITCHARS "[]" ; DIVIDERCHAR "/" ; MANUFACTURINGGRID 0.001 ; UNITS DATABASE MICRONS 1000 ; END UNITS LAYER M1 TYPE ROUTING ; DIRECTION HORIZONTAL ; PITCH 0.14 ; WIDTH 0.07 ; SPACING 0.07 ; END M1 SITE CORE SIZE 0.56 BY 1.26 ; END CORE MACRO INV CLASS CORE ; ORIGIN 0 0 ; SIZE 0.56 BY 1.26 ; SITE CORE ; PIN A DIRECTION INPUT ; PORT LAYER M1 ; RECT 0.01 0.50 0.10 0.76 ; END END A PIN Y DIRECTION OUTPUT ; PORT LAYER M1 ; RECT 0.30 0.30 0.40 0.56 ; END END Y OBS LAYER M1 ; RECT 0.10 0.76 0.56 1.26 ; END END INV END LIBRARY

逻辑说明:文件头部的VERSION 5.8表示这份 LEF 文件遵循 5.8 语法版本,它和参考手册版本号正好对应。MANUFACTURINGGRID 0.001声明工艺制造网格为 1 纳米,所有坐标必须落在这个网格上。UNITS DATABASE MICRONS 1000表示一个数据单位等于千分之一微米,也就是说“微米数值 × 1000”才是文件里的整数,但我在示例里直接写小数是为了阅读方便,真实工具通常接受两位小数并自动换算。

参数说明:LAYER 中TYPE ROUTING表示这是布线层,DIRECTION HORIZONTAL告诉布线器该层首选水平走线,这会影响绕线策略。PITCH是相邻走线中心到中心的距离,决定该层能塞多少条线。WIDTH和SPACING是最小线宽与最小间距。SITE 里的SIZE 0.56 BY 1.26是行高和单元宽度方向的基础网格,DEF 里建立 ROW 时会引用这个名字。

MACRO 的CLASS CORE告诉工具这是可自动放置的标准单元,而不是硬核或块。ORIGIN 0 0定义宏在单元格子里的坐标原点,SIZE必须与 SITE 的倍数关系一致,否则工具会认为该单元不能放进这一行。这里的 INV 宽度是 0.56,正好等于一个 SITE 宽度,高度等于行高,所以它只占一个 site 格。

3.2 PIN 和 OBS 的边界条件

PIN 是工具连接单元的关键。在 INV 中我写了两个 pin:A 是输入,Y 是输出。每个 pin 的DIRECTION声明信号流向,PORT内给出物理金属图形,可以是一个或多个LAYER配合多个RECT。如果 pin 分布在两层金属上,需要写多个 LAYER 块。注意每个PORT必须完整闭合END,而 PIN 本身也要闭合END A。少一个 END 都会导致解析错乱,且报错行未必是缺 END 的那一行。

OBS 是 Obstruction 的缩写,表示单元内部禁止布线器走线或放置过孔的区域。这个区域通常是单元里的扩散区、内部金属或电源走线。在示例里我把 OBS 放在从 x=0.10 到 0.56 的上半部分,覆盖了 Y pin 的右侧。如果 OBS 和某个 PIN 的 PORT 重叠,工具会认为该 pin 无法接入,或者接入后引起短路,于是最终网表里这个连接会被绕到很远的地方,时序反而恶化。

所以写 PIN 和 OBS 时,我的习惯是先画一张单元俯视图,把每个 RECT 的坐标点标在纸上,再用布尔运算确认 PIND 和 OBS 交集为空。这个动作虽然原始,但比在 GUI 里放大几十倍查坐标更快。手册里对 OBS 的定义同样遵循“层名 + 多个 RECT”的结构,而且 RECT 必须落在 MACRO 的 SIZE 范围内,越界语句会直接报错。

另外,SITE名字必须和 DEF 中的行列定义一致。如果 LEF 里叫 CORE,而 DEF 里写ROW r0 CORE_X,工具会提示找不到 site。这类命名一致性是 LEF/DEF 联调的常见问题,我会在写文件前把命名清单统一检查一遍,比如用grep提取所有 SITE 和 ROW 的第二个 token 排序对比。

4. 用 DEF 描述一次布局布线结果:手动解析并验证

4.1 DIEAREA / COMPONENT / NET 三个核心对象

DEF 是结果文件,它的语法比 LEF 更强调“实例”的概念。下面这段 DEF 描述了一个 4 个 INV 组成的简单设计:芯片边界是 4.2 微米见方,一行 CORE 行,四个单元分别摆在不同方向,三个网络把它们连接起来。

VERSION 5.8 ; DIVIDERCHAR "/" ; BUSBITCHARS "[]" ; UNITS DATABASE MICRONS 1000 ; END UNITS DIEAREA ( 0 0 ) ( 4.20 4.20 ) ; ROW CORE_ROW_1 CORE 0 0 N DO 7 BY 1 STEP 0.56 0 ; COMPONENTS 4 ; - U1 INV + PLACED ( 0.00 0.00 ) N ; - U2 INV + PLACED ( 0.56 0.00 ) FN ; - U3 INV + PLACED ( 1.12 0.00 ) S ; - U4 INV + PLACED ( 0.00 1.26 ) N ; END COMPONENTS PINS 2 ; - IN1 + NET in + DIRECTION INPUT + LAYER M1 ( 0.01 0.50 ) ( 0.10 0.76 ) + PLACED ( 0.00 0.00 ) N ; - OUT1 + NET out + DIRECTION OUTPUT + LAYER M1 ( 0.30 0.30 ) ( 0.40 0.56 ) + PLACED ( 0.00 0.00 ) N ; END PINS NETS 3 ; - in ( IN1 A ) ( U1 A ) ; - n1 ( U1 Y ) ( U2 A ) ( U3 A ) ; - out ( U4 Y ) ( OUT1 ) ; END NETS END DESIGN

逻辑说明:DIEAREA给出两个对角坐标,定义了芯片的物理边界,所有 component 的坐标必须落在这个矩形内。ROW定义了一条名为 CORE_ROW_1 的行,它引用 LEF 里的 CORE site,原点在 (0,0),方向为 N,DO 7 BY 1 STEP 0.56 0表示沿 X 方向重复 7 次,每次步进 0.56 微米。这决定了单元可以放在哪些 x 位置上。

COMPONENTS部分每行以-开头,后面是实例名 U1、宏名 INV,+ PLACED表示已放置,坐标是相对于 DIEAREA 原点的位置,最后的方向标识 N、FN、S 表示四种旋转状态:N 是 0 度,FN 是垂直翻转,S 是旋转 180 度。这些方向定义手册里有专门一张表,我不建议死记,用到时翻表即可。

NETS是连接关系表。括号里第一个 token 如果是只有一个名字,比如( IN1 A ),它指芯片引脚 IN1 的 A 端口;如果是两个名字( U1 Y ),指实例 U1 的 Y pin。这里in网络把芯片输入 IN1 和 U1 的 A 连在一起。注意 net 名不能与关键字符冲突,而且每个括号对与上一行之间可以用分号结束。

4.2 一致性检查:DEF 里 component 对应哪个 LEF macro

DEF 文件本身不包含单元内部几何,它只是引用了 LEF 中的 macro 名。所以验证 DEF 的第一步,是看每个 component 的第二个 token 是否都能在 LEF 文件中找到同名 MACRO。如果 DEF 里写的是INV,而 LEF 中只有INV_X1,解析器会直接在加载 DEF 时报出 “component type INV not found” 之类的错误。

手动比对时,我常用的命令是分别从两个文件里提取名字:

grep -hi "^MACRO" design.lef | awk '{print $2}' | sort -u > lef_macros.txt grep -hi "^-" design.def | awk '{print $3}' | sort -u > def_macros.txt diff lef_macros.txt def_macros.txt

这个脚本把 LEF 里的 MACRO 名字和 DEF 里 component 引用的类型名分别排序,然后 diff。输出中出现在 def_macros.txt 而不在 lef_macros.txt 里的,就是引用缺失。注意grep -hi的-h是不显示文件名,-i忽略大小写;但真实 LEF/DEF 关键字是严格大小写敏感的,这里忽略大小写只是为了快速发现拼写差异,确认后要回头用区分大小写的方式修。

一致性检查和坐标检查要一起做。比如 DEF 中 U2 放在 (0.56, 0.00) 方向 FN,但 INV 的 ORIGIN 是 (0,0),SIZE 是 0.56×1.26,那么 U2 的实际占位范围是 x 从 0.56 到 1.12,y 从 0 到 1.26,没有越界。如果改成方向 S,占位矩形会基于原点旋转,但 x 宽度不变,仍然要验证四个角落在 DIEAREA 内。我一般会把这类检查写成脚本,把每个 component 的占位矩形与 DIEAREA 做相交判断,一旦越界就按实例名打印出来。

5. 读 5.8 手册的常见问题排查:四处分分钟翻车

5.1 版本不一致:旧工具吞掉 5.8 新语法

现象:用 5.8 语法写的 LEF 放进某老版本后端工具里加载,工具不报错,但文件里某些语句被静默忽略,导致生成的版图缺层或缺 pin。

原因:旧工具对不认识的语法采取“读到就跳过”的策略,它只解析自己版本支持的子集。比如 5.8 中某些层属性或过孔扩展项,旧版本不识别就直接略过,看起来文件加载成功,实际信息已经丢了。

解决:在写文件头部强制声明VERSION 5.8 ;,然后在验证阶段用工具本身的 dump 功能把读到的 LEF 再写出来,对比原始文件,凡是丢掉的语句逐个查手册确认是“工具不支持”还是“我写错”。最省事的做法是找一台装有 5.8 配套工具的机器做解析,不要拿老版本碰新格式。

5.2 单位换算:MANUFACTURINGGRID 和 DATABASE MICRONS 的精度

现象:DEF 里 pin 的坐标与 LEF 中 macro 的 pin 坐标明明一样,但在 GUI 里显示偏离了几十个纳米。

原因:两边的MANUFACTURINGGRID不一致,或者DATABASE MICRONS的换算系数不同。LEF 里写DATABASE MICRONS 1000,DEF 里也写 1000,但它们各自配合的 MANUFACTURINGGRID 一个 0.001 一个 0.005,那么实际允许的坐标网格不同,四舍五入后产生偏差。

解决:检查两份文件头部的UNITS和MANUFACTURINGGRID,保证完全一致。我通常将所有坐标写成该 grid 的整数倍,例如 grid=0.001 时,所有 x/y 的小数位数不超过 3 位。调试脚本里也加入一个取模检查,如果坐标不在 grid 整数倍上,直接警告。

5.3 大小写敏感:缺一个 END 或错一个字母

现象:手写 LEF 时把END A写成END a,解析器直接报 unexpected keyword,甚至把后续几十行都当成一个对象。

原因:LEF/DEF 的关键字和对象名都是大小写敏感的,END A里的 A 必须与PIN A里的 A 完全一样。而end、END这样的关键字也严格区分。很多人从文本直接复制,引号变成全角,或分号用成中文分号,也会触发类似问题。

解决:写完后先运行文本格式检查,确保所有引号、分号都是半角。再用sed -n提取每个PIN到END的缩进层次,人工核对闭合关系。我自己的写法是每个 PIN 开头和结尾都顶格写PIN和END A,中间 PORT 缩进一层,这样错位一眼能看到。

5.4 OBS 与 PIN 重叠:连接永远拉不出来

现象:布线时某条 net 明明连接了两端,但生成的版图上该 pin 处没有过孔,芯片验证时该 net 开路。

原因:LEF 里 OBS 覆盖了 PIN 的 PORT 区域。布线器在避让 OBS 时认为 pin 不可用,于是连接从外部绕,但最终没有可接入点,只能丢弃连接。GUI 里检查时 net 显示为 dangling。

解决:写单元时把所有 PIN 的 RECT 坐标收集到一个列表,再把所有 OBS RECT 收集起来,做矩形相交判断。相交面积超过 0 就重新画。我通常在 LEF 文件最末尾放一组注释,记录每个 pin 和 obs 的边界坐标,方便日后复查。这个校验逻辑也可以直接写进自动检查脚本,见下一章。

6. 把手册变成自动化检查工具:一个解析 LEF/DEF 的脚本思路

与其每次手工去 diff,不如做一个最简单的 Python 脚本,用正则把 LEF 里的 MACRO 定义提取出来,把 DEF 里的 COMPONENT 引用提取出来,做映射检查。这个脚本不依赖任何第三方库,纯标准库就能跑,适合放在项目根目录当作预检查工具。

import re def get_macros_from_lef(path): macros = {} with open(path, 'r', encoding='utf-8') as f: text = f.read() for m in re.finditer(r'MACRO\s+(\S+)(.*?)(?=END\s+\1\s*;|MACRO\s)', text, re.S): macros[m.group(1)] = m.group(2) return macros def get_components_from_def(path): comps = [] with open(path, 'r', encoding='utf-8') as f: lines = f.readlines() inside = False for line in lines: stripped = line.strip() if stripped.startswith('COMPONENTS'): inside = True continue if inside and stripped.startswith('END COMPONENTS'): break if inside and stripped.startswith('- '): parts = stripped.split() comps.append((parts[1], parts[2])) return comps def check_def_lef_lef(def_path, lef_path): macros = get_macros_from_lef(lef_path) comps = get_components_from_def(def_path) missing = [c for c in comps if c[1] not in macros] if missing: for inst, mtype in missing: print(f"[MISSING] DEF instance {inst} references macro {mtype} not in LEF") else: print("All components have matching macro definitions.") check_def_lef_lef('design.def', 'design.lef')

逻辑说明:get_macros_from_lef用正则把MACRO 名字到END 名字之间的文本作为一个对象提取,保存到字典。这里用非贪婪匹配和正向预查保证不会跨 macro 截断。get_components_from_def只关心COMPONENTS段到END COMPONENTS之间那一行行以-开头的记录,取出实例名和宏名。

参数说明:正则里的\.\*?必须配合re.S使用,否则无法跨行匹配;(?=END\s+\1\s*;|MACRO\s)是零宽断言,代表“主体文本后面要跟 END 或下一个 MACRO”。如果你希望同时检查 PIN 与 OBS 重叠,可以继续扩展get_macros_from_lef返回的信息,把每个 PIN 内所有 PORT 的 LAYER/RECT 解析出来,再与 OBS 的 RECT 做矩形相交判断。

我每次改完 LEF 或 DEF,都会把这个脚本放在根目录跑一遍,低成本挡住 80% 的低级错误。剩下的 20% 才是真正需要开 GUI 或对照手册逐条理解的问题。希望这份基于 5.8 版手册的实操思路帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询