懂点儿底层原理 – 内存专题 | S05 | Bank、Row、Column——内存地址是怎么一步步映射到具体的 Cell 的

金句:把一个地址翻译成一次物理访问,需要经过多少层抽象。理解 Bank 内部结构,是理解 DDR 性能的关键。


1. DRAM 芯片内部结构:Cell 到 Bank 的完整层次

1.1 从一个 Cell 到一整片 Bank

Bash
一个 DRAM 芯片(Die)的组织层次:

最小单元:DRAM Cell(1 个 NMOS + 1 个电容)= 1 bit
         ↓
若干 Cell 组成一行(Row):每行连接同一根 Word Line
         ↓
若干行组成一个 Subarray(子阵列):
  - 典型 256~512 行 × 1024 列
  - 有独立的本地 Sense Amplifier(本地放大器)
         ↓
若干 Subarray 组成一个 Array(阵列)
         ↓
若干 Array 组成一个 Bank
  - 有自己的行解码器(Row Decoder)和列解码器(Column Decoder)
  - 可以独立接受 ACT/READ/WRITE/PRE 命令

一个 DDR4 x8 芯片(8Gb 容量)内部结构:
  32 个 Array × 每个 Array 内部 256 行 × 1024 列
  → 总计:32 × 256 × 1024 = 8,388,608 个 Cell(8Mb,实际因为多 bank 更大)
  → 加上 Bank 结构、Bank Group(DDR5)、IO 接口 → 完整芯片

1.2 Bank 的详细内部结构

Bash
一个 Bank 的内部结构(DDR4,简化图):

              Row Decoder(行解码器)
                    │
  Word Line 0 ──────┤
  Word Line 1 ──────┤
  Word Line 2 ──────┤
  ...
  Word Line N ──────┤
                    │
  ┌──────────────────────────────────────────────┐
  │           Bit Line(位线)纵向穿过            │
  │                                             │
  │  Cell[0,0]  Cell[0,1]  Cell[0,2] ... Cell[0,1023]  ← Row 0
  │    │          │          │              │
  │  Cell[1,0]  Cell[1,1]  Cell[1,2] ... Cell[1,1023]  ← Row 1
  │    │          │          │              │
  │  Cell[2,0]  Cell[2,1]  Cell[2,2] ... Cell[2,1023]  ← Row 2
  │    │          │          │              │
  │   ...        ...        ...            ...     ← ...
  │    │          │          │              │
  │  Cell[N,0]  Cell[N,1]  Cell[N,2] ... Cell[N,1023] ← Row N
  │                                             │
  └──────────────────────────────────────────────┘
                    │
              Sense Amplifier(感知放大器,列方向)
                    │
              Column Mux(列多路复用器)
                    │
                   IO

每个交叉点(Cell):一根 Word Line + 一根 Bit Line + NMOS + 电容

2. Row Buffer:ACT 之后行数据存在哪里

2.1 什么是 Row Buffer

Bash
Row Buffer(行缓冲):ACT 命令激活一个 Row 后,该行所有 Cell 的数据
被 Sense Amplifier 读取并保存在 Sense Amplifier 的锁存器里。
这个锁存器就是"Row Buffer"。

Row Buffer 的物理位置:
  - 就在 Bank 内部的 Sense Amplifier Array 里
  - 一行对应一组 Sense Amplifier(等于该行的列数)

Row Buffer 的作用:
  - Row 被激活后,整行数据都在 Sense Amplifier 里
  - Column 访问(READ/WRITE)是对 Row Buffer 中的数据操作
  - 不需要每次都从 Cell 电容重新读取(Cell 数据在 Sense Amp 中保持)

Row Buffer 的生命周期:
  1. ACT:行数据从 Cell 读到 Sense Amplifier(Row Buffer 建立)
  2. READ/WRITE:直接从 Row Buffer 读取/写入
  3. PRE:Row Buffer 被清空(Sense Amp 断开,Bit Line 恢复预充电电平)

Row Buffer 和 Cell 数据的关系:
  - Row 被激活时,Cell 数据被"复制"到 Row Buffer
  - Row Buffer 可以多次读取,不需要重新访问 Cell
  - Row Buffer 是易失性的(PRE 后消失),Cell 数据需要写回(如果被修改)
  - 如果 Row 有"脏"数据(被写过),PRE 时会自动写回 Cell

2.2 Row Buffer 命中 vs Row Buffer 未命中

Bash
Row Buffer 的状态决定访问延迟:

Row Buffer Hit(行命中,当前行已激活):
  → ACT 已完成,Row 已在 Row Buffer(Sense Amp)中
  → 直接发送 READ/WRITE → Column 访问
  → 延迟 = CL + tCCD × N

