做DFT的人,可能都经历过这样一个阶段:项目快要流片了,ATPG覆盖率还挂在92%上不去,领导每周例会都问一句“覆盖率还能不能提”,你一开始觉得是小case,结果各种手段试了一圈,真的就卡死了。这篇内容,我尽量把DFT ATPG提升coverage这件事讲透——从架构、逻辑、ATPG生成、测试点插入到具体案例,把那些能真正把coverage往上拉的方法论和细节,全部摊开讲。文章不会只停留在“跑一下工具、看几眼报告”的层面,而是会告诉你怎么判断瓶颈到底在哪、每一步操作背后的理由是什么,以及我踩过的坑。
1. 先从“覆盖率”这个数字说起:你到底在追什么
1.1 coverage的本质是风险度量,不是KPI
很多工程师把coverage当成一个必须达标的数字,比如99%、99.5%,好像达到了就万事大吉。但DFT的coverage本质上是一个风险度量:它告诉你芯片里的逻辑故障,有多少能被测试向量覆盖到、能在生产测试中被检测出来。剩下的未覆盖部分,不是“不存在风险”,而是“还没被证明是好的”。
这个认知直接决定了你后续的操作思路。比如,当你盯着报告里那1%的未覆盖故障时,你要想的不是“怎么硬凑几个向量把它盖掉”,而是“这部分逻辑为什么测不到、是不是存在设计问题、它在真实应用场景下会不会出问题”。我见过不少团队为了冲99%的覆盖率,硬塞了一堆毫无区分度的测试向量,结果测试时间翻倍,silicon故障检出率却没有本质提升,这就是把风险度量做成了KPI表演。
1.2 先看懂报告:test coverage、fault coverage和DC coverage
ATPG工具的报告里有几个容易混淆的指标:
| 指标 | 定义 | 实际意义 |
|---|---|---|
| Fault Coverage | 检测到的故障数 / 全部故障数(含未测试故障) | 最常用的报告指标 |
| Test Coverage | 检测到的故障数 / (全部故障数 - 未测试故障) | 剔除了不可测故障,更能反映ATPG真实能力 |
| DC Fault Coverage | 动态电流(IDDQ)测试覆盖 | 用于特定缺陷检测,与逻辑覆盖率互补 |
| Statically Untestable | 静态不可测故障 | 通常由冗余逻辑、约束条件造成 |
我建议你重点关注Test Coverage而不是Fault Coverage,因为Fault Coverage会把“不可测”的故障也拉进分母,导致数字偏低。比如说你插了scan chain,但某些异步逻辑没有做constraint,报告显示一堆unobservable故障,Fault Coverage就是99%,可实际上你想知道的是、在正常的可测试条件下,ATPG到底把多少真实故障打出来了。另外,需要在报告里区分两类不可测:stuck-at untestable和delay untestable。前者是逻辑冗余,后者往往涉及时序路径上的约束,两类问题的处理方式完全不同。
1.3 不要把综合后的coverage当成最终结果
还有一个常见误解:用综合网表跑一次ATPG,看到覆盖率差不多就收工了。实际flow里,从综合网表、DFT插入网表到布局布线后的网表,coverge会发生变化。尤其是走线延迟引入的真实时钟树、scan chain重排、时钟门控单元的插入,都会影响最终的ATPG覆盖率。所以业内正常做法是:综合阶段和DFT阶段各跑一些quick pattern做预检,签核阶段的一定要用post-route网表、带真实的时钟树和约束来跑最终覆盖率。否则你在前端看到的百分比,到了后端很可能会掉一截,那时候再回头改DFT架构就非常被动了。
2. 提升coverage的底层逻辑:可控性与可观测性
2.1 coverage本质受限于可控性和可观测性
先打个比方。测试芯片逻辑故障,就像警察在一个迷宫里找一个藏起来的人。scan chain给了你一个监控系统,让你可以从入口把任意状态灌进去(可控性),也可以从出口把任意状态读出来(可观测性)。ATPG的所有算法,本质上就是在解决这两个问题:怎样才能把某个节点设置成目标值,怎样才能把它的响应传出来。
所以提升coverage,永远是两条路:一是提高可控性,让更多逻辑节点能被设置成需要的状态;二是提高可观测性,让更多逻辑节点的响应能被捕获并传出来。很多人在ATPG层面折腾选项,不如先检查一下设计里到底哪些节点“看不见、摸不着”。而这些节点通常就是覆盖率漏洞的核心来源。
2.2 哪些逻辑天然影响可控性和可观测性
根据我的经验,常见的“漏洞点”包括:
- 黑盒(black box)逻辑:比如某些模拟IP接口、未建模的第三方宏单元,它们内部的故障测不到,边界上的逻辑也容易因为无法控制/观察而成为未覆盖。
- Memory和BIST逻辑:大容量SRAM通常用MBIST覆盖,但memory周围的控制逻辑如果不做约束,会拖累周边ATPG coverage。
- 跨时钟域(CDC)逻辑:同步器、脉冲同步等结构如果不做约束,ATPG会报大量unstable或untestable故障。
- 异步复位/置位逻辑:扫描单元如果异步复位没有被properly处理,复位树相关逻辑往往无法观测。
- 多周期路径(Multicycle Path)和false path:约束缺漏会让ATPG生成错误的时序假设,导致transition fault覆盖率异常。
在做任何coverage提升动作之前,先把这些逻辑筛选出来,搞清楚报告的uncoverage分布在哪里,比盲目加pattern重要得多。
2.3 coverage提升的三级火箭:架构、逻辑、ATPG
我习惯把coverage提升手段分为三级:架构级、逻辑级、ATPG级。架构级决定了覆盖率的天花板,比如你scan chain怎么接、时钟怎么处理、memory是不是用了BIST;逻辑级是在设计里加测试点、修冗余逻辑;ATPG级是调整故障模型、约束、向量生成策略。实际项目里,大多数人只用了第三级,也就是在ATPG工具里调参数,结果天花板就在那里,再怎么调也就那样。要做提升,必须先审视前两级。
3. 架构层面:把覆盖率天花板抬高
3.1 scan chain设计对coverage的影响有多大
scan chain的插入方式,直接决定了ATPG工具能把多少逻辑变成“可见”。我做过一个对比实验:同样一个IP,用默认的scan chain插入方式和经过优化的插入方式,覆盖率相差1.5到2个百分点。这不是小数目,尤其在项目要求99%的时候。
核心原则是:尽量让每一条scan chain的路径短而均衡,避免把大量逻辑挂在一条超长链上,否则不仅shift时间变长,ATPG对这条链上的故障观察也会因为链上冲突而受到影响。另外,scan chain的插入要尽量和RTL层次结构匹配。如果你把不同模块的逻辑混在一条链上,物理上可能要跨越很长的走线,ATPG依然能工作,但后端的时序收敛会出问题,最终可能导致不得不删掉部分chain段来修timing,coverage就掉了。
3.2 时钟和复位架构必须先理顺
coverage上不去,很大一部分原因在时钟和复位约束上。ATPG跑起来,工具需要知道每个时序单元在capture phase用什么时钟,在shift phase用什么时钟,时钟之间是否互斥。如果时钟关系没有在SDF文件中完整描述,或者DFT约束没有明确写CTI(Clock Tree Isolation),工具会产生大量的time-set冲突。
比如一个设计里有多组时钟域,ATPG默认会把不相关的时钟当作互相排斥(exclusive)来处理。如果你没有设置正确的clock grouping,工具就无法在同一个pattern里把两个时钟域的数据同时捕获,跨时钟域路径上的transition fault就会被标记为untestable。这类问题的典型特征是:覆盖率报告里有很多“unable to justify”或“constraint”故障,而你进到原理图里一看,路径本身并不复杂。
对异步复位的处理也类似。如果异步复位网络没有在DFT约束里做safe state设定,ATPG会为了满足复位值的初始化而浪费大量pattern,导致整体效率下降。我建议在DFT插入阶段就把所有异步复位强制为“scan mode下可控制”,在功能模式下保持真实复位行为。这个方案稍微有点麻烦,但对coverage的帮助非常明显。
3.3 Memory和黑盒逻辑不要硬扫
内嵌大量SRAM的设计,如果不用MBIST而是硬靠ATPG去扫描每一颗存储单元,coverage不仅低,测试时间还很长。原因很简单:SRAM的内部位线、字线、灵敏放大器不属于标准逻辑,ATPG的stuck-at模型根本描述不了它们的真实缺陷。所以业内通行做法是:memory用MBIST或者BIST controller覆盖,ATPG只覆盖memory周边的glue logic。
做这一步的收益,通常能让整颗芯片的coverage从80%拉到95%。但要注意:MBIST和ATPG之间要做隔离,否则MBIST logic会引入大量不可控的DFT逻辑,反过来拖累ATPG。我见过一个项目,MBIST controller放在了scan chain内部,没有做隔离,结果ATPG跑出来一堆“shadow logic”故障,覆盖率直接掉了4个点,这种问题排查起来特别费时间。
4. ATPG生成层面的调优:把工具的极限逼出来
4.1 故障模型:不要只跑stuck-at
提coverage,不能只盯stuck-at(SA)一种故障模型。现代DFT sign-off通常要求三套覆盖率:SA coverage、Transition Delay Fault(TDF)coverage和Path Delay Fault(PDF)coverage。TDF对高速时序缺陷更敏感,但它的覆盖率通常比SA低5到10个百分点,原因在于TDF需要对每个节点产生“上跳/下跳”两个事件,对时序约束和低频路径特别敏感。
如果你发现TDF coverage一直上不去,先检查SDF时序信息是否完整。很多TDF故障被判定为untestable,是因为工具的时序引擎发现目标路径上的时间太紧,无法满足setup/hold条件。另一个典型原因是时钟混合策略问题。TDF测试需要在capture pulse上做精确控制,多时钟域之间的交互处理不当会让工具选择保守策略,把大量跨时钟域路径排除在外。
4.2 动态压缩与pattern限制的平衡
ATPG生成过程中,工具会做动态压缩(dynamic compaction),想办法让一条pattern覆盖更多的故障。压缩率越高,pattern越少,测试时间越短,但同时可能牺牲一些可测故障的覆盖。这里的核心矛盾是:你既要coverage高,又不想测试成本爆炸,但测试成本在sign-off里是实打实的指标。
我的建议是:分两轮跑。第一轮用默认压缩,快速看一下coverage在哪个水位;第二轮针对覆盖率薄弱区域,关掉或者降低压缩率,生成专门的target pattern去补那些默认压缩丢失的故障。当然,也可以打开工具提供的“fault group”或“fault list optimization”功能,让工具优先处理那些对覆盖率影响最大的故障,而不是无差别地压缩。
4.3 ATPG选项和constraint的合理设置
ATPG选项里面有几个对coverage影响很大的设置,值得你逐个过一遍:
set_atpg -capture_phase相关设置:决定TDF pattern的capture方式,是launch from shift还是launch from capture,不同方式对时序要求不同,覆盖率结果也不同。set_atpg -abort_limit:ATPG对某个故障尝试的算法不收敛时,会“abort”掉它。这个abort limit设得太小,会过早放弃困难故障,导致coverage低;设得太大,会让run time暴涨,收益却不明显。通常从32开始试,根据情况调整到64、128。set_atpg -max_backtrace:后端回溯深度,影响对困难故障的求解能力。set_dft -include_non_scan:是否允许ATPG使用非扫描单元做约束。如果你不开启,一些无扫面功能的锁存器会变成黑盒,周边逻辑覆盖不上;开启之后工具能更大范围地做状态推理,但需要后端配合时序收敛。
这些选项调整起来非常花时间,一个合理的做法是建一个标准的option regression脚本,在多个benchmark block上跑一遍对比,而不是在某个模块上碰运气。
4.4 多模式ATPG:Shift、Capture和Slow/Fast模式
很多团队忽略了ATPG的模式组合。比如,有的故障在slow shift阶段可测,有的故障必须在fast capture阶段才能暴露,而有的故障需要把芯片置于特定power模式或test模式才能被激活。合理设置多模式组合,能把某些“方案性不可测”的故障变成可测。
典型的例子是低功耗设计里的power gating。如果你在ATPG阶段只跑正常power模式,那些处于常开域和可控关断域边界上的逻辑,会有大量故障因为isolation cell处于disable状态而不可测。这时候,搭配一个isolation测试模式或power-aware ATPG模式,覆盖率能提升1%左右。这种收益在逻辑规模越大的设计上越明显。
5. 测试点插入:对待疑难故障的最终手段
5.1 什么时候才应该上test point
Test point(测试点)是在设计里额外插入的DFT逻辑,目的是提高某些特定节点的可控性或可观测性。它不是默认选项,因为会带来面积、功耗和时序的开销。但当你发现coverage距离目标只差1到2个百分点,而且瓶颈集中在少数几个fanout极高或深度很深的逻辑锥时,test point就是性价比最高的手段。
判断标准我一般看三个参数:不可测故障数量、故障背后的根节点数量,以及这些根节点是否集中在某些宏单元/硬核周围。如果不可测故障有几百个但分散在几千个节点上,test point的效果就不明显;如果几百个故障都汇聚在同一个控制信号上,插一个观测点可能就解决一大半。
5.2 Test Point的分类与选择策略
Test point大体分三类:
- 可控性测试点(Control Point):把某个内部节点强制设置为0或1,绕开上游复杂的逻辑锥。适合那些因为上游约束导致无法置位的节点。
- 可观测性测试点(Observe Point):把某个内部节点的值连接到scan chain的观测端,让ATPG可以直接观察它的故障。适合那些下游拥塞、故障无法传播到主输出的节点。
- 混合测试点:同时提供控制和观察能力,面积开销更大,但在某些场景效果最好。
选择时考虑优先级:先解决可控性还是可观测性,取决于报告里fault的根因分类。如果故障大量报“unable to justify”,说明可控性不足,优先加control point;如果报“fault not observed”,说明传播路径断裂,优先加observe point。另外,test point不要太靠近时钟或异步控制端口,否则容易在测试模式下引入毛刺风险,ATPG跑出来的pattern在silicon上误触发。
5.3 Test Point插入后的时序和面积影响
Test point不是白给的。一个简单的control point由几个逻辑门组成,但放在关键路径上可能让时序slack变差几十ps。面积方面,比如一颗500万门的SoC,通常加1000到2000个test point还不至于让后端太难过;但如果为了冲99.9%的覆盖率而加太多,封装面积和布线资源压力就会显现。
在实际项目中,我会按照覆盖率目标倒推允许的最大test point数量。比如当前覆盖率是97.5%,目标是99%,那说明有大约1.5个百分点的缺口。在一个200万故障的设计里,这对应约3万个故障。根据经验,一个控制点大概能救下几十到几百个故障,一个观测点通常能救下几百个。按这个粗略估算,大约需要200到300个测试点才可能补上缺口。这个量级,通常不会对布局布线造成致命影响,比较可控。
5.4 工具如何自动推荐test point
我常用的EDA工具(例如Mentor Tessent、Synopsys DFTMAX)都有自动test point插入功能。Tessent里叫“Test Point Insertion(TPI)”,DFTMAX里也有类似流程,比如“Test Point Auto-Insertion”。使用前先跑一遍完整ATPG,生成coverage和fault report;工具会基于uncoverage fault自动分析候选点,并按预计覆盖率收益排序。你可以设定一个目标coverage,工具会选出最少的test point组合。
但我不建议全盘接受工具的推荐。工具选点往往偏乐观,没有充分考虑物理布局。比较稳妥的做法是:让工具推荐一批候选点,你再按模块、时序裕量过滤一遍,删掉那些位于关键路径上的点。这样既能保证覆盖率收益,又不会给后端带来太多麻烦。
6. 实战案例:一个82%卡壳设计怎么折腾到99.1%
6.1 项目背景和初始状态
这个项目是一个中高复杂度的SoC,包含MCU子系统、DSP子系统和大量的SRAM,规模在千万门级别。最初的ATPG结果只有82%的stuck-at coverage,离项目目标99%差得很远,而且TDF coverage连75%都不到。由于项目已经到中后期,RTL改动空间非常有限,所以我只能在DFT架构和ATPG层面做文章。
初始诊断阶段,我把fault report按模块归类,发现覆盖率最差的是DSP子系统中的两个部分:一个是异步FIFO接口,另一个是时钟门控阵列之后的组合逻辑。这两个区域贡献了将近一半的未覆盖故障。
6.2 第一轮优化:约束和时钟关系的修正
第一轮我不急着加test point,而是先清理约束。通过检查工具报出的类别,我发现异步FIFO接口附近出现了大量“unstable”故障。原因在于FIFO两端时钟域不同步,默认ATPG把两个时钟当成完全互斥,导致很多跨域信号无法在同一个pattern内被驱动和捕获。
解决办法是在DFT约束里定义一组虚拟异步时钟关系,让工具在生成pattern时允许跨时钟域信号在满足一定条件的情况下被观察和比较。同时,我把异步FIFO的内部存储单元设成“memory element”,让ATPG不再试图把FIFO内部的每一位当作普通触发器来处理,而是看作一个存储器。只这一步,stuck-at coverage提升到了89%。
6.3 第二轮优化:时钟门控和ICG的透明化处理
剩下的未覆盖故障,相当一部分集中在时钟门控单元(ICG)附近。ATPG默认处理ICG时,会把它当成一个普通门电路,而ICG内部其实有latche和与门结构,时序行为有时会给ATPG的自动推理带来困扰。
处理方法是在DFT约束里把ICG设置为透明(transparent),让工具在shift和capture阶段都认为ICG是直接导通状态。配合在scan chain端加上必要的lockup latch,避免shift期间ICG的时钟沿出现毛刺。这轮优化后,stuck-at coverage从89%上升到96%,TDF coverage也从75%提高到85%。
6.4 第三轮优化:Memory BIST隔离和测试点
96%之后,再往上走就是硬仗了。我把剩余未覆盖的故障拉出来逐个分析,发现其中约60%是MBIST controller自身的逻辑。这部分逻辑在function mode下由BIST状态机控制,ATPG的默认约束不知道BIST状态的合法取值,导致大量故障被标记为不可测。
解决方式是给MBIST controller加一组测试模式的约束,让ATPG知道在scan test mode下,BIST状态机可以被preload成任意合法状态,从而把controller内部的逻辑变为可测。这一下又拉高了约1.2个百分点,达到97.2%。
但距离99%还差一点。此时我开始启用test point插入。工具自动推荐了400多个候选点,我做了整理后保留了280个,剔除了位于关键时序路径上的点。插入后重跑了综合、DFT和ATPG,coverage提升到了98.9%。最后再补了一轮transition pattern的专门优化,以及让ATPG针对那些被abort的故障单独加大回溯深度,最终stuck-at coverage稳定在99.1%,TDF coverage在93%左右,达到了项目的sign-off标准。
7. 常见问题与排查技巧实录
7.1 高频问题速查表
| 现象 | 可能的根因 | 排查方法 |
|---|---|---|
| coverage卡在90%以下上不去 | 大量黑盒/存储器直接挂在扫描链上 | 检查black box设置,确认memory是否有BIST |
| 报告里大面积unstable故障 | 跨时钟域路径没有定义异步关系 | 检查clock group设置,补充异步约束 |
| transition coverage异常偏低 | SDF不完整或CAPTURE策略错误 | 确认timing lib和SDF加载是否完整,检查capture clock设置 |
| shift期间出现大量violation | scan chain上lockup不足、时钟沿竞争 | 检查ICG透明化处理和lockup插入情况 |
| coverage前一轮98%,后一轮变97% | 综合或后端网表更新后约束未同步 | 检查DFT constraint文件和timing lib的版本一致性 |
| abort故障数量特别多 | backtrace深度或abort limit设置过低 | 适当调大abort limit,结合regression对比效果 |
7.2 工具报告里的“水分”识别
ATPG报告里的coverage数字,有时会掩盖真实问题。比如有些工具默认会把某些黑盒边界的故障从分母中剔除,导致覆盖率“数学上”很高,但实际测试能力不足。所以不能只看百分比,还要同时看pattern数量、fault count、test coverage与fault coverage的差值。如果两者差距超过2个百分点,说明有大量故障被认为是“不可测”的,这些不可测故障才是你下一步要重点分析的。
还有一种情况是,工具为了满足某些过于严格的约束,自动把大量故障标为“redundant”。这种标注背后,可能是test mode下某个信号被强制为0,导致一长串逻辑不可测。遇到这类问题,就需要排查约束本身是否合理,而不是接受工具的判断。比如,某条power-down信号在测试模式下的取值,未必非要和功能模式一致,放宽之后覆盖率可能立刻上升。
7.3 那些年我踩过的坑
第一个坑:为了追求覆盖率,把ATPG的abort limit调得非常大,结果跑了三天三夜没跑完,而且覆盖率并没有提升多少。后来才意识到,abort limit只是工具内部求解器的尝试上限,真正让覆盖率上不去的是逻辑本身不可测,而不是工具不够努力。所以现在我的做法是:先用默认参数快速跑一遍,再用工具诊断不可测故障的分布,而不是盲目加运算时间。
第二个坑:在一颗有低功耗单元的设计上做ATPG,忘了设置isolation cell的测试模式。结果覆盖率始终在85%徘徊,报告里大量节点显示“not observable”。后来才发现,那些隔离单元在测试模式下默认是关闭的,隔断了信号通路。加上对应的约束之后,覆盖率马上回升。这个坑尤其在带power domain的设计里容易遇到,提醒项目里只要有level shifter、isolation cell和power switch,DFT约束里一定要先定义它们的测试行为。
第三个坑:在跑TDF coverage时,为了修timing,把某些路径设成了false path,结果ATPG自动把这些路径上的所有transition故障都当作不测。后来我用路径延迟分析工具看清楚,这些“false path”在测试模式下其实是可以满足时序的,于是把false path约束改为仅在功能模式有效。TDF coverage一下子提升了4个百分点。
7.4 一个不太常见但很有用的技巧:按fault类型拆分回归
很多团队的回归只看一个总覆盖率,问题数出来了再一股脑去debug。我后来养成一个习惯:按故障类型、模块、时域把coverage拆开看,比如单独看DSP子系统的stuck-at coverage和MCU子系统的TDF coverage。拆分之后,很多瓶颈会浮出水面——有些模块卡在可控性不足,有些模块卡在可观测性不足,解决策略完全不同。
另外,每次改完约束或网表,我都建议重新生成一次coverage report做对比。你可以用脚本自动解析报告里的Test Coverage和Uncollapsed Fault Count,并生成环比趋势。这样能及时发现回归,不用等下一步接手的同事来抱怨。
根据我个人的实操经验,DFT ATPG coverage的提升,从来不是某一个技巧的胜利,而是一个系统性的排查、优化循环。每一次把覆盖率往上拉一个点,背后都是对设计约束、时钟架构、ATPG算法和物理实现的一次更深入理解。希望这篇内容能让你少走一些弯路,至少在你下一次卡在99%门槛前,能有一套可以按顺序操作的方法在手边。