只读分享解决方案文档原理方案设计📅 2026-10-14🔖 Rev 1.0⏳ 还有3日到期
🔧解决方案&应用市场分析 -> 原理方案设计 -> 电子设计&技术探讨 -> NAND多平面Cache命令与Die交错_技术探讨

NAND多平面Cache命令与Die交错_技术探讨

同系列 · 原理方案设计
扫码打开本页
微信扫码

NAND 多平面、Cache 命令与 Die 交错

从账面带宽与真实带宽的缺口出发,讲清多平面交错读如何把 tR 折进流水、Cache Program 如何把 tPROG 藏起来、Die 与 LUN 交错如何再叠一层并行,以及如何从 datasheet 参数估算出真实有效带宽 —— 一份给存储电路与固件工程师的技术探讨 | 编制日期 2026-10-14 | 版本号 Rev 1.0

4 段
一次操作的完整分解
命令、传输、等待、收尾
1 段可藏
等待段是唯一值得隐藏的
tR / tPROG / tBERS 全在这里
提频无效
接口速率只压传输段
介质越慢,提频收益越小
3 层并行
多平面 / Cache / Die 交错
层次不同,可叠加但不等价
深度即效率
交错深度决定隐藏率
深度不足等于没做交错
1 个公式
有效带宽 = 数据量 / 端到端时间
口径不写清楚的数字一律无效

几乎每一份 NAND 数据手册的第一页都会写一个很漂亮的接口速率,工程师也很自然地把它乘以总线位宽,得到一个「账面带宽」。但把实测数据摆在旁边时,两者往往差出一倍甚至更多。缺口不在接口上,也不在控制器不够快,而在于账面值只统计了总线真正在传数据的那一小段时间 —— 介质把一页数据从阵列搬到页缓存所花的 tR、把电荷打进浮栅所花的 tPROG、把整个块清掉所花的 tBERS,一次都没有进入这个算式。本文要做的,就是把这段被漏掉的时间摊开来看清楚,并给出把其它操作塞进这段时间的三种手段:多平面交错、Cache 命令、Die 交错。这是三种层次不同的并行,不是三个同义词。

结论:NAND 的真实带宽不取决于接口有多快,而取决于介质忙的那段时间里,总线上有没有别的事可做。多平面交错让同一颗 Die 里的另一个平面在你等待时干活,Cache 命令让上一条命令的编程与下一条命令的数据载入重叠,Die 交错让另一颗 Die 在你等待时用同一条总线输出数据。三者做的是同一件事 —— 填满单平面操作留下的总线空闲窗口 —— 但代价、约束与失效模式各不相同,叠加时也不能简单相乘。

报告总结

面向做 NAND 器件选型、控制器固件设计、存储性能调优与带宽验收的工程师,本文回答五类在具体项目里反复出现的问题:

  • 账面带宽与实测带宽的缺口到底在哪里。不是「手册虚标」,而是两套口径在统计不同的东西。第 1 章把一次操作拆成命令、传输、等待、收尾四段,明确指出账面值只覆盖其中一段,并把「有效带宽」的定义与度量口径固定下来 —— 口径不写清楚的性能数字,无论多精确都没有意义。
  • 单平面操作的天花板有多低。在动手做任何并行优化之前,必须先知道串行基线是什么。第 2 章给出单 Die 单 Plane 的命令流水模型,说明总线的忙与介质的忙在这条链上几乎不重叠,以及为什么提高接口频率的收益会迅速递减。
  • 三种并行手段各自的机制、约束与代价。第 3、4 章讲多平面架构与交错读,第 5 章讲 Cache 读与 Cache Program 的两段式模型,第 6 章讲 Die 交错与多 LUN 并发。每一章都给出「它能藏掉什么」「它藏不掉什么」「它对地址与命令序列提出了什么约束」。
  • 怎么从 datasheet 参数估算真实带宽。第 9 章给出一套只用公开时序参数就能算出的估算方法,以及测量时必须避开的陷阱(热身不足、缓存命中、队列深度不匹配、把接口速率当成介质速率等)。第 11 章用四个典型场景把账本算给你看。
  • 设计核查与常见错误。第 12 章给出设计前必须回答的十个问题、交错配置的常见错误清单与验收测试建议,附录 B 汇总全部估算公式,附录 C 给参数表阅读指引与命令成对性核对表。

全文不给出具体 opcode 数值、寄存器地址与位域位置,涉及数值处一律标注「以正式 datasheet / 规范为准」;可写标准名(如 ONFI)与标准命令名(如 Read Page、Program Page、Read Cache、Multi-Plane 系命令),不写厂商排名与商业数据。文中所有量级表达都用相对关系,曲线形状与拐点位置均为示意。

读者路径

路线一 · 建立正确的带宽观
先接受「账面值不完整」这个前提
第 1 章讲清四段分解与有效带宽口径,第 2 章讲清单平面天花板与提频的收益递减。这条路线不涉及任何具体命令,读完能解释「为什么实测只有标称的一半」以及「为什么换更快的接口没用」。
所有读者都建议先走这条;不需要任何前置计算。
路线二 · 三种并行手段
从多平面到 Cache 再到 Die 交错
第 3、4 章讲多平面架构与交错读的流水,第 5 章讲 Cache 命令的两段式模型与多平面组合规则,第 6 章讲 Die 交错与多 LUN 的任务分配。这条路线是全文主干,回答「能藏掉多少、怎么藏、代价是什么」。
做控制器调度与固件实现时按这条读。
路线三 · 协议与测量落地
从命令集到可复现的实测数字
第 8 章讲命令成对性、状态判据、ONFI 多 LUN 机制与 SPI NAND 的表达差异,第 9 章讲测量口径、估算方法、扫描方法与陷阱。适合要写测试方案与验收报告的工程师。
涉及实测与验收时读这条。
路线四 · 算账与核查
把机制换成数字,再换成清单
第 11 章用四个典型场景把带宽账本逐项算出来,第 12 章给设计核查清单与常见错误,附录 B 是可以直接抄走的公式汇总,附录 C 是参数表阅读指引。
评审、选型与现场排障时按需查阅。
阅读前必须接受的三条前提

一、并行不是免费的。多平面操作对地址有约束(通常要求不同平面上的页地址满足某种对齐关系),对命令有约束(必须成对或成组发出),对错误处理有约束(一个平面失败会影响整组)。二、三种并行不等价也不能简单相乘。多平面交错在同一颗 Die 内部共享部分电路,Die 交错在不同 Die 之间共享总线,二者的瓶颈位置不同,叠加时的上限由更窄的那一处决定。三、本文所有数值都是量级与相对关系。任何要写进规格书、验收报告或设计文档的数字,都必须以对应型号的正式 datasheet 与实测报告为准。

1. 带宽的账面值与真实值

本章不谈任何具体命令,只做一件事:把「带宽」这个词的两个含义分开。一个是写在手册首页、由接口速率与总线位宽相乘得到的账面值;另一个是用户在真实负载下测到的有效值。二者的差不是误差,是两套口径在统计不同的东西。把这个缺口量化出来,后面所有并行手段的收益才有可比的基准。

1.1 标称带宽的三个隐含前提

把接口速率乘以总线位宽,得到的数字在物理上并没有错 —— 它确实是总线在传输数据那一瞬间的吞吐能力。问题在于,任何一份标称带宽要能等价于真实吞吐,都必须同时满足三个前提,而这三条在真实器件上一条都不成立。

前提一:介质能够按这个速率持续供给数据。也就是说,当控制器把一页读完、想要接着读下一页时,下一页的数据必须已经在页缓存里等着。实际情况是:控制器发完读命令之后,介质需要先花 tR 把整页数据从存储阵列感测、放大、锁存进页缓存,然后才能开始往总线上送。在这个 tR 期间,总线上一字节都没有。前提一在单平面操作下必然被违反。

前提二:一次操作里的等待时间不占用总线,或者说等待时间可以忽略。即使在最理想的实现里(命令完全流水化、没有软件轮询开销),等待段依然以「总线空闲」的形式存在于时间轴上。它不占用总线,但它在占用时间。而吞吐是数据量除以时间,时间轴上的任何一段空白都会直接压低吞吐。把「不占用总线」等同于「不影响带宽」是这里最常见的逻辑跳跃。

