芯片设计里有个很反直觉的现象:存储器面积占了SoC的一半以上,但测试它的方式却和普通逻辑“不一样”。你要是不给SRAM、DRAM单独设计一套自测试机制,上量之后良率问题能把整个项目拖垮。这就是MBIST存在的意义——Memory Built-In Self-Test,存储器内建自测试。我最早接触MBIST是从一片流片回来的MCU开始的,芯片整体功能正常,唯独内部SRAM在高温下读写出错,用ATE直接灌向量测又死活复现不出来。后来才意识到,存储器的故障模型和逻辑门完全不同,必须靠芯片内置的测试电路自己去跑算法,才能既保证覆盖度又压住测试成本。
这篇文章是PATR1,先把原理层面的东西彻底讲透:为什么存储器要单独特测、MBIST的四个核心模块怎么协同、March算法一族到底在测什么、从RTL到量产的完整落地链条,以及Tessent MBIST这类工具在工程化中需要做的关键决策。后面有空再写PATR2,专门聊修复方案和更多实战Debug案例。
1. 芯片里存储器越来越多,测试压力从哪来
1.1 功能测试为什么兜不住存储器的坏
很多人第一反应是:芯片里不都有CPU吗,让CPU用普通读写指令把存储器遍历一遍不就行了?道理上没错,功能测试确实能暴露一部分存储器故障,但放到量产环境里完全不现实。
问题在于三个层面。第一,功能测试需要CPU执行指令,一条读写指令背后有取指、译码、地址计算、Cache命中等一系列开销,速度很慢。一颗带几兆SRAM的芯片,指令级遍历要跑到秒级甚至几十秒,而量产测试中一颗芯片的总测试时间通常压在几毫秒到几十毫秒量级,否则测试机台成本根本压不住。第二,功能测试的故障覆盖率不可量化,你跑了一遍读写,但并不知道哪些故障模型被覆盖了、哪些没覆盖,DFT工程师最怕的就是这种“测了但说不清测了什么”的测试。第三,很多存储器故障只有在特定地址顺序、特定数据背景、特定操作序列下才会暴露,功能程序很难做到这种精细控制。
MBIST的思路则是直接把测试逻辑做到芯片里:一个专门的状态机,按照固化好的算法产生地址、数据、读写控制信号,直接对存储器发起测试,再把读回来的数据做比对。整个过程不依赖CPU,速度快一个数量级以上,而且算法确定之后,每种故障模型覆盖了多少是可以静态算清楚的。
1.2 故障模型:MBIST要抓的“坏”到底长什么样
想理解MBIST为什么这样设计,先得理解存储器会怎么坏。故障模型是测试算法设计的基准,下面这几个是整个行业反复验证后提炼出来的核心故障类型。
固定型故障(Stuck-At Fault, SAF):某个存储单元或某条位线永远读成0或永远读成1,相当于物理上被“焊死”在了某个电平。这是最经典的故障模型。
转换故障(Transition Fault, TF):单元无法完成0→1或1→0的翻转。比如某单元能写0也能写1,但理论上应该在时钟沿完成跳变,实际跳变过程慢到跟不上时序,读出来还是旧值。
耦合故障(Coupling Fault, CF):两个单元之间发生干扰。给某个单元(耦合单元aggressor)写入一个跳变时,会导致另一个单元(受害单元victim)被意外翻转。随着工艺线宽缩小、存储器密度提升,这类故障越来越常见。
地址译码故障(Address Decoder Fault, AF):地址译码逻辑出错,导致访问单元A时实际选中相邻单元B,或者一个地址同时选中多个单元。这类故障靠功能测试很难定位,但March算法对它有系统性的覆盖。
邻接干扰故障(Neighbor Pattern Sensitive Fault, NPSF):某个单元的值会受到周围单元特定数据组合的影响,属于更高阶的干扰模型。
正是因为故障类型这么多、行为又复杂,MBIST本身才不能只是简单做“写0读0、写1读1”,而是要设计一套有序的读写序列,让各种故障都能被规律性地刺激出来、观察出来。这个序列就是后面要讲的March算法。
2. MBIST架构拆解:四个模块各干一件事
2.1 控制器和模式生成器怎么配合出向量
从数字电路的角度看,一个完整的MBIST逻辑由四个部分构成:BIST控制器(BIST Controller)、测试模式生成器(Test Pattern Generator, TPG)、响应分析器(Response Analyzer)、以及存储器接口隔离逻辑(BIST Collar)。
BIST控制器是整个测试的大脑,负责状态流转。它接收来自外部的启动信号(通常通过JTAG/TAP接口下发),然后依据算法状态机的设计,把“初始化工位”“读某一地址”“写另一地址”“改变地址方向”“结束比对”这些状态逐一展开。它同时管着时钟和复位的处理:测试模式下的时钟可能与功能模式不同源,复位释放时机也必须精确控制,否则后面全部白跑。
TPG严格来说不是一个独立的随机数发生器,在大多数MBIST实现里,它和控制器合在一起,按算法需要产生地址序列、数据背景和读写使能信号。比如March算法里要求“从地址0递增遍历到地址N,在每个地址先读再写反”,TPG就得按时序给出对应的地址增量和数据翻转。这个“按序产生”的特性决定了MBIST测试是确定性测试,不是随机测,覆盖率可以精确计算。
2.2 响应分析与比对:MISR和比较器的取舍
读回来的数据怎么判断对不对?最简单的方式是每个周期都把读数据与期望值做逐位比较,一旦不相等立刻拉高fail标志。这种方式叫即时比较,优点是定位精确——fail的这个时刻对应的地址就是坏单元,但缺点是期望值生成逻辑复杂,而且对高速接口来说,组合逻辑路径上的比较延时会成为限制因素。
更工程化的做法是先把响应数据做压缩,再用压缩后的签名(signature)做比对。最经典的压缩器是MISR(Multiple-Input Signature Register),本质上是一组多输入的LFSR/CRC类寄存器。每个周期把存储器的读数据异或进MISR,最终测试结束后MISR里的值就是整个测试过程的签名,和仿真阶段算好的期望签名比对即可。
MISR的好处是逻辑开销小、对速度敏感度低,缺点是它只告诉你“整体过没过”,不告诉你具体哪一个单元坏了。所以工程上通常两种方案混合:先用MISR做整块存储器的快速pass/fail判定,如果fail了再进入一种降级模式,用逐地址比较去定位具体坏点。Tessent MBIST工具里也有类似的配置选项,可以根据项目需求选择故障字典(fail log)的详细程度。
2.3 存储器接口隔离:BIST Collar的作用
MBIST要访问存储器,但又不能影响功能路径的正常工作。设计上必须有一个隔离层,把MBIST的数据、地址、控制信号与功能信号通过MUX选择器连接起来。这个隔离层就是BIST Collar。
测试模式下,Collar让存储器端口全部从MBIST逻辑取数;功能模式下,Collar恢复原始信号通路。Collar还承担着处理存储器时钟门控、写使能时序、输出使能延迟等细节问题。很多刚接触MBIST的工程师会低估Collar设计的复杂度——存储器的时钟沿采样特性、读写时序要求在不同foundry工艺下差异很大,Collar里的时序约束写不对,测试时看到的fail就是假的,跟芯片真实缺陷毫无关系。这块后面在实测环节会专门展开。
3. March算法:为什么测试程序几乎是它的天下
3.1 March算法记法和执行逻辑
March算法的基本思想就是:用一条确定性的读写序列,按照指定的地址顺序(递增、递减或任意方向),把存储器完整走一遍或多遍。每走完一遍,就能覆盖一类或几类故障。它在存储器测试领域地位极高,因为实现简单、覆盖率可分析、执行时间可控,从20世纪70年代被提出到现在,所有商用MBIST工具的默认算法几乎都跑在March家族上。
March算法有一套简写记法,看懂了这套记法,算法本身就不神秘。比如March C-可以写成:
{⇕(w0); ⇑(r0,w1); ⇑(r1,w0); ⇓(r0,w1); ⇓(r1,w0); ⇕(r0)}
每个花括号内的分号分隔一个“March元素”。元素里的⇕、⇑、⇓表示地址方向:⇕表示地址可增可减,⇑表示必须递增,⇓表示必须递减。括号内是操作序列,r0代表读且期望为0,w1代表写1。例如⇑(r0,w1)的意思是“从地址0开始向高地址方向遍历,每个地址先读一次期望看到0,然后写入1”。
关键点来了:方向为什么重要?因为很多耦合故障只会在特定地址顺序下被激发出来。你从低地址往高地址走,和从高地址往低地址走,同一个单元受到的干扰模式是不同的。所以March算法里方向不能乱设计,每一种方向的取舍背后都有故障覆盖率的考量。
3.2 主流March算法对照:选型要看故障覆盖和代价
行业内常用的March算法有好几个变体,它们之间的差异本质上是“故障覆盖的增加”和“测试时间、逻辑开销的上升”之间的权衡。
March C是最基础的经典算法,操作数为13N(N为存储单元数)。它能覆盖固定故障、转换故障、地址译码故障以及大多数非链接耦合故障。March C-在其基础上删掉了一个冗余读操作,操作数降到10N,覆盖能力与March C相当,但速度更快,因此成为绝大多数设计默认选择的基线算法。
March SS是为检测链接耦合故障(linked CF)设计的。所谓链接故障,就是一次写操作既扰动了邻居A,同时又被另一个邻居B影响,这类故障用March C-不一定能稳定测出来。March SS把操作数提升到22N,逻辑也更复杂,通常只在存储器可靠性要求特别高的场合(比如车载、航天级)才启用。
March LR针对读/写干扰型故障优化,操作数与March SS接近。下面这张表可以快速对比:
| 算法 | 操作数 | 主要覆盖故障 | 相对成本 |
|---|---|---|---|
| March C | 13N | SAF, TF, AF, 基本CF | 低 |
| March C- | 10N | SAF, TF, AF, 基本CF,比C少一个冗余读 | 最低 |
| March LR | 14N左右 | 读/写干扰型故障 | 中 |
| March SS | 22N | 在C-基础上加链接耦合故障 | 高 |
实际项目里我的习惯是:默认先用March C-,跑完整测试后如果发现良率薄弱点与存储器相关,再开更大强度的March算法做A/B对比,用数据决定要不要把更强算法纳入量产。一来就上March SS,逻辑面积和测试功耗都多花不少,但良率未必有提升,没必要因噎废食。
3.3 测试时间估算:一个例子算给你看
测试时间是MBIST方案选型的硬指标。我们拿一个典型场景估算一下。
假设一颗芯片里有一块1Mbit的SRAM,按March C-算法,需要10N次存储器操作,也就是10,485,760次读写。假设存储器BIST时钟是100MHz,一次读写操作需要一个周期,那么单块存储器的测试时间是104,857,600ns,约0.1秒。
单看0.1秒似乎不慢,但芯片里往往不止一块存储器。一颗中等规模的SoC可能集成数十块大小不一的SRAM,如果串行测试,时间会线性叠加到数秒。这时候就必须考虑并行度:让多块存储器的BIST控制器同时跑,测试时间取决于最大那块存储器,而不是所有存储器的总和。但并行度提高又带来瞬时功耗上升和芯片引脚分配的问题,这就是第5章要展开讲的工程权衡。
4. 从RTL到量产,MBIST的完整落地链条
4.1 集成阶段:Collar和控制器是怎么绑上去的
原理清楚了,实际做项目时第一件事是在RTL阶段把MBIST逻辑“接”到每个存储器实例上。手工编写工作量太大且容易错,业界一般用工具自动生成。Tessent MBIST的典型流程是:先通过内存编译器的配置解析出每个存储器的端口属性、位宽、深度、时钟域,然后在Tessent Shell环境里用脚本定义测试策略,工具自动生成对应的BIST控制器、Collar逻辑以及顶层接口。
一个容易忽略的点:存储器IP的端口命名和时钟极性。不同foundry的SRAM IP,读时钟沿可能不同,有的在上升沿有效,有的在下降沿。这些信息必须通过.lib或.v模型传给工具,工具才能生成正确的时序约束。如果这里配错,仿真阶段就全红,但更糟的是某些异步端口的握手时序问题在仿真里未必完全暴露,容易留到芯片回来之后才爆发。
4.2 验证阶段:不注入故障的验证都是自欺欺人
RTL集成完成后,需要做功能仿真验证。很多团队只跑happy path:启动BIST、等finish信号拉高、去比对签名是否一致。这远远不够。MBIST毕竟是测试专用逻辑,如果它在仿真里从来没试过“抓到故障”,你怎么知道它对真实故障敏感?
正确的验证方式是在仿真模型里做故障注入。常见做法是修改存储器行为模型的某个bit位,强制让它出现stuck-at或转换故障,然后重跑BIST仿真,检查fail信号是否按预期拉高、签名是否与黄金签名不一致。Tessent的工具链支持这类故障注入流程,也可以手动在testbench里反标。不要嫌这一步麻烦——我见过不止一次,因为集成时地址总线有一根在Collar里被错接,导致所有仿真签名都对,但芯片回来功能全挂的惨案。故障注入的目的正是确认“测试逻辑本身会正确地报错”,而不仅仅是“好芯片能通过”。
4.3 芯片测试阶段:ATE怎么把MBIST叫醒
芯片流片回来后,测试机台(ATE)通过JTAG接口唤醒芯片内部的MBIST。具体来说,ATE往TAP控制器里移位送入一条操作码,这条操作码对应MBIST模块的USER指令。进入测试模式后,ATE给BIST控制器一个启动脉冲,控制器按算法跑完所有存储器,把pass/fail结果锁存到一个可由JTAG读回的寄存器里,再拉高finish标志。
ATE只需要做两件事:下发指令、读回结果。中间大量数据流都在芯片内部完成,不需要几百上千根测试引脚同时灌数据,这也是MBIST相比外部测试最大的成本优势——它把测试向量原来占用的机台存储深度和带宽开销整个省掉了。
量产环境下还会通过压缩测试程序、复用同一套向量做多站点并行测试等方法进一步降低单芯片测试成本。MBIST的引入,本质上就是用芯片面积换测试时间,用DFT逻辑的面积代价换取可观的量产成本下降和测试覆盖率提升。
4.4 修复扩展:从测试到BISR/RAS
如果芯片里存在冗余行/列,MBIST可以从“只测”升级为“测试+修复”。修复机制叫做BISR(Built-In Self-Repair)。原理是BIST先跑一遍全测试,发现故障地址后不直接fail,而是把故障地址记入非易失存储区(eFuse/OTP),启动阶段通过重定向地址映射把故障行/列替换成冗余行/列。这样原本要报废的芯片变成良品,良率收益非常可观。
但要注意BISR不是免费的:冗余存储器的面积开销、地址重映射逻辑、eFuse编程时间、测试流程的复杂度都会上升。是否引入修复机制,需要从芯片的失效分布去判断——如果失效主因是随机缺陷且集中在少数行/列,BISR效果显著;如果失效是系统性故障,BISR帮不上太多忙。车规、工规这些可靠性要求高的场景更愿意在这块加大投入。
5. Tessent MBIST这类工具落地时的关键选择
5.1 Tessent流程里最重要的几个决策点
Tessent MBIST是目前行业应用最广泛的商用MBIST解决方案(原Mentor产品线,现在属于Siemens EDA),它把从RTL集成到ATE向量生成的全链路工具化。我的经验里,用Tessent做MBIST有几个决策点直接决定项目成败。
第一个是存储器的分组策略。Tessent允许把多个存储器实例绑定到同一个BIST控制器下,也可以每个存储器独立控制器。绑定在一起的好处是控制器数量减少、面积节省、并行的存储器共享同一套算法逻辑;坏处是任何一个存储器测试过程中出现fail,整个组都会被标记fail,后续定位需要额外诊断流程。我的建议是:同一时钟域、同一读写时序类型的存储器放一组;跨时钟域的必须分开。
第二个是控制接口选取。Tessent支持通过标准TAP(IEEE 1149.1)运行MBIST,也支持通过IEEE 1500或自定义接口触发。绝大多数项目用TAP就够,但如果芯片有额外的安全岛(safety island)需求,可能要走独立的测试控制通道,这时就要在项目早期把接口选型定下来,否则后期加接口意味着大量逻辑改动。
第三个是签名的锁定方式。Tessent会在测试图形生成阶段算出期望签名,并把签名固化到测试程序里。假如存储器端口位宽有36位,其中4位是ECC校验位,MBIST跑的时候要不要连ECC位一起翻?Tessent里需要明确配置数据掩码(data mask)策略。不同项目对ECC的处理方式差异很大,有的测试时绕过ECC直接测原始存储阵列,有的则把ECC逻辑纳入测试。工具本身不替你决定,必须由DFT工程师根据产品需求去配置。
5.2 并行度与测试时间的权衡
并行度是MBIST功耗与时间博弈的核心旋钮。Tessent脚本里允许指定多个BIST控制器同时运行,也可以限制同一时刻最多跑多少个控制器。并行度越高,总测试时间越短,但意味着测试期间芯片内的开关活动率(toggle rate)急剧上升。
存储器大量翻转数据线和位线,瞬时功耗很容易冲到功能模式的数倍。如果你的芯片封装和供电网络撑不住这个冲击,量测时会出现误fail——明明存储器是好的,却因为电压跌落导致时序失配。这个坑非常隐蔽,因为实验室低电压、常温条件下未必复现,但量产机台通过电流墙(current limit)设置不同时就会波动。
保守做法是先按全并行跑一轮,测量电流曲线和电源压降仿真,再根据余量去调整并行分组。Tessent生成的测试协议里也支持插入空闲周期或分摊启动时刻,避免所有控制器在同一拍同时发起访问峰值。
5.3 低功耗、时钟复用这些绕不开的约束
低功耗芯片做MBIST,最典型的需求是测试模式的功耗不能超封装上限。业界常见的做法有几种:
- 分时隙启动BIST:将全部存储器分成M个批次,每批次轮流跑,牺牲测试时间换瞬态功耗收敛;
- 降低BIST时钟频率:测试时钟可以远低于功能时钟,因为MBIST本身对速度不敏感,故障模型都是逻辑级的,不需要跑满速去验证时序,真正验证时序是AC测试那部分的工作;
- 插入BIST空闲周期:在March元素间插入等待周期,让电源网络有时间缓冲。
时钟复用方面,Tessent允许BIST控制器与扫描链、逻辑BIST共用测试时钟源,但在时钟树综合时需要给MBIST时钟域单独设时钟组,否则CTS阶段时钟偏移会超标。千万不要为了省事把MBIST时钟与功能时钟不加区分地放进同一个组,树做出来跑进硅里,后续调试会非常痛苦。
6. 实测中常见的Fail场景与调试习惯
6.1 典型案例:MBIST fail但功能测试正常
最让人头疼的情况之一,就是芯片测试时MBIST报fail,但同样的芯片做功能测试又一切正常。第一次遇到这种事的工程师很容易怀疑是测试逻辑本身有问题。
实际上这种fail经常来自三个方向。第一,测试时序与存储器AC特性不匹配。比如Collar里给存储器输出数据的采样点设置得太靠近时钟沿,工艺角边缘情况下采样不稳,导致比较器看到错误数据。这是设计问题,不是存储器物理坏。第二,测试期间电源噪声太大。BIST跑起来后,大量存储器同时翻转,IR drop偏高,存储器的读写裕量被压掉,随机出现读写失败。这种fail的特点是复现性差,跑十次可能只有两三次fail,而且换电压条件后结果不同。第三,复位释放问题。BIST控制器要求复位在时钟稳定之后再撤销,如果片中电源监控(POR)时序与BIST启动时序配合不好,控制器初始状态不对,签名字段从第一个周期就错了。
排查的主要突破口是先看fail是稳定fail还是间歇fail,然后回读失败地址。稳定fail大概率指向物理缺陷或时序约束错误;间歇fail优先怀疑电源、时钟这类全局因素。
6.2 调试时波形先看哪里
用仿真或硅前调试来定位MBIST问题,不要一上来就盯着数据总线。我的习惯是先看控制器的状态机:地址生成器的递增方向对不对、读写使能序列与March元素定义是否一致、finish信号有没有被异常拉高。状态机行为正确,再进到存储器接口层看Collar处的信号:功能到测试模式的切换是否在安全时刻完成、输出使能时序是否满足读数据采样窗口。
确认接口时序没有问题后,再去看比对结果。如果是MISR方案,逐周期追数据不现实,应该先把MISR期望签名重新算一遍。很常见的低级错误是:工具版本更新后默认初始化值变了,或者ECC数据位被掩码了,但测试程序里的期望签名还是旧的,导致所有好芯片都报fail。签名对不上时先别怀疑存储器,先怀疑签名来源。
6.3 个人调试心法:从最小可运转单元开始
我调MBIST一贯坚持“先单块、再分组、后全芯片”的节奏。改动任何配置后,第一轮只跑一块最小的存储器,确认单控制器路径通;然后扩展到一个分组,确认多存储器并行交互没问题;最后才回灌全芯片测试。每次扩展只改变一个变量,出问题能立刻知道是哪一层引入的。
另外,MBIST相关仿真波形文件巨大,不要开全dump。用条件触发,只在bist_start信号上升沿前几个周期开始记录,直到bist_done结束。波形文件小了,调试效率才会高。
还有一个容易被忽略的点:MBIST测试结果寄存器要能在JTAG链上稳定回读。有些芯片在ATE上fail,工程师通过JTAG读寄存器时又发现读回来的值一直在变化,这时候往往是测试模式下的扫描链复位与JTAG复位互相干扰,而不是BIST控制器本身的问题。遇到这种情况,先隔离复位域,再重跑确认。
按这个节奏来,大部分MBIST调试问题都能在几个小时内收敛,而不是在硅上瞎试。
最后分享一个从实战里总结的小技巧:量产测试的MBIST通过率,一定要和晶圆厂CP测试时的存储器失效分布做交叉对比。如果MBIST报出来的fail地址和CP的电性测试定位高度重合,说明测试逻辑本身可靠,可以放心依赖;但如果两边对不上,先怀疑的不是芯片,而是MBIST的隔离时序和电源完整性。另外,对于带ECC的存储器,我习惯把ECC校验位一起纳入MBIST测试,虽然会增加一点算法时间,但能覆盖存储阵列本身和ECC逻辑的交互故障。这个做法在高端MCU和车规芯片上尤其推荐,相当于把测试的粒度又往下沉了一层。