ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

从DRAM Die到PHY:DDR内存分层架构与调试实战

2026/9/9 6:27:04 拓冰建站 浏览量
从DRAM Die到PHY:DDR内存分层架构与调试实战 做硬件和固件的人十有八九都见过这种场面PCB上整齐躺着一排BGA封装的DDR颗粒原理图里标着DDR4、DDR5或者LPDDR4结果板子上电之后系统就是起不来用示波器抓信号又是一堆毛刺和不确定电平。早几年我调一块FPGA板子DDR读有效信号一直拉低整整查了一个多星期最后发现根因根本不是内存颗粒本身而是我没有把从控制器到DRAM Die之间隔着的几层关系理清楚。实际上从一颗最原始的DRAM Die到系统里真正跑起来的DDR、LPDDR、HBM中间隔着封装、Rank、PHY、控制器这几个关键层级。每一层都有自己的规则哪一层出了问题表现都可能千奇百怪有的像供电噪声有的像时序违例有的干脆就连训练都过不去。这篇文章就沿着这条链路把这几个层级逐一拆开结合我实际调试中踩过的坑和验证过的方案讲清楚它们分别解决什么问题、相互之间怎么协作以及遇到典型故障时该怎么往下查。1. 先搞明白DRAM Die所有内存能力的起点1.1 一颗DRAM Die里到底装了什么DRAM Die是所有内存产品最底层的基本单位不管是DDR4 UDIMM、手机里的LPDDR5还是GPU旁边那颗HBM本质上都是若干颗DRAM Die经过不同封装、不同接口组织出来的产品。DRAM Die本身的结构并不神秘它由大量存储单元排成阵列每个存储单元由一个晶体管和一个电容组成电容用来存电荷、晶体管用来控制读写通道。问题在于电容会漏电。电荷存进去之后如果不处理几十毫秒内就会衰减到无法区分0和1所以DRAM必须不断刷新这也是“Dynamic”这个词的由来。控制器会周期性发出刷新命令让每一行存储单元重新把电荷恢复到满状态。这里就牵扯到热词里提到的autorefresh和MRSautorefresh是指DRAM芯片根据内部生成的行地址自动完成刷新不需要外部逐个指定行地址而刷新周期、刷新粒度这些参数通常写入MRSMode Register Set寄存器里。MRS就是DRAM的“配置文件”通过模式寄存器设置突发长度、CAS延迟、驱动强度等关键参数是初始化流程里必须做的一步。一颗Die内通常被划分成多个Bank每个Bank是独立的存储阵列芯片内部有行缓冲区一次激活命令会把某一行的内容整体搬到sense amplifier里之后对该行的读写都在缓冲区中进行。Bank的数量越多并发能力越强但对地址编码和调度策略的要求也越高。1.2 Bank、Row和Column是怎么协同工作的要理解DDR控制器为什么那么复杂首先要理解一次读操作在Die内部经历了什么。假设控制器要读一个64bit的数据它需要先发送激活命令激活命令里带上Bank地址和Row地址告诉芯片要打开哪个Bank的哪一行随后发送读命令携带Column地址从已经打开的行缓冲区里取出对应列的数据。这三个阶段有各自的延迟参数。从激活命令到读命令可以发出需要等待tRCD从读命令发出到数据出现在DQS上需要等待CLCAS Latency之后还有读数据到预充电的等待时间tRTP等等。控制器端有一个专门的状态机或者说调度器来管理每个Bank处于空闲、激活、预充电中的哪种状态并根据这些时序参数计算最快能安排下一条命令的时间。很多人刚接触DDR时会觉得Bank越多就越好实际没那么简单。Bank多确实能提升page命中率因为可以同时打开更多行但Bank组Bank Group之间还有约束DDR4里不同Bank Group之间的时序更宽松同一Bank Group内部反而要小心命令冲突。性能和时序是要互相权衡的这也是为什么训练和参数调优会直接影响实际带宽。1.3 DRAM、NAND和HBM到底差在哪热词里有个常见的困惑就是DRAM、NAND、HBM这三个名词经常出现在一起但比较容易混淆。简单来说DRAM是易失性内存按字节/字线性读写作为运行内存使用NAND是非易失性闪存需要先擦除再写入按页读写作为存储介质使用HBM本质上就是DRAM Die的堆叠产品使用的存储单元和DDR/LPDDR里的DRAM单元是同一种技术差别在于封装和接口组织完全不同。HBM把多层DRAM Die用TSV硅通孔垂直打通再用微凸点堆叠起来最底层是一颗逻辑Die承担接口控制的功能。因为IO可以做得非常宽动辄1024bit所以HBM的带宽远超DDR甚至GDDR。但它不是用来替代DDR的它的成本、工艺复杂度、功耗特性决定了它只出现在需要极限带宽的场景。后面第三章会专门展开讲HBM的封装细节这里先有个整体印象DRAM是技术本身DDR/LPDDR是主流接口标准HBM是面向带宽的高端封装路线。2. 从Die到颗粒再到DIMM封装和Rank的形成2.1 颗粒的数据位宽与多Die封装芯片厂商不会把一颗完整的Die直接焊到主板上而是先把一颗或多颗Die装进一个塑料/金属封装里形成“颗粒”。颗粒最重要的一个参数是数据位宽常见的有x4、x8、x16。x8颗粒表示这颗芯片参与数据总线时只提供8bit位宽x16就是16bit。为什么要在乎这个数字因为一颗DDR4 UDIMM的数据总线是64bit如果全部用x8颗粒就需要8颗芯片组成一个Rank如果用x16颗粒4颗就够了如果用x4颗粒就需要16颗。颗粒位宽越窄同容量下单颗芯片数量越多Rank内部的颗粒数就越多对地址/命令总线的负载也越大但容量扩展灵活性更好ECC场景通常用x4比较多。DDR5时代这个规则又变了一支DDR5 UDIMM内部被拆成两个32bit子通道常见的x8颗粒组单Rank一个子通道是4颗所以一支UDIMM通常能看到8颗或者16颗这和DDR4时代直观看到的颗粒数量逻辑是不同的。封装上也不总是一颗封装里只有一颗Die。某些大容量颗粒会在一个封装里堆叠多颗Die通过片选引脚区分访问哪一层。这种设计的本质就是在有限的PCB面积里塞进更多容量同时保持和单Die颗粒一致的引脚定义。2.2 Rank不是玄学是CS片选带来的结构Rank这个概念我刚工作那会儿也迷糊了很久。说白了Rank就是一组共享命令/地址总线的颗粒集合它们的数据引脚合在一起构成完整的数据总线宽度通过片选信号CS_n来区分当前命令是发给哪一组。用一个具体的例子来解释。一条普通DDR4 8GB UDIMM如果用的是8颗x8颗粒这8颗颗粒共享地址线、命令线、时钟、CS它们的数据线各提供8bit合并成64bit这就是一个Rank。如果这条内存是16GB双Rank那PCB上会有16颗x8颗粒其中8颗挂在CS0上另外8颗挂在CS1上。从控制器视角看Rank就像一栋楼里的不同单元地址命令是公共走廊但每个单元有自己的门牌号CS控制器只能对其中一个单元说话。同一时刻只有一个Rank的DQ会驱动数据总线否则两个Rank同时往总线上灌数据直接就是总线冲突。多Rank能提升单通道容量代价是命令/地址总线的负载变大电气时序变差双Rank DIMM在高端频率下经常要额外增加一个时钟周期延迟。这里顺便提一个容易撞车的小点数据分析里那个RANK()函数和内存Rank其实没有半毛钱关系。有人搜“partitionby和rank”会翻到内存Rank的内容那是SQL窗口函数处理的是排序编号和这里说的一组颗粒集合完全是两个领域别搞混了。2.3 双Rank/多Rank的布线代价与调度策略从PCB设计角度来看Rank数量直接影响走线拓扑。单Rank拓扑简单命令/地址线从控制器出来可以直接点对点或者简单分支双Rank就需要考虑T型或Fly-by拓扑中选择哪种以及末端要不要端接电阻。DDR4和DDR5都推荐Fly-by拓扑命令/地址/时钟在PCB上从控制器依次串联经过每个颗粒最后在末端端接。这样每条线的负载都差不多但每条颗粒收到命令的时间会有一个固定的延迟差控制器要通过写均衡训练来补偿。控制器调度方面多Rank不是免费的午餐。因为命令/地址总线是共享的从一个Rank切换到另一个Rank时总线需要空闲一定周期这期间不能发命令。有些控制器会做Rank interleave把连续地址分布在多个Rank上利用Rank间的切换来隐藏延迟。但实测下来双Rank内存对性能的提升通常有限尤其是随机访问场景切换代价可能抹平优点。服务器上要大容量那没办法必须上多Rank但消费级追求极致延迟的场景单Rank有时反而更快。3. HBM堆叠封装时代的异类也是DRAM3.1 TSV和堆叠层把Die变成了“楼层”HBM的“黑科技”核心其实就两件事把DRAM Die叠起来以及用TSV打通每一层之间的数据传输通道。常规DDR颗粒数据信号都是从封装引脚侧边引出要走很长的PCB走线才能到控制器信号速率和功耗都受限。HBM则完全不同每一层DRAM Die上都有大量TSV硅通孔信号从顶层到底层垂直传输底层再通过微凸点和硅中介层连接到控制器GPU/ASIC旁边。这样做最大的收益有两个一是数据路径极短延迟低、功耗低二是IO数量可以做得非常夸张HBM2E的接口宽度是1024bitDDR4只有64bitIO宽度差了一个数量级带宽自然不是一个级别。堆叠层数决定了容量HBM2E常见8层8-Hi堆叠单颗容量16GB后面对应的HBM3已经能做到12层甚至16层堆叠单颗容量奔着64GB去。不过堆得越高散热和制造良率压力就越大每一层的TSV还得保证对准和导通这也是HBM成本一直降不下来的原因之一。3.2 Pseudo Channel和1024bit宽接口HBM虽然数据引脚有1024bit但不能简单把它当成一个超大位宽的“一坨”内存来用。JEDEC标准把1024bit划分成若干个独立的伪通道Pseudo Channel每个伪通道有自己独立的行缓冲和命令接口可以独立调度。这个“伪”字很有讲究。它像Channel但没有完全独立的物理通道内部多个伪通道共享一部分资源所以叫Pseudo。控制器可以把一次访问拆到不同的伪通道上充分利用空间并行性。这也是HBM控制器和普通DDR控制器最大的区别DDR控制器面对的是Rank、Bank Group、Bank这个层级结构HBM控制器还要多考虑一层伪通道的映射。HBM的热词里提到“hbm autorefresh mrs”说明HBM也保留了DRAM通用的刷新和模式寄存器机制底层仍然是DRAM Die所以MRS配置和刷新策略和DDR是同一个家族的语言。只是HBM的刷新调度要考虑伪通道之间的同步稍复杂一点。3.3 HBM能替代DDR/LPDDR吗经常有人问HBM性能这么强为什么不把整台电脑都换成HBM答案很简单成本和形态都不允许。首先HBM必须搭配硅中介层和微凸点工艺制造良率和成本远高于普通DDR颗粒其次HBM的容量受堆叠层数限制同样的物理面积DDR颗粒可以做成更大容量的封装再次HBM的高功耗和散热需求也不是普通消费级主板能轻易承受的。所以现实格局很清楚HBM走的是超高带宽、面向AI加速和高性能计算的路线DDR走的是大容量、低成本、通用计算的路线LPDDR走的是低功耗、移动端的路线三者短期内谁也替代不了谁。真正的价值在于理解HBM之后再看DDR和LPDDR很多概念都能串联起来。HBM和LPDDR在某种程度上的共同点是都强调“缩短控制器与DRAM的距离”只是LPDDR用on-package贴装和低电压来实现HBM用堆叠和宽接口来实现。4. PHY到底在干什么连接协议与引脚的那一层4.1 DDR PHY的完整职责清单很多做应用层开发的人第一次听到“PHY”这个词是从以太网那里来的以为PHY就是一颗网络芯片。其实PHY是个通用概念物理层。DDR PHY就是负责把控制器发出的逻辑命令转换成符合DRAM电气标准的物理信号的那一层电路通常集成在SoC/FPGA内部或者作为独立IP核存在。DDR PHY的工作量远比想象中复杂。它至少要完成以下几件事产生并校准高速时钟确保DQS和系统时钟的关系可控驱动命令/地址线和DQ数据线保证信号满足电压摆幅、压摆率和时序要求实现读写数据通路的延迟对齐包括写数据的Tbypass、读数据的DQS gate控制片上端接ODT动态调整DQ/DQS的终端阻抗抑制反射实现ZQ校准通过外部240Ω参考电阻校准输出驱动强度和ODT阻值。DDR4以上频率动辄2400MT/s起步DDR5直接跑到4800MT/s甚至更高在这么高的速率下信号在PCB上的传播延迟、引脚间的串扰、电压波动都会严重影响时序裕量。PHY的作用就是尽可能补偿这些非理想因素让控制器拿到的数据和真实引脚上的数据尽量“讲究”。4.2 DFI接口、MRC与初始化训练流程DDR控制器和DDR PHY之间通常走DFI接口DDR PHY Interface这是一套标准化的总线控制器通过DFI下发命令和数据PHY通过DFI上报读数据和训练状态。把控制器和PHY分开设计的好处是显而易见的控制器只关心协议逻辑PHY只关心物理信号。如果PHY从DDR4升级到DDR5理论上控制器逻辑变动不大主要改DFI配置和训练流程即可。训练流程是整个PHY调试里最容易出问题的地方。所谓内存训练是指上电后控制器和PHY通过一系列握手动作测量并补偿时钟偏斜、读写延迟、DQS门控窗口、驱动能力等参数。这个训练动作在Intel/AMD平台对应的就是MRCMemory Reference Code在FPGA平台就是IP核自带的初始化状态机。训练环节的核心步骤粗略可以分为ZQ校准、写均衡、读均衡、写延迟调整、读DQS gate训练、以及最后的主数据眼图优化。任何一个环节没通过系统就不会给你一个“training passed”信号表现为内存容量识别失败、开机报错、或者系统刷机时直接提示DDR错误。很多DDR“疑难杂症”最后追根到底大多是训练参数和实际颗粒特性不匹配或者PCB走线质量太差导致没有裕量。4.3 LPDDR眼图测试与IBIS仿真模型LPDDR因为主要用在手机和平板上颗粒直接焊接在PCB或封装在SoC上方调试难度比DIMM高得多。想抓LPDRAM的信号只能通过专门设计的测试夹具或者在量产测试阶段用ATE探针。这时最常用到的就是眼图测试。所谓眼图就是把高速信号的多次跳变叠加在一张图上通过眼睛张开的大小判断信号质量。眼图测试能直观看到VCROSS交叉电压、眼高、眼宽、抖动等参数这些决定了PHY能否在噪声和偏斜中稳定采样。调试LPDDR速率上不去、低温/高温下偶发死机这类型问题拿眼图说话是最有说服力的。我见过很多方案常温下怎么测都稳到了高低温箱里就出问题拉出来眼图一对比发现高温下DQS和DQ的相对偏斜明显变大最后通过调整PHY的delay line和驱动强度解决。硬件仿真方面热词里提到的DDR IBIS模型是板级仿真的基础。IBIS是I/O Buffer Information Specification它描述芯片引脚的输出阻抗、转换速率、上下拉特性但不包含芯片内部逻辑所以仿真速度快适合做SI信号完整性分析。做DDR布线前正规流程是从芯片厂商拿到控制器侧和DRAM颗粒侧的IBIS模型在HyperLynx、ADS等工具里跑拓扑仿真确认走线长度、阻抗、端接方式是否满足时序要求。没有IBIS模型盲布高速DDR我个人的建议是除非你经验非常丰富否则别这么干。4.4 那些同样叫PHY的亲戚以太网PHY、JESD204和MCU内置问题DDR PHY叫PHY以太网PHY也叫PHY还有JESD204 PHY。容易混淆但原理上有共通之处。以太网PHY是最容易理解的类比。MCU/CPU里集成的通常是以太网MACMAC处理协议帧PHY负责把数据调制到双绞线上的电信号并且完成自协商、链路检测等工作。这就是为什么STM32F407这类MCU虽然内置以太网MAC但数据手册里明确说需要外接一颗PHY芯片比如LAN8720、DP83848因为它没有把PHY集成进去。很多人拿到STM32F407发现网络不通第一反应是代码问题检查半天才发现PHY芯片都没焊。另外以太网PHY有大量寄存器可以直接用来诊断链路状态Linux下常见的ethtool就能读取和修改部分PHY寄存器做PHY寄存器分析时通常是读ID寄存器确认PHY型号、读状态寄存器确认link和速度、读协商寄存器确认对端能力。JESD204 PHY则是高速ADC/DAC与FPGA/ASIC之间的SerDes类物理层它做的事情比DDR PHY简单一些主要是把并行数据串行化、接收端恢复时钟和数据。但概念上也是把逻辑数据变成物理信号打交道。这些PHY的共同点在于都是数字逻辑世界和模拟物理世界之间的“翻译官”都要做校准和训练都会因为PCB质量和电源噪声而出问题。理解了DDR PHY再去看其他PHY很容易触类旁通。5. 从控制器到DRAM的完整链路是真的把数据读回来了5.1 一次读请求的完整旅程把前面几章的内容串起来完整跑一次读请求链路是这样的CPU发起读地址经过Cache和内存控制器控制器把地址翻译成对应的通道、Rank、Bank Group、Bank、Row、Column。控制器检查目标Bank的状态如果当前行不在缓冲区先发预充电命令关闭当前行再发激活命令打开目标行。接下来控制器通过DFI接口把读命令交给PHYPHY把逻辑信号转换成物理引脚上的电平。命令/地址线到达DRAM颗粒后颗粒内部根据Bank和Row地址做行选通读出数据到列选通电路再经过一定延迟后DQS和数据DQ一起输出到总线上。PHY等到读DQS到来后用DQS作为采样时钟把DQ上的数据采集回来再通过DFI接口汇报给控制器。控制器做ECC校验如果有最后把数据返回给CPU。这条链路上任何一个环节的延迟估算偏差都会导致数据采样出错。这也是为什么PHY训练要反复测量往返延迟不仅仅是初始化时训练一次运行过程中温度变化、电压漂移都会影响时序所以很多PHY还支持定期重训练或者在线监控。把这个全链路画清楚这里不用画图心里有个数就行再去看DDR调试问题定位范围会小很多。5.2 SPD、MRS、autorefresh——上电后DRAM如何被唤醒每次系统上电DRAM都要经历一个严格的上电初始化序列这个流程在JEDEC规范里规定得很细。第一步是提供稳定的电源和时钟CKE时钟使能保持低电平。然后复位信号释放等待一段时间后拉高CKE。紧接着控制器通过I2C总线读取SPD芯片里的内容。SPD是颗EEPROM里面存着完整的内存模块信息容量、位宽、Rank数、支持的时序参数、刷新周期、温度范围等。MRC拿到SPD数据后据此决定采用哪组时序配置也决定用什么频率档位。接下来就是MRS握手。控制器依次向DRAM写入模式寄存器设置突发长度、CAS延迟、写恢复时间、驱动强度等。DDR4的MR0到MR6各有分工DDR5的MR数量更多。配置完MRS之后进行ZQ校准再执行DLL校准。这些步骤完成后DRAM才能进入可用状态。这期间autorefresh也是关键环节。DRAM上电后如果不刷新很快数据就会丢所以控制器从初始化完成后就必须周期性地发送刷新命令。刷新命令分为自动刷新autorefresh和自刷新self refresh两种前者由控制器定期调度后者是芯片进入低功耗模式后自己靠内部定时器刷新。LPDDR的省电策略很多都体现在刷新调度上比如温度补偿刷新温度高时刷得勤一些温度低时刷得少一些。5.3 晶晨刷机报DDR错误到底是什么情况热词里有一条很接地气“晶晨刷机报错DDR是bl锁”。这个场景在电视盒子、机顶盒刷机圈子里很常见就是刷固件时工具提示DDR错误很多人以为是引导加载程序被锁住了其实很多时候是另一回事。刷机过程中的DDR报错常见原因大致有这么几类第一固件里配置的DDR初始化参数和板子上实际焊的颗粒不对应比如固件是按DDR3写的板子其实是DDR4第二DDR供电电压不对第三DDR频率设太高颗粒体质不够初始化或training失败第四引导阶段的DDR自检程序在扫描容量时出错通常是飞线、虚焊这类硬件品质问题。和BL锁的关系要分清楚。BL锁是引导加载程序关于签名校验的策略它主要限制“能不能刷非官方镜像”。DDR错误发生在BL锁校验之前也就是引导最早期CPU要先初始化DDR才能把后续代码加载到内存里跑。如果DDR初始化都过不去后面压根谈不到校验。所以如果报错明确是DDR阶段先按硬件和参数去查别什么都往BL锁上套。5.4 FPGA控制DDR读有效信号一直为低的排查实录最后分享一个我实际处理过的例子就是文章开头提到的那块FPGA板子。现象是FPGA控制DDR时读有效信号一直为低读命令发出去了数据总线上也有波形但控制器就是不给“读数据有效”的应答。排查过程大概按这个顺序走。第一步确认PHY初始化完成信号也就是init_calib_complete有没有拉高。这一步很关键因为如果PHY的校准/training没完成控制逻辑即使发了读命令也不会收到读数据。实测下来初始化都没过那问题就大了要往回查DDR复位时序、CKE、电压、时钟。如果初始化过了才进入下一步。第二步检查读命令的地址映射是否正确。DDR控制器把逻辑地址映射到Rank/Bank/Row/Column的规则各有不同FPGA IP核一般有可配置的地址映射表。如果配置不对看起来在读某个地址实际上激活的行和读的列根本不是同一个Bank数据缓冲区永远是空的。第三步检查DQS gate。在DDR读操作中DQ上的数据必须被DQS采样而DQS在非读时段是三态高阻PHY必须通过DQS gate电路把有效的DQS窗口“放行”进来。如果gate窗口没对准采回来的数据是错的控制器校验不过读有效信号就不会拉高。这一步在仿真里往往看不出来因为仿真环境的行为级模型不会完全模拟DQS三态和往返延迟。最终我们把问题锁定在环境配置上不是PHY坏了也不是DDR颗粒坏了而是FPGA工程里给DDR核的参考时钟频率和SPD芯片标识的速率档位不一致导致PHY训练后转换出的时序参数仍然偏差读DQS gate落在错误位置。改掉参考时钟配置后重新跑training读有效信号立刻正常。这个案例给我的教训就是调DDR先分层先确定是哪一层的问题再动手改东西。PHY层、控制器层、颗粒层、板级走线层层层独立排查比漫无目的地改参数有效得多。关于FPGA控制DDR还有一类常见的坑是XDMA和DDR配合使用。很多人在FPGA里用XDMA IP搬运数据到DDR结果DMA读写失败第一反应是XDMA配置有问题查半天发现还是DDR核的PHY训练没通过。XDMA只是一个PCIe搬数据的引擎它访问DDR的路径同样要经过DDR控制器和PHY底层不牢上层全是表象。6. 一个小建议把“分层”刻在脑子里做DDR/LPDDR/HBM相关调试这些年我最深的体会就是“分层”二字。DRAM Die是物理基础封装决定形态Rank决定容量组织PHY决定信号是否能真实到达颗粒控制器决定逻辑时序每一层都独立但有严格的接口约束。遇到问题先问自己现象出现在哪一层最底层还没通就急着改应用逻辑往往白费力气。如果你也是刚开始接触这块我建议先从颗粒手册和控制器参考手册入手把每个信号线的作用、每类命令的时序要求弄清楚遇到问题能画出链路图心里有数再动手会节省大量时间。别信什么“酷炫工具能一键搞定DDR”真正让你走得远的是对从Die到系统这条链路扎实的理解。