前提三:器件内部的并行度能被主机负载用满。现代 NAND 器件内部普遍有相当高的并行资源(多个平面、多个 Die、多个 LUN)。但只有当主机提交的请求足够多、地址分布足够分散、调度器足够聪明时,这些并行资源才真正被同时点燃。单线程、顺序、小深度的负载,会把一颗内部并行度很高的器件跑成一颗串行器件。

隐含前提账面值假设它成立真实器件上的情况违反后的后果谁能补救
介质能持续供给数据下一页永远已在缓存里每读一页都要先付一次 tR输出流被切成一段一段,中间是空的多平面交错读 / Cache 读
等待时间可忽略等待段短到不影响吞吐tPROG 与 tBERS 远长于传输段吞吐被等待段主导,与接口速率脱钩Cache Program / Die 交错
内部并行度能用满负载天然分散到所有并行单元串行负载只点燃其中一个单元器件跑成串行器件,带宽掉到几分之一队列深度 / 调度器 / 地址布局
操作之间无间隙命令可以背靠背发出命令之间还有轮询与判定的开销短操作被固定开销吃掉大部分收益状态轮询优化 / 命令队列
时序参数不随环境变典型值就是工作值温度、磨损、电压都会改写时序参数高温与寿命末期带宽明显低于常温温度补偿 / 时序降额

这五条里,前两条决定了「有没有缺口」,后三条决定了「缺口有多深」。值得强调的是最后一条:时序参数不是常数。tR 与 tPROG 会随温度、随擦写循环次数、随器件个体差异而变化,datasheet 给出的通常是特定条件下的典型值与最大值。做带宽预算时如果只按典型值算,就会得到一个在常温新片上都勉强成立、在高温老片上完全不成立的乐观数字。这一点的展开见第 10 章 10.3。

1.2 一次操作的四段分解:命令、传输、等待、收尾

一次操作的四段分解:命令、传输、等待、收尾(长度按典型量级示意,非等比)四段的顺序随操作类型变化:读是「命令 - 等待 - 传输 - 收尾」,写是「命令 - 传输 - 等待 - 收尾」页读页编程命令 + 地址tR 等待:介质把页搬进缓存数据输出(传输)收尾命令 + 地址数据载入(传输)tPROG 等待:介质编程收尾总线空闲(读)总线空闲(写)命令段总线:忙(发命令与地址周期)介质:译码与寻址长度:极短,与接口速率相关能否隐藏:基本不需要隐藏传输段总线:忙(数据真正搬家)介质:页缓存串行移位输出长度:页大小 / 接口速率能否隐藏:只能靠提频压缩等待段总线:完全空闲介质:tR / tPROG / tBERS长度:与接口速率无关能否隐藏:唯一值得隐藏的一段收尾段总线:忙(状态读与判定)介质:内部复位与校验长度:短,但必须等能否隐藏:可与下一条命令重叠这张图要说明的事带宽的账面值只覆盖「传输段」:接口速率乘以位宽,算的是总线忙的那一段能跑多快。等待段既不在账面值的分子里,也不在它的分母里 —— 它根本没被算进去,于是账面值天然偏乐观。把等待段藏进别的操作背后,是提升有效带宽唯一真正有效的手段;提频只是在压缩已经很短的传输段。
图 1 · 一次操作的四段分解时间轴

要量化缺口,先要把「一次操作」这个黑盒拆开。无论读、写还是擦除,任何一次 NAND 操作在时间轴上都可以切成四段,而且这四段的归属方完全不同 —— 有的段总线在忙、介质在闲,有的段反过来。图 1 把这件事画了出来。

命令段:控制器把操作码与地址周期送上总线,介质接收并译码。这一段总线是忙的,介质在做事(译码与寻址),但两者做的是同一件事的上下游,无法分离。命令段的长度与接口速率强相关,但它本身极短,通常不是瓶颈。

传输段:真正的数据搬家。读操作时是介质把页缓存里的数据串行移位到总线上;写操作时是控制器把数据从总线载入介质的页缓存(或数据寄存器)。这一段总线和介质同时在忙,也正是账面带宽唯一统计的那一段。它的长度约等于「页大小 / 接口速率」,是唯一能用提频直接压缩的一段。

等待段:介质在内部做物理动作 —— 读时是把阵列里的一页感测并锁存进页缓存(tR),写时是把页缓存里的电荷真正打进单元并完成验证(tPROG),擦时是对整个块施加擦除脉冲并验证(tBERS)。这一段总线完全空闲,介质完全忙碌。它是三者中最长的一段,也是本文唯一关心的一段。

收尾段:操作完成的判定与清理。读时可能是内部 ECC 的解码与纠错、状态寄存器的更新;写时必然有一次编程状态读取(判断这次编程是成功还是失败)。这一段总线又忙起来,但很短。它能不能被重叠,取决于协议是否允许「不等这一条收尾就发下一条」。

段总线状态介质状态长度的主导因素能否被提频压缩能否被并行隐藏
命令段忙译码与寻址接口速率与地址周期数能,收益很小可与前一条操作的收尾重叠
传输段忙同步参与页大小 / 接口速率能,收益明显不能 —— 总线已被占满
等待段完全空闲tR / tPROG / tBERS介质物理特性,与接口无关完全不能能 —— 这是全部并行手段的目标
收尾段忙状态更新与校验协议规定的判据与轮询方式能,收益很小能与下一条命令重叠

表里最需要记住的是「等待段」那一行:它完全不能被提频压缩,但完全能被并行隐藏。这两个性质决定了本文的全部走向 —— 凡是想靠换更快的接口解决问题的思路都会落空,凡是想靠「让别的操作在这段时间里干活」解决问题的思路都有可能成立。

还有一点容易被忽略:四段的顺序不是固定的。读操作是「命令 → 等待(tR)→ 传输(输出)→ 收尾」,写操作是「命令 → 传输(载入)→ 等待(tPROG)→ 收尾」。写操作的传输段在等待段之前,这带来一个重要的不对称:写的数据载入一结束,总线就空出来可以服务别人,但这次写要等 tPROG 走完才算数;而读必须等 tR 走完才有数据可传。正是这个不对称,让写流水(Cache Program)比读流水更容易做深 —— 第 5 章会回到这一点。

1.3 tR、tPROG、tBERS 藏在哪里

三个时间参数都藏在等待段,但它们的性质差别很大,对带宽的影响方式也不同。分清三者,是做带宽账本的第一步。

  • tR(阵列读时间):从介质收到读命令到整页数据被锁存进页缓存的时间。它出现在每一次页读的等待段,直接决定顺序读的流水能有多密。tR 的量级通常在几十微秒量级,具体以 datasheet 为准。关键性质:它与接口速率无关,也与页大小基本无关 —— 无论这一页有多大,感测与锁存整页的耗时主要由阵列物理决定。
  • tPROG(编程时间):从数据载入完成、编程命令确认,到单元被真正写好并通过验证的时间。它出现在每一次页编程的等待段,是写带宽的主要杀手。tPROG 通常显著长于 tR,且在多层单元(每单元存更多比特)上明显更长 —— 因为需要更多次增量编程脉冲与验证。关键性质:它随写入的数据类型、随器件磨损程度、随温度变化,是一个分布而不是一个常数。
  • tBERS(块擦除时间):擦除整个块所需的时间。它是三者中最长的,通常比 tPROG 再高一个量级。关键性质:它以块为单位,而读与写以页为单位,所以擦除的等待段一旦出现在关键路径上,影响范围远大于单次读写。
参数藏在哪个操作的等待段量级关系(以 datasheet 为准)主要可变因素被哪种并行手段针对
tR页读三者中最短,几十微秒量级温度、读重试、器件个体差异多平面交错读 / Cache 读 / Die 交错读
tPROG页编程显著长于 tR单元层数、数据内容、磨损、温度Cache Program / 多平面写 / Die 交错写
tBERS块擦除三者中最长,比 tPROG 高一个量级块位置、磨损、温度多平面擦除 / 把擦除挪到后台
tWB / 命令忙时间命令段与收尾段极短,纳秒到微秒量级接口速率命令流水化与队列
tRR / 总线释放操作之间的间隙短但每次都要付接口速率、总线负载命令队列与减少轮询

