简介:《Mentor_mbist学习总结》面向数字IC设计、DFT验证及可测性设计初学者与工程实践者,围绕存储器内建自测试的完整知识链路展开,帮助读者理解MBIST为何加入芯片、适用于哪些场景,以及其在测试效率、成本与故障覆盖之间的权衡。文档从Memory类型与MBIST基本结构入手,延伸到永久性/暂时性等故障类型、LFSR与PRNG等测试算法,并结合Mbistarchitect说明MBIST输入输出生成、工具使用、ATPG语法和Bist变量等内容,附录还涉及ROM/SRAM库形式与脚本实现,便于建立从概念到工具落地的整体认识。资源包共1个docx文件,约319KB,篇幅紧凑、目录清晰,适合作为学习笔记或查阅提纲。已有1448人学习,可作为DFT入门梳理与项目前预读的参考材料。
1. 一颗芯片四成面积压在 memory 上:MBIST 到底在补哪段失效风险
某次流片回来的板子,功能测试在高温 corner 偶发读错,抓波形定位到一颗内嵌 SRAM 的某个地址在特定访问序列之后数据翻转,换一片就消失。这种问题最难受的地方在于它不可复现,也不在普通逻辑测试pattern的覆盖范围里。MBIST(Memory Built-In Self-Test,内嵌存储器自测试)解决的就是这一段:在 memory 周围加一圈测试逻辑,让存储器自己给自己发激励、自己比对结果,把失效拦在测试厂而不是客户手里。这份材料是一份 MBISTArchitect 工具链的实操总结,从 memory 分类、BIST 结构讲到 .atpg 建模、do 脚本、Makefile 批处理和 March 算法选型,附了 SRAM/ROM 的 model 模板和 ROM content file 格式。适合刚接手 DFT、手里有一堆 memory 要加 BIST 但不知道第一步从哪下手的验证和后端工程师。
2. Memory 分类与 MBIST 结构:BIST 逻辑怎么用 MUX 接管 SRAM
2.1 五类 memory 的测试差异与 MBIST 适用边界
动手写 .atpg 之前,先把对象分清楚。memory 的划分有三组维度:深度和位宽、同步还是异步、单端口还是多端口。类型上常见 SRAM、DRAM、EEPROM、EPROM、ROM。不同 memory 的访问协议差别很大,测试激励不能一套打天下,这也是为什么 MBIST 不是给所有 memory 都无脑加。
| 类型 | 访问特征 | MBIST 适配度 | 实际操作 |
|---|---|---|---|
| SRAM | 同步、读写时序固定、访问方式单一 | 高 | 标准 MBIST 主力对象,March 系列直接套 |
| ROM | 只读、地址到数据映射固定 | 高 | TPG 只发地址,RA 需要 content file 提供期望值 |
| DRAM | 需要周期性刷新、行列地址复用 | 低 | 刷新时序与 BIST FSM 冲突,一般走专用内存测试机 |
| EEPROM | 写入需要高压和较长编程时间 | 低 | 编程时序不是功能时钟能覆盖的 |
| EPROM | 同上,擦除还依赖外部条件 | 低 | 同上 |
SRAM 和 ROM 之所以适合固定 MBIST,是因为它们的时序比较固定、访问方式单一,一个有限状态机加地址计数器就能把激励发全。DRAM 的刷新请求会随时打断访问序列,EEPROM 的写操作要拉高压、等编程完成,这些都不是在功能时钟域里跑几百个周期能解决的,硬塞进标准 BIST 流程只会让 FSM 变得不可维护。
三组维度里,对 BIST 结构影响最大的是端口数。单端口 memory 只有一组地址和控制线,一套 TPG 就够;双端口或双口 RAM 每个 port 有独立的地址、使能和数据通路,两个 port 可能同时被访问,BIST 必须给每个 port 单独指定算法和比较逻辑,否则另一个 port 完全没有被覆盖,覆盖率报表上看着是满的,实际漏了一半。
同步和异步的差别落在 wait 的数量上。同步 memory 的读延迟固定,.atpg 的 read_cycle 里写几个 wait 就是几个周期;异步 memory 的访问完成时间取决于内部时序,建模时要按最坏情况给等待周期,否则比较器会在数据还没稳定的时候就采样,误判成故障。
提示:先确认 memory 的端口数和同步方式,再决定这套 BIST 是单控制器多 memory 还是每个 memory 一个控制器,顺序反了后面要返工。
2.2 TPG、CUT、RA、DM 与 MUX 接管路径
MBIST 的结构可以拆成四块:TPG(Test Pattern Generator)负责按算法生成地址、数据和控制信号;CUT(Circuit Under Test)就是那颗 memory;RA(Response Analyzer)把读回的数据和期望值比对;DM(Diagnostic Module)在失败时记录出错的地址和数据,供后续失效分析。
这四块加上系统的功能控制逻辑,通过 MUX 做选择。正常工作时 MUX 选功能通路,测试模式下选 BIST 通路,选择信号来自测试控制端口或者 BIST FSM 的 test_mode。写成 RTL 大概是这个形态:
// 功能通路与 BIST 通路的二选一,test_mode 由 BIST FSM 或测试端口驱动 assign mem_cen = test_mode ? bist_cen : func_cen; assign mem_wen = test_mode ? bist_wen : func_wen; assign mem_a = test_mode ? bist_a : func_a; assign mem_d = test_mode ? bist_d : func_d; // 输出侧一般不分 MUX,直接分叉:功能逻辑照常拿数据,比较器同时采样 assign func_q = mem_q; assign bist_fail = (mem_q !== bist_expect_q);这段代码里有几个点值得说清楚。MUX 只切输入侧,地址、数据、片选、写使能四组都要切,漏掉任何一组都会出现“测试模式下 memory 还在被功能逻辑写”的诡异现象。输出侧不分叉而是直接分叉,是因为读数据本来就只有一份,功能逻辑和比较器可以同时看,多一级 MUX 反而在关键路径上多一段延迟。
bist_fail的位宽和压缩方式决定了诊断分辨率。如果 RA 用压缩器把 32 位输出压成 1 位,面积小、速度快,但失败时只知道“某一步错了”,不知道哪一位错;要做失效分析就得关掉压缩,或者打开 DM 记录出错地址。
MUX 的位置也影响时序。切在 memory 输入端,延迟落在地址建立时间上;切在输出端,延迟落在读数据到下游寄存器的路径上。常见做法是切输入端,因为 memory 的输入建立时间通常比输出到寄存器的路径余量更宽松。
2.3 四个判断条件、面积代价与数据路径延迟
什么项目该上 MBIST,材料里给了四个判断条件,我按实际项目里的优先级重新排一下:
第一,中大型嵌入式 memory 的系统。memory 位宽和深度到一定程度,外部测试机直接访问内部节点不现实,必须靠内建逻辑。
第二,IP 类型的 memory。这类 memory 来自外部供应商,内部结构不可见,你只能通过它的接口做黑盒测试,MBIST 是少数能覆盖到阵列内部的手段。
第三,需要快速测试的 memory。MBIST 能做实速测试,按 memory 的目标频率跑,比如目标应用是 100MHz,就保证它在 100MHz 下没问题。这条比覆盖率更值钱,因为很多失效是时序相关的,降频测不出来。
第四,片内有多个嵌入 memory。多个 memory 可以共享一套 BIST 控制器,用地址译码轮流测,测试时间不会线性叠加,管理成本也可控。
代价有两块,必须在方案阶段就算清楚。面积上是少量增加,FSM、地址计数器、比较器、压缩逻辑加起来相对 memory 阵列不大,但也不是零,尤其当 memory 数量多、每个都要独立比较器时。更值得关注的是数据路径上的 MUX 延迟:在功能关键路径上插一级 MUX,具体多少要看工艺库,通常不会大到离谱,但如果这颗 memory 的输出本来就贴着时序红线,这一级就可能把余量吃干净。
评估方法不复杂,综合前看功能通路里 memory 输出到下游寄存器的路径余量,把 MUX 延迟和布线估算加进去,如果余量不够,就考虑把 MUX 挪到输入端,或者给 BIST 通路单独加 pipeline 寄存器,让测试路径和功能路径的时序解耦。这一步偷懒,后面 timing signoff 会连本带利还回来。
3. 把读写时序写成 .atpg:change、assert、expect、wait 四个事件怎么落
3.1 SRAM 与 ROM 的 model 骨架和必填参数
MBISTArchitect 需要一份描述 memory 协议的文本文件,扩展名 .atpg。它不描述 memory 内部怎么实现,只描述“从端口看进去,读写一个单元需要什么样的信号序列”。工具靠这份文件理解 memory,写错了后面全错。
先看 SRAM 的骨架:
model sram_2k32 (Q,CLK,CEN,WEN,A,D,OEN) ( bist_definition ( address A(array=10:0;); data_in D(array=31:0;); data_out Q(array=31:0;); clock CLK high; chip_enable CEN low; write_enable WEN low; dont_touch OEN high; tech = generic18; vendor = mem_ip_vendor; version = "1.0"; message = "synchronous 2048X32 SRAM"; address_size = 11; min_address = 0; max_address = 2047; data_size = 32; read_write_port ( write_cycle ( change A; change D; assert CEN; assert WEN; wait; ) read_cycle ( change A; assert CEN; wait; wait; expect Q move; ) ) ) )参数逐项过一遍。address A(array=10:0;)表示地址总线 11 位,和下面的address_size = 11、max_address = 2047必须对得上,这三个数字是联动的,改一个忘改另外两个是最常见的翻车点。data_in和data_out分开声明,因为有些 memory 是双向数据总线,那种情况要写成 inout 并在读写周期里分别处理方向。
clock CLK high说明时钟上升沿有效;chip_enable CEN low、write_enable WEN low说明这两个是低有效,这个有效性声明直接决定后面 assert 的语义——assert 一个低有效的信号,意思是把它拉到 0。
dont_touch OEN high是个容易被忽略的字段。OEN 是输出使能,BIST 期间工具不应该去动它,标成 dont_touch 就是告诉工具“这个信号别管”。不标的话,工具可能把它当普通控制信号一起驱动,BIST 模式下输出使能乱翻,读回的数据全是 X。
read_write_port把读写周期包在一起,表示这是一个可读可写的端口。多端口 memory 就写多个 port 块,每个 port 各自带一套 write_cycle 和 read_cycle。
3.2 四个事件的语义与读写周期对齐
.atpg 的语法是基于事件的,一句话一个动作。四个事件分别是 change、assert、expect、wait,理解它们的时间语义比背语法重要。
change表示指定的输入信号接到一个新值,比如地址或数据总线。它本身不消耗时钟周期。
assert表示把某个控制信号拉到有效状态。有效是高还是低,由前面bist_definition里的声明决定。关键点在于:被 assert 的信号在下一个 wait 事件之后会自动回到无效状态,除非你连续写多个 assert 把它保持住。
expect表示你预期某个输出信号因为前面的事件而发生改变。它的实际作用是给比较器打一个采样指示,告诉 RA“这个时刻的数据是有效的,可以比了”。
wait插入一个测试时钟周期。所有写在 wait 之前的事件,都在同一个测试时钟周期内完成,wait 才是推进时间的那一下。
把 read_cycle 拆开看:
read_cycle ( change A; // 地址换到目标单元 assert CEN; // 片选拉有效 wait; // 第一个时钟周期,memory 采样地址 wait; // 第二个时钟周期,数据在 Q 上稳定 expect Q move; // 告诉比较器此刻采样 Q )两个 wait 对应这颗 memory 的两周期读延迟。如果实际 memory 是一周期读,这里多写一个 wait,比较器就会在数据有效之前采样,报一堆假错;少写一个 wait,采样点落在数据还没建立的时候,同样报错,而且波形上看不出明显异常,因为 CEN 和地址都是对的,只有采样时刻偏了。这类问题的排查成本很高,血泪经验是:read_cycle 的 wait 数量必须照着 memory 数据手册的读延迟一个一个数,不能凭感觉。
assert 的保持行为也值得单独说。下面两种写法时序完全不同:
// 写法一:oe 只有效一个周期 assert OE; wait; // 写法二:oe 连续有效两个周期 assert OE; wait; assert OE; wait;写法一里 OE 在 wait 之后的那个周期自动回无效;写法二通过第二次 assert 把它续上。如果你的 memory 要求输出使能覆盖整个读周期,就得用写法二,否则第二个周期 Q 上可能是高阻。
3.3 ROM content file 的区间写法与 lib 对应关系
ROM 的 BIST 和 SRAM 有一个本质差别:ROM 不能写,只能读出来比对,所以 TPG 只发地址,期望数据必须由外部提供。这个“外部”就是 content file。
格式长这样:
0 / ffffffff; 1 / ffffffff; 2 / ffffffff; 3 / ffffffff; 4 / ffffffff; 5 / ffffffff; 6 / ffffffff; 7 / ffffffff; 8 / ffffffff; 9 / ffffffff; a / ffffffff; b / ffffffff; c / ffffffff; d / ffffffff; e / ffffffff; f / ffffffff; 10-7ff/ 00000000;每行是“地址 / 数据;”的结构,斜杠前面是地址,后面是该地址上电后应该读出的值,分号结尾。地址和数据的进制都是十六进制,不用加 0x 前缀。
最后一行10-7ff/ 00000000;是区间写法,表示从 0x10 到 0x7ff 这一段全部是 0。区间写法是为了避免几万行逐地址罗列,但有几个约束:区间必须递增、不能重叠、不能跨越已单独列出的地址。写乱了工具会报解析错误,或者更糟——不报错但期望值错位,整片 ROM 测出来全错。
content file 和 .atpg 里的 ROM model 是配套的。model 里声明address_size = 11、max_address = 2047,content file 的地址范围就必须覆盖 0 到 0x7ff,少一段工具会认为这部分地址没有期望值,run 的时候直接失败。生成 BIST 时用add memory models rom -filename ./atpg/rom.ascii把两者绑在一起,这个 -filename 参数就是给 ROM 用的,SRAM 不需要。
4. MBISTArchitect 跑通全流程:七步交互、三个输出文件与 Makefile 批处理
4.1 交互式七步:从 mkdir 到 save bist
第一次上手建议走交互模式,把每一步的输出看清楚,再转批处理。整个流程七步:
# 1. 建工程目录 mkdir project cd project # 2. 把 .atpg 文件拷进来 cp /path/to/atpg/*.atpg ./ # 3. 启动工具(无 GUI 时用 -nogui) mbistarchitect # 4. 工具内加载 model 定义 load library sram_2k32.atpg # 5. 把 model 加进当前 BIST 工程,注意参数是 model 名不是文件名 add memory models sram_2k32 # 6. 生成 run # 7. 保存输出 save bist -verilog -replace exit第 4 步和第 5 步是最容易混淆的地方。load library的参数是文件名,作用是让工具认识这个 model 长什么样;add memory models的参数是 model 名,作用是把这颗 memory 实例化进当前 BIST 工程。传错参数类型,前者报文件找不到,后者报 model 未定义。
第 6 步 run 之前,工具的默认配置已经够跑出一个能用的 BIST,但如果要多 memory 共享控制器、加诊断、加 pipeline 寄存器、改压缩器结构,就得在 run 之前用配置命令改。默认配置不一定是你想要的结构,这一点后面第 6 章会展开。
第 7 步save bist -verilog -replace里的-replace表示覆盖已有输出文件。批处理流程里必须带这个参数,否则第二次跑会因为文件已存在而中断。
4.2 _bist.v、_bist_con.v、_tb.v 各管什么
跑完之后输出三个 HDL 文件,名字和职责要分清楚,不然接进 SoC 的时候会接错层次。
| 文件 | 内容 | 后续用途 |
|---|---|---|
*_bist.v | BIST 核心:算法 FSM、地址/数据生成、比较器、压缩逻辑 | 综合进芯片,不放 memory 例化 |
*_bist_con.v | 连接模块:memory 例化 + 功能/BIST 通路的 MUX | 顶层接线的依据,确认端口连接 |
*_tb.v | 测试平台:给 BIST 灌时钟复位、跑算法、报 fail | 仿真验证用,不综合 |
_bist.v是算法本体,它不知道自己要测的是哪颗 memory,只负责按 March 序列发地址和数据。_bist_con.v才是把 BIST 和具体 memory 缝在一起的那一层,MUX 就在这个文件里。实际项目里我一般先看 con 文件的端口列表,对照 memory 的端口一个一个核,核完再去看 bist 文件里的算法配置对不对。
_tb.v用来跑前仿,确认 BIST 能把 memory 测通、fail 信号在注入错误时能拉起来。这个文件里的 memory 通常是行为模型,不是你真实的 memory 网表,所以 tb 跑通只代表算法和连接逻辑没问题,不代表硅上没问题。
4.3 do 脚本与 Makefile 管理多个 memory
memory 一多,交互式一步步敲就不现实了。把命令写成 do 脚本,再用 Makefile 串起来。
# rom_bist.do reset state load lib ./atpg/rom.atpg add memory models rom -filename ./atpg/rom.ascii setup mbist algorithms Rom1 setup observation scheme -compress setup mbist compressor -localcomparator set design name controller -module rom_bist set file naming -bist_model ./rom_bist/rtl/rom_bist.v set file naming -connected_model ./rom_bist/rtl/rom_bist_con.v set file naming -testbench ./rom_bist/rtl/rom_bist_tb.v set file naming -script ./rom_bist/script/rom_bist.scr set file naming -ctdl ./rom_bist/script/rom_bist.ctdlf set file naming -wgl ./rom_bist/script/rom_bist.wgl run save bist -verilog -script -replace exit -discard# sram_2k32_bist.do reset state load lib ./atpg/sram_2k32.atpg add memory models sram_2k32 set design name controller -module sram_2k32_bist set file naming -bist_model ./sram_bist/rtl/sram_2k32_bist.v set file naming -connected_model ./sram_bist/rtl/sram_2k32_bist_con.v set file naming -testbench ./sram_bist/rtl/sram_2k32_bist_tb.v set file naming -script ./sram_bist/script/sram_2k32_bist.scr set file naming -ctdl ./sram_bist/script/sram_2k32_bist.ctdl set file naming -wgl ./sram_bist/script/sram_2k32_bist.wgl run save bist -verilog -script -replace exit -discard两个脚本的差别在 ROM 那份额外指定了-filename绑 content file,并且指定了算法名Rom1和压缩方案。set file naming这一串是把每类输出落到指定路径,不写的话工具按默认名吐在当前目录,多个 memory 一起跑就混在一起了。
Makefile 负责建目录和调工具:
#----------------------------------------------------------------------------------- # Makefile:每个 memory 一个 target #----------------------------------------------------------------------------------- RBIST_DIR = ./rom_bist SBIST_DIR = ./sram_bist rbist: mkdir -p $(RBIST_DIR)/rtl $(RBIST_DIR)/script $(RBIST_DIR)/log mbistarchitect -bistgen -dofile rom_bist.do \ -logfile $(RBIST_DIR)/log/rom_bist.log \ -replace -nogui sbist: mkdir -p $(SBIST_DIR)/rtl $(SBIST_DIR)/script $(SBIST_DIR)/log mbistarchitect -bistgen -dofile sram_2k32_bist.do \ -logfile $(SBIST_DIR)/log/sram_2k32_bist.log \ -replace -nogui clean: rm -rf $(RBIST_DIR) $(SBIST_DIR)-bistgen是批处理模式,-dofile指定脚本,-logfile把过程记到文件里,-replace覆盖旧输出,-nogui不弹界面。五个参数各司其职,缺-nogui在无显示环境的服务器上会卡住,缺-replace第二次跑就报错。
这里有个 Makefile 的写法坑:材料里原始版本用分号加分号续行的方式写多条 mkdir,mkdir a; mkdir b; \这种混用在不同 shell 下单步失败会让后续命令继续执行,目录没建全,工具输出路径不存在,报出来的错跟目录无关,查半天。改成mkdir -p一次性建多级目录,失败即停,问题定位快得多。
5. 避坑与排查:.atpg 协议写错、算法不匹配的五个翻车现场
5.1 五条踩坑记录:现象、原因、解决
第一条:add memory models 传了文件名。
现象是工具报 model 未定义,但你确认文件就在当前目录,load library那步也没报错。
原因是load library和add memory models的参数类型不同,前者吃文件名,后者吃 model 名。model 名是 .atpg 文件里model xxx (...)那个 xxx,不是文件名。
解决是把参数换成 model 名。如果 model 名和文件名不一致,先grep "^model" *.atpg看一眼再填。
第二条:read_cycle 少写一个 wait。
现象是仿真里 fail 信号在第一次读就拉高,但波形上 CEN、地址、WEN 全都对,memory 行为模型也确实输出了正确数据,看不出哪错了。
原因是比较器的采样时刻比数据稳定时刻早了一个周期。expect Q move的位置决定了 RA 什么时候采样,前面的 wait 数量不够,采样点就落在数据还没建立的时候。
解决是照着 memory 数据手册的读延迟数 wait。同步 SRAM 的读延迟是一周期还是两周期,手册第一页就写着,不要凭经验猜。
第三条:多端口 memory 只建模了一个 port。
现象是覆盖率报表上这颗 memory 是满的,但硅上回来发现另一个 port 对应的地址段有失效。
原因是 .atpg 里只写了一个read_write_port块,工具就只给这一个 port 生成了 BIST 和比较逻辑,另一个 port 完全没被测试。双端口 RAM 两个 port 可能访问同一阵列的不同地址,必须分别覆盖。
解决是每个 port 写一个 port 块,各自带读写周期,并在配置阶段给每个 port 单独指定算法。
第四条:ROM 没绑 content file。
现象是 run 阶段报错退出,或者更隐蔽——跑完了但比较器没有期望值,所有读回数据都被判为通过,等于没测。
原因是 ROM 不可写,TPG 只能发地址,期望数据必须由 content file 提供。add memory models不带-filename,工具就没有比对基准。
解决是生成 content file 并在add memory models后面加-filename ./atpg/xxx.ascii。注意 content file 的地址范围要覆盖 model 里声明的min_address到max_address全集。
第五条:全速模式下 BIST 时钟和功能时钟冲突。
现象是门级仿真里 BIST 跑起来一堆时序违例,或者仿真出现大量 X,但 RTL 级仿真完全正常。
原因是实速测试要求 BIST 按 memory 的目标频率跑,BIST 时钟往往直接复用功能时钟,而时钟切换的 MUX 和约束没有在 con 文件和后端约束里同步处理。RTL 仿真不带时序,看不出这个问题。
解决是在 con 文件里确认时钟 MUX 的连接关系,后端约束里给 BIST 模式单独定义时钟和 false path,门级仿真时用 SDF 反标跑一遍。
5.2 从 log 和波形定位问题
工具的 log 是最先要看的东西,-logfile指定了路径就直接 grep 关键字:
# 看算法配置和 memory 例化情况 grep -iE "algorithm|memory model|instance|port" rom_bist.log # 看警告:未连接端口、地址越界、期望值缺失 grep -iE "warning|unconnected|out of range|no expected" rom_bist.log # 看失败点和出错地址 grep -iE "fail|mismatch|error at" rom_bist.loglog 里出现 unconnected 要格外注意,多端口 memory 少接一个 port 的信号就是这种提示,但它不会让流程中断,很容易被忽略。
波形上重点看三个位置:CEN 和 WEN 的有效窗口是否和 .atpg 描述一致;地址变化和 CEN 有效的相对关系对不对;expect对应的采样时刻 Q 上数据是否已经稳定。三者里任何一个偏了,先回去改 .atpg,不要在下游逻辑上找原因。
5.3 生成后自检三条
BIST 生成完,接进顶层之前做三个静态检查,能挡掉大部分低级错误。
第一,端口比对。把 con 文件的 memory 例化端口和 memory 的 lib 端口列表逐一对,重点看低有效的使能信号有没有接反、dont_touch 的信号有没有被误接。
第二,地址位宽。BIST 输出的地址位宽必须等于 memory 的地址位宽,多一位少一位在 Verilog 里可能只是隐式截断或补零,仿真不报错,硅上访问错地址。
第三,memory 数量。con 文件里例化的 memory 个数要和设计里的 memory 个数一致,多 memory 共享控制器时尤其要数一遍,漏一颗就是一颗没测。
6. 算法选型与实速验证:March C+ 的 14 步怎么跑成可签核的 BIST
算法选型看两件事:要覆盖哪类故障,愿意花多少测试时间。MBIST 常见的故障类型有四类——短路错误(对 0 或对 1 短路)、转换错误(0 到 1 或 1 到 0 转不过来)、耦合错误(一个单元影响另一个)、邻居错误(一个单元影响相邻单元)。对应的激励策略也不一样:短路靠全 0 全 1 写读扫一遍;转换靠写完立刻读,抓转换时间;耦合靠写读扫描所有单元;邻居错误最麻烦,需要 pattern 足够强,复杂到一定程度可以选择性放弃。
| 算法 | 主要覆盖 | 相对开销 | 适用场景 |
|---|---|---|---|
| March A / March B | 部分链接错误 | 中 | 老工艺、算法资源紧张 |
| March C | 短路、转换、部分耦合 | 中 | 通用 |
| March C- | 与 C 接近,步数略少 | 中 | 追求测试时间 |
| March C+ | 在 C 基础上加强 | 偏高 | 主力选择 |
| March3 | 扩展覆盖 | 高 | 高可靠场景 |
| Column March | 列方向耦合 | 中 | 阵列结构特殊时 |
| 地址唯一棋盘 | 邻居、耦合 | 取决于实现 | 补强项 |
March C+ 跑 1Mbit RAM 是 14 步,按顺序是:
write 0s # 全阵列写 0 read 0s, write 1s, read 1s read 1s, write 0s, read 0s read 0s, write 1s, read 1s read 1s, write 0s, read 0s read 0s # 收尾全读 0每一步都是一次全阵列扫描,14 步就是 14 遍。测试时间的量级是“单元数 × 步数 / 测试频率”,所以提高测试时钟就是最直接的提速手段,这也是实速测试的价值所在——按 memory 目标频率跑,既压缩了时间,又顺带验证了时序。
实速跑起来要在 con 文件里把 BIST 时钟切到功能时钟,并确认三件事:BIST 的 FSM 在目标频率下能收敛;比较器的采样窗口覆盖 memory 的最坏读延迟;测试模式下的时钟树和功能模式一致,不能一个走 PLL 一个走旁路。我一般会在门级仿真里用 SDF 反标跑一遍全速 BIST,把 X 和时序违例挡在流片前。
要做失效分析的话,压缩器就得让位给诊断。setup observation scheme -compress配合setup mbist compressor -localcomparator是面积友好的默认配置,失败时只给一个 fail 标志;如果这颗 memory 后续可能要定位到具体单元,就关掉压缩、打开诊断记录,代价是比较逻辑面积上升、测试时间略增。这个取舍在项目初期就要定,后期改结构等于重跑一遍流程。从那以后我每次生成 BIST 都会先问一句“这颗失败了要不要定位到地址”,答案是要,就把诊断配置写进 do 脚本里,不给自己留后悔药。希望帮到你。
本文还有配套的精品资源,点击获取