Row Buffer Miss(行未命中,需要激活新行):
  → 当前 Row Buffer 不是目标 Row
  → 必须:PRE(关闭当前行) → tRP → ACT(激活新行) → tRCD → READ/WRITE
  → 延迟 = tRP + tRCD + CL + tCCD × N

Row Buffer Conflict(行冲突,同一行的两个不同实例):
  → 两个 Rank 上同一 Row 都被激活
  → 内存控制器需要序列化访问
  → 延迟加倍

Row Buffer 的有效利用:
  - 如果应用有良好的行局部性(连续访问同一行),Row Buffer 持续命中
  - 如果应用随机访问跨行,Row Buffer 频繁未命中
  - 这就是为什么矩阵乘法等顺序访问场景 DDR 性能好

3. Sense Amplifier(感知放大器):Cell 数据是怎么被读出来的

3.1 Sense Amplifier 的工作原理

Bash
Sense Amplifier(SA,感知放大器)是 DRAM 里最核心的模拟电路:

结构:差分放大器(Cross-Coupled Inverter Pair)

  Bit Line(BL)            Bit Line Bar(BLB)
       │                        │
      ┌┴────────────────────────┴┐
      │                         │
      └────────┬────────┬───────┘
               │        │
               ↑        ↑
            Inverter1  Inverter2
               │        │
               └────────┘
                  ↑↑(正反馈)

工作原理:
  1. 预充电:BL 和 BLB 都充电到 1/2 VDD
  2. ACT 激活:Cell 电容连接到 BL
     → 如果 Cell 有电荷(存"1"),BL 电压轻微上升
     → 如果 Cell 无电荷(存"0"),BL 电压轻微下降
     → 电压变化幅度:约 100~200mV(非常微弱)
  3. Sense Amp 检测 BL 和 BLB 的电压差,放大到 VDD/GND
     → 差分放大器靠正反馈稳定在"1""0"
     → 放大过程约 5~10ns
  4. 放大完成后,数据被锁存在 Sense Amp(这就是 Row Buffer)
  5. 同时,BL/BLB 电压恢复完整电平("刷新"了 Cell 的电荷)

为什么叫"放大器"而不是"比较器":
  → 它把微弱的模拟信号(100~200mV 差分)放大成数字电平(0~VDD)
  → 本质是一个带正反馈的差分放大器
  → 放大过程需要时间(tRCD 的一部分),这是 DRAM 延迟的物理来源

3.2 Sense Amplifier 的时序

Bash
Sense Amplifier 的关键时序参数:

1. 放大建立时间(Amplifier Settling):
   → ACT 后,Word Line 拉高,Cell 和 BL 连接
   → BL 电压变化,Sense Amp 开始检测
   → 约 4~8ns 后放大完成(达到稳定逻辑电平)
   → 这就是 tRCD 的一部分

2. 放大器复位(SA Reset):
   → PRE 命令后,Sense Amp 需要复位到初始状态
   → BL/BLB 恢复到 1/2 VDD
   → 约 2~3ns(包含在 tRP 内)

3. 读写共用 Sense Amp:
   → 读:Cell → SA → DQ(数据输出)
   → 写:DQ → SA → Cell(数据直接写入 Sense Amp 或 Cell)
   → 读写共用同一组 Sense Amp,节省硬件

Sense Amp 的功耗:
   → 激活一行 = 激活一整行 Sense Amp(1024~8192 个)
   → 每个 SA 消耗约 10~50µA
   → 一行 SA 总功耗约 10~50mA
   → 这就是为什么 DRAM 激活行时有功耗峰值
   → 行命中率高 → 更多激活行 → 更高功耗

4. Bank Read 的完整流程

4.1 Bank 读操作的 6 个阶段

Bash
一次完整的 Bank Read 操作(DDR4-3200):

阶段 1:ACT(行激活)
  - 内存控制器发送 ACT 命令 + Row 地址 + Bank 地址
  - Row Decoder 选通对应的 Word Line
  - 整行 Cell(1024~8192 个)通过 NMOS 连接到 Bit Line
  - Sense Amp 读取并放大整行数据 → 建立 Row Buffer
  - 耗时:tRCD = 13.75ns(22 cycles)

阶段 2:等待 Sense Amp 稳定
  - Sense Amp 放大 BL 上的微弱电压变化
  - 约 4~8ns 稳定到 VDD/GND
  - 这是 tRCD 的物理来源(Cell 充放电 + SA 放大)

阶段 3:发送 READ 命令
  - Column 地址通过地址引脚发送
  - 列解码器在 Row Buffer 中选择目标列
  - 延迟:CL = 13.75ns(22 cycles)

