Tessent MBIST实战指南:从存储阵列故障模型到片上自测试实现
发布时间:2026/10/6 17:41:03 锦皓数字建站

1. 先想明白一件事为什么存储阵列不能靠扫描链解决1.1 SoC里那 60% 的硅片面积其实“看得到测不到”做过几颗芯片的人都会有这种感觉前几年做一颗MCU片内SRAM加起来几十KB就算“大缓存”了现在随便一颗带AI加速的SoC片上存储动辄几MB到几十MBGPU的cache、NPU的中间结果buffer、多核之间的共享内存再加上各种IP自带的FIFO和寄存器堆存储器占芯片总面积的比例轻轻松松超过60%。这直接改变了一件事流片回来之后在测试机台上最花时间、最让DFT工程师头疼的往往不是标准单元逻辑而是这些密密麻麻的存储阵列。存储阵列的问题在于它太“密”了。同样面积下SRAM的位单元数量比标准单元逻辑多出一个数量级每个位单元都可能存在单独的开路、短路、漏电缺陷而这些东西在功能测试里往往要跑到特定的读写组合才能暴露出来。更麻烦的是存储阵列内部几乎没有可观测节点你不可能把一个几千行的存储矩阵里每一根位线、字线都引到封装管脚上去观察。扫描链能解决标准单元逻辑的可控可观测问题但对存储阵列来说扫描寄存器根本塞不进去——硬塞进去面积代价大到不现实而且还会破坏存储单元本身的物理特性。所以行业里很早就走了另一条路不把存储阵列当作“逻辑”去测而是专门为存储器设计一套自测试电路。这就是MBISTMemory Built-In Self-Test存储器内建自测试。而我这里要讲的Tessent MBIST就是西门子EDA原Mentor Graphics那套在业界用得相当广泛的存储器自测试插入工具它解决了“怎么把测试电路加进去”“怎么生成测试向量”“怎么保证加了BIST之后功能不变”这一整条链路的问题。1.2 存储器的故障模型远比逻辑复杂得多我刚接触DFT那会儿总觉得测存储器不就是“写0、读0写1、读1”嘛有什么难的。真做了几个项目之后才发现存储器的故障模型比逻辑电路丰富一个数量级。逻辑电路最常见的是固定故障和跳变故障但存储器还要面对位单元固定故障stuck-at fault某个位始终为0或始终为1跳变故障transition fault从0到1或从1到0无法按时完成耦合故障coupling fault一个位单元的跳变会影响另一个位单元地址译码故障address decoder fault地址映射错误某地址读写不到对应单元或者多个地址指向同一个单元保持故障retention fault单元在掉电或长时间不刷新后无法保持数据这对一些低功耗设计特别重要写恢复故障write recovery fault连续写入时前一次写操作没有完整收敛就开始了下一次操作。扫描链只能覆盖逻辑层面的可控可观测问题对上述这些存储器特有的故障模型基本无能为力。你可以尝试把这些存储阵列包上一层扫描 wrapper通过扫描链把地址、数据、控制信号都搬进去但这样测试时间会爆炸——位单元的pattern动辄几百上千个,外部ATE逐个搬进去的代价完全不可接受。这就像你想用显微镜检查一整栋楼的每一块砖逐块搬过去看显然不现实正确做法是在楼里装一套自动巡检装置让它在楼内跑一圈把有问题的地方标记出来。MBIST干的就是这件事。1.3 MBIST 在整颗芯片 DFT 策略里的定位如果要给DFT画一张全景图可以把测试手段分成这么几块scan test解决逻辑电路的制造缺陷boundary scan解决板级互连和封装测试MBIST专门解决片上存储器的测试IO test解决输入输出单元的问题还有analog/RF的各类test。MBIST在其中承担的任务是“大屏高速”的存储阵列测试它最大的优势是测试向量不是存在ATE上而是存在芯片内部的控制器里由控制器自动产生并执行所以测试速度可以做到很高也不受ATE通道数的限制。把MBIST定位为“片上ATE”也很贴切。它在功能模式下是透明的不干扰正常读写一旦进入测试模式就把存储阵列的控制权接管过来按照预设的算法跑一轮读写最后给出一个GO/NO-GO结果。这个思路听起来简单但要把“接管控制权”“生成算法”“比较结果”“报告故障”这些环节都做对并且保证插入之后不破坏原有功能时序里面其实有一大堆细节。Tessent MBIST就是把这套流程工具化的一个成熟方案。2. Tessent MBIST 硬件架构一次看懂 Controller、BAP、Shadow、Y 向量2.1 MBISTController测试过程的“指挥官”Tessent MBIST在芯片里插入的核心是MBISTController你可以把它理解成一个专门执行存储器测试算法的小型处理器。它内部有一组状态机按微码或硬连接的指令序列运行依次完成三个动作产生测试地址、产生测试数据和读写控制信号把从存储器读出的数据与期望值逐周期比较记录失败信息并对外报告测试完成状态。它对外暴露的端口通常就是一组测试模式信号常见的有BIST_EN进入测试、BIST_DONE测试完成、BIST_GO/NOGO测试通过与否可能还有时钟和复位。在测试模式下这些信号由测试机台或片上测试控制器拉起来测试完成后通过GO/NOGO判断好坏。控制器内部还维护着失败计数器和故障边界信息比如第一次失败的地址、第一次失败的数据、失败发生的周期数这些信息对后续诊断非常重要。控制器本身也是可测的。它里面无论是状态机还是微码ROM插完后还会通过扫描链串进整个DFT网络里所以Tessent会把MBIST控制器当作一个普通的逻辑模块做扫描接入确保控制器自身的制造缺陷也不会漏掉。2.2 串行访问接口与 Shadow 逻辑光有控制器还不够Tessent还需要解决一个问题控制器和存储器之间怎么连接。直接由控制器把地址、数据、控制线全部连到每个存储器的端口上会带来两个问题一是功能模式下面控制器必须完全让位否则两条驱动路径会打架二是多条长连线会在物理实现阶段造成不小的布线拥塞和时序压力。Tessent的典型做法是引入shadow逻辑和BAPBIST Access Port的串行接口。shadow影子逻辑是插在功能数据路径和存储器端口之间的一组寄存器/旁路逻辑在功能模式下它只是一个透明的缓冲把CPU或DSP的数据正常地搬到存储器端口在测试模式下它切断功能侧数据转由BIST逻辑驱动。可以把它理解成舞台上的“幕后换景”:观众在场时一切照常运行演出结束时幕后工人迅速替换场景。BAP是一组串行访问用的接口它允许外部的测试机台或片内的test access端口通过一串移位寄存器去配置和观察BIST电路。这有点像JTAG但Tessent的BAP做得更灵活既可以级联多个BIST域也可以和JTAG接口打通。正是因为有了这层串行访问能力Tessent才能把多颗存储器的测试统一调度起来。2.3 Y 向量描述存储测试序列的“语言”如果你打开Tessent生成的BIST库代码会看到一类看起来像一行行“0/1/上升沿/下降沿”的向量表这就是Y向量。Y向量本质上是用一组周期性的信号序列描述“测试算法怎么扫存储阵列”它把地址变化方向、数据背景值、读写控制时序全部抽象成一张表。业界常见的存储器测试算法在Tessent里都有对应的Y向量模板故障模型典型测试算法覆盖范围测试时间/周期数stuck-at faultMarch C-位单元固定故障、部分地址译码故障N×若干操作量级为O(N)transition faultMarch C- / March LR跳变故障、部分耦合故障O(N)耦合故障March LR / March SS耦合故障覆盖更完整O(N)但常数项更大地址译码故障March 类算法均可覆盖地址译码O(N)保持故障写数据后延时读取数据保持能力取决于延时参数read disturb反复读某地址观察邻居变化读干扰特殊循环初看这些算法名字很唬人其实March类算法的核心思想很简单用一组固定的“写值→改地址→读写校验”的操作序列按地址递增或递减的方向把整个存储矩阵扫一遍。比如March C-的基本格式是对每个地址依次做“写0、读0、写1、读1”等等操作地址方向根据阶段不同进行递增或递减。测试复杂度控制在线性量级这是它能在片内跑起来的根本原因。Tessent在默认配置里会针对不同类型的存储器给出推荐算法。你只要指定“这块SRAM用March C、那块ROM用写入读出校验”工具就会把对应的Y向量展开到BIST控制器的微码里在测试模式下一拍一拍地扫完整片存储。2.4 控制器资源怎么定共享 or 独立Tessent允许你把系统里所有存储器都挂到一个MBISTContoller上也可以给每块存储配一个独立控制器还可以按时钟域、按电源域分组。这个决策直接决定了面积、测试时间、诊断粒度之间的平衡。我自己在项目里总结的经验是完全共享一个控制器面积最省但缺陷定位很粗测试一旦失败只知道某个大组里有坏单元要靠Tessent Diagnostic继续逐块定位每个存储配独立控制器定位精确且测试可以并行但面积代价大尤其在小芯片上非常不划算。比较均衡的做法是按时钟域和物理位置分组让同一时钟域、物理上靠近的存储共用一个控制器既能并行调度又不至于把BIST连线拉得太长。还有个细节是测试调度。Tessent支持多个BIST域以serial chain或parallel方式调度serial chain里一个域测完再测下一个测试时间相加parallel方式下多个域同时启动测试时间短但对同时开关的功耗更敏感。低功耗设计里一次性把所有存储同时测试可能会触发片内IR drop问题这时候就得把并行度降下来用两三个窗口分批测。3. 从零到一Tessent MBIST 的完整落地流程3.1 先把输入件准备齐网表、库模型、内存清单Tessent MBIST流程的第一步是把设计的输入数据准备齐。你需要有RTL网表或者已经完成一部分综合的门级网表、标准单元库和存储器单元库的逻辑模型、时钟和复位定义以及一份完整的存储器实例清单。很多新人在这一步就翻车——存储器实例清单对不上。芯片里的SRAM可能是memory compiler生成的也可能是一个个例化出来的硬宏还可能被包了一层自定义wrapper逻辑。Tessent在插入时要精确识别出“哪些instance是存储阵列”“它是哪种类型”“端口怎么定义”。如果RTL里存着的是经过封装后的wrapperTessent很可能识别不了这时候就需要提供存储器接口模型或者先用脚本把wrapper里的存储宏“揪”出来。所以我在项目开始前一定会拿着memory compiler的databook逐项核对每个宏的名字、端口名、时钟数、读写模式确认和Tessent读到的库模型一致。另外如果你用的是门级网表最好先跑一遍时序检查确保综合后的网表没有悬空引脚或逻辑环路。BIST插入是在一个本来就干净的网表上加逻辑如果原始网表本身有结构问题后面查起来会非常痛苦。我见过有人对着一个综合结果不对的网表强行插BIST结果check_connectivity报了几百条错误根本分不清哪些是BIST引入的、哪些是原本就有的排查了一整天才发现是综合时library没给全。3.2 Spec文件用一段配置描述“测什么、怎么测”在Tessent Shell里核心输入是一份MBIST spec文件它定义了哪些存储器参与测试、每个存储器用什么测试算法、按什么规则分组挂到哪个控制器。你可以直接用文本编辑器写也可以在工具里通过交互命令生成再修改。一个简化版的Spec概念大致是memory_list { inst_u0_sram_a : sram_64x32 ; inst_u0_sram_b : sram_64x32 ; inst_u1_fifo_data : fifo_32x128 ; } algorithm { default March C- ; inst_u1_fifo_data RetentionTest ; } controller { name mbist_ctrl_0 ; memory inst_u0_sram_a, inst_u0_sram_b ; } controller { name mbist_ctrl_1 ; memory inst_u1_fifo_data ; }这只是一个示意。实际工具里每条命令的关键字和格式在不同版本间有差异但核心思想一致先列出所有存储实例再指定算法再把存储分给控制器。Spec文件写得越清晰后面插入和调试越省心。有几个容易忽略的点我这里额外提醒一下一是存储器端口的clock port和reset port在spec里要显式给出Tessent需要为每个存储生成正确的时钟/复位接入逻辑二是具备多端口的存储器要区分test mode下用哪组端口有些双端口SRAM在测试时只需要用到主端口另一个端口要固定到安全状态三是异构存储比如CAM内容寻址存储器或register file它们的测试时序和标准SRAM不完全一样得在spec里单独指定对应的测试模型。3.3 插入、连接检查与形式验证确认BIST逻辑真的“长”对了Spec准备好之后在Tessent Shell里执行插入。常见方式是写一个批处理的dofile脚本大致流程如下# 进入Tessent DFT环境 set_context dft -scan # 读入设计和库 setup_design -lib my_lib read_verilog ./rtl/netlist.v # 插入MBIST insert_mbist -spec ./mbist_spec.txt # 做连接性检查 check_connectivity -type mbist # 写出插入后的网表和报告 write_design -format verilog -output ./out/mbist_inserted.v write_reports -output ./out/mbist_report插入命令执行后工具会在网表中增加BIST控制器、shadow逻辑、BAP接口等模块。这一步通常会检查存储实例是否都能正确识别、端口连接是否完整、是否有悬空的BIST控制信号。接下来check_connectivity的作用特别关键它会基于时钟域、电源域、复位域做拓扑检查发现那些“看起来连上了、实际在物理上不可驱动”的连线问题。在完成结构检查之后我强烈建议做一次形式验证。Tessent MBIST插入L的逻辑理论上在功能模式下是透明的但“理论上透明”不代表每个版本、每个配置下都自动保证。用逻辑等价性检查工具把原始RTL网表和插入MBIST后的网表做一次功能等价性比对能确认功能路径没有被BIST shadow逻辑改动。这一步我从来不敢省尤其当设计里存在异步接口、多时钟域穿越的时候插入逻辑很可能会轻微改变某些功能路径的时序语义。check_connectivity报错的时候先看时钟域。这是我在多个项目里验证过的最省时的办法。BIST逻辑本身通常工作在测试时钟下而存储器的功能时钟可能来自不同PLL或分频器。如果测试时钟和功能时钟的关系没有在约束里定义清楚连接检查会持续报出“无法建立时序关系”的警告有时还会把正常路径误包成违规。先把时钟关系和复位关系理顺绝大多数连接性问题都能迎刃而解。3.4 生成并 retarget把网表级的BIST变成可执行测试插入MBIST之后设计里确实有了一套自测试电路但要让测试机台能真正执行还需要把BIST的测试调度和向量“打包”成测试程序。Tessent在这个环节做的事情叫做retarget和vector generation。retarget的概念可以简单理解为把“BIST电路内部的测试序列”翻译成“外部测试机台能对芯片执行的操作序列”。机台本身不需要知道March C-内部怎么走地址它只需要知道怎么把芯片打到MBIST测试模式、怎么触发BIST_EN、等待多少个周期、最后读取BIST_DONE和BIST_GO/NOGO。Tessent会自动生成这套外部测试序列同时生成对应仿真用的testbench以及面向ATE的测试向量文件。实际项目里这一步还会涉及测试向量压缩和时钟设置的联合优化。BIST测试的周期数由算法决定但外部机台执行时每拍时钟的触发方式和scan链之间的协同还需要仔细约束。Tessent支持把多个BIST域串到一个测试程序里依次触发也可以把多个域作为一个并行组同时触发具体采用哪种方式通常要和ATE的通道数目、片内功耗预算一起评估。3.5 仿真联调把错误拦在流片之前生成了testbench之后一定要在仿真环境里跑起来不要直接跳去跑ATE。Tessent会输出一个带有测试序列的testbench你可以直接用VCS或QuestaSim跑一遍在波形里观察BIST_EN的拉起、控制器状态机跳转、存储器的地址/数据变化、最后的BIST_DONE和BIST_GO/NOGO是否按预期翻转。这里有个很实用的技巧故意在仿真中注入一个存储位翻转验证BIST是不是真的能抓到。做法很简单在testbench里给某个存储输出端口人为加一个常数错误或者用force命令强行翻转某根数据线。正常情况下BIST的GO/NOGO应该变成失败状态同时故障信息寄存器的值要指到发生错误的地址。这一步验证成本很低但能确认BIST逻辑不是空转真的具备故障检测能力。还有仿真时别只盯着功能正确性还要去检查时钟沿和复位时序。BIST电路的测试时钟往往来自DFT时钟控制器这个时钟在testbench里是用外部激励模拟的。如果BIST逻辑需要两个时钟沿才能完成某次采样而testbench给的是单沿仿真可能碰巧过到了机台就抓瞎。宁可多花半天时间把时序逻辑理清楚也不要等到测试机台上才发现问题。4. 实战中常见的坑与排查技巧4.1 存储器库模型和实际时序对不上Tessent做BIST插入时默认会参考存储器单元库的端口逻辑模型。如果你用的memory compiler版本比较新或者宏的端口定义里有隐藏的redundancy repair逻辑比如带redundancy的SRAM工具可能高估或低估实际存储容量。一旦库模型的位宽、深度与RTL例化不一致BIST控制器产生的地址在边界处就可能遍历到不存在的存储单元测试结果就会莫名其妙地失败。查这类问题我一般会先对比BIST报告中每种storage的address range再回到RTL里数一下地址线位宽。容易出错的多半是带column mux的SRAM地址线可能被分成了row address和column select两部分工具如果把它们都算作完整地址地址范围就会翻倍。4.2 shadow逻辑没有复位测试启动时随机态跑飞另一类高频问题是shadow逻辑缺复位。影子寄存器在功能模式下处于旁路状态如果不给它一个确定的初始值测试模式第一次拉起BIST_EN时shadow逻辑里的老数据可能是仿真中的X态也可能是实际芯片里的随机态。如果是随机态BIST控制器在接管存储器的第一个周期就可能对存储器写入随机地址、随机数据结果整个测试从第一步就错了。解决方式其实很简单确保所有shadow/BAP相关逻辑在测试初始化阶段被复位到已知值。我习惯在spec里把BIST逻辑的复位源和功能逻辑分开给一个明确的“test_mode复位”。同时在仿真阶段把复位释放前的X态传播检查打开看有没有X态在BIST_EN拉起时出现在地址或数据路径上。这类问题在仿真里尤其容易被忽略因为带有X态传播的严格仿真本身就会把问题暴露得很明显。4.3 多个BIST域共享控制器的调度坑把多个存储器挂在同一个控制器下听起来很省面积但实际项目中会碰到一个很尴尬的调度问题不同时钟域或不同电压域的存储不能同时被同一个控制器驱动。比如CPU cluster的SRAM工作在1.0VNPU的buffer可能在0.7V的低功耗域两个域之间有时序隔离。如果强行共用一个BIST控制器测试时要么需要先把低频域抬到共同电压要么需要插入level shifter复杂度立刻上来了。我的建议是在做MBIST controller分组时先看电源域和时钟域再看物理距离。跨域的存储尽量分别归属不同控制器或者至少在spec里定义清晰的“测试时钟域”。不要贪图省那一点BIST逻辑面积把自己后面调试整得焦头烂额。4.4 GO/NO-GO只能告诉你“坏了”诊断才是关键芯片流片回来MBIST测试Fail了这时候很多人的第一反应是“存储器坏了启动diagnostic”。但经过几次真实项目的检验后我发现“MBIST Fail”背后可能有多种原因存储阵列本身真有缺陷、BIST控制器逻辑因制造缺陷也坏了、时钟或电源网络在测试模式下出现异常、甚至测试程序本身约束错误。Tessent提供了一套diagnostic流程它不仅能告诉你哪个BIST域Fail还能通过失败信息的边界值与故障字典做对比推断可能的物理缺陷类型和位置。跑诊断之前最好把第一次失败的地址、数据、周期数完整保留下来。如果连故障信息寄存器都是乱的那大概率不是存储阵列的问题而是BIST控制器或者时钟网络出了问题这时候先回头查测试时序和复位别急着定位具体位单元。4.5 测试时钟复用BIST用功能时钟还是独立时钟很多设计中BIST扫描和MBIST会共用一套测试时钟。省事是省事但要注意测试时钟的频率上限。BIST测试时地址和数据翻转频率很高如果测试时钟频率压得太低一些高速缺陷反而测不出来如果压得太高建立保持时序可能过不了。Tessent会基于存储器的时序库模型给出最大BIST时钟频率估计你可以把这个频率作为约束交给后端时钟树综合。实际测量中还有个容易忽略的问题同一片存储功能时钟和BIST时钟的相位关系可能不一致。功能路径往往是经过PLL的,而测试时钟是从外部直接打进来的。如果两者相位错开太大部分设计里可能导致shadow逻辑在功能与测试模式切换瞬间出现亚稳态。我通常会在测试时钟路径上加与功能时钟相似的延迟让两条路径的时钟沿尽量对齐从根源上减少切换毛刺。5. 一点个人体会做MBIST这个方向久了我最大的体会是工具流程可以很快上手但真正拉开差距的是对“为什么要这样插、插完怎么验证、坏了怎么定位”这层逻辑的理解。Tessent MBIST作为一个成熟的商业工具已经把很多细节自动化了但工具越是自动化越需要我们清楚它背后做了什么假设。比如shadow逻辑的复位假设、时钟域的划分假设、存储器库模型的正确性假设任何一个假设被打破生成的测试电路就可能失效。我自己的习惯是每个项目在MBIST插入完成后除了跑工具自带的检查还会手动抽查两三个存储器实例的BIST连接从控制器出来的地址、数据、控制信号是不是真的经过shadow逻辑接到了存储端口功能路径是不是真的能穿透shadow逻辑整个链条的时钟沿是不是对齐的。这套手动检查花不了多长时间但能帮我在项目早期发现很多工具报告里不会写的问题。最后再分享一个小技巧无论项目多急BIST插入脚本一定要版本管理起来而且spec文件和网表要一一对应。我见过太多次因为某版综合网表更新了但MBIST spec没同步导致插入结果和预期差了一大截的事故。把这份脚本当作设计的一部分来维护你后面的日子会好过很多。
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。