做芯片测试这行,最焦虑的时刻之一就是覆盖率报表出来那一眼。我刚接一个 MCU 类 SoC 项目的时候,纯 LBIST 跑完,stuck-at 覆盖率卡在 87.3%,工艺厂 spec 卡在 95%;切到纯 TestKompress(咱们圈里习惯叫 TK)压缩向量,覆盖率倒是能拉上去,但 ATE 上的 pattern memory 直接见底,多 site 并行测试铺不开,测试时间成本压不下来。后来在 Tessent Shell 里把 LBIST 和 TK 打通成 Hybrid 流程,才真正找到平衡点。
这篇文章把整套方案讲透:两种模式为什么需要混合、Tessent Shell 里怎么搭、覆盖率怎么一步步调到合格、仿真和量产阶段会遇到哪些坑。给还在 TK/LBIST 割裂着用的 DFT 同行一个可以直接参考的落地思路。
1. 先摸清 TK 和 LBIST 各自的脾气:为什么单打独斗会吃亏
1.1 同为扫描测试,底层逻辑完全不同
TK 的本质是确定性测试。ATPG 工具拿到网表后,针对具体的 stuck-at、transition fault 反推激励序列,保证每个目标故障都能被激活并观察到。它的强项是覆盖率可控、可诊断定位,但代价是向量量不小,必须在 ATE 或外部存储里放测试数据,哪怕有 EDT 压缩,几十万条 pattern 也是常见的事。
LBIST 是另一条路线。Tessent 在芯片内部搭建 PRPG 产生伪随机向量,灌进扫描链,再用 MISR 把响应压成签名。它几乎不占 ATE 存储,几百条指令就能在板级或者系统级自检跑起来。但伪随机就是伪随机,对某些难测故障(大扇出控制信号、长组合链、依赖特定状态的时序逻辑)经常撞不上。
这两种模式的差异,用一张表看更直观:
| 对比维度 | TestKompress(TK) | LBIST |
|---|---|---|
| 向量来源 | ATPG 确定性生成 | PRPG 片上伪随机 |
| 测试数据存储 | 需要 ATE/外部存储 | 几乎不需要,片上生成 |
| 覆盖率上限 | 高,可定向补测 | 相对低,依赖随机命中率 |
| 测试时间 | 由 pattern 量决定 | 周期数固定,通常更快 |
| 系统级/在线测试 | 不适用 | 非常适合 |
| 故障定位能力 | 可诊断到扫描链/单元 | 只有签名比对,定位弱 |
1.2 分开用的问题:覆盖率天花板与测试成本失控
纯 LBIST 做中低端 MCU 还有戏,但到了车规、AI 加速这类对缺陷率要求极高的芯片,几乎撑不住。我见过一个项目,LBIST 跑满 8192 个伪随机周期,stuck-at 覆盖率还是卡在 89% 左右。原因是设计里有几个大状态机,状态组合多,伪随机序列很难同时把状态寄存器和输出条件打到位。你想靠加周期硬磨,边际收益非常低,5000 周期之后覆盖率基本不怎么动。
纯 TK 的问题不在覆盖率,在成本。压缩比做到 100:1 已经很可观,但一个 300 万门的设计,全速 transition 向量一般还得几万条。ATE 测试时间 = pattern 深度 × 周期时间 × 站点数,这里面每一项都是真金白银。更麻烦的是,很多产品要支持板级和系统级自检,TK 的向量不可能全搬到系统里,这个时候没有 LBIST 就很被动。
1.3 Hybrid 的本质:共用扫描链,按需切换
所谓 Hybrid,并不是两套 DFT 结构堆在一起各测各的,而是在 Tessent Shell 里把两条路打通:同一组扫描链,既接到 TK 的 EDT 压缩/解压逻辑上,也能在 LBIST 模式下由 PRPG 直接驱动。通过 TAP 指令或测试控制寄存器切换模式。
流片之后,你可以在 ATE 上先跑 LBIST 快速筛一遍,再用 TK 的高覆盖确定性向量补残差;出厂之后,系统板卡还能周期性地调用 LBIST 做现场自检。两条腿走路,覆盖面、成本、可测试性都能照顾到。
2. Tessent Shell 搭 Hybrid 流程:从网表到 pattern 的完整链路
2.1 插入前准备:库、网表、黑盒与复位策略
Tessent Shell 是一个 Tcl 驱动的环境,第一步是喂数据。综合后门级网表、标准单元库的 function 模型(不是 timing lib,是仿真用的 Verilog/VHDL model)、UPF 功耗意图(如果设计有多电源域)、以及所有模拟 IP 和 SRAM 的真值模型。
这一步最容易被忽略的,是黑盒(black box)的定义。模拟 IP、未加密的 third-party hard macro,如果你不想让工具尝试推逻辑,就需要明确设成黑盒。否则 DFTCompile 阶段工具会对黑盒输出产生一堆约束,后面 LBIST 的 X 态处理也会跟着出问题。
复位策略要在插入前想清楚:LBIST 启动时要求所有时序单元处于已知状态,否则 MISR 在 warm-up 阶段就会被未知值污染,签名永远比对不上。所以设计里必须有测试模式下的全局复位通路,或者能保证 scan reset 覆盖所有 FF。我一般会在这一步写进 DFT spec,不让后端后期再来补。
2.2 配置骨架:把 EDT、LBIST 控制器挂到同一组扫描链上
下面是我们项目里用的精简配置骨架,命令名在不同 Tessent 版本里会有差异,但核心要告诉工具的“物理对象”是这几样:扫描链、EDT 通道、PRPG/MISR、控制寄存器。
# 读入综合后网表与标准单元库 read_verilog top_synthesis.v read_library tsmc28hpc_ss.lib # 定义混合测试模式 add_test_mode "hybrid_tk_lbist" # 扫描链基础结构 add_scan_chains -name chain0 \ -in top/chain0_in -out top/chain0_out -length 256 add_scan_chains -name chain1 \ -in top/chain1_in -out top/chain1_out -length 256 # TK 侧:EDT compressor/decompressor add_edt -compressor top/edt_comp \ -decompressor top/edt_decomp \ -channels 16 -ratio 50 # LBIST 侧:PRPG/MISR 与 phase shifter add_lbist -prpg top/prpg -misr top/misr -phase_shift 256 insert_dft实际做的时候,扫描链数量、长度、EDT 通道数都要根据设计规模和测试机台通道数来定。EDT 的 compression ratio 取决于你能接受的 pattern 数量和扫描链平衡程度。LBIST 侧的关键是 phase shifter 的设计,它决定伪随机序列喂给各条扫描链时会不会产生强相关性,相关性一旦严重,覆盖率就会莫名其妙地塌一块。
2.3 生成 LBIST 与 TK pattern,并完成仿真签核
insert_dft 之后,不要急着直接生成 pattern。先verify_dft确认扫描链 shift/capture 通路没有 violation,再看测试控制寄存器的连接是否符合预期。这一步能省后面大量 debug 时间。
LBIST 的 pattern 在 Tessent 里通常以 pattern set 或 do 文件形式生成,指定运行周期数、warm-up 周期、seed 值。TK 侧则是generate_patterns(或等价命令)跑确定性的 stuck-at 和 transition 向量。
之后要做门级仿真签核。我的习惯分两步:第一轮跑 unit delay 仿真(忽略时序),只验证逻辑功能、模式切换、MISR 签名是否正确;第二轮再上 SDF 做带时序的仿真,重点看 at-speed pattern 有没有 setup/hold 问题。顺序不要反,不然一轮时序仿真跑下来,报错太多根本分不清是逻辑错了还是时序错了。
2.4 时钟约束里最容易被忽略的两个细节
Hybrid 流程的时钟约束比单一模式要复杂,因为同一套逻辑要服务两套测试架构。第一个坑是测试时钟与 capture 时钟的约束分离。LBIST 自测时钟通常是内部 PLL/divider 产生的低频时钟,TK 的 at-speed 向量则可能由 ATE 直接给高频时钟。在 Tessent Shell 里要把这两种时钟域分开定义,否则插入 DFT 时工具可能生成不合理的 mux 逻辑,测试模式下时序那叫一个乱。
第二个坑是 scan enable 与功能时钟的组合环路。工具一般会查,但你的 RTL 里如果有 latch 或者 gating clock,容易漏掉。我的经验是插入前把时钟门控单元的 enable 信号单独检查一遍,凡是被 scan_enable 影响且又反馈回时钟路径的组合逻辑,都必须提前处理。
3. 覆盖率从 87.3% 到 97.2%:一次 Hybrid 调优实录
3.1 拿到覆盖率报告先看什么
Tessent 的覆盖率报告一出来,很多人只盯着最终百分比,这是不对的。要把 fault class 拆开看。拿我们当时的报告举例(数字做了脱敏,量级类似):
| Fault Class | Count | 占比 |
|---|---|---|
| Detected | 1234567 | 87.3% |
| Undetectable | 12700 | 0.9% |
| Undetected | 156789 | 11.1% |
| Total faults | 1415101 | 100% |
这里面的关键是:Undetectable 很大一部分是约束、冗余逻辑造成的,不算真正的欠账;真正要追的是 Undetected 里那些分类为可测但没测到的故障。我会把 Undetected 的故障按模板块和扫描链两个维度聚类,一般很快就能看出来是哪几个模块在拖后腿。
3.2 三个投入产出比最高的优化动作
按照从省力到费力的顺序,我一般依次做三件事:
第一,清理 X 态和约束。黑盒输出没有 bound、某些信号在测试模式下没有被正确约束,都会导致工具把大片故障标记为 not observable,覆盖率被系统性吃掉。把 SRAM、模拟 IP 的输出用 X-bounding cell 钳到固定值之后,经常一次能涨 2 到 3 个百分点。
第二,插 test point。在小规模特定区域增加 observe point 和 control point,让难测的节点变得可控可观察。但 test point 要钱要面积,不能全芯片乱插,我都是根据故障聚类报告,只挑硬骨头区域加。
第三,上 Hybrid 补测。LBIST 伪随机覆盖不了的残差故障,切换到 TK 生成 deterministic 向量定向攻击。这一步是 Hybrid 流程的精髓所在。
项目里最终的数据是:纯 LBIST 跑到 87.3%,清理完 X 态和约束之后到 90.1%,加了一批 test point 后到 92.4%,最后靠 TK 的确定性向量把 stuck-at 补到 97.2%,transition 也到了 89.4%。这个覆盖率对于量产已经够用,而且测试时间没有失控。
3.3 覆盖率数据怎么合并才靠谱(VCS/Questa/ModelSim)
如果你在验证阶段想用 VCS 做 gate-level 仿真,顺带看额外的 toggle/cond coverage,可以这样跑:
vcs -sverilog +vcs+coverage+on -cm line+tgl+cond+branch -f filelist.f -l comp.log ./simv -cm line+tgl+cond+branch -l sim.log urg -dir simv.vdb -format text -report coverage_report多个用例或者多核并发跑批之后,合并覆盖率数据库要注意不是简单叠加文件内容。VCS 下用urg -dir simv1.vdb simv2.vdb -merge final.vdb合并;Questa/ModelSim 环境则是vcover merge all.ucdb test1.ucdb test2.ucdb。
这里提醒一句:如果有人把每份报告的 txt 导出之后用 Excel 手工求和,赶紧劝住。不同 run 的 hierarchy 深度、模块实例路径拼接规则可能不一致,求和出来的数字根本没有物理意义。还有一些团队把 LBIST 和 TK 的覆盖率分开统计,最后要交给客户的是合并后整个 Hybrid 策略的整体覆盖率,中间要对齐的是“测试对象是不是同一份网表、同一个测试模式集合”,这个语境不统一,合并数字就失真。
4. 仿真跑不通、签名对不上:Hybrid 流程踩坑全记录
4.1 复位不彻底,签名在 warm-up 就被污染
第一个坑来自复位。LBIST 跑起来之后,PRPG 开始往扫描链灌向量,MISR 同步压缩响应。如果某个寄存器的初值在启动前是 X,这个 X 会顺着观察逻辑进入 MISR,从此以后的每个周期签名都带着这个未知数,仿真和芯片实测一定对不上。
我们当时查了两天才定位到:一个异步 FIFO 的读指针寄存器没有被 scan reset 覆盖,LBIST 启动时它还是 X。解决办法是在测试控制序列里加一段全局 reset 指令,确保 LBIST 运行前所有 FF 都进入确定态。排查技巧:仿真波形里看 MISR 输入端,在 warm-up 周期结束后是否还是 X,如果是,顺着 X 的传播路径倒追来源。
4.2 黑盒 X 态漏进 MISR,覆盖率被系统性地吃掉
第二个坑是黑盒输出的 X 态。芯片里总有几个 SRAM 编译器的行为模型,或者第三方的模拟 IP,仿真时输出经常是 X。这些 X 一旦进入扫描链,传到 MISR 里就会让签名报废。为了避免这个问题,工具通常会自动把相关观察窗口 mask 掉,结果就是被测区域的所有故障全部变成 not observed,覆盖率报表上表现为一整块模块的检测数异常低。
处理办法是提前给黑盒输出加钳位逻辑,也就是 X-bounding cell。在 DFT 插入阶段,通过约束把黑盒输出在测试模式下强制拉到 0 或 1。如果你不想额外加面积,还有一个折中:用 LBIST 的 observe enable 机制,只在确定安全的周期窗口开启观察。但这种方式配置起来麻烦,而且对 TK 模式帮助不大,我建议还是老老实实做钳位。
4.3 at-speed 波形与内部 PLL 组合的坑
Transition fault 测试要求 at-speed 的 launch/capture 时序。我们的设计里既有内部 PLL,又有外部时钟输入。最初 TK 的 transition pattern 在 SDF 仿真里报了海量 violation,一查发现是测试模式下 PLL 没有配置成 reference clock,内部分频逻辑在 capture 沿附近翻转,把 setup 全毁了。
解决思路分两步:第一,明确 launch 和 capture 时钟到底用内部还是外部,不要混着用;第二,在 Tessent Shell 的时钟约束里把 PLL 的 lock 过程、分频关系完全建模进去。经验是先在 unit delay 仿真里确认逻辑和波形控制是对的,再上 SDF。如果直接拿 SDF 结果去调 pattern generator,你会把逻辑问题和时序问题搅在一起,调试周期至少翻倍。
4.4 扫描链平衡与 EDT 压缩率之间的 trade-off
Hybrid 流程对扫描链的平衡要求比纯 TK 更苛刻。扫描链长度如果差异很大,EDT 的压缩效率会被最长链卡住,因为每条 pattern 的深度由最长扫描链决定。而 LBIST 模式下,扫描链长度差异还会影响 PRPG 伪随机序列的均匀分布,某些链太长导致扫描深度大,故障激活概率被稀释。
我经历过一次:为了后端布局方便,有一条链被拉得很长,TK 的 compression ratio 报出来只有 60:1,而设计本身按 100:1 规划。后来和后端协商,把寄存器重排,让几条链长度更均衡,压缩比才回到 90:1 以上。建议在做 scan chain 规划时就把 Hybrid 需求告诉后端,别等 pattern 生成阶段才发现链长失衡。
5. 流片之后:Hybrid 策略在 ATE 与系统级测试中的部署思路
5.1 量产测试程序的常见排序
流片回来,量产测试程序的排序其实有讲究。我的习惯是:
- 连接性/漏电测试:先确认管脚没有短路、漏电在规格内;
- LBIST 快速自检:几百到几千个周期跑完,能做到几十毫秒内给出一个“有没有大问题”的粗判;
- TK 的 stuck-at 压缩向量:覆盖大部分逻辑缺陷;
- TK 的 at-speed transition 向量:抓时序相关缺陷;
- 其他 IP 的专用 BIST:比如 SRAM 的 MBIST。
这个顺序的好处是:一旦 LBIST 挂了,后续所有测试都不用跑,直接判废,省了 ATE 时间。LBIST 几乎不占 pattern memory,对高并行度测试特别友好,多 site 同时跑的时候优势非常明显。
5.2 LBIST 做自检,TK 做诊断,各干各的活
LBIST 的最大短板是没有故障定位能力。MISR 签名不匹配,只说明芯片有毛病,但毛病在哪一条扫描链、哪一个逻辑锥里,完全不知道。所以线上策略我一般这样设计:LBIST 作为系统级和板级自检手段,负责日常健康监控;一旦 ATE 上发现签名错误,马上切到 TK 的诊断模式,生成专门用于故障定位的 pattern,通过 fail log 做 diagnosis,把嫌疑逻辑缩小到具体单元。
从测试覆盖率体系来看,这两者也不是替代关系。LBIST 提供的是一个快速、低成本的基线覆盖,TK 负责把覆盖率拉到 spec 级别,并承担可诊断性这个关键职责。混合流程的价值就在于,你不需要为了高覆盖率牺牲系统自检能力。
5.3 我坚持的一个验证习惯
最后分享一个我踩过不少坑之后形成的习惯:每次 Hybrid 配置有改动,我会先单独跑一遍纯 LBIST,再单独跑一遍纯 TK,两边签名都对了,才去跑 Hybrid 的交叉切换用例。否则一旦混合模式出问题,很容易搞不清是控制器切换逻辑坏了,还是两边各自的 pattern 本身有 bug。这个顺序看着笨,但能帮你少熬好几个通宵。