S08 —— 一个地址从 CPU 出发,是怎么到达 DRAM Cell 的

金句:每一比特数据的旅行,都有它完整的路线图。


从 CPU 到 DRAM 的完整路径

CPU 发出的地址,是怎么最终选中一个 DRAM Cell 的?这需要一个完整的地址解析流程。

Bash
完整路径(简化):

CPU(虚拟地址 VA)
  → MMU 翻译(VA → PA)[K01 会详细讲]
  → 内存控制器(Memory Controller)
  → DDR 协议:地址解码(Channel → Rank → Bank → Row → Column)
  → DRAM 颗粒引脚(行地址 + 列地址)
  → DRAM Cell 访问

现代计算机的地址解析层级:
  VA(虚拟地址,48-bit64-bit)→ PA(物理地址,36~52 bit)→ DRAM 地址(Row/Col/Bank)

物理地址(PA)的宽度和可寻址内存

CPU 的物理地址宽度,决定了系统最多能支持多少内存。

Bash
物理地址宽度和内存上限:

36-bit 物理地址(传统 x86):
  最大可寻址 = 2^36 = 64 GB
  典型:Intel Xeon 早期型号,PAE 模式

38-bit 物理地址(现代桌面 x86):
  最大可寻址 = 2^38 = 256 GB
  典型:Intel Skylake 之后的桌面 CPU

40-bit 物理地址(服务器级 x86):
  最大可寻址 = 2^40 = 1 TB
  典型:AMD Zen 架构服务器

48-bit 物理地址(ARM 服务器):
  最大可寻址 = 2^48 = 256 TB
  典型:ARMv8-A 服务器 CPU

52-bit 物理地址(理论最大,ARMv8.2+):
  最大可寻址 = 2^52 = 4 PB(实际不这么做,成本太高)

注意:物理地址宽度 ≠ 你实际插的内存大小。系统可能只用了物理地址空间的一部分(比如只插了 32GB,但 PA 是 38-bit,支持 256GB)。


内存映射(Memory Map):地址空间怎么分配

物理地址空间不是全部给 DRAM 用的,有一部分要留给MMIO(Memory-Mapped I/O)——也就是外设的寄存器。

Bash
x86 物理地址空间分配(典型 4GB 地址空间的系统):

0x0000_0000 ~ 0x0009_FFFF:传统 640KB 低端内存区(兼容 IBM PC)
0x000A_0000 ~ 0x000B_FFFF:Video RAM / VGA 寄存器(128KB)
0x000C_0000 ~ 0x000F_FFFF:硬件 ROM 区(BIOS/Option ROM,640KB)
0x0010_0000 ~ 0xFFFF_FFFF:DRAM 主区域 + MMIO

DRAM 区域:0x0010_0000 ~ 0xDFFFF_FFFF(约 3.5GB 可用,取决于系统)
MMIO 区域:0xE000_0000 以上(外设寄存器)

ACPI 表、DMA 缓冲区、设备寄存器都在 MMIO 区域。
这就是为什么插了 4GB 内存的 32 位系统,只有 ~3GB 可用——其余被 MMIO 占用。

地址总线宽度和 DIMM 槽位

内存控制器有多少地址线,决定了它能访问多少 DRAM 颗粒。

Bash
DDR4 地址线配置(64-bit 双通道):

每个通道 51 根地址/命令引脚(有些是复用):
  - BA[2:0]:Bank Address(3 bit = 8 bank)
  - BG[1:0]:Bank Group(DDR5 有,2 bit = 4 group)
  - RA[16:0]:Row Address(17 bit = 最多 128K 行)
  - CA[9:0]:Column Address(10 bit = 最多 1K 列)
  - CK/CK#:时钟
  - CKE:时钟使能
  - CS#:片选(Chip Select)
  - ODT:阻抗匹配

物理地址到 DRAM 地址的映射(简化版):
  PA[35:30]:保留或 Channel 选择
  PA[29]   :Rank 选择(双 Rank DIMM)
  PA[28:26]:Bank Group(DDR5)
  PA[25:23]:Bank
  PA[22:14]:Row
  PA[13:6] :Column
  PA[5:0]  :Byte offset

为什么内存条有不同的容量(8GB vs 16GB vs 32GB)

不同容量的内存条,是因为 DRAM 颗粒的数量和每个颗粒的密度不同。

Bash
内存条容量分解:

8GB DDR4(单面×1 Rank):
  8 颗粒 × 8Gb/颗粒 = 64Gb = 8GB(每个颗粒是 8Gbit = 1GB)
  8 颗 × 8bit = 64bit = 1 通道(单通道)

16GB DDR4(双面×2 Rank):
  16 颗粒 × 8Gb/颗粒 = 128Gb = 16GB(还是 8Gb 颗粒,但两面都焊接)
  2 Rank = 每 Rank 8 颗 × 8Gb = 64Gb
  2 Rank = 128Gb = 16GB

  内存控制器需要多根 CS#(片选)线来分别选中两个 Rank

32GB DDR5(单面×1 Rank):
  8 颗粒 × 32Gb/颗粒 = 256Gb = 32GB
  DDR5 颗粒密度更高(16Gb/颗粒 → 32Gb/颗粒)

内存条上的小芯片( chips):
  每个小芯片是一个 DRAM 颗粒(Die)
  多个颗粒并联,组成总数据宽度(64 bit 或 40 bit ECC)

内存条上的 SPD 芯片

每个内存条都有一个 SPD(Serial Presence Detect)芯片,存储内存条的配置信息。

Bash
SPD 芯片(EEPROM,8-pin SOIC 封装):

存储内容:
  - 容量:8GB / 16GB / 32GB
  - 速度:DDR4-2400 / DDR5-4800 等
  - Timing:CL-tRCD-tRP-tRAS 等
  - 电压:1.2V(DDR4)/ 1.1V(DDR5)
  - Rank 数:单/双/四 Rank
  - 厂商:Samsung / SK Hynix / Micron 等

SPD 通过 I2C 总线连接:
  SCL(时钟)、SDA(数据)→ 内存控制器在启动时读取 SPD
  → 自动配置内存时序和频率

Linux 查看 SPD 信息:
  $ decode-dimms
  或
  $ dd if=/sys/class/i2c-adapter/i2c-0/0-0050/eeprom of=/tmp/spd.bin
  $ xxd /tmp/spd.bin | head -20

总结

  • CPU 到 DRAM 的路径:VA → MMU → PA → 内存控制器 → DDR 协议 → DRAM Cell
  • 物理地址宽度:36-bit(64GB)/38-bit(256GB)/40-bit(1TB)/48-bit(256TB)
  • MMIO 区域:物理地址空间的一部分留给外设寄存器,不是全部给 DRAM
  • 地址总线:51 根引脚(复用 BA/RA/CA),负责选中 Channel/Rank/Bank/Row/Column
  • 内存容量:由颗粒密度(8Gb/16Gb/32Gb)和颗粒数量决定
  • SPD 芯片:存储内存条配置信息的 EEPROM,通过 I2C 总线供 BIOS/系统读取

下篇预告(S09):内存不只是”存数据”,还有纠错能力——ECC(Error Correction Code)是怎么工作的?单比特错误怎么发现,怎么纠正?


关注公众号「AI不着急」,回复”资料”获取内存学习路线图。

最后修改: 2024年6月8日

作者

评论

发表评论

您的邮箱地址不会被公开。