读内存数据是一封迟来的回信。host发一条READ命令,DRAM不会立刻回复,而是要磨蹭一阵才把DQS和数据送回来。而且这个磨蹭多久还因人而异,每一颗颗粒、每一次都不太一样。因此host压根不知道回信的精确的几点几分的时间。
host内存控制解决这个问题就只用一招:装一扇门 DQS Gate,在回信到门口的那一瞬间打开接住它。Receive Enable 就是训练这扇门几点开的过程 。开门策略很有讲究,开早了放进噪声,开晚了漏掉数据。一个人守一扇门,要精准卡住那个点,正所谓一夫当关,万夫莫开。

一、为什么读方向要守门,写方向不用?
写数据是host自己寄货 ,节奏自己定,几点寄几点到心里有数。读数据是DRAM的回信,节奏DRAM定,host发完命令只能眼巴巴等着猜回信几点到。
读延迟到底由什么构成?
host发READ到DRAM数据回到host,中间隔着三段:
host发READ
↓ ① CK坐公交,fly-by逐站停靠
DRAM收到命令(CK边沿)
↓ ② DRAM内部准备(访问延迟,折算成 CL):访问存储单元、读出、驱动DQS/DQ
DRAM吐出DQS+DQ
↓ ③ DQS/DQ 坐专车点对点回给host
host接住数据
为什么不分别调整各个阶段的的延时?
现在的做法是读方向没有分别去处理 CL / tDQSCK / fly-by / 飞行时间各是多少,而是把它们当成一个黑盒子,只关心回信总共迟到多久。
黑盒子不是一个精确的数字,因为每颗颗粒、每次都有差异,所以只能让DRAM用固定节拍演练,去扫出来门在哪个时间打开正好能接住。扫出来的门的时刻就是总延迟,三个阶段的延迟一次性全搞定。简单、粗暴、有效!
用黑盒统一处理不是偷懒而是这四个分量拆不开,不得已而为之!
| 分量 | 性质 | 能不能训 |
|---|---|---|
| CL(读延迟周期数) | host 设定的写进DRAM的MR | 不用训自己定的 |
| tDQSCK | DQS 上升沿相对 CK 的位置(固定偏移,查表可得) | 不用训,查表 |
| fly-by skew | 拓扑物理属性 | 读方向只能吸收 |
| 飞行时间 | DQS、DQ 从 DRAM 飞回 host 的走线时间 | 只能测出,不能改 |
CL不是host自己写的吗?为什么写进去却不能调? 关键在写≠调,CL是CAS Latency列选通延迟,表示的是READ命令到第一笔数据的 时钟周期数,CL的值在MR0里表示。它看着像host随便定的,其实被DRAM的物理速度锁死了: CL = tAA / tCK 。tAA = DRAM 内部真实的列访问时间,纳秒级别由硅工艺决定;spec里 DDR5-3200 档 tAA(min)=16.25ns,tCK是一个时钟周期的长度。host只是 把物理纳秒换算成几拍,写到MR0中。 就像厨师做一道菜真实耗时3分钟(tAA),假设节拍1秒,host说下单后第180拍上菜,节拍缩到0.5秒频率翻倍,就得说第360拍上菜。host只负责换算记录。
tDQSCK 是 DQS 相对 CK 的位置(固定偏移) ;fly-by skew 读方向体现在每颗chip的DQS返回时间差没法拉齐,只能让门跟着各开各的;飞行时间 是DQS、DQ从DRAM飞回host的走线时间只能知道总路程也改不了。 CK沿fly-by链一站站停,每颗chip的CK到达时刻不同,于是每颗chip的DQS返回时刻也跟着不同。这就是读数据回来时间参差不齐的根源,也是写方向Write Leveling训练就是对表解决这个skew的。 DQS/DQ 坐专车点对点回给host时间取决于板子/DIMM 的物理走线总长度,host不完全知道精确值。 读延迟的大头是 CL,不是 tDQSCK。 tDQSCK(DQS output access time from CK,JESD79-5 参数)是DQS上升沿相对CK的位置 一个固定偏移(6400 档约 0.348 tCK)不是访问延迟。每次都不一样的其实是 tDQSCKi(抖动窗口,0.41~0.60 tCK),spec 只给范围。 所以无论怎么拆,最终都要回到总延迟 = CL + tDQSCK + fly-by + 飞行时间。拆开分别测再相加结果一样还多一堆步骤,而且有的部分测不准,tDQSCKi 是范围(抖动窗口)、fly-by 读方向只能吸收。
遇到一堆不确定量,有两种方法来搞定:① 拆开分别消除不确定;② 把不确定封装成一个黑盒子统一调。 读方向这四个部分拆不开,所以也就只能选封装成黑盒子关在门里面。
那么写方向为什么能拆开? 写方向的fly-by skew是可补偿的,因为DQS是从host主动发出的,所以就能在host端加延迟去对齐各自CK,所以写方向可以拆开分别补偿这就是Write Leveling。
| 写方向(Write Leveling) | 读方向(Receive Enable) | |
|---|---|---|
| 不确定量 | fly-by skew可补偿 | 总读延迟拆不开 |
| 设计手法 | 拆开分别补偿 | 封装成黑盒守门 |
我不关心你内部磨蹭几毫秒、公交停了几站、飞了多远,我只想知道回信几点到门口,然后把开门时间卡在那个点。
二、几点开门?先细后粗
| 坐标 | 问什么 | 谁来定 |
|---|---|---|
| 周期内 第几格 | 回信落在一个时钟周期里的哪个位置 | 这叫细Fine,先跑 |
| 第几个周期 第几拍 | 回信是发命令后第几拍到的 | 这叫粗Coarse后跑 |
就像坐高铁,我们得先知道坐的这班G7219停在几号站台,这样我们才知道去哪里坐,然后还得知道是哪天的G7219,选错出发的日子也不行。
等等,CL不是已经说好第几拍了吗?怎么还要量?因为CL只是 名义时刻表 (理论上第CL拍),真实到达带着偏移(tDQSCK 位置 + fly-by + 飞行时间)和抖动(tDQSCKi),每颗chip每次都不一样。 时刻表写 9:00,车从来没准点过 ,所以 Fine/Coarse 就是量这班车到底几点几分到。
而且量出来的结果 不写进DRAM的MR ,门长在host的 PHY里:Coarse写进RxIoTclDelay(第几拍的整周期延迟),Fine写进RecEnDelay(拍内哪一格的PI相位)。MR只是训练前的考场布置(MR2进演练模式、MR8前导长度),不是训练结果。
三、让DRAM进前导训练模式提前亮牌
平时DRAM是收到单才发货,发完就拉倒,host吃不准他的脾气和节奏。在开启ReceiveEnable训练时,host会让DRAM进演练模式,这时host不停下单,DRAM就按固定节拍不停地发。
这就是 JESD79-5 §4.18 Read Preamble Training Mode :把MR2里的一个位(read_preamble_training)置1后,DRAM按已知的固定节奏送出DQS前导,让host探测读命令后第一笔数据选通何时回来。
平时快递你下单我才发货,训练模式我按时刻表不停发,你习惯了就能掌握规律摸着节拍收货。
四、Fine先跑找到灯在周期里的位置
DRAM进了演练模式,DQS就像一盏每个周期都亮一下的灯。host拿快门扫一个周期,找灯亮的那一段:起点(Rising Edge)、终点(Falling Edge)、亮多久(Pulse Width)、正中(Center)。这就是灯在一个周期里的坐标位置,靠相位插值器再把1个时钟周期切成很多小格的毫米尺,一格一格精扫所以叫Fine。
五、Coarse后跑数这是第几趟的灯
Fine精扫只告诉我们灯会在一个周期在第几格,没告诉我们这是第几个周期的灯。Coarse粗扫就是来补这一维的。从灯亮着挪到灯还没亮,从1翻成0的瞬间, 前导刚露头表示往返延迟找到。
Fine细扫找灯在周期里的位置,Coarse粗扫数这灯是第几趟到的。先知道停哪个站台,再数哪一天的车。
六、前导偏移收尾
门的最终位置还要根据读前导长度(MR8的ReadPreamble Settings,1/2/3/4 tCK)再平移一格。细节:训练模式强制 1 tCK 前导(spec §4.18.3),真实运行用MR8编程的长度,所以训练完要把1tCK测的相位换算回真实长度下的相位。
最终门位置就是往返延迟第几拍加上周期内的哪一格的相位再加上前导偏移。
七、写对表对比读守门
| 维度 | Write Leveling(写) | Receive Enable(读) |
|---|---|---|
| 方向 | host发DQS,DRAM采样反馈 | DRAM发DQS,host开门接住 |
| 本质 | DQS对齐CK | 门在何时打开守门 |
| spec 模式 | 写均衡模式 | 读前导训练模式 |
| 两段式顺序 | Coarse 先,Fine 后 | Fine 先,Coarse 后 |
| 耗时 | 更慢 | 更快 只扫一个边沿加一个周期数,不扫整片眼图 |
同一个 fly-by skew,写靠补偿、读靠吸收
| 方向 | fly-by skew 怎么处理 |
|---|---|
| 写 | 主动补偿 写数据同时发到所有chip,但每颗chip的CK到达时刻不同,所以把每颗chip的 DQS 错开延迟去对齐它自己的 CK |
| 读 | 被动吸收 每颗chip的DQS返回时刻本来就不同,它的CK到的晚,host的门每颗 chip 各开各的 |
写方向像给不同楼层送餐,错开时间让每层的人在自己饭点收到;读方向像不同楼层的人各自下楼取餐,把每层的取餐口开在各自到达的时刻。
八、顺序为什么反转?
写方向 先Coarse后Fine ,读方向 先Fine后Coarse 。根本原因是读方向的DQS是周期循环的,灯每个周期都亮,所以可以先找格再数拍,两件事正交;写方向的DQS是一次性的,所以先得对齐第几拍,才能谈拍内哪一格。
读方向可以三步走:① 理论估算框到大致第几拍→ ② Fine扫满一个周期找高相位→ ③ Coarse递减往返延迟,从亮(1)挪到灭(0),把第几拍精确化。
九、DQS为什么一定比CK早?
这是理解fly-by 拓扑的隐藏前提:写方向能加延迟对齐,靠的是DQS天生比CK早到。
- CK蛇形长线 fly-by,绕大圈逐站停靠,DQS走点对点短线直达、等长。
- 同样速度的信号,路程长的晚到,所以对远端chip,CK 绕了大圈所以必然晚到、DQS直达肯定早到,DQS一定比CK快,且快多少随chip越远越大。
所以写方向永远只需要让专车等等公交 ,永远不会遇到公交到了、专车还没来这种没法减延迟的死局。
fly-by拓扑的设计动机: 牺牲CK的路程变长、逐站偏差,换来DQ的等长点对点、快且齐,从而让加延迟对齐成为可能。
十、为什么所有训练都是host做,DRAM只能当个傻瓜?
把前面几个为什么汇聚到一起,那么你可能会想为什么不简单点在 DRAM chip上也装个门,省得每次都要host忙活? 答案有三:
- DRAM越笨越好:DRAM是JEDEC标准化的量产颗粒主打一个便宜、量大管饱,行业形成普通的共识就是复杂的训练逻辑全让host来做,DRAM越单纯越好。而且如果给每颗DRAM加训练逻辑那就会增加成本,也会不标准。
- 调节的旋钮只能在host:错开DQS要用的延迟线(相位插值器)长在host的PHY里;DRAM里再各上这个逻辑就重复了。
- DRAM是slave,没资格主动训练:训练 = 测量 + 调整 + 反馈的闭环,只有host能够纵观全局掌握所有的信息。
测量者和调整者必须在同一侧。 host既看得见skew、又握着调整延迟线的方法,所以训练只能是host责无旁贷。
写方向对一次表,读方向守一次门;门开早了进噪声,开晚了漏数据------一夫当关,万夫莫开。