阶段 4:数据从 Row Buffer 输出到 IO
  - BL = 8(一次 Burst 传输 8 个数据字 = 64 bytes)
  - 每个数据字 1 个时钟周期(DDR = 上升沿+下降沿各一次)
  - 8 cycles 传输 8 × 8 = 64 bits
  - 耗时:4 cycles(DDR 上升沿+下降沿各一次)

阶段 5:PRE(预充电)
  - 如果不再访问该行,发送 PRE 关闭行
  - Sense Amp 复位,Bit Line 恢复预充电电平
  - Row Buffer 清空
  - 耗时:tRP = 13.75ns

阶段 6:恢复时间
  - tRRD:同一个 Rank 的下一个 ACT 需要等待
  - 不同 Rank 可以并行(tRRD_L = 2 cycles)

总延迟(行命中,单次读):
  - tRCD + CL + tCCD + tRP ≈ 13.75 + 13.75 + 3.4 + 13.75 = 44.65ns

连续读同一行(行命中,无 PRE):
  - tRCD + CL + N×tCCD ≈ 13.75 + 13.75 + N×3.4ns
  - 第一次访问:~27.5ns,后续每次 +3.4ns

4.2 写操作的 Bank 流程(对比)

Bash
Bank Write 操作(DDR4-3200):

阶段 1:ACT(和读相同)
  - 发送 ACT 命令 + Row 地址 + Bank 地址
  - 打开目标行,建立 Row Buffer
  - 耗时:tRCD = 13.75ns

阶段 2:发送 WRITE 命令 + 数据
  - Column 地址 + 写数据同时发送(数据立即进入 DQ 引脚)
  - 数据写入 Row Buffer(Sense Amp 锁存)
  - 延迟:WL = CWL = 11 cycles(6.875ns)
  - 数据 Burst 长度:BL = 8

阶段 3:数据从 Row Buffer 写入 Cell
  - 这是透明发生的(不需要额外等待)
  - Cell 写操作比读慢,需要完整充电到 VDD

阶段 4:PRE(预充电)
  - 如果不再访问,PRE 关闭行
  - 注意:如果刚写过,Cell 需要充电稳定时间(tWR = 15ns)
  - PRE 之前必须等待 tWR

读 vs 写的主要区别:
  - 读:数据从 SA → DQ(SA 放大后输出)
  - 写:数据从 DQ → SA → Cell(直接写入)
  - 读有 CL 延迟(等待数据返回),写有 CWL 延迟(数据到 DQ 的时间)
  - 读破坏性(但 SA 有锁存,Row Buffer 不丢失),写后需要 tWR 才能 PRE

5. 多 Bank 操作和 Bank 级并行

5.1 多 Bank 流水线的优势

Bash
多 Bank 的设计就是为了让不同 Bank 的操作并行:

Bank 0:ACT[Row=0] ── READ ─────────────────────────────── PRE
Bank 1:          ACT[Row=1] ── READ ─────────────────────── PRE
Bank 2:                    ACT[Row=2] ── READ ────────────── PRE
Bank 3:                              ACT[Row=3] ── READ ──── PRE

时间线:
  Cycle 0:   Bank0 ACT
  Cycle 22:  Bank0 READ(tRCD 后),Bank1 ACT(tRRD 后)
  Cycle 44:  Bank0 数据输出,Bank1 READ,Bank2 ACT
  Cycle 66:  Bank1 数据输出,Bank2 READ,Bank3 ACT
  ...

带宽利用率(4 Bank 交错):
  - 单 Bank 有效带宽 = 1 / (tRCD + CL + tRP) ≈ 1 / 44ns ≈ 22.7 MT/s
  - 4 Bank 交错带宽 ≈ 22.7 × 4 = 90.8 MT/s(峰值)
  - 实际 DDR4-3200 带宽 = 3200 MT/s(因为每个 Cycle 传 2 次 = DDR)

Bank 数量的影响:
  DDR4 典型:8 个 Bank(含 2 个 Bank Group 的设计)
  DDR5 典型:32 个 Bank(更多 Bank → 更少行冲突)
  → 内存控制器可以把多个请求分散到不同 Bank
  → 提高 Row Buffer 命中率(减少行冲突)

5.2 Bank Group(DDR5)的并行能力

Bash
DDR5 有 2 个 Bank Group,每个 Group 内部有 4 个 Bank(2BG × 4Bank × 4Bank = 32 Bank):

Bank Group 的独特能力:
  → 两个 Bank Group 可以同时执行不同的命令类型
  → 例如:Group 0 正在读(READ),Group 1 同时可以预充电(PRE)
  → 读和预充电并行,延迟重叠

DDR5 Bank Group 并行示例:

  Group 0:ACT[Bank0] ── READ ── PRE
  Group 1:         ACT[Bank4] ── READ ── PRE
                              ↑
                        Group 0 和 Group 1 的 ACT 可以重叠
                        PRE 也可以和另一个 Group 的 ACT/READ 重叠

