
coverage卡死在96.8%连续两轮regression一丝不动。盯着report_faults里那一长串unobserved故障你会清楚地感受到DFT可测试性设计和ATPG自动测试向量生成这门活儿的微妙之处覆盖率从来不是一条命令能拉满的它更像是做一次coverage path planning——把网表里每个扇区都扫过去看哪些角落被落在了视野之外。这篇不是教科书是我自己在几个项目里把coverage从九十六七推到九十九以上的完整方法链。从指标口径、网表架构、ATPG约束、pattern生成策略到内嵌存储器和模拟IP的处理再到顶层合并验证都会按实际操作顺序讲清楚。适合正在跟coverage死磕的DFT工程师也适合想系统建立DFT覆盖率概念的数字IC后端、验证工程师。1. 先搞清楚coverage的账怎么算指标口径和故障分类1.1 三个容易混的指标做DFT的人如果在coverage问题上跟人吵架八成是口径没对齐。fault coverage、test coverage、fault efficiency这三个词在不同公司甚至不同工具里经常被混着叫实际含义差不少。fault coverage是最直觉的定义检测到的故障数除以故障总数。这个指标最诚实因为它把所有stuck-at或transition故障都算进分母包括那些压根测不到的。test coverage或fault efficiency则是把不可测故障untestable faults从分母里剔除只算“在可测范围内覆盖了多少”。两者一对比就明白为什么有些项目报出来的coverage很好看因为分母已经被砍过一刀了。指标计算公式关注点常见误区Fault Coveragedetected faults / total faults真实测试质量数值偏低但最诚实Test Coverage / Fault Efficiencydetected faults / (total faults - untestable faults)工具验证充分度容易掩盖结构问题Transition Coverage同上但故障模型为跳变延迟故障at-speed测试能力与stuck-at覆盖率的损失原因完全不同我自己的习惯是两套数字都看交付报告时给签约指标用test coverage内部质量评估一律看raw fault coverage。还有一个容易被忽略的点不同工具对untestable的判定标准不同同一份网表在TetraMAX和FastScan里跑出来可能差0.5到1个百分点项目前期必须锁死工具链不然后面分析全是噪音。1.2 从故障分类看懂根因ATPG工具输出报告时会把每个fault标成detected或者undetected而undetected下面通常会再细分。不同厂商的命名有差异但逻辑骨架是通用的不可控制uncontrollable和不可观测unobservable。不可控制本质是这条线上你没办法把它稳定地置成0或1。常见场景三态总线使能信号不受扫描控制、异步复位信号一直处于激活态、模拟IP输出给数字逻辑的status信号没有确定值、内部反馈回路形成组合环。不可观测则是你能控制它翻转但翻转的效应传不到任何扫描观察点。典型例子深嵌套逻辑被黑盒挡在中间、扇出只有一条路径且终点是没人管的模拟宏、或者观察点本身被约束mask掉了。这里有个关键判断stuck-at coverage损失更多来自结构问题transition coverage损失则大量来自时钟域处理和约束问题。如果stuck-at都到不了98%先别急着调pattern回网表找结构毛病如果stuck-at不错但transition死活上不去重点查capture时钟和复位约束。我见过太多团队用同一套方法处理两类问题结果事倍功半。1.3 先画一张coverage损失地图不要一上来就改约束、插test point。正确的第一步是打开工具的fault report按模块、按fault class、按标准单元类型三个维度各出一张表把最大的损失项排出来。具体做法在顶层跑完一版baseline ATPG后导出所有undetected fault的分布。按层次模块聚合看哪个子模块贡献最多不可测故障再按fault class聚合看uncontrollable和unobservable各自占比最后按单元类型聚合类似AOI、锁存器、三态缓冲器是不是重灾区。三张表交叉着看基本能把问题定位到具体网表区域。这一步花半天时间能帮你避开后面几周的盲目试错。2. 从网表和架构根治coverage损失scan chain、时钟复位和三态总线2.1 scan chain设计对coverage的隐形影响coverage上不去的根因有一大半在scan chain设计阶段就已经注定了。最常见的问题是把不可扫描单元直接挂在chain中间。比如latch、内部存储单元、甚至一些模拟宏的数字旁路逻辑它们没法完成正常的shift操作结果整条链的连续性和可观测性都打折扣。处理方式有两种一是工具自动插入lockup latch把非扫描单元前后隔离二是让逻辑绕过这些单元做成scan-through模式。无论哪种都要在插入后跑chain test确认每条链的shift和capture都干净。我的经验是chain integrity fail导致的coverage损失往往以“大面积不可测”形式出现一个chain fail可能让整条链上几百个fault全部变undetected这种损失靠后端的ATPG优化根本救不回来。链长均衡也是个容易忽视的点。ATPG生成的pattern数受最长chain限制链长差异过大会导致短的链被反复填充无效数据产生大量冗余pattern。虽然这不直接压coverage但会压缩你后续做增量pattern迭代的时间预算——回想一下deadline前的那些深夜你就明白时间也是覆盖率的一部分。2.2 时钟与复位的ATPG视角处理好时钟和复位等于解决了transition coverage的一半问题。在shift阶段所有扫描单元需要跟着移位时钟稳定地串行进出这时候任何不受控的时钟翻转都会污染数据。在capture阶段你需要的是功能时钟精确地打一拍把组合逻辑的响应捕获到扫描单元里。这两个阶段对时钟的要求完全不同ATPG工具靠的是一套精心设置的时钟分组和capture策略约束文件里写错一个clock group就可能让部分时钟在capture时乱翻产生大量误判fault。门控时钟是重灾区。功能模式下为了省电很多模块的时钟是门控的由内部逻辑决定是否放行。如果scan mode下没有把门控时钟的使能信号拉成确定值ATPG仿真时时钟表现为X态该时钟域下所有fault都直接判为不可测。常规做法是在scan_enable有效时强制旁路门控逻辑或者把门控使能接到一个可测试pin上。异步复位和置位同理。功能模式下异步复位很正常但ATPG的shift阶段如果复位一直处于有效状态扫描单元永远被置成同一个值控制和观测全部失效。常见手段是scan_reset统一控制shift阶段mask掉复位capture阶段再按需释放来覆盖复位路径的故障。要特别注意异步复位释放时的毛刺问题处理不好会在capture沿附近产生race不仅影响coverage还可能在真实芯片上造成误判。2.3 三态总线和双向IO的处理三态总线在SoC里遍地都是。ATPG最怕的其实就是多驱动冲突一条总线上多个输出使能同时有效逻辑值直接打架仿真器给X后续逻辑全部失去确定性。处理策略没有太多花哨给总线上的每个output enable信号在scan mode下提供确定的控制方式。要么直接把enable信号接到可控的测试pin上要么通过扫描单元强制它进入确定状态。项目后期如果发现总线相关fault大面积uncontrollable优先检查这一层。双向IO pad的capture模式也很讲究。建议在约束里把所有双向IO在capture阶段统一配成输入模式避免输出驱动和外部测试设备冲突。否则不仅coverage受影响ATE上还可能烧device。这个属于安全红线测试工程师一定会强调。2.4 反馈回路与非扫描数字逻辑组合反馈环对ATPG来说是个噩梦。仿真一旦走进去信号就一直在环里打转永远不会收敛到确定值。常见来源模拟比较器的迟滞逻辑、纯组合的异步握手、以及一些安全机制里的表决逻辑。对待反馈环治本方案是打断它。可以在RTL阶段插入test point或者在环上断开一处让ATPG视作纯组合路径。工具层面也有break loop的选项但自动打断往往选点不理想会对功能路径造成额外约束coverage损失反而更大。我个人的做法是先在网表里把所有组合环筛出来逐个看反馈路径人工决定打断位置工具自动break只作为兜底。锁存器和内部三态缓冲器也归在这一类。锁存器在扫描链上如果没做特殊处理会引入透明窗口导致capture时序不确定。内部三态就更麻烦了它不像IO pad可以在约束层统一mask必须靠网表修改或者插入隔离逻辑解决。3. ATPG约束与pattern生成策略把工具压榨到位3.1 约束文件是最大的杠杆不得不承认ATPG工具的能力边界很大程度取决于你喂给它的约束文件。一个干净、完整的约束文件价值抵得上一个资深DFT工程师好几周的调试时间。一个标准的ATPG约束文件应该覆盖时钟定义和clock group、复位和异步set/reset、primary input和primary output的约束、内部三态和双向IO的处理、以及黑盒和存储器的边界条件。很多人图省事直接把综合时的SDC拿过来给ATPG用这是个非常危险的惯性思维。综合时的false_path和multicycle_path是给时序收敛用的ATPG阶段直接套用可能把原本该测的时序路径mask掉了。比如异步FIFO的跨时钟路径在SDC里通常是false path到了ATPG里如果不做任何处理这些路径上的transition fault全部变成不可测覆盖率立刻掉下来。正确做法是单独维护一份ATPG约束专门定义哪些异步接口要按真实逻辑建模、哪些要特殊处理不要让综合约束直接代管。3.2 向量类型与launch方式的选择ATPG的pattern generation不是只跑basic scan就完事。stuck-at是基础transition delay fault决定at-speed测试能力path delay则针对特定critical path。coverage目标不同pattern结构完全不同。transition fault的生成方式里launch from shift和launch from capture是最核心的分叉。launch from shift用移位时钟的最后一拍直接产生跳变实现简单、约束宽松coverage通常更高但测的其实是shift路径和真实功能路径有偏差。launch from capture用功能时钟的capture沿产生跳变更接近真实时序但对时钟分组、skew、复位释放都有严格要求稍有不慎就大面积over-constraint。我的策略是两种方式都跑分别统计coverage贡献。通常launch from capture为主因为它更接近真实故障launch from shift作为补充把capture方式下测不到但确实可能存在的故障兜住。两种方式都跑完transition coverage能比单跑一种高出几个百分点。3.3 多pass运行策略一次run就想把所有故障榨干是不现实的。不同故障的测试难度差异巨大一套参数很难同时兼顾“快速收敛”和“深度挖掘”。我常用的策略是分三个pass。pass1用标准的abort limit和pattern上限做快速收敛拿到一个包含大量detected fault的基线。pass2专门针对pass1剩余的undetected fault把abort limit调大、pattern数上限放开让工具对每个难测fault多挣扎一会儿。这轮时间开销可能是指数级增长所以通常用fault list限定范围而不是全量再跑一遍。pass3是定向模式从pass2的输出里把仍然undetected但理论上可测的fault捞出来手动指定测试点或临时增加约束后再跑。这个策略看起来笨但比一次性把所有限制调大靠谱得多。全量放开abort limit的结果往往是运行时间爆炸、内存吃满而coverage收益可能只有零点几个百分点。定向挖掘反而更可控。3.4 压缩与覆盖率的平衡test compression是现代DFT的标配TestKompress、DFTMAX这类工具能把pattern数压掉一个数量级。但压缩不是免费的压缩率越高coverage掉得越明显。在我做过的项目里compactor ratio从10调到40pattern数确实少了但coverage损失常常在0.3到0.8个百分点之间。如果项目coverage目标本来就紧张这个损失其实很难接受。建议流程上先跑一版uncompressed的baseline得到理论上限然后逐步加大压缩力度找到pattern数和coverage的拐点。至于拐点在哪每个设计都不一样但一般在压缩率20到30之间开始出现明显收益递减。量产测试时间当然重要但COGS和coverage目标需要放在同一张表上权衡。项目组经常为了省测试时间把压缩拉满等到coverage不达标又来反向优化来回折腾的时间早就把省下的测试时间吃掉了。3.5 增量仿真和迭代闭环coverage优化的本质是个迭代过程。每次修约束、改网表、插test point都要重新验证收益如果每次都全量跑ATPG一天能跑两轮就不错了。增量故障仿真就是干这个的。工具支持只仿真受影响的fault集合修改约束后只重新计算被约束影响的时钟域或模块插入test point后只仿真观察点覆盖的路径。我通常会让脚本自动对比前后两版约束文件自动筛选需要重新仿真的fault list这样每轮迭代从小时级压缩到分钟级。别小看这个效率提升它能让你在一周内尝试的优化方案数量翻倍覆盖率自然就走得更远。4. 存储器、模拟IP与统一DFT流程绕不开的coverage黑洞4.1 存储器黑盒不是免死金牌内嵌SRAM和寄存器堆是ATPG最尴尬的存在。SRAM的内部单元无法通过扫描链直接控制和观测强行跑ATPG只会得到一堆uncontrollable和unobservable的fault。于是很多项目图省事直接把SRAM设成black box。这么做的确让ATPG进程清爽了但注意黑盒化会把memory相关的故障从统计分母里整个拿掉。总故障数10万条其中memory相关2万条黑盒后分母变8万逻辑覆盖率显示99%但真实的memory阵列故障一个都没测到。这种“coverage注水”在交付时很容易被测试团队拆穿。正确的做法是给SRAM配MBISTMemory Built-In Self-Test或者至少用wrapper逻辑把memory包起来。MBIST真正覆盖存储阵列的故障ATPG则负责memory周边的读写控制逻辑。项目在规划coverage目标时应该明确把MBIST的故障覆盖折算到整体指标里而不是让ATPG的report孤零零地代表一切。4.2 模拟IP的数字接口要包一层PLL、DLL、ADC、DAC、LDO这些模拟宏不会出现在扫描链上但它们给数字逻辑的status、lock、ready信号往往是数字域的观测盲区。处理方式很成熟在RTL阶段就给模拟IP包一层digital wrapper把模拟宏的数字接口统一转换成ATPG友好的信号。所谓“ATPG友好”就是接口上的每个信号都能被扫描单元控制和观测模拟内部的具体行为对ATPG完全透明。PLL的lock信号如果直接连到数字逻辑在ATPG仿真里永远是不确定的包装一层寄存器锁存逻辑后lock状态变得可观测后续数字逻辑的测试路径就通了。有些模拟IP内部还有数字状态机这时候光有wrapper还不够需要在wrapper里插入test point把状态机的关键状态引到观测链上。代价是面积和布线资源但相比覆盖率缺口这点代价通常值得。4.3 UDFM和dft flow的衔接价值UDFMUnified DFT Flow Methodology这类统一DFT流程的核心价值不在于某个工具功能多强大而在于它让coverage分析不再滞后。UDFM强调从RTL阶段的dft spec定义、扫描插入、压缩插入到ATPG生成共用一套约束和test mode定义每个阶段都能预览coverage。很多项目都是在综合之后才发现覆盖率上不去这时候网表已经定型改动成本极高。UDFM的做法是把DFT review提前RTL阶段先做可测性分析预估coverage风险扫描插入后立刻跑一版快速ATPG验证扫描结构和约束的一致性压缩插入后再评估压缩带来的coverage损失。整个过程是流水线式的问题越早暴露修复成本越低。我在实际项目里的体感是光有工具流程还不够更关键的是把“coverage是每个阶段的输出”写进checklist而不是让它在ATPG signoff时才第一次出现。这个观念的转变比任何工具升级都能更快地提升最终coverage。5. 一次coverage从96.8%到99.1%的项目复盘5.1 拿到基线报告后的第一件事这个项目的初始数据stuck-at coverage 96.8%目标是99%以上。我接手后的第一周没改任何东西全在分析。把undetected fault按模块汇总后最大的四个损失项逐渐清晰内部三态总线相关故障占总不可测数的35%、异步复位处理不当贡献了22%、两个64KB SRAM黑盒贡献了18%、组合反馈环贡献了10%。剩下15%零散分布在各模块。优先级矩阵立刻出来了三态总线和异步复位是修复成本低、影响面大的项目先做SRAM黑盒需要动BIST周期长并行推进组合反馈环需要分析安全机制逻辑排最后。按这个顺序做每一轮修改都有立竿见影的coverage反馈也方便项目组看到进展。5.2 逐项修复的实际收益第一刀切在三态总线。问题根源是总线输出使能信号使用了内部逻辑控制shift时不受控。通过约束文件把所有OE信号在scan mode下统一置为确定值并增加一个测试pin强制进入非驱动状态。这个修改让stuck-at coverage直接涨了0.7个百分点。第二刀是异步复位。原有约束把所有异步复位都mask掉了虽然仿真干净但复位相关fault全部不可测。改成scan_reset统一控制复位shift时屏蔽、capture时按需释放并在复位释放路径上做了毛刺过滤。这一项贡献了约0.3个百分点。SRAM那边两个64KB SRAM原本是黑盒BIST控制器早就存在但没接入ATPG流程。接入后memory相关故障从黑盒口径转入MBIST口径折算进综合指标后贡献了约0.4个百分点的账面提升更重要的是真实测试能力提高了。组合反馈环处理起来最费劲最后通过插入7个test point打断反馈换来约0.4个百分点。transition coverage也有进展。把launch方式从单一的shift改为capture为主、shift为辅后上涨了约0.2个百分点。最后关闭了压缩力度过大的配置pattern数增加了14%但coverage补回了0.5个百分点。合在一起96.8%到了99.1%。注意这些数字不是简单相加因为有些fault同时受多个问题影响修了一个之后另一个的收益会被吞掉整体是边际递减的。5.3 别只盯着coverage一个数字coverage达标了交付还没结束。pattern数从原来的两万七变成了三万二产测时间拉长了COGS也随之变化。同时要确认修改后的约束文件在STA静态时序分析里没有引入违例尤其是test point插入对布局布线的影响。我们在仿真环境里跑了完整的零故障仿真确认无误又在ATE上做了冒烟测试。这里给一个具体场景三态总线的修改让IO配置变了ATE上的IO电平、负载电容设置都要同步更新测试程序不配套的话芯片在ATE上的表现会非常迷惑。回头复盘最大的感受是coverage不是单一工具或单一角色的产物它是DFT架构、约束管理、工具选型和测试交付的综合结果。越早把这些串起来后期返工就越少。6. 容易被忽略的coverage提升“隐藏水位”6.1 仿真器差异和X态传播同一份网表、同一份pattern在两个主流仿真器里跑出的coverage可能差0.5个百分点。原因在于X态传播规则不同尤其遇到多驱动、未初始化寄存器和异步接口时一个仿真器可能给出确定值另一个给出X并向后传播把一大片逻辑的观测全部挡住。这类问题很难通过改约束彻底解决但有几个项目级的缓解措施统一仿真器选型和精度设置不让team里一部分人用RTL级、另一部分人用gate级结果混着对标在测试bench里对未初始化区域做合理的preset对X态源头比如模拟IP输出加确定性建模。最好在项目启动时就定好这些规则事后追认基本来不及。6.2 test point不是越多越好test point是提升coverage的利器但也是个吃面积和时序的资源消耗品。插入位置不好不光coverage没提升反而因为路径变长导致setup违例。判断test point是否该插我的标准是先看这条路径上fault的测试难度是不是确实由可控性/观测性缺失导致再看影响面积有多大。一个观察点如果能同时覆盖几百条fault值得插只为一条fault插基本不划算。还要考虑布局布线的可实施性跟后端工程师提前打招呼让他们在floorplan阶段给test point预留位置。6.3 跨时钟域逻辑的处理跨时钟域CDC在功能设计里是个大话题在ATPG里同样棘手。异步FIFO的读写指针跨时钟传输在仿真里经常出现X态ATPG工具无法确认capture时刻指针稳定导致相关fault不可测。常见的处理手段有两种一是对CDC同步器做扫描旁路scan bypass让同步器在测试模式下退化成普通寄存器消除跨时钟的不确定性二是给异步FIFO加测试旁路逻辑让capture阶段两个时钟域能够同步合作。无论哪种都需要设计团队提前把CDC模块标注清楚DFT工程师才能在约束里做相应处理临时抱佛脚会发现STA、仿真全都不配合。6.4 顶层合并时coverage掉点block级coverage都很好看一合并到顶层就掉这个问题在大型SoC里尤其常见。掉点的原因通常是顶层互联逻辑和IO约束没有及时传递下去block内部可测的fault到了顶层因为周围逻辑的X态传播而不可测。我惯用的方式是顶层ATPG和block级ATPG共用同一套接口约束block级做DFT分析时就把顶层视角考虑进去。具体做法是在block级跑完后把顶层的IO约束和pad约束导出给block级做一致性检查确保block级认为可控的信号在顶层确实可控。此外顶层专门跑一版针对互联逻辑的pattern把block级漏掉的边界故障补上。最后分享几个实际操作的体会coverage提升这件事我做了这么多年最大的体会是它没有银弹。每一版coverage数字背后都是一堆约束、网表、工具选项和团队协作的综合结果。所谓方法就是把账算清楚、把根因找对、把工具选项系统地跑一遍然后保持迭代的耐心。如果只能带三句话到下一个项目第一口径必须先统一fault coverage和test coverage搞清楚别自欺欺人第二约束文件要单独维护别让综合的SDC代管ATPG第三DFT review往前移越早发现coverage风险修复成本越低。最后再说个小技巧每周固定把coverage报告和约束文件diff一起过一遍很多隐蔽的问题都是这么被提前抓出来的。