做DFT时间久了你会发现,ATPG跑完、pattern生成出来,只是万里长征走完一半。真正的分水岭在Verify Test Pattern这一步——测试向量到底能不能在仿真器里原样跑通,能不能交给ATE工程师直接上机台,全靠这一关把关。很多刚接触Tessent的人不太重视这个环节,以为create_patterns之后coverage达标就万事大吉,结果把STIL文件交出去之后,才发现要么仿真器编译不过,要么波形里一片X态,要么在tester cycle下都违反时序。今天就把这块掰开讲清楚:从Tessent ATPG的verify流程、常见踩坑,到怎么把这一环做扎实。
Tessent ATPG这套工具本身不复杂,复杂的是把pattern从工具里导出来以后,整个链条的各种细节:库模型对不对、时序文件全不全、STIL格式转换时的位序有没有反、波形定义跟ATE是否兼容。Verify Test Pattern恰恰就是把这些问题集中暴露出来的阶段。这篇文章我会从原理讲到实操,再配合我实际踩过的坑,尽量让刚上手的工程师少走弯路。
1. Verify Test Pattern是什么,它到底在验证什么
1.1 生成pattern不等于可用pattern
ATPG工具生成测试向量时,内部有一套自己的“理想假设”。它假设扫描链连接正确、时钟沿干净、tester周期内信号能稳定建立、响应能在一个明确的时刻被捕获。但在真实环境里,pattern要跑在ATE或者仿真器里,面对的是具体的波形定义、信号沿、建立保持时间、驱动能力、库单元延迟这些物理因素。
这么说吧,ATPG生成的pattern像是一个剧本,但剧本写好了不代表戏能直接上台。Verify Test Pattern就像是彩排,把剧本放到真实的“舞台”——也就是仿真模型和tester时序——上去演一遍,看能不能完整走下来。彩排之前没人知道哪天哪个信号会掉链子。
我之前在一个项目上就吃过亏:ATPG生成阶段coverage漂亮得很,报告上98%的stuck coverage,结果STIL文件丢给测试工程师后,对方在机台上怎么跑都fail。后来在仿真器里复现,才发现是pattern里scan_enable的时序沿跟capture时钟沿贴得太近,在波形上差了一个很小的余量,多数corner下会有竞争。这种问题不在Verify环节专门跑一遍,根本不暴露。
1.2 Verify到底在验证哪几个层面
我理解Verify Test Pattern主要验证三层东西,分别对应了pattern能不能跑的三个前提。
第一是逻辑正确性。pattern施加到扫描链上之后,每个cycle期望的响应和实际仿真的响应是不是一致。这个层面出问题,通常说明pattern生成的设置或者网表转换过程中有错误,比如扫描链顺序反了、位序对不上、故障模型选错。
第二是时序有效性。tester周期里信号能不能稳定建立和保持,从ATE的角度看,就是shifter、capture这些动作在给定的时钟沿和使能信号沿之间能不能不发生竞争。这一层最容易在带有SDF反标的仿真里暴露问题,也跟Tessent里设置的tester timing参数直接相关。
第三是可判定性。响应当中不能有X态,否则测试机台无法判断芯片是好是坏。X态可能来自未初始化寄存器、三态总线、memory模型输出,或者异步信号没处理好。
很多时候工程师只看第一层,也就是pass/fail。但真正决定pattern能不能稳定量产的是第二层和第三层。Verify的意义在于,不只是告诉你“这个pattern逻辑对不对”,而是告诉你“这个pattern在指定的tester时序下能不能可靠判定”。
1.3 不认真做的代价有多大
不Verify的代价,很少有人算过这笔账。如果pattern直接到ATE上验证,一次试错差不多占用几个小时机时。稍微复杂一点的芯片,pattern集动辄几十万条。在机器上发现一串fails,你得反过来差到底是芯片本身坏了、还是PCB连接问题、还是pattern本身有毛病。机台调试不像仿真器,你能拉出的信息非常有限,经常只能用datelog和波形倒查,非常痛苦。
更麻烦的是,ATE fail和芯片好坏混在一起的时候,你没法跟测试工程师说清楚边界。我见过最典型的情况就是:DFT这边说pattern’s clean,测试那边说机台就是跑不过。两边来回推,最后发现是STIL的tester spec文件里有一根tristate pin定义不一致,导致机台在比较窗口读到的是高阻态。这种问题,如果提前在verify环境里跑一遍并对比ATE波形,十分钟就能看出来,根本不用扯皮半天。
1.4 这个话题适合谁来关注
如果你是DFT工程师、ATPG流程的所有者、芯片测试工程师,或者刚转行做数字芯片验证但搞不清scan pattern原理的人,这篇内容都能给你一个完整的视角。DFT工程师关注它,是因为verify是交付前的最后一关,出了问题最先被追责的就是你。测试工程师关注它,是因为理解了Tessent的pattern时序定义,才懂得拿到手后怎么换算成机台波形。验证工程师关注它,是因为许多X态、race问题同样会出现在功能仿真里,处理思路是相通的。
2. 动手前必须理清的三件事:库模型、时序模型与Pattern格式
2.1 库模型:verify的基石
我第一次做Tessent ATPG时,以为库模型就是综合用的那个.lib,后来发现完全不是一回事。Verify Test Pattern需要的是用于仿真的模型,通常是Verilog或者VHDL格式,包含单元的行为描述和时序引脚定义。Foundry会把这些模型跟.lib一起打包交付,但很多人直接忽略,到了verify阶段才发现缺文件。
需要重点确认的是:库模型和综合库之间的一致性。ATPG工具在生成pattern时,会用综合库做逻辑映射。而verify仿真时,仿真器用的是behavioral model。如果这两个模型对某一个cell的功能描述不一致,比如某个cell的复位极性搞反,或者某个UDP原语的X态传播行为不同,就会出现“工具里看着对,仿真里一堆X”的现象。
实操中还有一个麻烦是加密模型。很多厂商的库模型是加密过的,扩展名可能是.vp或者被工具加密过的变体。这时候你必须确认Tessent安装里的仿真器版本支持对应加密格式,以及encrypted model的license feature有没有开起来。否则编译阶段就会报一堆module not found,或者莫名其妙的parse error。
我的建议是:专门维护一个verify用库清单。上面写清楚当前项目用到的库文件路径、格式、加密状态、需要open哪些macro定义。否则换一个工艺节点、换一个库版本的时候,verify环境经常因为库文件混用而出怪毛病。
2.2 时序模型:tester timing和SDF的取舍
Verify Test Pattern里的“时序”来自两个地方。一个是Tessent处理pattern时使用的tester timing,也就是waveform定义,比如时钟周期、沿的位置、scan_enable的建立和释放时间。另一个是你给仿真器反标的SDF,也就是门级延迟信息。
在Tessent ATPG流程里,tester timing一般会通过DRC和波形定义文件带入。你需要在ATPG设置里把周期、时钟沿这些定义写清楚,导出的STIL才会带上正确的waveform。STIL文件里有一个WFT(WaveformFunctionalTiming? 准确说是Waveform timing)区块,这里描述的就是ATE每个cycle里信号怎么拉高拉低、什么时候比较响应。
至于SDF反标,我个人的经验是分层处理。早期功能正确性验证,不反标或者用unit delay跑,速度快、问题收敛快。等pattern基本稳定了,再做一次带SDF的full timing verify,去抓那些只有库延迟叠加之后才会出现的race和hold问题。带SDF的仿真通常慢十倍以上,但这一遍不能省,尤其对于老工艺下多约束、多corner的设计。
还有一个容易忽略的点:Tessent里面生成的pattern,有时候会包含所谓的“danger”信息,比如某些cycle里工具会覆盖掉tester timing的默认值,写上warning。这种warning不要无视,它通常意味着该处信号变化窗口非常紧张,verify阶段要重点看。
2.3 Pattern格式选择:为什么verify优先用STIL
Tessent ATPG可以导出多种pattern格式,常见的有STIL、WGL、VCD和内部格式。每个格式适合的场景不一样。
STIL是IEEE标准格式,最大的优点是把pattern和tester波形定义放在同一个文件里。仿真器或者ATE拿到STIL,理论上不需要额外信息就能跑。这也是为什么业界verify和交付通常首选STIL。WGL更多是老一代工具遗留的格式,需要转换到STIL或者专用仿真testbench,否则很多现代仿真器不认识。VCD主要用于调试,能直观看到信号波形,但它不带tester时序,不适合直接作为交付格式。
如果你从Tessent输出STIL,注意检查它是否包含了完整的signal list和scan chain定义。有些项目里IP block只输出了partial pattern,STIL里缺了其他block的信号,拿到集成环境里验证时会报“signal not found”。
另外一个小技巧:如果集成环境里已经有别的工具生成的testbench,不要把STIL强行拼进去。宁可让Tessent直接生成一个干净完整的STIL,再通过仿真器的STIL编译流程转testbench,这样等价性可控。
2.4 顺带说一句MBIST和SSN
最近网上“tessent mbist”、“tessent ssn”这些词很热,其实MBIST、SSN和ATPG属于Tessent体系里不同的domain。MBIST主要负责memory测试pattern,SSN(Streaming Scan Network)主要是解决多tester通道下scan压缩的问题。它们的验证思路跟ATPG的Verify Test Pattern是相通的,都是要把pattern放到跟最终使用环境一致的地方去跑一遍。只是MBIST更关注memory model的初始化、内建时序;SSN更关注压缩网络里面的scan channel映射和tester channel约束。这些后续有机会单独展开,今天先聚焦在ATPG的verify上。
3. Verify Test Pattern完整实操流程
3.1 实操之前的输入文件检查
一套完整的Tessent ATPG到Verify流程,开始前你要确保手头有这些文件。
第一是gate-level网表,这个不用多说,一定是做完scan insertion之后、带扫描链信息的网表。第二是库文件,既包括综合库,也包括2.1里说的仿真模型库。第三是DRC rule deck或者约束文件,Tessent里通常会有一个专门的dofile或者constraints文件,定义了时钟、复位、扫描链信息。第四是你希望使用的pattern格式和tester timing定义。
检查完这些,建议先跑一个最小DNI(Do Nothing? 实际上可以跑一个最小test pattern)来验证环境本身是通的。比如只生成一两条pattern,导出STIL,再在verify环境里跑通。这个“hello world”看起来浪费几分钟,实则可以省掉后面几百分钟的debug时间。环境配错是最隐蔽的坑,越早发现越好。
3.2 Tessent ATPG生成pattern的命令流程
下面是一个典型Tessent Shell流程的示意,只写主流程,具体命令在不同版本可能略有差异。
# 读入门级网表 read_verilog ../netlist/chip_scan.v # 读入库模型(注意这里是综合/仿真用的库,根据工具要求) read_verilog ../lib/slow_vt.v # ... 其他库文件 # 建立scan和时钟约束 set_current_design chip # 假设以前已经定义好了scan chains、clock signals # 运行DRC run_drc # 添加故障并生成pattern add_faults -class stuck create_patterns -class stuck -effort high # 查看覆盖率 report_patterns # 导出用于验证的STIL文件 write_patterns ../verify/chip_verify.stil -format stil每一条命令跑的时候都要留意log里的warning。比如run_drc之后,如果有DRC violation,说明扫描结构或者约束设置有问题,这时候强行往下走生成的pattern大概率在verify阶段出乱子。add_faults之后如果fault number为零,那就不是pattern的问题,是你的故障库设置和网表不匹配。write_patterns之后,务必打开STIL文件第一页,确认文件头部的signal名跟网表端口对得上。
我个人的习惯是,write_patterns之后再跑一个report_patterns -summary,把pattern数量和覆盖率都记录下来。这样verify阶段如果修改过约束或者库,重新生成pattern之后可以快速对比,看覆盖率是不是回归了。
3.3 从STIL到仿真testbench
STIL本身不是仿真器直接认得的东西,你要么用Tessent自带的verify功能,让它自动调用仿真器做仿真;要么在外部仿真器里通过STIL编译器/转换工具,把STIL转成仿真的testbench。两种方式各有适用场景。
Tessent自带verify流程的优点是方便,工具会帮你把STIL、网表、库和仿真选项组合起来,一键跑。缺点是出问题的时候内部封装太厚,log信息不够直观,你得花时间从海量日志里找有效信息。外部仿真器自己搭testbench的优点是透明,你可以完全控制编译选项、后处理、波形dump,一旦失败定位起来很快。
如果是用VCS或者Xcelium这类主流仿真器,通常流程是这样:先把STIL文件通过STIL编译器转换成带tester波形的testbench,或者直接由工具生成一个testbench wrapper,然后跟门级网表和库模型一起编译仿真。仿真器会施加pattern中的激励,比对期望响应,最后报告pass/fail。
我自己更倾向于在早期用外部仿真器搭一个固定testbench模板。因为做DFT debug的时候,你最需要的不是“方便”,而是能随时拉出任意pin的波形、快速定位到出错的cycle。外部仿真器在这方面的灵活性无可替代。Tessent自带流程适合量产环境里的回归验证,两者可以共存,但至少要有一个是你能完全掌控的。
3.4 仿真执行与结果判定
假设我们已经在VCS里把testbench和环境搭好了,运行结束后怎么判断verify是否通过?最简单的方法是在仿真log里搜索“pass”或者“fail”,但更可靠的是看比较器报告。一般testbench会在每个pattern结束或者整个pattern set结束后打印一行总结信息,告诉你failure数量、violation数量、以及出错的cycle和pin。
一个典型的失败log可能是这样:
Error: Testbench mismatch at cycle 127, pin D[3], expected 1, actual 0看到这种日志后,先不要慌。下一步是在波形里打开cycle 127附近所有相关的信号,包括scan_enable、clock、scan_in、以及D[3]的驱动源。绝大多数情况,你会在波形里看到一个X态或者一个沿附近的竞争窗口。
如果仿真在比较差的环境中没有做SDF反标,那么像“expected 1, actual 0”这种错误,优先怀疑逻辑问题,比如扫描链的test pattern bit顺序不一致。如果带了SDF,那么优先怀疑时序问题,比如某个组合逻辑路径延迟过大,导致capture窗口采到旧值。
3.5 一个真实例:STIL位序错误导致的verify失败
这个坑我印象太深了。那是一个小规模芯片,整个scan chain大约两万多个scan cell,stuck coverage不错,Tessent里run_drc和create_patterns都正常。结果第一次verify,一整条扫描链的数据全部mismatch,从第一个scan cell开始就错。
我当时第一反应是扫描链定义是不是反了。检查了dofile里的scan chain定义,方向没问题。又检查了STIL文件,发现STIL中scan_in的bit顺序跟Tessent内部模拟结果一致。直到我把波形里的scan_in数据和某个scan cell的输出放在一起对比,才发现它从某一位开始整体往后偏了一位。
这个“偏一位”不是巧合,是因为Tessent导出STIL时,我用了某个库cell的scan cell输出名称后缀作为映射,而实际网表里扫描链的最后一级有一个额外的单元,导致exclusive cell的数目差了一。最后验证方案是重新检查了netlist里scan chain的完整extent,然后在ATPG设置里显式指定了扫描链的终点。verify立刻通过。
这个例子想说明的是:verify失败时,不要惯性认为是pattern生成的问题,回头查一下扫描链定义、库映射和STIL位序,往往更快。
4. 高频问题与排查技巧实录
4.1 X态传播:verify的第一大杀手
X态可能是Verify Test Pattern里遇到最多的拦路虎。X态一旦出现,不仅该cycle比较会失败,还会顺着组合逻辑一路传播,导致后面一大片的响应都无法判定。
X态来源通常有几个:异步复位没有初始化、memory读端口输出X、三态总线没有pull-up/pull-down、某些cell在特定输入组合下的行为未定义。ATPG工具一般会通过初始化和约束尽量压制X态,但仿真器跟工具对X态的处理语义不完全一致,经常会出现“工具觉得是0,仿真器跑出来是X”的情况。
处理X态,我常用的排查路径是:先在waveform里找到第一个出现X的位置,顺着往下追它的源头。如果source是一个memory模型,检查该memory的初始化流程有没有在pattern最开始执行;如果source是一个DFF,检查它的复位端口是不是在仿真开始时拉到了复位态;如果source来自三态总线,检查总线两边是否有tristate buffer同时开启,造成总线冲突变成X。
有时候实在处理不掉,Tessent也有办法,比如插入额外的control point或者初始化序列。但这些都是治标,最好还是把根因找到。
4.2 竞争与冒险类的timing violation
跟X态不同,时序violation更多出现在带SDF反标的仿真里。现象通常是仿真log里出现“Timing violation”警告,紧接着后面某几个cycle就开始mismatch。这类问题本质是:pattern里的某个信号变化沿跟采样沿之间,余量小到在库延迟下已经满足不了setup/hold要求。
最典型的是scan_enable信号。很多设计里scan_enable从ATE进入芯片后经过一段数字缓冲器,延迟可能跟时钟树不完全对齐。如果在tester waveform里scan_enable的下降沿跟capture时钟的上升沿设置得太近,那么在仿真里就可能会在这个点产生race。
这种问题的处理思路有两条:一条是修改tester waveform,把scan_enable的变化沿往前移,增加余量。另一条是在Tessent设置里加额外的约束,让工具在生成pattern时就知道这个三角形窗口,为后续的capture留出足够的裕度。具体用哪种,取决于你的ATE实际支持能力。记住一个原则:尽量让pattern在宽松的时序下也constantly通过,这样的pattern上机台后稳定性最高。
4.3 编译与库相关的坑
verify环境里最耗时的往往不是仿真本身,而是编译阶段的报错。常见问题包括:库文件路径不对导致module not found、define宏没open导致某个cell的行为模型没加载、加密库版本跟仿真器不兼容、文件列表里同时包含了两个版本的库导致重定义冲突。
处理这类问题有一个稳当的办法:准备一个小规模的smoke test,只含少数几个标准单元和一个简单的scan chain,确保整个编译链路是通的。每次换库、换仿真器版本、换Tessent版本之后,先跑smoke test再跑真实项目。我见过太多人为了省这几分钟,结果花了几十分钟在一个“库没加载”的问题上反复试错。
编译阶段还有一种情况:仿真器跟Tessent对Verilog的某些语法支持不完全一致,尤其是一些旧版UDP原语或者隐式wire声明。这类问题很难直接从报错里看出因果,基本要靠经验。如果你遇到“library testbench has syntax error”这类提示,优先怀疑是不是库模型文件太旧,跟新仿真器不兼容。
4.4 verify通过但ATE上仍然fail
这个场景最让人头疼,因为从DFT角度来看“我已经验证过了”,但测试端就是不认。实际上pattern验证通过只能说明pattern本身的逻辑和时序在仿真环境里是正确的,不能保证ATE硬件、PCB走线、socket接触等方面没有引入新的问题。
遇到这种情况,我一般会先做一次波形级对比:把ATE的datelog或者捕获到的实际波形,跟verify仿真产生的期望波形放在同一个时间轴上对比。重点看几个地方:tristate pin的实际电平、比较高低的设置、tester period内的信号毛刺、以及scan_enable的实际沿跟仿真假设的沿差多少。
如果ATE波形和仿真波形大体一致,那就不是pattern问题,应该去查硬件通道和电平转换。如果ATE波形跟仿真波形差得很远,那就需要回头确认STIL文件里的waveform定义是否跟ATE的pattern form真的有对应关系。很多问题出在STIL到ATE格式转换过程中,比如waveform character表被改了,或者比较窗口的算法不同。
4.5 高频问题速查表
| 现象 | 可能原因 | 处理建议 |
|---|---|---|
| 仿真log里大量“mismatch at cycle ...” | 扫描链位序、STIL位序、库模型不一致 | 比对波形,检查scan chain定义和STIL信号映射 |
| 从某个cycle开始全是X | 存储器未初始化、异步复位未拉起 | 检查初始化序列和复位约束 |
| 只有带SDF时才出现violation | 时序窗口余量不足 | 调整tester waveform,增加race margin |
| 编译阶段module not found | 库路径、加密库、define缺失 | 用smoke test验证编译链路 |
| verify通过但ATE fail | 机台波形、比较窗口或硬件连接差异 | 波形级对比ATE与仿真波形 |
| 覆盖率跟预期差很多 | 故障模型或约束设置不完整 | 检查fault list和DRC约束 |
这张表算是把最常见的几类问题都覆盖了,但实际项目里总能混合出新的组合。真正遇到的时候别慌,按“先看log、再看波形、最后改设置”的顺序一步步来,大部分问题都能在半个小时内定位到根因。
4.6 调试工具与日志习惯
最后聊一个很实在的话题:调试Verify Test Pattern时,日志和波形怎么留。我的习惯是,每次仿真跑完,至少保留三样东西:完整的仿真log、fsdb/vpd波形、以及被测图案的STIL文件。三者缺一不可。仿真log用来快速定位第一个异常点;波形用来追踪信号级别的因果关系;STIL文件用来核对pattern本身的生成条件和覆盖目标。
日志命名上,我会把pattern文件版本号、库版本号、是否带SDF、跑在哪个corner这些信息拼进文件名里。比如verify_ss_0p81v_125c_stil_r12。这样每次回归或者回溯老问题,一眼就知道当时跑的是什么环境。缺少这个习惯的话,一天跑几十个case下来,极容易把不同环境的log弄混,debug时找错了对应关系,纯粹浪费时间。
Tessent自带流程里通常也会生成log,但我还是会额外dump一份testbench侧的log,方便跟工具侧log对比。两边都看,才能分清楚问题是出在pattern生成阶段还是仿真阶段。
5. 一些收尾心得
做Tessent ATPG这几年,我越来越觉得Verify Test Pattern是整个ATPG流程里最需要“敬畏心”的一环。很多人把它当成一个可选项,觉得生成完pattern点一下verify按钮就算完事了。但真实项目里,决定你交付质量的往往不是coverage数字多漂亮,而是这堆pattern能不能在仿真、ATE、量产三个层面都稳定跑过。
我个人现在做项目的固定套路是:先花20分钟把verify环境基座打牢,库、模板、脚本都固定好;然后每次迭代,先跑unit delay版本的verify,确认逻辑正确性;确认切换后,再跑一次带SDF的full timing verify;最后导出STIL,挂到外部仿真器里,做一次与ATE波形完全对齐的“模拟机台仿真”。这套流程看起来繁琐,但每次都帮我挡掉了不少隐藏问题。
如果在读这篇文章的你正准备做自己的第一个Tessent ATPG项目,我的建议很简单:别跳过verify,也别迷信工具自动生成的报告。去认真看一次波形,手动追一条scan chain的shift数据,亲手把X态根源找出来。这个过程会让你对pattern的理解上升一个台阶,远远比多跑几个pattern提升0.1%覆盖率更有价值。