DDR 时序参数、调度算法与交织深度解析¶
1. JEDEC DDR 核心时序参数与物理波形时序¶
DDR SDRAM 的每一次物理访存都必须遵循 JEDEC 规范严格定义的时钟周期约束。
sequenceDiagram
participant MC as 内存控制器 (DMC)
participant CMD as 命令总线 (CA Bus)
participant DQ as 数据总线 (DQ/DQS)
Note over MC,DQ: 1. 激活行 (Row Empty 或 Conflict 后)
MC->>CMD: PRECHARGE (关闭旧行, 等待 tRP)
MC->>CMD: ACTIVATE (打开新行, 等待 tRCD)
Note over MC,DQ: 2. 读取列数据
MC->>CMD: READ (发送列地址, 等待 tCL / CAS Latency)
CMD-->>DQ: 数据在 DQS 选通下连续传输 (Burst of 8 / 16)
Note over MC,DQ: 3. 行周期维持与写转读
Note over MC,DQ: 维持打开状态满足 tRAS; 两次 ACT 间隔满足 tRC
JEDEC 十大关键时序参数速查与微架构含义¶
| 时序参数 | 全称与物理含义 | 典型值 (DDR4-3200) | 违例后果与影响 |
|---|---|---|---|
| $t_{CL}$ (CAS Latency) | 发送 READ 命令到数据总线输出第一拍数据的时钟周期数 |
22 周期 ($\approx 13.75\text{ns}$) | 直接决定 Row Hit 状态下的纯读取延迟 |
| $t_{RCD}$ (RAS to CAS Delay) | 发送 ACTIVATE 激活行到允许发送 READ/WRITE 列命令的最小间隔 |
22 周期 ($\approx 13.75\text{ns}$) | 决定 Sense Amplifier 读出电荷并建立电压所需时间 |
| $t_{RP}$ (Row Precharge) | 发送 PRECHARGE 关闭行到允许发送下一个 ACTIVATE 的最小间隔 |
22 周期 ($\approx 13.75\text{ns}$) | 决定将位线(Bitlines)重新预充电恢复至 $V_{DD}/2$ 的时间 |
| $t_{RAS}$ (Row Active Time) | 激活行后,该行必须保持打开状态的最短时间 | 42 周期 ($\approx 26.25\text{ns}$) | 过早 Precharge 会导致读出放大器尚未将数据完全写回电容而丢失数据 |
| $t_{RC}$ (Row Cycle Time) | 同一 Bank 内两次连续 ACTIVATE 的最小间隔 ($t_{RC} = t_{RAS} + t_{RP}$) |
64 周期 ($\approx 40\text{ns}$) | 决定同一个 Bank 的极限访存频率上限 |
| $t_{FAW}$ (Four Activate Window) | 在任意滑动时间窗口内,允许在同一 Rank 发起 ACTIVATE 的最大次数(最多 4 次) |
34 周期 ($\approx 21.25\text{ns}$) | 芯片供电瞬态保护:限制同时给 4 个 Bank 读出放大器供电的峰值瞬态电流(di/dt) |
| $t_{WTR}$ (Write to Read Delay) | 写数据结束到允许发送 READ 列命令的物理死区间隔 |
12 周期 ($\approx 7.5\text{ns}$) | 读写总线电气转向(Bus Turnaround)延迟 |
| $t_{RFC}$ (Refresh Cycle Time) | 发送 REFRESH 命令到 Rank 恢复可用状态的恢复时间 |
350 周期 ($\approx 350\text{ns}$) | 刷新期间整个 Rank 处于冻结状态,造成显著尾延迟 |
2. 内存控制器行策略与 FR-FCFS 调度算法¶
Open-Page vs Close-Page 策略对比¶
- Open-Page(开页策略):数据读写完毕后,保持当前 Row 处于 Active 状态。
- 优点:若后续请求命中同一 Row(Row Hit),延迟极低(仅需 $t_{CL}$)。
- 缺点:若下一次访问发生 Row Conflict,必须先承受 $t_{RP}$ 预充电惩罚。
- 适用场景:具有高局部性的通用桌面、移动终端与服务器 CPU 工作负载。
- Close-Page(关页策略):每次读写完毕后立即附带 Auto-Precharge 将行关闭。
- 适用场景:多 Master 高度随机散布访问(如 GPU/网络路由交换机)。
FR-FCFS 动态调度与防饿死(Aging)¶
现代 DDR 控制器维护深层命令队列,采用 FR-FCFS(First-Ready First-Come-First-Served) 调度算法: 1. 优先级 1(Row-Hit First):能够直接命中当前已打开行的命令优先发射(消除 $t_{RP} + t_{RCD}$ 延迟)。 2. 优先级 2(Oldest First):当无行命中时,按照 FIFO 请求先后顺序发射。 3. 防饿死老化计数器(Anti-Starvation Aging Counter):若某个 Row Conflict 请求被连续抢占超过 $N$ 个周期,强制提升其优先级,打断连续 Row-Hit 流。
3. 物理地址交织(Address Interleaving)与 XOR Hash¶
为了最大化利用 Bank-Level Parallelism(BLP,多 Bank 并行处理),物理地址被按位切分并映射到不同的物理维度:
flowchart TD
PA["物理地址 PA (例如 36 位)"] --> Map["地址映射解算器"]
Map --> Row["Row 地址 (高位: 16 位)"]
Map --> Bank["Bank / Bank Group (中间位: 4 位)"]
Map --> Rank["Rank (1 位)"]
Map --> Channel["Channel (1 位)"]
Map --> Col["Column 地址 (低位: 8 位)"]
Map --> Offset["64B 行内偏移 (最低 6 位)"]
为什么必须引入 XOR Bank Hashing?¶
- 传统线性映射缺陷:若某程序以固定步长(如每步 $64\text{ KB}$)循环读取数据,地址的中间 Bank 位可能恒为
0000,导致所有请求全部砸向同一个物理 Bank,造成 100% 行冲突。 - XOR Hash 解冲突:将物理地址的高位 Row 地址与低位 Bank 地址进行异或($\text{Bank}_{\text{final}} = \text{PA}[15:12] \oplus \text{PA}[19:16]$)。这样即使低位地址相同,高位地址的变化也会将请求均匀散列到不同的 Bank 中,有效打散连续对齐访问引发的 Bank 冲突瓶颈。
4. 常见关键时序陷阱与排查手册¶
陷阱 1:DVFS 动态变频时时序换算少算 1 个周期(Ceil 向上取整 Bug)¶
- 现象:系统从高频(DDR-3200)降频到低频(DDR-1600)以节省功耗时,随机发生数据校验错误或死机。
- 微架构根因:
- 规范要求 $t_{RCD} = 13.75\text{ ns}$。在 1600 MT/s(时钟周期 $1.25\text{ ns}$)下: $$\text{Cycles} = \lceil 13.75 / 1.25 \rceil = 11\text{ 周期}$$
- 驱动代码若使用整数除法截断(Floor)而非向上取整(Ceil),计算出 $13.75 / 1.25 = 10$,导致控制器实际只等待了 10 个周期($12.5\text{ ns} < 13.75\text{ ns}$),在读出放大器尚未完全建立电压时就提前读取,引发电平误判!
- 规避准则:在 BSP 时序配置宏中使用标准安全公式:
#define NS_TO_CYCLES(ns, tCK) (((ns) * 1000 + (tCK) - 1) / (tCK))。
陷阱 2:频繁读写折返(Turnaround Thrashing)吃空总线¶
- 现象:代码中交替执行
*addr_a = val; dummy = *addr_b;(写一次立即读一次),总线吞吐下降 80%。 - 根因:每次写转读都必须强制插入 $t_{WTR}$ 物理气泡周期。
- 优化:在软件上将写操作批量聚合,读操作批量聚合,由控制器批量连续发射。