ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

256位小内存故障覆盖率如何决定SoC测试成败:RAMFLT方法论解析

256位小内存故障覆盖率如何决定SoC测试成败:RAMFLT方法论解析 简介这份PPT资料围绕内存的故障模型与测试算法设计展开面向计算机体系结构、集成电路测试及嵌入式存储方向的学习者与工程人员帮助理解内存工作模式、静态与动态故障分类以及March系列等经典RAM测试算法的设计思路。压缩包内共1个PPT文件约238KB以幻灯片形式系统梳理了离线RAM测试、功能故障模型、耦合与桥接故障、故障覆盖率分析及RAMFLT评估方法等核心内容并涉及BIST设计与嵌入式内存测试场景。目前已有335人学习下载。资料从功能单元阵列模型出发讲解粘滞、过渡、数据保留等故障的敏化与检测机制并对比确定性测试与伪随机测试的覆盖度量适合作为内存测试入门与算法选型时的参考框架也可用于理解测试时间复杂性与故障覆盖率之间的权衡关系。1. 为什么 256 位小内存的故障覆盖率能决定一颗 SoC 的测试成败很多人第一次接触内存测试会觉得这是后端测试工程师的事跑个 March C-覆盖率报表好看就行。但真正做过嵌入式存储 BIST 的人都知道问题往往出在“覆盖率数字是怎么算出来的”。同一颗 256 位、16 行 × 16 列的存储阵列March X 对三单元耦合故障的覆盖率可能只有 25%而 GALPAT 能到 48% 以上对 Type I 邻域敏感故障March C- 只有 12.5%GALPAT 却能到 40.6%。这些差距不是算法“好坏”的直觉判断而是由故障模型定义、敏化/去敏化规则和仿真方法共同决定的。RAMFLT 这套方法论的价值就在这里它不把故障模型硬编码进仿真器而是把故障模型当作输入用统一的敏化、去敏化、检测三态来描述任意测试序列。这样你既能评估已有的确定性 March 算法也能评估伪随机 BIST 方案还能给多端口、FIFO 这类特殊存储结构做覆盖率排序。适合谁读做 DFT/BIST 的验证工程师、写内存测试算法的同学以及需要向团队解释“为什么换算法”的人。2. 功能单元阵列模型与故障行为的形式化2.1 位寻址二维阵列与三值状态RAM 的功能模型可以抽象成一个位寻址的二维阵列每个存储单元 m(i,j) 保存一个二进制值。但在故障仿真里单元状态不是简单的 {0,1}而是 {0, 1, 0/1, x}0 和 1 是正确值0/1 表示故障导致值不确定x 表示未知。读、写 0、写 1 是三种基本操作。这个三值集合是后面所有敏化和检测判断的基础。提示把 x 单独拿出来是为了处理多故障同时存在时的掩蔽效应。如果只用二值逻辑很多耦合故障的传播路径会被错误地判定为已检测。2.2 敏化、去敏化与检测的判定规则一次写操作可能让某个故障进入敏化态也可能把它打回去敏化态一次读操作则把当前敏化的故障标记为已覆盖。形式化地说case write判断哪些故障被敏化或去敏化case read把所有处于敏化态的故障归类为 covered。这个规则看起来简单但它允许仿真器处理任意测试序列而不要求测试必须是规则 March 结构。下面这段伪代码展示了单次写操作的处理逻辑# 单次写操作对故障集合的影响 def apply_write(faults, addr, value, mem): for f in faults: if f.is_sensitized(mem, addr, value): f.state sensitized # 本次写操作敏化该故障 elif f.is_desensitized(mem, addr, value): f.state desensitized # 本次写操作去敏化该故障 mem[addr] value # 更新功能模型中的存储值 # 单次读操作把敏化态故障标记为已覆盖 def apply_read(faults, addr, mem): for f in faults: if f.state sensitized: f.covered True return mem[addr]is_sensitized和is_desensitized由具体故障模型提供仿真器本身不关心故障类型。mem是功能阵列的当前值写操作先判断故障再更新存储值顺序不能反否则敏化判断会用到错误的内存状态。2.3 故障模型的输入式规格故障模型不是写死在代码里的而是用“写操作 内存模式”的序列来描述。格式是 write op. mem. pattern write op. mem. pattern ...以两单元 OR 型桥接故障为例敏化和去敏化序列可以写成阶段操作内存模式作用敏化write-1, aa0, b0建立初始态敏化write-1, ba1, b0触发 OR(a,b) 错误检测read a 或 read b—返回 OR(a,b)去敏化write-0, a—清除敏化态去敏化write-0, b—清除敏化态这种规格化描述让新增故障模型只需要写配置不用改仿真内核。常见做法是把 25 种以上功能故障模型都做成这样的输入文件覆盖单单元、耦合、桥接、邻域敏感四大类。3. 从静态故障到动态故障模型分类与延迟状态转换3.1 单单元与耦合故障的分类单单元故障包括 stuck-at、transition、stuck-open、data-retention。耦合故障分两单元和三单元版本再按 idempotent、inversion、state、dynamic 细分。桥接故障有 AND 型和 OR 型同样分两单元和三单元。邻域敏感故障NPSF分 active 和 passivestatic 又分 Type I 和 Type II 邻域。这些分类不是学术摆设。仿真结果里March X 对 local 3-cell CFid 的覆盖率是 25.0%对 global 2-cell CFid 是 50.0%March C- 对 local 3-cell CFid 是 50.0%对 global 2-cell 是 100%。同一类“耦合故障”局部和全局的覆盖率能差一倍原因就在于算法遍历地址的顺序是否覆盖了耦合单元对的空间关系。3.2 延迟状态转换与 DRAM 睡眠病延迟状态转换用来建模 retention 故障典型场景是 DRAM 的“sleeping-sickness”失效单元在写入后经过延迟 tD 才发生 0→1 或 1→0 的翻转。仿真时敏化和去敏化不是立即生效而是在 tD 之后发生。这意味着测试序列中如果两次访问同一单元的间隔小于 tD故障可能来不及表现。# 带延迟的状态转换 def apply_write_with_delay(faults, addr, value, mem, t, tD): for f in faults: if f.delay_type retention: # 延迟 tD 后才更新敏化状态 schedule_event(t tD, f.update_sensitization, mem, addr, value) else: f.update_sensitization(mem, addr, value) mem[addr] valuetD是模型参数通常按工艺和刷新周期设定。schedule_event把状态更新排进事件队列保证延迟语义正确。如果忽略这个延迟retention 故障会被误判为已覆盖。3.3 多故障掩蔽与敏化序列的相互影响多故障同时存在时一个被敏化的故障会改变内存模式进而影响其他故障的敏化/去敏化序列。原文给了一个很直观的例子单元 C 周围的模式全为 1 时sleeping-sickness 故障才被敏化但如果故障 A 或 B 先被敏化并改变了周围值C 的敏化条件就被破坏。这就是 error masking。仿真器必须按测试序列逐条推进每步都重新计算所有故障的状态不能假设故障之间独立。复杂度上对测试序列长度 t 是 O(t)对邻域大小 k 是 O(2^k)对内存大小 n 和耦合单元数 k 是 O(2^k · n^k)。NPSF 的单元在物理上相邻耦合故障的单元可以在阵列中任意位置这个区别直接决定了仿真时要不要做空间剪枝。4. March 算法覆盖率对比与 RAMFLT 仿真流程4.1 March X、March C-、GALPAT 的序列结构三种算法的操作序列March X: ⇑(w0); ⇑(r,w1); ⇓(r,w0); ⇓(r,w1); ⇓(r,w0); ⇓(r) March C-: ⇑(w0); ⇑(r,w1); ⇑(r,w0); ⇓(r,w1); ⇓(r,w0); ⇓(r) GALPAT: 以每个单元为基点先全阵列写反值再读回逐单元推进⇑表示地址递增⇓表示地址递减r是读w0/w1是写 0/写 1。March 类算法的复杂度是 O(n)GALPAT 是 O(n²)。复杂度差异直接反映在覆盖率上GALPAT 对 local 3-cell CFid 达到 48.2%对 global 2-cell CFid 达到 99.7%而 March X 分别是 25.0% 和 50.0%。4.2 256 位阵列上的覆盖率数据原文给出的 256 位16×16仿真结果故障类March XMarch C-GALPATType I NPSF Active6.25%12.5%11.7%Type I NPSF Passive6.25%12.5%15.6%Type I NPSF Static0.39%0.78%0.98%Type II NPSF Active1.76%3.52%4.10%Type II NPSF Static0.39%0.78%0.81%local 3-cell CFid25.0%50.0%48.2%global 2-cell CFid50.0%100%99.7%注意 March C- 在 global 2-cell CFid 上达到 100%但 GALPAT 只有 99.7%。这说明覆盖率不是“越慢越高”算法结构和故障模型的空间关系匹配才是关键。4.3 用 RAMFLT 跑一次覆盖率仿真的步骤常见做法是先把故障模型写成输入规格再喂测试序列最后统计 covered 比例。一个可复现的流程# 1. 准备故障模型库输入式规格非硬编码 ramflt --load-faults faults/npsf_type1_active.spec # 2. 指定测试序列支持 March 和任意序列 ramflt --test tests/march_c_minus.seq --mem 16x16 # 3. 运行仿真输出覆盖率统计 ramflt --simulate --report coverage.csv # 4. 按故障类聚合便于对比算法 ramflt --aggregate --by fault_class --input coverage.csv--load-faults加载的是规格文件不是编译进二进制的模型--test接受规则 March 或伪随机序列--mem指定阵列尺寸16x16 对应 256 位--report输出逐故障的 covered 状态--aggregate按故障类汇总方便做算法排名。失败时先看规格文件里的敏化/去敏化序列是否和算法操作顺序对得上再看内存模式是否在写操作前正确建立。注意仿真结果对阵列尺寸敏感。256 位上的覆盖率不能直接外推到 1Mb 阵列因为耦合故障的空间距离分布变了。5. 覆盖率曲线追踪与 BIST 方案评估的实操技巧5.1 用测试序列条目定位覆盖率拐点原文给了一条 ANPSF 测试的仿真追踪曲线横轴是测试序列条目0 到 1307010纵轴是覆盖率百分比曲线里能看到 SAF、TF、2-cell CFid、3-cell CFid、Type I ANPSF、Type II ANPSF 各自的增长拐点。实操时把--report输出按序列条目排序找出覆盖率从 0 跳到目标值的那个条目就能定位是哪条写操作触发了敏化。import csv # 读取逐条目覆盖率找每个故障类的首次覆盖点 def first_covered(csv_path): first {} with open(csv_path) as f: for row in csv.DictReader(f): fc row[fault_class] if fc not in first and float(row[covered]) 0: first[fc] int(row[seq_index]) return first # 输出{SAF: 12, TF: 48, 2-cell CFid: 130, ...} print(first_covered(coverage.csv))seq_index是测试序列条目编号covered是该条目后的累计覆盖率。这个脚本帮你把“覆盖率什么时候涨上去的”变成可查的数字而不是只看最终百分比。5.2 算术 BIST 方案的覆盖率排序对嵌入式内存的 BIST常见做法是用线性反馈移位寄存器生成伪随机序列再用 RAMFLT 评估覆盖率。评估时要注意三点一是伪随机序列长度要足够否则覆盖率曲线还没收敛二是要和确定性 March 算法做同故障类对比不能只比总覆盖率三是多端口和 FIFO 结构要单独建模因为端口间的耦合故障模型和单端口不同。评估维度确定性 March伪随机 BIST序列长度O(n)通常更长覆盖率收敛可预测需仿真确认适用结构规则阵列多端口/FIFO评估方法RAMFLT 直接跑RAMFLT 序列生成器5.3 覆盖率数字之外的验证习惯我一般会在拿到覆盖率报表后做两件事第一抽查几个被标记为 covered 的故障手动推一遍敏化序列确认不是仿真器的误判第二把同一算法在不同阵列尺寸上各跑一次看覆盖率随尺寸的变化趋势。如果某个故障类的覆盖率随尺寸急剧下降说明算法对该故障的空间覆盖不足换更长的序列或改地址遍历顺序比单纯增加测试时间更有效。覆盖率是手段不是目的能解释清楚“为什么这个数字是这样”才算真正跑通了 RAMFLT 这套方法。本文还有配套的精品资源点击获取
返回列表