ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Tessent_StdcellLib 标准单元库 DFT 建模与扫描链实战

Tessent_StdcellLib 标准单元库 DFT 建模与扫描链实战 上周三下午一个刚从后端转岗做 DFT 的同事把厂商发来的一个压缩包丢到共享盘上转头问我Tessent_StdcellLib 这堆东西到底哪些要读进 Tessent哪些可以放着不管这个问题我前后回答过不下十遍。标准单元库std cell library是数字芯片的地基但 DFT 流程对它的诉求跟综合、时序分析完全不在一个频道上——综合关心驱动能力和延迟Tessent 关心的是这颗触发器能不能被打断、这个门控单元的使能在移位阶段能不能被拉住、这个 tie cell 究竟输出高还是低。名字里的 Tessent_StdcellLib 听起来很直白就是面向 Tessent 的标准单元库可落到真实工程里它往往指三件不同的事处理手法差得很远。这篇内容写给三类人第一次把厂商库接进 Tessent 的 DFT 新人、要同时维护好几个工艺节点库的库管理员、以及被扫描链插不进去覆盖率整块掉点折磨过的验证工程师。我会先讲清楚 Tessent_StdcellLib 的三种典型含义再说明一份库要满足哪些条件才算真正能被 ATPG 读懂然后给出一套可以直接照做的环境搭建、属性建模、报错回追和长期维护方法。所有命令和字段写法我会尽量给出可复制的片段同时标注哪些地方跟工具版本强相关避免你照抄之后在另一个版本上卡住。1. Tessent_StdcellLib 的三种含义先分清再动手拿到这个名字第一件事不是打开文件而是判断你手上的目录属于哪一类。我见过太多次有人把厂商原始库直接塞进流程结果读进去报一堆语法警告然后花两天去查工具问题——其实方向从一开始就偏了。1.1 含义一厂商交付的、已经带 DFT 视图的标准单元库包多数成熟工艺的库厂商除了给综合用的.lib、给布局用的.lef、给 LVS 用的.cdl、给仿真用的.v还会额外提供一份面向测试的视图。这份视图里最核心的东西是 Liberty 里的test_cell组它告诉 Tessent 哪个引脚是扫描输入、哪个是扫描使能、哪个是扫描输出。有些厂商把它单独放在一个dft子目录有些直接内嵌在功能.lib里。如果你手上的目录里同时能翻到.lib、.lef、.gds、.v、.cdl基本可以确定这是含义一。这类库原则上不该手改改了就脱离了厂商的可追溯性后面 tapeout 出问题会很难解释。1.2 含义二项目内部维护的 Tessent 库封装目录第二种情况更常见公司内部有一个目录就叫Tessent_StdcellLib里面装的不是原始库而是转换脚本、补丁文件、编译产物和一份说明文档。为什么要有这么一层因为厂商给的库经常不完整——某些低功耗单元没建模、某些 mux 没有 DFT 属性、某些工艺角只给了典型角。库管理员会写一套 Tcl 或者 Perl 脚本把厂商库读进来补齐缺失的属性再输出一份Tessent 友好的库。这一层最大的价值是可复现。厂商库升级了跑一遍脚本就能重新生成不需要人工回忆上次改了哪几行。如果你的团队还没有这一层强烈建议补上哪怕只是几个 shell 脚本加一份 README。1.3 用一张文件清单快速判定你手上的是哪一种不想逐层翻目录的话对着下面这张表扫一遍就能定性。表里的缺失后果一栏是我在实际项目里踩过或见过别人踩过的不是理论推演。文件/目录特征典型归属缺失后果.lib带test_cell组厂商完整库扫描链插入阶段找不到扫描等价单元仅有功能.lib无测试视图厂商基础库需要人工补 DFT 属性*.tcl*.patchREADME内部封装层换库时无法复现历史改动编译缓存目录libc之类工具生成物不该进版本库会污染 diff只有.db二进制时序库综合侧产物Tessent 读不了必须拿回 Liberty提示编译缓存目录不要提交到 Git。它是工具生成的二进制跟工具版本、绝对路径强绑定换台机器就跑不起来还会把仓库撑大。2. 一份库要被 Tessent 正确理解缺哪几样东西判断完含义接下来是硬功夫这份库到底缺什么。我习惯按功能视图、扫描属性、扫描等价单元、特殊单元、低功耗单元五个层次依次过一遍顺序不能乱因为后面的层次依赖前面的。2.1 功能视图别让工具把标准单元当黑盒Tessent 要做 DRC 和 ATPG必须知道每个单元的逻辑行为。如果某个单元没有功能模型工具会把它当黑盒随之而来的是一串输出不可控无法传播的违规。很多新人以为.lib就够了其实不然——Liberty 主要描述时序和功耗逻辑功能要靠 Verilog 行为模型来补。标准做法是把厂商提供的仿真模型通常是.v或者带 UDP 定义的库文件读进来或者在库建模阶段为每个单元生成一份简化的功能描述。我一般会重点检查这几类复合逻辑门比如 AOI、OAI、带复位或置位的触发器、时钟门控单元、以及各种 tie 单元。这几类一旦缺模型DRC 的报错会非常密集而且互相遮掩很难一眼看出根因。2.2 扫描属性test_cell组决定扫描链能不能拼出来这是整份库的灵魂。下面是一段简化的 Liberty 节选展示带扫描端口的触发器该怎么描述。注意这是节选实际字段比这多具体写法以厂商模板为准cell (DFSQ) { area : 10.5 ; ff (IQ, IQN) { next_state : D ; clocked_on : CK ; } pin (D) { direction : input ; } pin (CK) { direction : input ; clock : true ; } pin (SI) { direction : input ; signal_type : test_scan_in ; } pin (SE) { direction : input ; signal_type : test_scan_enable ; } pin (Q) { direction : output ; function : IQ ; signal_type : test_scan_out ; } }关键就在于signal_type这几个取值。Tessent 读库的时候靠它识别扫描端口识别不到工具就会认为这颗触发器不可扫描转头去找扫描等价单元——通常是一个 2:1 mux 加一颗普通触发器。找不到扫描链就断在这里。我建议在库评估阶段用最简单的命令先数一遍grep -c ^cell ( stdcell.lib grep -c test_scan_in stdcell.lib grep -c test_scan_enable stdcell.lib第一个数字和第二个数字的差距基本就等于需要插 mux 的触发器数量。差距过大时要么是厂商库没给全要么是你们选的触发器型号本身就不带扫描端口这两种情况的处理方式完全不同。2.3 扫描等价单元为什么库里必须有 mux以及 mux 放在哪很多人以为扫描触发器是必须的实际上 Tessent 允许用普通触发器加 mux 来构造扫描单元这就是所谓的扫描等价单元。这样做的代价是面积和延迟收益是库的选择面更宽。这里有个容易忽略的细节mux 必须出现在库文件里并且带有能标识它可以作为扫描 mux的属性而不是靠工具去猜逻辑。如果库里只有 mux 的功能模型、没有测试属性工具可能仍然识别但识别结果不稳定不同版本表现可能不一样。我的习惯是明确建模不依赖推断。另外插入位置也有讲究。Tessent 倾向于在触发器前紧挨着插 mux这样对时序影响最小但会改变局部布线密度。如果你们的设计在扫描插入后经常出现局部拥塞可以评估一下是不是插入策略导致的这时候调整约束比改库更有效。2.4 时钟门控、tie、三态 pad三个最容易被忽略的建模点时钟门控单元ICG是低功耗设计的标配也是 DFT 踩坑的重灾区。移位阶段时钟必须持续翻转这就要求门控单元的使能在移位时被强制打开。如果库里没有把使能引脚建模成工具能识别和控制的形态Tessent 就没法在移位模式下拉住它结果就是扫描链一动不动波形上看时钟根本没有脉冲。tie 单元的问题更隐蔽。它输出恒定值工具必须知道这个值才能正确判断某条路径是不是常量。如果 tie 单元被当黑盒工具会保守地认为该点可控于是漏掉本该报出的违规覆盖率也可能因此出现虚高。三态 pad 同理双向端口在测试模式下必须被正确置成输入或输出否则 DRC 会报不可控。这三类单元我建议单独建立一份清单每次换库都拿这份清单去核对比漫无目的地扫.lib快得多。2.5 多电压域下 isolation、level shifter、retention 的测试态处理设计一旦上多电压域库里就会多出隔离单元、电平转换单元和保持单元。这三类在测试模式下的行为必须明确隔离单元在测试时要放行还是钳位、电平转换单元在测试时是否透明、保持单元在移位时是否保持。这些东西光看 Liberty 是不够的通常还要结合电源意图文件一起看。我的经验是把测试模式下的电源状态单独列一张表跟库里的单元逐一对上确认每个单元在测试态都有确定的行为。这一块一旦出错往往是硅后才能发现代价极高。3. 从安装包到可用环境把 Tessent 和库文件摆到正确的位置库文件准备得再好环境不对也白搭。这一节讲的是把工具和库摆到正确位置的具体做法以及为什么某些看起来省事的做法后患无穷。3.1 安装包形态与安装后的自检清单从官方渠道拿到安装包之后通常有图形化和静默两种安装方式。图形化适合个人工作站静默安装适合服务器批量部署。这里不展开具体参数因为不同年份的安装包形式差别不小以随包附带的安装说明为准。安装完别急着跑流程先过一遍自检清单。下面这几项我每次都做能省下大量为什么工具起不来的排查时间。检查项期望结果不达标时的常见原因命令行能启动正常输出工具版本号环境变量 PATH 没配能进入交互模式不报许可证缺失许可证变量未设置或指向错误库文件可读读库命令返回正常无 error路径权限或文件损坏编译缓存生成工作目录下出现编译库目录工作目录只读或磁盘空间不足版本匹配工具版本不低于库语法要求库用了新版语法工具太老后面两项经常被忽略。尤其是版本匹配很多库读不进去的报错本质上是新版 Liberty 语法撞上旧版工具这类问题改库没用只能换工具或换库。3.2 库目录怎么组织为什么不要直接引用厂商原始路径我见过最糟糕的做法是流程脚本里直接写厂商解压目录的绝对路径。这么做的后果是厂商升级一次库所有脚本的路径全要改同事在自己的机器上复现路径对不上半年后有人清理共享盘整个流程崩掉。比较稳的组织方式是给每个库建一个带版本号的目录流程脚本只引用一个统一的软链接或环境变量。目录结构大致长这样lib/ stdcell_tt_1v0_25c_r3/ liberty/ verilog/ lef/ dft_patch/ MANIFEST.md stdcell_tt_1v0_25c - stdcell_tt_1v0_25c_r3换库的时候只改软链接的指向流程脚本一行都不用动。MANIFEST.md里记清楚这个版本相对上一版改了什么、什么时候改的、谁改的出问题时能快速回溯。3.3 编译库缓存与库、工具、项目三者的版本绑定Tessent 读 Liberty 之后会在工作目录下生成编译缓存后续运行直接复用速度会快很多。但这带来一个隐患缓存是跟工具版本绑定的。工具升级之后用旧缓存可能报奇怪的错误或者行为跟预期不一致。我的做法是把缓存目录按库版本 工具版本命名并在启动脚本里做一次校验CACHE_DIR.libcache_${LIB_VER}_${TOOL_VER} if [ ! -d $CACHE_DIR ]; then echo 首次使用该组合需要重新编译库 fi别小看这一行判断它能避免至少一类昨天还好好的今天怎么就不对了的问题。版本组合这块宁可多花几分钟重新编译也不要赌缓存能用。4. DFT 属性加在库级还是实例级这是一个架构决定补属性这一步做法有很多种但最关键的决策只有一个属性加在库里还是加在网表实例上。这个决定看起来是细节实际上影响整个流程的可维护性。4.1 库级建模的收益与代价库级加属性的最大好处是一次建模全设计生效。ATPG 是针对整颗芯片所有实例工作的库级的属性对所有实例自动适用包括后续新插入的单元。而且库一旦建好多个项目可以共用边际成本递减。代价在于库变成了共享资产改动需要走评审。曾经有同事为了赶进度直接在库里改了一个时钟门控单元的属性结果另一个项目复用了同一份库测试模式下的行为全变了。所以我现在的规矩是库改动必须记录、必须回归不允许临时改一下先跑通。4.2 用 Tcl 补属性的典型场景和写法有些属性确实不适合放在库里比如某个特定实例要特殊处理。这种情况用 Tcl 在流程脚本里补更合适。下面是一段骨架具体命令名在不同版本里略有差别以你们所用版本的命令手册为准# 读取标准单元库与设计网表 read_cell_library ./lib/stdcell_tt.lib read_cell_library ./lib/icg_tt.lib read_verilog ./netlist/top_scan.v # 声明测试模式下需要用到的基本信号 add_scan_mode shift_mode -scan_enable scan_en -scan_clock clk # 运行设计规则检查先看库层面的问题 check_design_rules顺序上我坚持先读库、再读网表、最后加约束。反过来的话工具在解析网表时拿不到单元的完整信息会先报一轮未知单元的警告把真正的问题淹掉。4.3 黑盒、dont_use 与库里有但设计里没用的单元库里通常会包含大量设计里根本没用的单元比如各种驱动强度的缓冲器、各种变体触发器。这些单元留着不影响正确性但会拖慢库解析速度。如果库里单元数量在四位数以上可以考虑裁剪出一份项目专用子集。dont_use的处理要小心。有些单元被标了dont_use扫描插入时工具就不会选它如果恰好某个 mux 被标了扫描链就插不出来。遇到这种情况先确认是厂商标错了还是确实不该用别直接删掉标记了事。黑盒单元的处理更直接如果某类单元在测试模式下确实不需要被分析比如某些模拟模块的接口单元可以显式声明为黑盒避免它污染 DRC 结果。但声明黑盒等于放弃对它的检查这个口子要开得克制。4.4 建模完必做的三项自检库改完之后至少跑这三项再往下走。第一项是库解析自检确认没有 error 级别的报错警告逐条看一眼。第二项是端口识别自检抽查几个典型触发器确认扫描端口被正确识别。第三项是小规模试插用一个几十个触发器的测试模块跑一遍扫描链插入看能不能拼出完整链。这三项加起来通常不到十分钟但能把绝大多数库层面的问题挡在正式流程之前。跳过它们直接跑全芯片出问题之后定位成本要高一个数量级。5. 报错往回追从 DRC 清单定位到库文件的那一行哪怕前面都做对了还是会有问题。这一节讲的是出问题之后怎么往回追。核心思路是不要一上来就改东西先按症状分类再顺着链路往回走。5.1 症状、根因、动作对照表下面这张表是这些年攒下来的覆盖了八成以上的常见情况。表里的动作一栏我刻意写成可执行的操作不是检查一下这种空话。症状或报错常见根因处理动作读库时 parse errorLiberty 语法超出工具版本支持换用厂商低版本语法库或升级工具不要手改语法找不到扫描等价单元库里既无带 SI/SE 的触发器也无可用 mux补 mux 的测试属性确认 mux 未被 dont_use某引脚报不可控该引脚由 tie 或 ICG 驱动单元被当黑盒确认对应单元有功能模型某模块覆盖率整块为 0该模块用的特殊单元未建模单独补属性后重跑该模块移位阶段波形不翻转门控时钟在移位时未打开检查 ICG 使能的识别与测试态约束报重复定义的单元同一单元被多个库文件重复定义合并库或用库优先级明确覆盖关系重复定义这一条特别值得说。项目里往往同时读入标准单元库、IO 库、存储器库、IP 库不同库之间偶尔会出现同名单元。工具的行为取决于读入顺序而读入顺序常常写在脚本深处没人记得。遇到诡异的行为差异先查库的读入顺序。5.2 一次完整的排查链路ICG 使能引脚被建模成内部节点说个真实案例。当时的情况是扫描链能拼出来DRC 也基本干净但移位阶段仿真出来发现某一段链的数据不往前走。工具报告里没有任何显式错误只有几条低优先级的警告很容易被忽略。第一步确认时钟。抓了门控时钟的输入端和输出端波形输入端有脉冲输出端是平的说明门控没打开。第二步找使能。使能信号来自一个控制寄存器的输出上电复位后是默认值。第三步看测试模式约束。约束里确实有拉高该使能的操作但作用于寄存器实例的端口上。第四步追到库。翻出 ICG 单元的 Liberty发现使能引脚被建模成了一个内部节点外部端口映射到的是另一个名称。约束写在外部端口上根本没生效。根因是库建模时引脚命名跟约束里用的名字不一致。修法有两个改库里的引脚命名或者在约束里用工具实际识别的名字。我们选了前者因为库命名应该跟厂商文档保持一致约束里写库里的真实名字只是权宜之计。这个案例的教训是没有报错不代表没有问题。低优先级警告里经常藏着关键信息尤其是跟端口识别、属性缺失相关的警告值得逐条过一遍。5.3 覆盖率掉点先怀疑库还是先怀疑约束覆盖率莫名其妙掉了几个点大家第一反应通常是查激励和约束。我的经验是先把库排除掉因为库的问题往往表现为整块区域完全没有覆盖而约束问题通常表现为某个功能点没被激活两者的分布形态很好区分。判断方法是按模块统计覆盖率。如果某个模块覆盖率接近零而且该模块用的单元类型比较特殊八成是库的问题。如果各个模块覆盖率都还行只是某些特定故障类型没覆盖那更可能是约束或激励的问题。还有一种情况是覆盖率虚高应该报的违规没报出来分数很好看但实际有风险。这种通常在 tie 单元或黑盒单元没建模时出现。所以看覆盖率不能只看数字还要看违规清单是否合理。6. 库的长期维护多节点、多版本下的工程化做法一次性把事情做对不难难的是半年后换库、换工具、换人之后还能做对。这一节讲的是把前面这些工作沉淀成机制。6.1 版本命名、校验和与变更记录版本命名我建议包含工艺角、电压、温度、修订号四段信息比如tt_1v0_25c_r3。这样从目录名就能判断适用场景不用打开文件确认。每份库在入库时算一遍校验和记在清单里下游使用时可以做一次比对防止文件在传输过程中损坏或被误改。变更记录不要求写得多正式但至少要回答三个问题改了什么单元、为什么改、影响哪些项目。我见过太多这个属性为什么是这么写的没人知道的情况最后只能靠猜。6.2 换库后的回归清单换库是高风险操作必须走回归。回归清单不用很长但每一项都要有明确的通过标准库解析无 error警告数量与上一版对比无异常增长典型触发器的扫描端口识别结果与上一版一致小规模测试模块的扫描链插入成功链上单元数量符合预期设计规则检查的违规数量与上一版对比新增项逐条确认覆盖率基线对比掉点超过阈值就停下来查最后一项是关键。新增的违规逐条确认这句话的意思是不允许出现反正多了三条应该没事这种判断。每一条新增违规都要有明确结论是库变化引起的合理变化还是引入了新问题。6.3 一小段自动化脚本省下的人力前面这些检查手工做一遍大概要半小时到一小时而且容易漏。写个脚本把这些检查串起来成本很低#!/bin/bash set -e LIB_DIR${1:?请传入库目录} echo 库文件数量统计 grep -c ^cell ( $LIB_DIR/liberty/*.lib echo 扫描端口统计 grep -c test_scan_in $LIB_DIR/liberty/*.lib echo 校验和 find $LIB_DIR -type f -name *.lib -exec md5sum {} \;这个脚本很粗糙但它能在一分钟内给出三个关键数字跟上一版的记录一比就知道有没有异常。真正有价值的不是脚本本身而是它逼着你把这一版和上一版差在哪变成一个可以自动回答的问题。我在实际操作中的体会是标准单元库这块的工作技术难度其实并不算高难的是保持一致性——同一个属性今天这么写、三个月后还是这么写换个人接手也是这么写。真正让项目出事的往往不是某个复杂的建模技巧而是一个被悄悄改掉的引脚名、一份没走回归的新库、一个以为应该没事的新增违规。把检查做成习惯比把技巧学全更重要。另外分享一个小技巧每次改库之前先在版本库里打一个标签改完跑完回归再合并这样任何时候都能退回去对比比事后靠记忆回忆改了什么靠谱得多。
返回列表