DDR4(无 Bank Group):
  → 两个 Bank 的 ACT 也不能重叠
  → 必须等 tRRD = 4 cycles 才能发下一个 ACT

DDR5 Bank Group 优势:
  → 行冲突的等待时间被 Bank Group 并行隐藏
  → 有效带宽比 DDR4 提升约 15~20%(在相同频率下)

6. 内存地址到 Cell 的完整映射

6.1 地址位分配详解

Bash
DDR4 系统地址映射(Intel Skylake 例子,32GB = 2 Channel × 16GB/DIMM):

物理地址 PA = 35 bits(对应最大 64GB,但只有 32GB 可用)

Bit 分配:
  [34]        → Channel Bit(哪个 Channel,01)
  [33]        → Rank Bit(哪个 Rank,双面 DIMM 有 2 个 Rank)
  [32:31]     → Bank Group(DDR4 实际不需要,但有些实现用它做对齐)
  [30:28]     → Bank(哪个 Bank,3 bits = 8 个 Bank)
  [27:15]     → Row(哪一行,13 bits = 8192 行)
  [14:6]      → Column(哪一列,9 bits = 512 列,但只用部分)
  [5:0]       → Byte offset in Cache Line(64B = 6 bits)

DDR5 地址映射(DDR5-48002×32GB):

  [35]        → Channel(哪个 Channel)
  [34]        → Rank
  [33:32]     → Bank Group(2 bits = 4 个 Group,DDR5 有 2 个 BG)
  [31:29]     → Bank(哪个 Bank,3 bits = 8 个 Bank per Group)
  [28:14]     → Row(15 bits = 32K 行)
  [13:5]      → Column(9 bits)
  [4:0]       → Byte offset(32B aligned,DDR5 BL16 模式)

实际内存控制器地址映射(优化策略):
  - 把行地址放在高位(容易触发行冲突)
  - 把列地址放在低位(列内访问无切换开销)
  - 把 Bank 地址放在行地址之上(减少同一行内的 Bank 冲突)
  - 把 Channel/Rank 放在最高位(最大粒度分离)

6.2 行列冲突的实际例子

Bash
假设访问模式:

场景 1:顺序访问数组(行命中)
  for(i=0; i<1024; i++)
    a[i]++

  地址连续递增:PA → Row 不变,Column 递增
  → 只需一次 ACT,后续全是 Column 访问
  → Row Buffer 持续命中
  → 带宽利用率高

场景 2:随机访问(行冲突)
  for(i=0; i<1024; i++)
    j = rand() % 1024
    a[j]++

  地址随机:Row 频繁切换
  → 每次访问:PRE → tRP → ACT → tRCD → READ
  → 延迟 = tRP + tRCD + CL + tCCD ≈ 13.75 + 13.75 + 13.75 + 3.444.65ns
  → 带宽利用率低

场景 3:结构体数组(Structure of Array,SoA vs AoS)
  struct Point { x, y, z } points[1024];

  SoA(Structure of Array,x/y/z 分开存):
    x[0], x[1], ... x[1023](行命中)
    y[0], y[1], ... y[1023](行命中)
    z[0], z[1], ... z[1023](行命中)
    → 3 次行激活,每次 1024 次访问,高效

  AoS(Array of Structure,x/y/z 交错存):
    points[0].x, points[0].y, points[0].z, points[1].x, ...(每次跨行)
    → 每次访问都触发行切换
    → 延迟增加约 3

7. 总结

  • Bank 内部结构:Cell → Row → Subarray → Array → Bank,Row Decoder + Sense Amplifier + Column Mux + IO
  • Row Buffer:ACT 后整行数据保存在 Sense Amplifier 锁存器里,READ/WRITE 直接操作 Row Buffer,不需要每次都访问 Cell
  • Sense Amplifier:差分放大器,把 Cell 过来的微弱电压变化(100~200mV)放大到 VDD/GND,是 DRAM 延迟的物理来源(tRCD 的一部分)
  • Bank Read 流程:ACT(tRCD)→ READ(CL)→ 数据输出(tCCD)→ PRE(tRP)→ 关闭行
  • 多 Bank 并行:8~32 个 Bank 可以流水线化,减少行冲突概率
  • DDR5 Bank Group:2 个 Bank Group 可以并行执行读/预充电,隐藏行切换延迟
  • 地址映射:PA → Channel → Rank → Bank → Row → Column → Byte offset,具体映射因 CPU 而异

下篇预告(S06):DDR5 相比 DDR4,内存带宽翻倍的秘密是什么?Bank Group、BL16、CAM Downlink、决策反馈均衡(DFE)——DDR5 的架构改革。


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

最后修改: 2024年3月1日

作者

评论

发表评论

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