这里必须澄清一个常见的误解:把 tR 与「读的延迟」混为一谈。tR 是介质内部的动作时间,不是主机感受到的读延迟。主机读延迟还要加上命令段、传输段、收尾段,以及排队时间。反过来,一次操作的延迟高,不等于带宽低 —— 如果多笔操作能重叠,单笔延迟可以很高而整体吞吐依然很好。带宽账本关心的是「单位时间完成了多少笔」,延迟账本关心的是「一笔要多久」,两者必须分开记。第 4 章 4.4 会给一个完整的延迟账本示例。

三者的量级关系决定了优化优先级

因为 tBERS 远长于 tPROG 远长于 tR,所以对带宽影响最大的是写而不是读,是擦除而不是写。这解释了为什么工程上「把擦除挪出关键路径」的收益往往大于「把读做得更快」:擦除一次,阻塞的是整个块的时间;而它完全可以被安排在后台,只要在前台需要这个块之前完成即可。第 7 章专门讨论这一点。

1.4 有效带宽的定义与度量口径

既然账面值不完整,就需要一个能替代它的量。本文统一使用有效带宽这个词,定义如下:

有效带宽 = 一次观测窗口内真正交付给上层的数据量 / 这个窗口的端到端时间。

这个定义看起来平淡,但它有三个必须显式声明的自由度,任何一个不说清楚,数字就不可比:

  1. 分子算什么。是纯用户数据,还是包含 ECC 校验与 spare 区的物理数据量?是否扣除因纠错失败而重读的部分?是否扣除被缓存命中、根本没有访问介质的那部分?
  2. 分母从哪算到哪。从命令发起到最后一次数据字节离开总线?还是包含命令排队时间?是否包含后台操作(垃圾回收、读刷新、磨损均衡)占用的时间?
  3. 观测窗口有多长。窗口太短会被冷启动、缓存预热、突发调度等瞬态污染;窗口太长又会掩盖抖动。窗口必须长到足以覆盖稳态。

这三个自由度在不同测试里被默认成不同值,是「同一颗器件测出三个不同带宽」这类争议的主要来源。本文约定:除特别说明外,分子为上层真正收到的用户数据量(不含 ECC 与 spare,不含缓存命中未访问介质的部分),分母为从第一条命令发起到最后一条命令完成的端到端时间(含排队与轮询开销,不含与本次负载无关的后台操作),观测窗口为足以穿透稳态的长度。

口径分子(数据量)分母(时间)会得到什么数字适用场合容易踩的坑
接口瞬时带宽总线上传输的字节数只算总线忙的时间最高,等于账面值评估接口是否成为瓶颈被当成器件带宽,乐观数倍
介质有效带宽用户数据量命令发起到完成,含等待段中等,是本文的默认口径评估器件与调度器的综合表现未扣除缓存命中会偏乐观
应用有效带宽应用真正拿到的数据量含排队、含文件系统开销最低,接近用户感受评估端到端体验混入了主机侧开销,难归因
稳态带宽稳态窗口内的用户数据量稳态窗口长度最低但最可信验收与寿命核算窗口不够长会得到冷态数字
峰值带宽任一短窗口的最大值该短窗口长度很高但不可持续说明上限,不能用于承诺被写进规格书造成纠纷
报告带宽数字时必须同时给出口径

一个没有口径的带宽数字,和一个没有单位的物理量一样没有意义。本文建议的最小报告集合是:读写比例、请求大小、队列深度、地址分布(顺序 / 随机 / 局部)、观测窗口长度、是否扣除缓存命中、器件磨损与温度状态。少了任何一项,这个数字都无法与别人的数字比较。第 9 章 9.5 会给一个完整的报告格式模板。

1.5 为什么提频救不了慢介质

这是本章最实用的一条结论,也是最容易在评审现场被反复争论的一条。先看一个清晰的推理链。

一次页读的总时间 约等于 命令段 + tR + 传输段 + 收尾段。其中只有命令段与传输段随接口速率缩短。假设传输段占总时间的比例为 r,那么把接口速率提高到原来的 k 倍,总时间只会缩短到原来的 1 - r + r/k 倍。当 r 很小(介质很慢)时,无论 k 多大,总时间几乎不变。

举个量级上的直觉:如果 tR 与传输段处于同一量级,把接口速率翻倍,总时间大约缩短四分之一,带宽提升约三分之一 —— 看起来还不错。但如果介质慢一个量级(tPROG 远长于传输段,这是 TLC 及以上器件的常态),把接口速率翻倍,总时间的缩短可能只有百分之几。这时再提频,买到的只是更贵的接口、更难的布线与更严的信号完整性要求。

介质相对速度传输段占总时间的大致比例接口速率翻倍带来的带宽提升提频是否值得应该改做什么
快介质(传输段与等待段同量级)约一半约三分之一值得,但收益已开始递减可继续提频,同时做多平面
中等介质(等待段约为传输段数倍)约四分之一到三分之一约百分之十几到二十几边际收益,需权衡成本优先做交错与 Cache 命令
慢介质(等待段比传输段高一个量级)约十分之一及以下约百分之几基本不值得只能靠并行度与后台化
擦除主导的场景占比极低几乎为零完全不值得把擦除挪出关键路径
随机小页场景传输段被命令开销淹没约百分之几不值得增大请求粒度与队列深度
提频真正的价值在别处

提频并不是毫无价值 —— 它压缩的是传输段,而传输段恰恰是总线被占用的那一段时间。在做了多平面交错或 Die 交错之后,总线要在多个并行单元之间分时复用,此时总线占用率的下降会直接提高「总线能同时供养多少个并行单元」。换句话说:提频的收益要在并行度做起来之后才兑现。先提频后做并行,顺序反了,钱花了看不到效果。

另一个常被忽略的点是:提频往往伴随严格的时序裕量与信号完整性要求(见同系列《ONFI / Toggle 高速接口 SI》篇)。在布线能力或器件等级不支持的情况下强行提频,换来的是偶发的重读与纠错,反而把有效带宽拉低。

把第 1 章收成一句话:账面带宽统计的是传输段,真实带宽受制于等待段,而等待段既不能靠提频压缩,也不能靠更快的控制器消除,只能靠「在它发生的时候让别的操作也在发生」来掩埋。第 2 章先把不掩埋时的天花板算清楚,从第 3 章开始进入掩埋的手段。

本章要带走的三句话

一、账面值只覆盖传输段,等待段(tR / tPROG / tBERS)一次都没被算进去。
二、等待段不能被提频压缩,但能被并行隐藏 —— 这一条决定全文走向。
三、任何带宽数字必须同时给出分子口径、分母口径与观测窗口,否则不可比。

2. 单平面操作的性能天花板

在讨论任何并行手段之前,必须先把串行基线钉死。本章回答一个看似简单的问题:一颗只有单个 Die、单个平面的 NAND,在理想控制器下,带宽最高能到多少?答案是「一页的数据量除以四段之和」,而这个和由 tR 或 tPROG 主导。知道了这条基线,后面每加一层并行,收益才有了可比的参照。

2.1 页读入缓存的串行链

一次最简单的页读,在命令层面是一条严格的串行链,任何一环都不能跳过,也不能与另一环重叠:

  1. 发起读命令。控制器送出 Read Page 命令与完整的地址周期(列地址 + 行地址,行地址里含块号与页号)。总线忙,介质接收。
  2. 等待 tR。介质把选中字线上的一整页单元同时感测,经灵敏放大器放大、判决,锁存进该平面的页缓存(也叫数据寄存器)。总线空闲,介质忙。这一步结束后,介质通常会通过 Ready/Busy 信号或状态位告知「数据已就绪」。
  3. 串行输出。控制器切换总线方向,按列地址顺序把页缓存里的数据字节逐个读出。总线忙,介质同步配合。这一步的时间约等于页大小除以接口速率,也与起始列地址有关(可以只读页的一部分)。
  4. 收尾。内部 ECC 对读出的数据做解码与纠错(若器件内置纠错),并把结果体现在状态信息里;介质回到可接受新命令的状态。

