简介:《LEF/DEF 5.8 语言参考》是Cadence于2017年发布的官方英文技术手册,面向集成电路设计工程师、版图设计人员及EDA工具链使用者,系统讲解LEF与DEF两种IC描述语言的语法规则与设计用途,解决工艺库定义、网表交换与物理实现中的格式一致性问题。手册对LEF的工艺层定义、单元几何模型、间距规则、填充与隔离区域、宏模型等要素做了完整说明,涵盖金属层、多晶硅层及接触层的电气属性,并介绍填充单元与隔离区域如何优化布局热性能和电磁兼容性;对DEF的模块布局、网络连线、约束设置、物理分区、物理属性等内容也逐一展开,重点说明DRC、LVS、ERC约束以及电源域、时钟区域、过孔等对象的设计信息,可为物理综合、布局规划、验证及流片前分析提供直接参考。这份PDF文件为Cadence原始发行版,共1个文件,大小2.48MB,便于按需查阅不同章节。目前已有2171人学习下载。阅读后,读者能系统理解LEF/DEF 5.8的命令结构、对象属性与设计规则写法,并领会增强约束管理、更精确物理描述等特性,在实际项目中规范使用标准交换格式,减少跨工具数据错误。对于初学者,它能帮助建立对标准格式的整体认知;对于资深工程师,则适合作为日常查证的参考。
1. lefdefref-5.8 到底是什么:一份让物理设计不再“黑匣子”的文本规格
在物理设计流程里,LEF/DEF 参考手册 5.8 往往是那个被扔在工具安装目录深处、不到万不得已不会翻开的 PDF。可一旦工艺库更新、绕线结果异常、或者自写脚本解析版图数据出错,最先被怀疑的总是 LEF 和 DEF 文件本身。LEF 描述库单元的几何形状、引脚和布线阻挡,DEF 描述摆放结果和连线关系,两者合起来才构成一次完整物理实现的文本快照。lefdefref-5.8 就是把这两类文件的语法、关键字、单位约定钉死的规范。无论是做库验证、跑布局布线,还是维护转化脚本,能读懂这份文本格式,比会点按钮更能减少无效加班。这篇笔记直接按文件结构拆开讲,每一步都能照着复现。
2. 从 UNITS 和 LAYER 开始读 LEF 5.8:参数、单位与层约束
拿到一个 LEF 文件时,大部分人第一反应是搜 MACRO 关键字,或者直接去翻引脚坐标。但真正决定坐标怎么解释的,是文件头部的 UNITS 段和 LAYER 段。单位搞错,后面所有坐标都是白看;层约束搞错,绕线结果必然和预期偏离。LEF 5.8 的文本结构从VERSION开始,以END LIBRARY结束,中间是一系列可重复的具名块,每个块用END关键字收束。解析时先把这几段读明白,后续才谈得上验证单元和网络。
2.1 读 UNITS 段:数据库微米决定坐标换算基准
LEF 文件里的坐标几乎都是整数,比如矩形坐标( 1000 2000 ),但它实际对应的物理尺寸由 UNITS 段决定:
VERSION 5.8 ; BUSBITCHARS "[]" ; DIVIDERCHAR "/" ; UNITS DATABASE MICRONS 2000 ; END UNITS MANUFACTURINGGRID 0.004 ;DATABASE MICRONS 2000的含义是 1 微米换算成 2000 个数据库单位。也就是说,一个坐标为( 5000 5000 )的矩形角点,实际位于 2.5 微米 × 2.5 微米处。这个数字常见取值有 1000、2000、4000,不同工艺库可能不同,甚至同一个库的 LEF 和 DEF 文件也会出现不一致。MANUFACTURINGGRID 0.004表示制造栅格是 4 纳米,所有坐标值应当是它的整数倍,脚本做四舍五入时也必须按最小栅格取整。
读 LEF 时我习惯把 DATABASE MICRONS 存成全局常量,而不是每读到一段坐标就临时换算一次。这样做的直接好处是:当脚本同时读 DEF 和 LEF 时,只要两个文件的 DATABASE MICRONS 不一致,就能在早期发现偏差,而不是等绕线工具报出一堆短路。MANUFACTURINGGRID则常被忽略,但它对坐标合法性的校验非常有用,自己写生成脚本时,输出坐标前必须做一次取整,否则版图到了签核阶段会有一堆网格违例。
2.2 读 LAYER 段:布线层的方向、间距和偏移量
LAYER 段描述的是版图中每一层金属的布线属性,是绕线工具做轨道规划的依据:
LAYER M1 TYPE ROUTING ; DIRECTION HORIZONTAL ; PITCH 0.14 ; WIDTH 0.07 ; SPACING 0.07 ; OFFSET 0.07 ; END M1这里的PITCH、WIDTH、SPACING都以微米为单位,和 UNITS 段里的 DATABASE MICRONS 无关。DIRECTION HORIZONTAL表示该层金属的绕线走向优先是水平方向,数字单元库里的 M1 通常是水平引脚,M2 是垂直引脚,这样一层一层错开,绕线工具才能规划出畅通的轨道。PITCH 0.14说明相邻轨道中心距是 0.14 微米,OFFSET 0.07表示第一条轨道偏离原点的距离,WIDTH 0.07和SPACING 0.07分别是最小线宽和最小间距。
很多解析脚本只抓 WIDTH 和 SPACING,却没有读 PITCH 和 OFFSET。实际在绕线轨道合法性检查时,PITCH 是否等于 WIDTH 加 SPACING 是第一个要验证的关系。如果 PITCH 小于两者之和,同层相邻线必然短路;如果 OFFSET 没有按 PITCH 的一半设置,轨道可能压到单元引脚边缘。我一般会在解析 LAYER 段时把 PITCH、WIDTH、SPACING、OFFSET 四个值全部提取出来做一次算术检查,任何一项异常都直接报警,而不是等工具层面爆出 DRC 违例。
2.3 读 MACRO 段:引脚矩形和 OBS 阻挡区域的配合
MACRO 段定义了标准单元的物理轮廓、引脚位置和阻挡区域,这是 LEF 文件里信息量最大的部分:
MACRO BUF_X2 CLASS CORE ; ORIGIN 0 0 ; SIZE 0.56 BY 2.72 ; PIN Y DIRECTION OUTPUT ; USE SIGNAL ; PORT LAYER M1 ; RECT 0.14 0.63 0.35 1.19 ; END ; ANTENNADIFFAREA 1.2 ; END Y OBS LAYER M1 ; RECT 0.07 0.07 0.35 0.63 ; RECT 0.14 0.56 0.42 2.65 ; END M1 ; END OBS END BUF_X2SIZE给出单元宽高,ORIGIN是单元坐标原点,绝大多数单元是0 0,但也有库会把原点设在单元中心。引脚 Y 的PORT段列出该引脚在每一层上的矩形位置,RECT的四个数字依次是左下角 X、左下角 Y、右上角 X、右上角 Y。OBS是障碍区域,表示该区域禁止绕线工具穿过,通常覆盖了单元内部不能被金属走线覆盖的部分。
读 MACRO 段时最容易犯的错是只关注 PIN 矩形而忽略 OBS。如果把 OBS 也当作不可布线区域合并到引脚集合里,绕线工具的结果会相对保守但安全;反之,只保留 PIN 矩形,工具可能会把线穿进单元内部,后期 DRC 才爆出一堆违例。自写脚本做单元合法性检查时,我会把 PIN 矩形和 OBS 矩形统一转成微米后存入数组,再按层合并,这样后面做实例摆放重叠检查时,可以直接复用同一份数据。
3. 用 DEF 反查 LEF:芯片摆放与绕线连接的数据对照
LEF 描述的是“库里有什么”,DEF 描述的是“这次设计放成了什么样”。布局布线工具最终输出的 DEF 文件里包含芯片面积、单元实例、引脚位置、信号网络和电源网络。只看 DEF 而不回查 LEF,很多错误发现不了,因为 DEF 里的单元名、引脚名、层名都必须能在 LEF 中找到对应定义。把两份文件放在一起对照,才是验证物理实现的正路。
3.1 先读 DIEAREA 与 COMPONENTS:坐标从文本到物理位置的第一步
DEF 文件的头部结构比 LEF 更贴近“一张设计快照”:
VERSION 5.8 ; DIVIDERCHAR "/" ; BUSBITCHARS "[]" ; DIEAREA ( 0 0 ) ( 80000 80000 ) ; COMPONENTS 4 ; - BUF_X2 u1 + PLACED ( 1000 2000 ) N ; - BUF_X2 u2 + PLACED ( 5000 2000 ) FN ; END COMPONENTSDIEAREA的两个坐标点给出芯片左下角和右上角,单位是数据库单位。注意这里的坐标基准必须和 LEF 的 DATABASE MICRONS 一致,如果 LEF 里DATABASE MICRONS 2000,那么DIEAREA ( 0 0 ) ( 80000 80000 )表示的是 40 微米 × 40 微米的芯片面积。COMPONENTS 段逐行列出每个实例的单元名、实例名、摆放坐标和方向,N表示正向,FN表示 Y 轴镜像后再旋转 180 度,方向和绕线结果强相关,只看坐标不看方向会漏掉大量隐患。
解析 COMPONENTS 时我很少直接信任坐标,而是把实例名、宏名、方向和坐标单独存成结构体,再去 LEF 里查找对应 MACRO 的 SIZE。比如实例 u1 的坐标是( 1000 2000 ),宏 BUF_X2 的尺寸是 0.56 × 2.72 微米,按 DATABASE MICRONS 2000 换算后相当于 1120 × 5440 个数据库单位,那么 u1 的边界应当横跨 X 方向 1000 到 2120。如果超出 DIEAREA 或者和其他实例重叠,说明摆放本身就有问题。这个验证步骤用文本方式就能完成,不需要启动任何图形界面。
3.2 按 NETS 与 SPECIALNETS 追踪信号和电源连接
NETS 段记录了信号网络里每个引脚之间的连接关系,SPECIALNETS 段记录电源和地网络,后者通常带USE POWER或USE GROUND属性:
NETS 3 ; - n_test ( u1 Y ) ( u2 A ) ; SPECIALNETS 2 ; - VDD ( u1 VDD ) ( u2 VDD ) + USE POWER ; END SPECIALNETS END DESIGN- n_test ( u1 Y ) ( u2 A )表示网络 n_test 连接了实例 u1 的引脚 Y 和实例 u2 的引脚 A。这里引脚名必须能在对应 LEF 宏的 PIN 段中找到,否则就是连接断链。SPECIALNETS 里的电源网络往往还会带+ ROUTED描述绕线路径,但做连接性验证时只需要关注引脚的完整性。
我排查连接断链的方法是:先从 LEF 中提取每个宏的合法引脚集合,再从 DEF 的 COMPONENTS 里收集每个实例使用的引脚,最后把 NETS 里出现的每个( 实例名 引脚名 )对逐一匹配。只要一个网络里的某个引脚在 LEF 宏定义中不存在,就说明库和设计之间不同步,这种问题靠图形界面很难一眼定位,但文本对照起来非常直接。SPECIALNETS 的数量通常比信号网络少,但电源连接一旦断掉,整个模块的功能仿真都会失败,所以我会把电源网络的引脚也纳入同样的匹配逻辑。
3.3 LEF 与 DEF 交叉验证的字段映射表
两份文件的字段对应关系并不总是直观,做脚本验证前最好先定一份对照表:
| 数据对象 | LEF 中的定义位置 | DEF 中的引用方式 | 常见不一致现象 |
|---|---|---|---|
| 标准单元几何 | MACRO + PIN + OBS | COMPONENTS 引用宏名 | 宏名缺失或大小写不一致 |
| 引脚连接 | PIN 段中的引脚名 | NETS 里的( 实例 引脚 )对 | 引脚在 LEF 中不存在 |
| 布线层 | LAYER 段中的层名 | 引脚 PORT 和绕线路径引用层名 | LEF 缺少对应 LAYER 定义 |
| 数据库单位 | UNITS 段的 DATABASE MICRONS | DIEAREA 与 PLACED 坐标 | 两份文件 DBU 不一致,坐标整体偏移 |
这张表既是解析脚本的需求清单,也是人工排查时的检查顺序。碰到布局工具输出异常,按这个顺序逐项核对,通常能在十分钟内定位问题,而不是靠肉眼在版图窗口里反复缩放。每次生成新的库或新的 DEF 文件,我第一件事就是跑这个映射检查,确认数据库单位一致、宏名存在、引脚可匹配,然后再谈其他细节。
4. 写一个只提取关键信息的解析脚本:30 行代码建立校验基线
完整实现一个 LEF/DEF 解析器的工作量很大,但日常维护根本不需要。只需要从文本里提取 UNITS、LAYER、COMPONENTS 等关键段并做交叉校验,就能覆盖绝大部分排查需求。下面这套脚本以 Python 3 为主,不依赖额外库,适合直接扩进自己的验证流程。
4.1 抽取 LEF 的 UNITS 和 LAYER 段
先写一个通用的按关键字切块的函数,然后提取 LEF 里的 UNITS 和 LAYER 信息:
import re from pathlib import Path def extract_sections(text: str, name: str): # 匹配 "LAYER M1\n...\nEND M1" 这类成对结构 pattern = re.compile( r'\b' + name + r'\s+(\S+)\b(.*?)\nEND\s+\1\b', re.S ) return [(m.group(1), m.group(2)) for m in pattern.finditer(text)] def load_lef(path: str): txt = Path(path).read_text(encoding='utf-8', errors='replace') units = extract_sections(txt, 'UNITS') layers = extract_sections(txt, 'LAYER') return units, layers if __name__ == '__main__': u, ly = load_lef('sample.lef') for name, body in u: db = re.search(r'DATABASE\s+MICRONS\s+(\d+)', body) print(f'UNITS {name}: DBU={db.group(1) if db else "N/A"}') for name, body in ly: pitch = re.search(r'PITCH\s+([\d.]+)', body) width = re.search(r'WIDTH\s+([\d.]+)', body) print(f'LAYER {name}: pitch={pitch.group(1) if pitch else "N/A"}' f' width={width.group(1) if width else "N/A"}')extract_sections里的正则用(.*?)\nEND\s+\1匹配非贪婪内容,遇到第一个END就停。这个写法对于 LAYER、UNITS 这种不嵌套的段没问题,但遇到 MACRO 内部嵌套多个 PIN 时,\1必须带上具体名字才能正确结束。参数re.S让点号能匹配换行符,少写这个标志是解析多行段失败的最常见原因。errors='replace'作用是遇到非法字符不直接抛异常,避免一个文件的编码问题中断整批验证。
4.2 解析 DEF 的 COMPONENTS 段落
DEF 的 COMPONENTS 每一行以-开头,格式稳定,用逐行扫描加正则提取即可:
import re def extract_components(def_text: str): comps = [] in_sec = False for raw in def_text.splitlines(): line = raw.strip() if line.startswith('COMPONENTS'): in_sec = True continue if in_sec and line.startswith('END COMPONENTS'): break if in_sec and line.startswith('- '): # 示例: - BUF_X2 u1 + PLACED ( 1000 2000 ) N ; m = re.match(r'-\s+(\S+)\s+(\S+)(.*)', line) if not m: continue macro, inst = m.group(1), m.group(2) ori = re.search( r'PLACED\s*\([^)]*\)\s*([A-Z]+)\s*;', m.group(3) ) comps.append({ 'inst': inst, 'macro': macro, 'orient': ori.group(1) if ori else None, }) return comps这个解析器的正则只匹配PLACED关键字,如果实例是FIXED或者COVER,方向字段会解析成None,不影响其他字段提取。实际项目中 COMPONENTS 行可能带+ WEIGHT、+ STATUS等额外属性,但只要宏名和实例名在行首,正则就能稳定工作。方向字段在后续做旋转验证时很关键,N和FN对应的宏旋转结果完全不同,哪怕坐标相同,OBS 覆盖的区域也不一样。
4.3 文件解析后的人工复核要点
脚本输出不是终点,真正要做的是一份“解析结果对照预期”的复核:
| 检查项 | 解析结果怎么判断 | 异常时先查哪一段 |
|---|---|---|
| DATABASE MICRONS 数值 | 是否与工艺文档一致 | LEF 头部 UNITS 段 |
| LAYER 层数 | 是否等于工艺金属层数 | LEF 中TYPE ROUTING的块数量 |
| LAYER PITCH 与 WIDTH 的关系 | PITCH 应不小于 WIDTH + SPACING | 对应 LAYER 段的三个数值 |
| COMPONENTS 宏名 | 是否全部能在 LEF MACRO 中找到 | DEF 的 COMPONENTS 行与 LEF 的宏名 |
| COMPONENTS 方向字段 | 是否全部都有合法方向值 | PLACED/FIXED后的字符 |
我习惯把解析结果输出成一份纯文本报告,和上一版文件做 diff。物理尺寸没变但引脚数增加、OBS 面积变化、层数从五层变成六层,这些信息在报告里一目了然。没有这一份基线,任何 LEF/DEF 相关的改动都只能靠猜。
5. LEF/DEF 5.8 常见问题与踩坑排查:现象、原因、解决顺序
LEF 和 DEF 是文本格式,但它不像普通配置文件那么宽容,语法错一点,轻则某个层的数据丢失,重则整个布局工具直接崩溃。下面这五类问题是我在项目里反复遇到的,每一条都按“现象 → 原因 → 解决”的顺序写清楚,排查时照着走基本不会白费功夫。
5.1 坐标整体放大或缩小:数据库中位不一致
现象是 DEF 里实例摆放坐标看起来正常,但导到版图验证工具后,单元间距整体差了一倍,有时是两倍。比如 LEF 里DATABASE MICRONS 4000,DEF 里坐标却按DATABASE MICRONS 2000输出,解析脚本只要混用两个单位,所有坐标都会偏移。
原因是不同工具对 DBU 的处理策略不同,有的在输出 DEF 时按内部默认单位,有的按库文件里的值。解决方法是统一换算:所有坐标读入后立即换算成微米,内部只存微米值,输出时再按目标文件的 DBU 转回去。只要把换算动作收敛在读写边界,而不是散布在业务逻辑里,这类问题就能彻底避免。
5.2 单元方向与预期差 90 度或镜像翻转
现象是单元摆放坐标准确,但绕线结果里单元内部的引脚位置全部旋转了。原因是 DEF 里方向字符N、FN、E、W没有和 LEF 宏的几何定义一起旋转验证,工具沿用了默认方向。
解决方法是做一次“旋转后中心校验”:把 LEF 宏里所有 PIN 矩形的中心坐标算出来,再按 DEF 方向字符做旋转和平移,检查结果是否落在 DIEAREA 内的合理位置。如果旋转后的引脚中心偏离了期望点,方向字符大概率配错了。这步用文本脚本就能完成,不需要打开版图工具。
5.3 文本块被内部 END 提前切断
现象是自写解析器提取 LEF 的 MACRO 段时,只读到了第一个END M1就停止,导致 OBS 内容缺失。原因是 MACRO 内部嵌套了 PIN、PORT、OBS、LAYER 多个层级,而正则里的非贪婪匹配在遇到第一个END时就结束了。
解决方法是改用计数器扫描:遇到块开始关键字加一,遇到匹配的END减一,计数器归零才算整个块结束。这个方法比正则更稳,适用于 MACRO 这种嵌套结构。代码实现上只需要维护一个深度变量和一份关键字到结束标记的映射。
5.4 版本字段与语法字段冲突
现象是文件头写VERSION 5.8,但工具解析时按 5.6 的语法处理,导致部分关键字无法识别。原因是文件经过中间脚本转换后,版本号字段没有同步更新,或者旧工具强行读取了新版本文件。
解决办法是在解析前先提取 VERSION 值,再根据版本号决定启用哪些正则规则。不要试图让一套代码兼容所有版本,直接用if version >= "5.8"分支处理。手工修改文件时也要保持版本字段和语法一致,否则工具内部的解析分支会走错。
5.5 总线名和特殊字符导致网络断链
现象是 DEF 里的网络名addr[0]在脚本处理后变成addr0或直接被丢弃,绕线结果里少了关键连接。原因是BUSBITCHARS和DIVIDERCHAR没有在解析脚本中生效。
解决方法是先读取文件头部的BUSBITCHARS和DIVIDERCHAR,在切割网络名之前确认分隔符。常见写法是BUSBITCHARS "[]"配合DIVIDERCHAR "/",解析时把[、]、/统一替换成下划线再处理,避免 split 时误伤。这个细节在人工检查时很难发现,但一旦触发,所有带总线的网络都会出问题。
6. 把 5.8 手册用成检查工具:版本迁移与验证习惯
6.1 直接可用的版本字段迁移对比
从旧版本库切到 5.8 时,与其逐页翻参考手册,不如把几个关键字段做成对比表,每次迁移时逐项核对:
| 对比对象 | 旧版本常见写法 | 5.8 版常见表现 | 迁移检查重点 |
|---|---|---|---|
| UNITS 段 | DATABASE MICRONS 1000/2000 | 单位写法不变 | 确认 DBU 值,不要沿用旧文件默认值 |
| MANUFACTURINGGRID | 0.005常见 | 常出现0.004、0.0025 | 校验坐标按最小栅格取整 |
| LAYER 段 | WIDTH 和 SPACING 分开 | 部分库增加 MINWIDTH 字段 | 先查 WIDTH,再查 MINWIDTH,防止取错值 |
| SPECIALNETS | USE POWER在属性后 | 网络名与引脚名规则一致 | 保留电源网络命名连续性,不做额外重命名 |
这份表的核心作用不是帮你背语法,而是给出“迁移时先对比什么”的优先级。每次换版,先把解析结果打到一份报告里,逐项对比旧版本输出,差异一眼就能看出来。
6.2 一个值得长期坚持的验证习惯
我所有 LEF/DEF 相关工作的第一步,都是跑一遍第四节里的最小解析脚本,拿到四个量:DATABASE MICRONS、LAYER 数量、MACRO 数量、COMPONENTS 数量。这四个数字在不同版本之间发生变化时,能够直观看到新库是否引入预期改动。如果工艺层数从五层变六层,但 LEF 里TYPE ROUTING的块数量没有增加,那文件一定有问题。同样的,如果宏数量增多但 COMPONENTS 数量减少,摆放结果的覆盖率就值得怀疑。
这种验证方式成本极低,却能提前拦住大量问题。最深刻的教训来自一次绕线工具崩溃,追查到最后,原因不过是在 LEF 文件转换时 DATABASE MICRONS 被人从 2000 改成了 1000,而 DEF 里的所有坐标都按 2000 输出。工具崩溃在绕线阶段,但根因在文本头部。从那次以后,凡是读 LEF 和 DEF 的地方,我第一行代码一定是读取 UNITS 段并打印出来。坐标相关的问题从来不是出错的那一行代码造成的,而是它上面几行没读对。养成先确认单位、再核对层名、最后使用坐标的习惯,能省掉大量无意义的返工。希望这份笔记能帮你把 5.8 参考手册真正用起来,少踩几个我已经踩过的坑。
本文还有配套的精品资源,点击获取