这条链上有一个细节值得单独指出:第 2 步与第 3 步之间,介质内部的页缓存是两套东西。感测锁存的那一级与往外串行移出的那一级在结构上是分开的,这正是 Cache 读(第 5 章)能够成立的物理基础 —— 可以在输出上一页的同时,让阵列开始感测下一页。但在普通读命令下,这个结构没被利用起来,第 2 步与第 3 步严格串行。

链上的环节耗时由什么决定总线介质能否与下一笔重叠(普通读命令下)
发起读命令接口速率、地址周期数忙译码寻址能与上一笔的收尾部分重叠
等待 tR阵列感测与锁存时间空闲忙不能 —— 普通读命令不允许
串行输出页大小 / 接口速率忙同步输出不能 —— 总线被本笔占着
收尾与纠错ECC 解码方式与纠错量忙或空闲状态更新能与下一笔的命令段重叠
操作间间隙轮询与调度开销忙空闲能被命令队列消除

表里「能否重叠」那一列是全章的钥匙。普通读命令之所以慢,不是因为每一段长,而是因为协议不允许重叠:必须等这一笔完全结束,才能发下一笔。后面几章讲的每一种手段,本质上都是在协议允许的范围内,把「不能」改成「能」。

2.2 页编程与 tPROG 占空比

页编程的串行链与读结构相同、顺序不同:发起 Program Page 命令与地址 → 把数据从总线载入介质的页缓存(这一步总线忙,是传输段) → 发出编程确认命令 → 等待 tPROG(总线空闲,介质忙) → 读状态判断成功与否(收尾段)。

这里引入一个非常好用的量:占空比。定义「某段占一次操作总时间的比例」。对读操作,等待段占比 = tR /(命令 + tR + 输出 + 收尾);对写操作,等待段占比 = tPROG /(命令 + 载入 + tPROG + 收尾)。占空比越高,说明这次操作里总线空闲得越久,也就意味着并行手段的理论空间越大。

写操作的等待段占比通常显著高于读操作,原因是 tPROG 远长于 tR,而且随着单元层数增加(每单元存更多比特),tPROG 增长得比 tR 更快。这带来一个反直觉但重要的推论:器件越「慢」,并行优化的收益空间反而越大,因为等待段占比更高。同时它也意味着,慢器件对「有没有做并行」极度敏感 —— 同一颗 TLC 器件,做了与没做 Cache Program,写带宽可以差出好几倍。

操作类型等待段是什么等待段占空比的典型水平传输段位置并行优化的理论空间主要约束
页读(单平面)tR中等,通常与传输段同量级或略高在等待段之后中等输出顺序与总线占用
页编程(单平面)tPROG高,通常显著高于读在等待段之前大编程失败的判定与回退
块擦除(单平面)tBERS极高基本没有传输段很大,但单位粒度是块块粒度导致难以流水化
状态读取几乎没有等待段极低几乎全是传输段无意义轮询频率本身就是开销
读状态后的重试额外的感测时间随重试次数线性上升与读相同越大说明器件越不健康重试会打断流水

还有一条必须写进账本的东西:tPROG 不是一个常数,而是一个分布。同一颗器件上的不同页、不同数据内容、不同磨损阶段,实际编程时间会有明显离散性。做流水设计时如果按典型值排程,就会不断遇到「这一笔比预期慢」的情况,流水被打断、后面的操作被迫等待。工程上的处理办法是按偏保守的分位数排程,而不是按典型值 —— 这会略微降低理论效率,但换来流水的稳定性。第 10 章 10.4 会讨论参数表怎么配。

2.3 单 Die 单 Plane 的命令流水模型

单 Die 单 Plane:三次连续页读,总线的忙与介质的忙几乎不重叠命令流水:每一拍都由「命令 - tR 等待 - 输出 - 收尾」四段串成,没有任何一段被叠起来总线介质CMDtROUT感测 + 锁存输出CMDtROUT感测 + 锁存输出CMDtROUT感测 + 锁存输出总线空闲窗口三次操作之间没有重叠:第 N 拍输出结束,第 N+1 拍命令才开始第 1 拍第 2 拍第 3 拍串行链的本质单 Die 单 Plane 时,一次操作内部四段串联,操作之间也是串联。总线的忙与介质的忙在整条链上几乎不重叠,两份时间都得付。为什么加不了速把接口速率提上去,只能压扁CMD 与 OUT 这两小段;tR 那段纹丝不动。介质越慢,传输段在总时间里占比越低,提频收益越小 —— 这就是收益递减曲线。唯一的出路既然总线的忙与介质的忙不重叠,就把「介质忙的时候」拿去服务别的介质。多平面交错、Cache 命令、Die 交错,做的都是同一件事的不同层次。记住这张图单 Die 单 Plane 的带宽上限,等于「一页数据量」除以「四段之和」,而不是除以「传输段」。总线空闲窗口有多长,就决定了后面所有并行手段能往上叠多高 —— 这是一个天然的天花板,不是缺陷。本书后面四章讲的每一种交错手段,都是在回答同一个问题:这段空闲窗口,能不能被别的操作填满。
图 2 · 单 Die 单 Plane 命令流水模型

图 2 把三次连续页读画在同一条时间轴上,分「总线」与「介质」两条泳道。可以清楚看到三件事。

  • 每一拍内部,总线的忙与介质的忙几乎不重叠。总线忙的是命令段与输出段那两段(图里的 CMD 与 OUT),介质真正忙的是 tR 那一段。这两段时间互不覆盖,所以总时间就是它们之和,一秒都没有省下来。
  • 每一拍之间也没有重叠。第 N 拍的输出刚结束,第 N+1 拍的命令才开始。中间的间隙是收尾段与轮询开销。在命令队列不被使用的情况下,这个间隙是纯损失。
  • 总线空闲窗口(图里红色虚线框)是全部优化的目标。它的长度就是 tR 的量级。谁能在这段时间里让总线干点别的,谁就把带宽提上去了。

把这张图抽象成公式,就是本章的核心结论。设一页的用户数据量为 D,命令段耗时为 Tcmd,等待段为 Twait(读时是 tR,写时是 tPROG),传输段为 Txfer,收尾与间隙为 Ttail,则单平面带宽上限为:

BW_single = D / (Tcmd + Twait + Txfer + Ttail)

而账面带宽是 D / Txfer。两者之比就是「缺口倍数」。由于 Twait 通常远大于其余三项之和,这个缺口倍数很容易达到数倍 —— 这正是实测与标称差出一个量级的来源。

这个公式怎么用

它只有一个用途:给任何优化设一个不可逾越的上限,并告诉你优化该往哪个方向使劲。如果一个方案号称把带宽提升了数倍,先用这个公式算一下它的理论空间 —— 若理论空间只有百分之几十,那么声称的数倍一定来自口径变化(比如把缓存命中算进了分子),而不是真实提升。第 9 章 9.4 会列出这类伪影。

2.4 Ready/Busy 轮询与总线空闲

等待段结束时,控制器必须知道「介质已经好了」。这件事看起来琐碎,但在单平面模型下它直接吃掉一部分可用带宽,因为轮询本身要占用总线时间,且轮询的粒度决定了等待段的实际长度。

常见的判据有三类。第一类是专用 Ready/Busy 引脚(并行 NAND 上的 R/B# 一类信号):它是独立的硬件信号,查询它不占用数据总线,控制器可以在等待期间去服务别的 Die 或做别的事,代价是需要额外的引脚与布线,且它通常只反映「这个 Target 忙不忙」,粒度较粗。

第二类是读状态寄存器 / 读状态命令:通过总线发一条状态查询命令并读回若干位。它的粒度可以很细(能区分读完成、编程完成、编程失败、擦除完成等),代价是占用总线、需要额外的命令周期,而且如果轮询太频繁,会挤占本可用于数据传输的总线时间;如果轮询太稀疏,会把等待段人为拉长(实际已完成,但要等下一次轮询才知道)。

第三类是协议层的命令队列与完成通知(如 ONFI 体系里的相关机制):控制器把多条命令排进队列,由器件在有进展时主动告知,控制器不必轮询。这是效率最高的方式,代价是控制器与器件都要支持,且实现复杂度明显上升。第 8 章 8.3 会展开。

判据方式是否占用数据总线粒度对等待段实际长度的影响实现成本适用场合
专用 Ready/Busy 引脚不占用粗,通常只反映忙闲几乎不增加需要额外引脚与布线并行 NAND 的传统做法
读状态命令轮询占用,每次查询都要发命令细,可区分多种完成与失败状态取决于轮询间隔,可能显著拉长低,所有器件都支持SPI NAND 与低成本方案
命令队列 + 完成通知基本不占用细,可区分到具体命令最小高,需要双方支持追求高并行的控制器
固定延时盲等不占用无,纯靠时序余量必须按最坏情况留足余量极低仅用于原型验证,不推荐量产
中断式通知不占用中小,但有中断响应延迟中,需要中断线与处理主机侧负载较轻时
轮询间隔是一个真实的调参项

轮询太密:总线被查询命令占满,数据传输被挤掉,实测带宽下降,而且这种下降不会体现在任何器件参数里,只表现为「莫名地跑不满」。轮询太疏:等待段被人为拉长,等待段时间越长,这个绝对误差的影响越小,但对短操作(状态读、小页读)影响很大。经验做法是按等待段长度的某个小比例设置轮询间隔,并在温度升高、时序参数变差时自动收紧 —— 具体比例以实测为准。

2.5 单平面情况下的带宽上限估算

把前面四节合起来,可以给单平面情形下一个完整的可执行估算流程。这套流程只需要 datasheet 上的公开时序参数,不需要任何实测,因此可以在选型阶段就用来判断「这颗器件值不值得做并行优化」以及「做了之后大概能到多少」。

  1. 确定页大小与用户数据量 D。注意区分物理页的 spare 区与用户可见部分,分子只算用户数据。
  2. 查出等待段参数。读用 tR,写用 tPROG,擦用 tBERS。注意 datasheet 给的是典型值还是最大值,做预算要用接近最大值的那一档,并考虑温度与磨损的额外降额。
  3. 算出传输段。Txfer 约等于 D / 接口速率(注意接口速率要换算成字节每微秒,并扣除协议开销与总线周转空闲)。
  4. 估算命令段与收尾段。命令段按地址周期数与接口周期算;收尾段按状态查询命令的开销加 ECC 解码时间算,若 datasheet 未给出,按与命令段同量级估计并留出余量。
  5. 相加求倒数,得到单平面上限。BW = D /(四段之和)。
  6. 与账面值对比,得到缺口倍数。缺口倍数 =(四段之和)/ Txfer。这个数字就是并行手段的理论空间上限。

下面这张表给出参数敏感性,说明哪一项的不确定性对结果影响最大 —— 它决定了你在 datasheet 上该花时间核对哪一项。

参数典型不确定性对单平面带宽的影响权重该不该花时间核对备注
等待段 tR / tPROG典型值与最大值可能差很多决定性,通常主导总时间必须核对,且要问清测试条件温度与磨损会进一步拉长
接口速率通常明确只影响传输段,权重随介质变慢而下降核对,但别指望它救场要扣除协议开销
页大小明确分子与传输段同时受影响核对即可大页有利于摊薄固定开销
命令段开销常被忽略小,但对短操作显著核对地址周期数多平面命令的地址周期更多
收尾与轮询取决于实现方式中,取决于轮询策略必须核对,这是控制器可控项是少数可优化的纯软件项
总线周转空闲常被漏算小到中核对时序参数双向总线换向需要空闲周期
第 2 章的结论,也是全文的基线

单 Die 单 Plane 的带宽上限,等于一页数据量除以四段之和;而四段之中,等待段既最长、又不能靠提频压缩、还完全不占用总线。这个「总线空闲而介质忙碌」的窗口有多长,就决定了后面所有并行手段往上能叠多高。带着这个基线进入第 3 章:第一种掩埋手段是让同一颗 Die 里的另一个平面,在你等待的时候也开始干活。

3. 多平面架构与寻址模型

第一种掩埋手段是「让同一颗 Die 里的另一个平面在等待期间干活」。要用好它,必须先回答两个问题:物理上哪些东西是独立的、共享到什么程度;协议上怎么点名某一个平面。本章讲前者(层级)与后者(地址),并给出多平面操作的合法组合与失败模式 —— 多平面不是「想对几个平面操作就对几个」,它对地址有硬约束。

3.1 Plane、Die、Target、LUN 的层级关系

NAND 器件内部的并行资源是一棵树。理解这棵树的关键不在于记住名字,而在于回答一个问题:两个操作各自处在这棵树的哪个分支上,它们之间共享了哪一级的资源。共享得越少,并行度越高。

从外到内,常见的层级是这样的:

  • Target(也常按 CE# 称呼):总线上的一个片选目标。控制器通过片选信号在这若干个 Target 之间做选择。同一条总线上可以挂多个 Target,它们共享总线,但各自有独立的命令接口与状态。
  • LUN(逻辑单元):能够独立接收并执行命令的最小单位。这是并行语义上最重要的一级 —— 「独立执行」意味着它可以有自己的状态机、自己的忙闲,别的 LUN 在忙不影响它接收新命令。第 6 章讲的 Die 交错,本质上就是 LUN 级的交错。
  • Die(物理硅片):一颗封装里的一个物理裸片。在很多器件上,一个 LUN 就对应一个 Die,两者常常被混用;但在多 Die 堆叠封装里,一个 Target 下可能有多个 Die,此时二者不等价。
  • Plane(平面):Die 内部的阵列分区。每个平面有自己的页缓存(数据寄存器),这是多平面操作能并行的物理基础 —— 两个平面可以同时把各自的页感测进各自的缓存。但同一 Die 内的多个平面仍然共享更高层的资源(命令译码、电荷泵、总线接口等),这是多平面并行度有上限的原因。
  • Block 与 Page:真正的存储组织单位,也是多平面操作最终作用到的对象。
并行单元的两套坐标:物理层级(左)与行地址里的平面选择位(右)层级关系(自外向内:越往外独立越强,越往内共享越多)Target / CE#总线上的一个片选目标LUN能独立接收并执行命令的最小单位Die一颗物理硅片,常与 LUN 一一对应Plane独立页缓存 + 独立阵列分区Block → Page多平面操作真正作用到的对象注意:Plane 是本文三种并行手段里最内层的一层行地址的构成(位序与位宽以正式 datasheet 为准)一次 Multi-Plane 操作送出的行地址:块地址页地址平面选择位平面选择位不一定在最低位,位数由器件支持的平面数决定同一个块地址 + 页地址,配上不同的平面选择位 = 不同平面上的同一相对位置两个平面各自的物理实体:Plane 0页缓存 0阵列分区 0Plane 1页缓存 1阵列分区 1Plane 2页缓存 2阵列分区 2互不共享的部分:页缓存与感测电路 → 这是能并行的物理前提仍然共享的部分:命令译码、电荷泵、总线接口 → 这是并行的上限来源层级决定独立性两个操作要能并行,前提是它们各自处在互不共享资源的分支上。同平面的两页共享页缓存 → 不能并行;不同平面的两页各有页缓存 → 能并行。地址决定能否成组多平面操作要求参与的各页在地址上满足器件规定的对应关系。不满足就不是「更慢」,而是被拒绝或产生未定义行为。命名因人而异Target / LUN / Die / Plane 这组术语在不同厂商文档里口径不一致。核对时看它「能不能独立执行命令」,不要只看名字。这一章的图要说明的事左边是「物理上谁能和谁并行」的答案:越靠外的分支,共享的电路越少,独立执行的能力越强。右边是「协议上怎么点名」的答案:行地址里专门有几位用来选择平面,位数决定这颗器件最多支持几个平面。两者必须一起看 —— 物理上能并行,协议上点不中,等于没有;协议上能点中,物理上共享了电荷泵,并行就会打折。
图 3 · Plane/Die/Target/LUN 层级与页地址中的 Plane 选择位
层级独立性体现在哪与谁共享资源能支撑哪种并行常见混用与坑
Target / CE#可被片选单独选中与总线上其它 Target 共享总线带宽通道级 / Target 级交错片选切换有建立保持时间,频繁切换有代价
LUN能独立接收并执行命令与状态机共享总线与部分接口逻辑Die 交错(第 6 章)文档里 LUN 与 Die 常互换,须核对语义
Die物理上独立的硅片多 Die 堆叠时共享封装与部分引脚Die 交错多 Die 封装下 Target 与 Die 不是一对一
Plane独立的页缓存与阵列分区共享命令译码、电荷泵、总线接口多平面交错(第 4、5 章)平面数上限由器件定,软件调不出来
Block / Page阵列内的组织单位同一平面内的块共享该平面的全部资源不构成并行把块级并行误当平面级并行

表里最容易踩的坑是术语混用。不同厂商、不同代际的文档对 LUN 与 Die、Target 与 CE# 的用法并不统一,有的文档甚至在同一份文件里切换口径。可靠的核对方法是看它「能不能独立接收并执行命令」:能,就是 LUN 级;不能、只是阵列分区,就是 Plane 级。名字不重要,语义重要。

3.2 页地址中的 Plane 选择位

物理层级解决「谁能并行」,地址解决「怎么点名」。NAND 的行地址(选块与选页的那部分地址)里,通常专门有若干位用来选择平面。理解这几点就够了:

  • 这些位的位置与宽度由器件决定。它们未必在行地址的最低位,也未必连续;位数由器件支持的平面数决定(支持两个平面至少需要一位)。具体位置与位序以正式 datasheet 为准,本文不给出任何位域位置。
  • 多平面操作送的是「同一份块页地址 + 多个平面选择」。也就是说,参与一次多平面操作的各页,其块内相对位置(页号)与块地址必须是相同的,只有平面选择位不同。这是多平面操作最核心的地址约束,见 3.3。
  • 单平面操作时这些位照常出现。它们只是恰好选中了某一个平面。换句话说,多平面命令与单平面命令在地址形式上往往差别不大,差别在于命令本身是否承诺「我要同时对多个平面下手」,以及控制器是否在同一个操作里送出了多组平面选择。
  • 列地址不受平面选择影响。列地址选择的是页内的字节偏移,与选哪个平面无关。所以它不参与多平面约束。
一个实用的自查方法

拿到一颗器件,先问三个问题:它有几个平面?行地址里哪几位选平面?多平面操作时是否要求各页的块地址与页地址完全相同?这三个问题的答案决定了你后面所有调度策略的形态。如果 datasheet 对第三点语焉不详,就按「必须完全相同」来设计 —— 这是绝大多数器件的口径,保守设计不会错。

3.3 多平面操作的地址约束与边界条件

多平面操作不是「任意挑两个页一起操作」。器件对参与同一个多平面操作的各页地址有明确约束,违反约束的后果不是「变慢」,而是操作被拒绝、行为未定义,或者写到不该写的地方。这一节列清常见的约束类型。

约束一:页地址必须相同。参与同一次多平面操作的各页,其块内页号必须一致。这是最常见的约束,理由是地址译码逻辑通常把「平面选择」放在地址通路的最末一级,各平面并行执行同一套行译码。

约束二:块地址在多数器件上也要求相同。即参与操作的各页必须位于各个平面的同一块号上。这一条比第一条更严格,也更容易被忽略。少数器件允许块地址不同但页地址相同,具体以 datasheet 为准。

约束三:块的类型必须相同。参与多平面擦除的各块必须都是同一类(例如都是普通数据块,或者都在同一个分区内)。把不同类型的块(例如某些器件上末尾的块有不同用途)混进同一次多平面擦除,可能导致部分块擦除失败而状态寄存器只报一个错。

约束四:坏块与已标记的块不能参与。如果参与操作的某个块是坏块,整组操作都会失败,而且失败信息可能不足以定位到是哪一个平面出了问题。控制器必须在成组之前做坏块筛选。

约束五:边界与地址回绕。当连续流水的地址跨越块边界、平面边界或 Die 边界时,成组关系必须重新计算。一个常见的实现错误是「按页号连续地自动成组」,结果跨越边界时把不同块号的页组在了一起。

约束类型具体内容违反后的典型表现控制器侧该怎么防严重程度
页地址相同各平面的块内页号必须一致操作被拒绝或部分平面未执行成组前校验页号相等高
块地址相同多数器件要求块号也一致写到错误的块 / 未定义行为成组前校验块号相等极高
块类型相同不能混入特殊用途块部分块擦除失败且难定位维护块类型位图,成组时过滤高
排除坏块坏块不能参与成组整组失败,错误信息不足成组前查坏块表高
边界重算跨块 / 跨平面 / 跨 Die 要重算组跨边界后组合非法成组逻辑以块为最小单位重新发起中高
平面数不超限成组数不能超过器件支持的平面数多余的组被忽略或报错从参数表读取平面数上限中

这里给一条工程经验:把成组逻辑建立在「块」而不是「页流」上。也就是说,调度器在决定一次多平面操作包含哪些页时,应当先确定块、再在块内按页号推进,并且在跨块时强制结束当前组、重新成组。这样写出来的代码天然满足前两条约束,也天然处理了边界问题。反过来,如果按「连续的页流」自动切分成组,就必须在每一组生成时做一次完整的地址校验,代码更容易出错,也更难评审。

3.4 多平面读、写、擦除的合法组合

多平面操作在读、写、擦除三类操作上的支持程度并不对称。一般来说,擦除最容易成组(因为它不涉及数据传输,只是对多个块同时施加擦除脉冲),读次之,写最复杂(因为要涉及数据载入、编程确认与失败判定的组合)。下面这张表给出三类操作的组合规则与注意点。

操作类型是否能成组成组后共享什么成组后不共享什么主要注意点
页读能,多平面读命令命令译码与总线输出阶段各平面的页缓存与感测电路输出顺序固定,且输出阶段总线独占
页编程(普通)能,多平面编程命令数据载入阶段与编程启动各平面的编程执行与验证任一个平面失败会影响整组的状态判定
页编程(Cache 模式)能,多平面 + Cache 组合数据载入与上一组编程的等待段各平面的编程执行组合规则最复杂,见第 5 章 5.3
块擦除最容易成组命令与擦除脉冲的启动各块的实际擦除过程块地址约束最严,且要排除特殊块
读状态 / 读回通常不成组无无状态要按参与的每个单元分别读
复位与模式切换通常作用于整个 Target整个 Target 一起生效无会打断正在进行的流水

还有一个必须写清楚的边界:多平面操作内部不能混操作类型。不能在同一次多平面操作里让一个平面读、另一个平面写;也不能让一个平面编程、另一个平面擦除。多平面命令的语义是「同一类操作,作用在多个平面上」。想让读与写重叠,那是Die 交错(第 6 章)或命令队列要解决的问题,不是多平面命令能解决的。

这一点经常被误解。多平面交错的并行是同构并行:同一类操作,在多个平面上同时推进。而 Die 交错的并行可以是异构并行:一颗 Die 在编程的同时,另一颗 Die 在读。二者的适用场景完全不同 —— 前者适合主机负载本身是同构的大批量读或大批量写,后者适合读写混合的负载。

3.5 跨 Plane 边界操作的失败模式

当成组逻辑出错、或者器件状态与控制器假设不一致时,多平面操作会以一些特征性的方式失败。这些失败模式的共同特点是:症状出现在离根因很远的地方,而且状态寄存器给出的信息往往不足以唯一定位。认识它们,能显著缩短排查时间。

失败模式触发条件直接症状为什么难定位排查切入点
部分平面未执行成组地址不满足约束,器件只执行了其中一部分读回的数据一半是旧的状态位可能仍报成功读回比对,而不是只看状态
整组失败但只报一次错某一个平面编程或擦除失败整组标记为失败不知道是哪个平面逐平面单独重发一次定位
数据错位输出顺序假设与实际不一致两个平面的数据被拼接错位校验和可能碰巧通过用已知图案做顺序验证
跨边界组非法连续流成组时跨块未重算偶发写入错误,与地址相关只在特定地址段复现把触发地址打印出来找规律
坏块混入成组坏块表未及时更新整组失败,且失败率随时间上升坏块是运行期新产生的核对坏块表的更新时机
状态读取时机错误在组内某个平面还没完成时就读了状态误判成功,数据实际未写好与时序强相关,难稳定复现严格按照协议要求的判据与时机
多平面操作最重要的设计纪律

多平面操作的错误处理粒度是「组」,不是「页」。这意味着一个平面的失败会连累整组,而回退动作也必须按组来做。设计时必须提前回答:组失败后是整组重发、还是拆成单平面逐个重发?重发时地址要不要变(例如写到另一个块)?元数据怎么记录「这个组只成功了一部分」?
把这三个问题留到出错时才想,几乎一定会写出不一致的回退路径。

第 3 章的小结

多平面并行是同构并行:同一类操作,作用在多个平面上,靠各自独立的页缓存实现感测与编程阶段的 overlapping。它对地址的约束是硬性的(页号、通常还有块号必须相同),错误处理的粒度是组而不是页。带着这三条进入第 4 章 —— 那里把多平面读的流水画出来,并把收益算清楚。

4. 多平面交错读:把 tR 折进流水

知道了多平面的物理与协议基础,现在算第一笔账:交错的收益到底是什么。本章给命令序列、流水图、深度与效率的关系、输出顺序的保证、延迟账本,以及一个可以直接套用的有效带宽估算式。核心结论是:交错省掉的是 tR 的重叠部分,而输出阶段仍然要依次占用总线 —— 这个不对称决定了收益的天花板。

4.1 交错读的命令序列与流水图

一次多平面交错读的命令序列,与两次独立的单平面读相比,差别只有一处:第二条读命令必须在第一条的数据开始输出之前发出。正是这一处差别,让两个平面的阵列感测(tR)在时间上重叠起来。

典型的序列是这样的(命令名以规范为准,此处只讲顺序):

  1. 发起第一个平面的读命令,地址里带上第一个平面的选择位。介质开始对平面 0 做行译码。
  2. 不等平面 0 的 tR 走完,立刻发起第二个平面的读命令,地址里带上第二个平面的选择位。这一步有严格的时间窗口:必须在平面 0 的数据开始输出之前完成,否则重叠失败。
  3. 两个平面同时进行阵列感测。总线上没有数据,但两个平面各自都在把整页感测并锁存进自己的页缓存。这就是被折进流水的时间。
  4. 依次输出两个平面的数据。先输出先发命令的那个平面,再输出后发的那个。这一段总线是满的,两次输出串行。
  5. 收尾与状态判定。两个平面各自完成,状态按协议规定读取。
两次页读:非交错(上)与两平面交错(下),总线与两个平面的占用关系非交错:两次单平面读,总时间 = 两次完整操作之和总线Plane 0CMDtR(总线空闲)OUT阵列感测 + 锁存输出CMDtR(总线空闲)OUT阵列感测 + 锁存输出总时长 = 2 ×(命令 + tR + 输出)交错:一次 Multi-Plane 读,两次 tR 重叠,两次输出依次进行总线Plane 0Plane 1CMD0CMD1tR:两个平面同时感测OUT0OUT1已省出的窗口tR(Plane 0)输出tR(Plane 1)等待输出总时长 = 2×命令 + tR + 2×输出:省掉的是一整个 tR省掉的是 tR,不是输出交错让两次阵列感测同时进行,但两次数据输出仍必须依次占用总线。所以收益上限受限于 tR 在总时间里的占比 —— 见的第 2 章占空比。命令必须成对发出两个平面的读命令要在第一个平面开始输出之前全部发完,否则第二个平面的 tR 就启动不了,重叠失败。这就是第 8 章说的成对性要求。输出顺序由协议定死先发哪个平面,就先输出哪个平面,控制器不能随意调换。调度器必须按这个顺序安排主机侧的接收缓冲,详见第 4 章 4.3。同样两页数据,交错把总时间从「2 × 完整操作」压到「一份 tR + 两份命令与输出」
图 4 · 多平面交错读时序流水
序列环节单平面读(两次)两平面交错读差值来源是否可被进一步压缩
命令段两次,分别发起两次,背靠背发起基本相同,交错略省间隙能,靠命令队列
等待 tR两次串行,各付一次一次,两者重叠这是全部收益的来源能,靠加大深度
数据输出两次串行两次串行,顺序固定没有差别不能 —— 总线已被占满
收尾与状态两次两次(或按组合并一次)略省能,靠合并状态读取
操作间间隙两次间隙一次间隙省一次能,靠流水化

表里最后一行值得单独说:交错不仅省了 tR,还顺带省了一次操作间间隙。这个收益在单看 tR 时容易被忽略,但在小页、高频次的负载下,间隙占的比例并不小,省下来的部分可能相当可观。反过来,这也说明大页负载下交错的相对收益更高吗?不 —— 恰恰相反:大页时传输段更长,tR 占比下降,交错的相对收益变小。第 11 章 11.1 会把这笔账算清楚。

4.2 交错深度与 tR 隐藏效率

把两个平面换成 N 个平面,就是交错深度 N。设一次单平面读的总时间为 T1 = Tcmd + tR + Txfer,那么深度 N 的交错读总时间约为:

TN 约等于 N × Tcmd + tR + N × Txfer

对应的每页平均时间为 Tcmd + tR/N + Txfer,有效带宽提升倍数为:

增益(N) = (Tcmd + tR + Txfer) / (Tcmd + tR/N + Txfer)

这个式子的形状非常明确:深度为 1 时增益是 1;深度趋于无穷时,增益趋于 (Tcmd + tR + Txfer) / (Tcmd + Txfer),即「总时间 / 非等待段时间」,也就是第 2 章说的缺口倍数。所以缺口倍数既是并行手段的理论上限,也是这条曲线的渐近线。

交错深度与有效带宽:收益集中在前两级,之后由总线与共享资源接管有效带宽随交错深度的变化(示意曲线,拐点与斜率以实测为准)4×3×2×1×12345678交错深度(同时参与交错的平面数)常见器件的平面数上限收益最大的一步:深度 1 → 2实测曲线:总线占用与共享资源先饱和理论曲线:假设 tR 完全可重叠为什么深度 2 最划算从 1 到 2 直接把等待段对半砍,是整条曲线上唯一「翻倍投入换翻倍收益」的区间。之后再加深,每加一级的边际收益都在变小。为什么实测更早上限理论曲线假设只有 tR 在重叠,真实器件上命令译码、电荷泵、总线接口是共享的。深度越大,这些共享资源越先成为瓶颈。深度不是越深越好深度加大意味着一次性占用的页缓存与缓冲更多,错误回退的代价更大,且对地址连续性要求更苛刻。深度 2~4 是常见的工程折中。这条曲线怎么用选型阶段:查清器件支持几个平面,就知道自己坐在这条曲线哪一段 —— 深度上限是硬件决定的,软件调不出来。估算阶段:用第 2 章占空比算出理论曲线,再按「总线占用率」与「共享资源竞争」打折,得到实测曲线近似。验收阶段:扫一遍深度(见第 9 章 9.3),把实测点画到这张图上。偏离理论曲线过远,说明调度器或地址布局有问题,不是器件问题。
图 5 · 交错深度与 tR 隐藏效率曲线
交错深度每页平均等待段理论增益(示意)实测常见增益(示意)差距来源工程评价
1(基线)tR1.0×1.0×无串行基线,一切比较的参照
2tR / 2约 1.8×约 1.6× ~ 1.8×命令段翻倍开始显现性价比最高的一级
3tR / 3约 2.4×约 2.0× ~ 2.3×共享资源竞争收益仍然明显
4tR / 4约 2.8×约 2.3× ~ 2.6×总线占用与缓冲压力常见器件的实际上限
超过器件平面数不适用无意义无意义硬件不支持必须用 Die 交错再叠一层
深度不足(有资源但没填满)介于两者之间低于理论明显低于理论地址分布不分散 / 队列太浅最常见的实际瓶颈
「深度不足」是实测跑不满的第一号原因

器件支持 4 个平面,但实测增益只有 1.5 倍 —— 这种情况极少是器件问题,几乎总是深度没有被真正填满。三个高频原因:① 队列深度不够,主机一次只提交一两笔请求,调度器没有足够的候选去凑满一组;② 地址分布集中,连续的请求落在同一个平面的相邻区域,凑不出跨平面的组合;③ 成组约束太严,例如强制要求块号相同,导致大量请求无法成组。
排查顺序建议:先看队列深度 → 再看地址分布 → 最后看成组命中率。第 10 章 10.1 会讲调度器怎么提高成组率。

4.3 读数据输出的顺序保证

多平面读的输出顺序是协议规定的,不是控制器可选的。通常的规则是:按发出命令的顺序,先发的平面先输出。这条规则看起来简单,但它对控制器的缓冲区管理提出了明确要求,忽略它会造成一类非常隐蔽的数据错位。

为什么顺序不能随便换?因为页缓存是硬件资源:平面 0 的数据被感测进平面 0 的页缓存,平面 1 的在平面 1 的页缓存。总线上一次只能选通其中一个往外移。器件内部并没有一个「任意读取某个页缓存」的自由仲裁 —— 输出顺序固化在命令序列里。

这对控制器提出三点要求:

  • 接收缓冲必须按输出顺序排列。如果主机请求 A 映射到了平面 1、请求 B 映射到了平面 0,那么物理上先出来的是 B 的数据。控制器必须知道这一点,把数据送到正确的主机缓冲。
  • 主机侧的完成通知顺序不等于提交顺序。在多平面与多 Die 混合的调度下,先提交的请求可能后完成。上层协议如果假设了顺序完成(某些简化的固件会这样假设),就会出现偶发的错误。
  • 出错时的重排必须显式处理。如果某一组里前一个平面失败、需要重读,那么后一个平面的数据可能已经输出。此时要么把它丢弃重来,要么先把已输出的数据落地 —— 不能假设「失败就整组重来」。
顺序相关的环节协议保证什么控制器必须做什么出错会怎样如何验证
组内的输出顺序按命令发出顺序依次输出按此顺序安排接收缓冲两个平面的数据错位拼接用已知图案填满两页再读回比对
组间的完成顺序通常按组推进,但可被调度打乱不要假设 FIFO 完成上层收到乱序数据打乱提交顺序做压力测试
失败后的剩余数据协议不保证可以跳过显式决定丢弃还是落地缓冲泄漏或数据丢失注入失败观察回退路径
随机读的部分输出可以只读页的一部分(列地址)记录每笔请求的实际列范围读到多余或缺失的字节列地址边界用例
跨 Die 的组合顺序不同 Die 之间顺序由调度器决定维护每笔请求的目标 Die 记录跨 Die 数据混淆多 Die 并发压力测试

验证顺序保证的方法很直接:用可辨识的图案填满多个平面(例如每个平面写入不同的固定图案),然后按各种提交顺序读回,逐字节比对。这个测试要覆盖「提交顺序与输出顺序相反」这一最坏情况。很多只在顺序负载下验证过的固件,在第一次遇到乱序负载时就会暴露问题。

4.4 交错读的延迟账本

带宽账本回答「单位时间完成多少笔」,延迟账本回答「一笔要多久」。这两个账本必须分开记,因为它们对交错的响应是相反的。这一点非常重要,也是很多性能争议的来源。

就单笔延迟而言,交错不但没有改善,通常还会略微变差:因为在交错模式下,第一笔数据要等到「整组命令发完 + tR + 排在它前面的平面输出完」才能开始传输。如果它排在组内第二个,它还要额外等第一个平面的输出走完。也就是说,组内越靠后的平面,单笔延迟越高。

就整体吞吐而言,交错明显改善:因为整组的总时间被 tR 的重叠压短了,单位时间交付的数据量上升。

于是就有了那个经典的现象:吞吐上升的同时,平均延迟上升、尾部延迟上升得更明显。对于吞吐型负载(大文件拷贝、扫描、备份),这是纯赚;对于延迟敏感型负载(小随机读、交互式响应),这可能是亏的。第 11 章 11.2 会量化这个塌陷。

账本项目单平面读两平面交错读(组内第 1 个)两平面交错读(组内第 2 个)趋势
命令发出到数据开始输出tR命令 ×2 + tR命令 ×2 + tR + 第 1 个的输出变差
单笔端到端延迟T1略高于 T1明显高于 T1变差,且组内位置越后越差
组内平均延迟T1约 1.0 ~ 1.3 × T1同左略变差
单位时间交付页数1 / T1约 1.6 ~ 1.8 / T1同左明显变好
尾部延迟(P99 一类)由重试与排队决定叠加了组内排队叠加更多变差,且更依赖调度
对交互式负载的友好度较高中较低下降
什么时候不该做交错

如果负载是单笔延迟敏感、并发度低的(例如小随机读、元数据查询、交互式响应),强行成组会让每一笔都等组内其它成员,得不偿失。成熟调度器的做法是动态决定成组与否:队列里有足够多可以成组的同构请求时才成组,队列浅时直接单发。这个判断逻辑的收益,在很多真实负载下比「把深度调到最大」更大。第 10 章 10.1 展开。

4.5 多平面读有效带宽估算

把本章的公式整理成可以直接套用的估算流程。它只需要 datasheet 上的 tR 与接口速率,加上页大小,就能给出量级正确的结果。

  1. 算出传输段:Txfer 约等于 页大小 / 有效接口速率(扣除协议开销与总线周转)。
  2. 查出等待段:tR,取接近最大值的那一档,并按温度与磨损留出降额。
  3. 算出命令段:Tcmd 约等于 命令与地址周期数 × 接口周期;多平面命令的地址周期通常更多,不要沿用单平面的数。
  4. 确定可用深度 N:取「器件支持的平面数」与「调度器实际能凑出的深度」两者中较小的那个 —— 后者常常是短板。
  5. 代入:BW_mp = N × D / (N × Tcmd + tR + N × Txfer + Ttail)。
  6. 对比基线:增益 = BW_mp / BW_single,与第 4.2 节的表对照,看是否落在合理区间。若不落在合理区间,先查深度有没有被填满。
输入量从哪里来常见误差来源对结果的影响核对优先级
页大小 Ddatasheet混淆物理页与用户可见部分线性影响分子高
tRdatasheet 时序表用典型值代替最大值;忽略温度降额主导结果最高
接口速率datasheet / 控制器配置未扣除协议开销与总线周转只影响传输段中
命令周期数datasheet 命令表多平面命令地址周期更多小,但深度大时会被放大中
实际深度 N调度器统计队列浅 / 地址集中 / 成组约束往往是最大误差源最高
尾段时间 Ttail实测或估计轮询策略不同差异很大中小中
第 4 章的结论

多平面交错读省掉的是 tR 的重叠部分,输出阶段依然串行;因此它的增益受限于 tR 在总时间里的占比,渐近线就是第 2 章的缺口倍数。深度 1 → 2 是最划算的一步;再往上受制于器件平面数与共享资源。它提升吞吐,但会推高单笔与尾部延迟 —— 对吞吐型负载是纯赚,对延迟敏感型负载要慎用。
第 5 章处理写侧:那里因为传输段在等待段之前,流水可以做得更深,机制也完全不同。

相关报告 · 交叉引用 1 器件全部展开收起 ▾
点开类目即可展开:具体文档 / 章节(点章直接跳转到该章)
SPI NAND
电路设计指南
软件设计规范
Linux 驱动开发
样机问题排查
量产问题排查4
全志平台 SPI NAND NOR
章节(点章跳转,共 11 章)
海思平台 SPI NAND 量产常见失败
章节(点章跳转,共 11 章)
烧录成功但不开机 SPI NAND
章节(点章跳转,共 12 章)
瑞芯微平台 SPI NAND eMMC
章节(点章跳转,共 11 章)
系统设计指南3