懂点儿底层原理 – 内存专题 | S04 | DRAM 访问的完整时序:命令、信号、和延迟的来源
金句:数据从 Cell 到 CPU 核心的旅程,每一步都刻在时序图上。读懂时序图,就读懂了 DRAM 的一半。
1. DRAM 命令和信号概述
1.1 DDR 颗粒的命令接口
DDR 颗粒通过一组并行信号接收命令。每个命令在时钟上升沿(或上升沿+下降沿)被采样:
DDR4 颗粒的命令信号(CS, RAS, CAS, WE, CKE, ODT):
CS#(Chip Select) :片选,拉低时 DRAM 接收命令
RAS#(Row Address Strobe):行地址选通,低电平表示"行相关命令"
CAS#(Column Address Strobe):列地址选通,低电平表示"列相关命令"
WE#(Write Enable) :写使能,低电平表示"写命令"
CKE(Clock Enable) :时钟使能,控制时钟信号是否有效
ODT(On-Die Termination):片上终止电阻,用于信号完整性
命令编码(CS# + RAS# + CAS# + WE#):
ACT = (0, 0, 1, 1) ← Row Activate(行激活)
READ = (0, 1, 0, 1) ← 列读命令
WRITE = (0, 1, 0, 0) ← 列写命令
PRE = (0, 0, 1, 0) ← Precharge(行预充电,关闭当前行)
REF = (0, 0, 0, 1) ← Refresh(刷新)
MRS = (0, 0, 0, 0) ← Mode Register Set(模式寄存器配置)
NOP = (0, 1, 1, 1) ← No Operation(空操作)
地址信号(A[17:0]):
- 传送行地址时表示 Row Address(用于 ACT)
- 传送列地址时表示 Column Address(用于 READ/WRITE)
银行地址(BA[2:0]):
- 选择 8 个 Bank 之一
命令有效条件:CS# 必须为低1.2 时钟和数据信号
DDR 的时钟和数据信号:
CK/CK#(Clock):差分时钟,DDR 采样沿
- DDR1:只在 CK 上升沿采样(SDR)
- DDR2/DDR3/DDR4:CK 上升沿 + 下降沿都采样(DDR)
- CK 频率 = 实际数据传输率的一半
DQS/DQS#(Data Strobe):数据选通信号
- 读操作时:由 DRAM 驱动,和数据边沿对齐
- 写操作时:由内存控制器驱动,和数据边沿对齐
- 接收端用 DQS 采样 DQ 数据(和 DDR 时钟原理相同)
DQ(Data):数据信号,x8 颗粒 = 8 条
DM/DBI(Data Mask / Data Bus Inversion):
- DM:写数据屏蔽(Mask),用于部分写
- DBI:数据总线翻转标记,用于降低功耗
命令时序示例(ACT → READ → PRE):
Cycle: 0 1 2 3 4 5 6 7 8 ...
CK ─┐ ─┐ ─┐ ─┐ ─┐ ─┐ ─┐ ─┐ ─┐ ─┐
└ ─┘ ─┘ ─┘ ─┘ ─┘ ─┘ ─┘ ─┘ ─┘
CS# ─┐ ─┐
└────────────────────────────┘ └
RAS# ─┐ ──────────────────────────── ─┐
└┘ │ └┘
CAS# ──────────────────────────── ──────────────────────── ─┐
│ └
WE# ──────────────────────────────────────────────── ────── ─┐
│ └
A[17:0] Row Addr ──────────────────────────────────────────────────
Col Addr ──────────────────────────────
BA[2:0] Bank ───────────────────────────────────────────────────────
说明:
Cycle 0-1:ACT 命令(行地址 + 银行地址)
Cycle 2+ :READ 命令(列地址)
数据在 READ 命令后延迟 RL 输出2. 完整访问周期:ACT → READ/WRITE → PRE
2.1 行激活命令(ACT)
ACT(Activate)命令的详细时序:
发送:CS#=低, RAS#=低, CAS#=高, WE#=高
伴随:A[17:0] = 行地址,BA[2:0] = 目标 Bank
ACT 之后发生的事(按时间顺序):
tRCD(ACT to READ/WRITE Delay):
→ ACT 命令到第一个 READ/WRITE 命令的最小延迟
→ DDR4-3200 标准:tRCD = 13.75ns = 22 个时钟周期(@1600MHz)
→ 如果 tRCD 太短,Sense Amp 还没稳定,数据会出错
tRCD 的内部过程(物理分解):
T=0: ACT 到达,Row Decoder 接收行地址
T=1ns: Word Line 开始拉高(NMOS 导通)
T=2ns: 所有 Cell 电容通过 NMOS 连接到 Bit Line
T=2-4ns:电荷重分配(Cell 电容和 Bit Line 电容共享电荷)
→ Bit Line 电压轻微上升或下降(取决于存储的"1"或"0")
→ 电压变化幅度约 100~200mV(很微弱)
T=4-10ns:Sense Amp 开始放大
→ 差分放大器检测 BL 和 BLB 的电压差
→ 放大到接近 VDD/GND 的完整电平
T=10-13ns:Sense Amp 稳定,行数据可用
T=13.75ns:满足 tRCD,可以发送 READ 命令2.2 读命令(READ)和数据返回
READ 命令:
发送:CS#=低, RAS#=高, CAS#=低, WE#=高
伴随:A[17:0] = 列地址,BA[2:0] = 目标 Bank
READ 后延迟 RL(Read Latency)个时钟周期数据才到达 DQ 引脚:
DDR4 RL 的完整分解:
RL = CL + tDQSCK + tDQSQ
CL(CAS Latency):
→ READ 命令到数据开始输出的时钟周期数
→ DDR4-3200 CL=22 时:CL = 22 × 0.625ns = 13.75ns
→ CL 是以时钟周期为单位的延迟,乘以 tCK 才是实际时间
tDQSCK(DQ Skew,Clock to DQ):
→ DQS 引脚相对于 CK 时钟的延迟
→ 约 0.5~1.0ns
→ 内存控制器需要知道这个延迟来正确采样数据
tDQSQ(DQS to DQ Setup/Hold):
→ 数据信号 DQ 相对于 DQS 的建立/保持时间
→ 约 0.2~0.4ns
总 RL(DDR4-3200 CL22):
RL = 22 + 0.8 + 0.3 ≈ 23.1 个时钟周期
实际时间 ≈ 23.1 × 0.625ns ≈ 14.4ns
加上前面 tRCD 的 13.75ns → READ 命令发出到数据输出 ≈ 28ns
DDR4-3200 READ 完整时序:
Cycle N: 发送 ACT[Row=X, Bank=A]
Cycle N+tRCD:发送 READ[Col=Y, Bank=A](tRCD = 22 cycles)
Cycle N+RL:数据开始出现在 DQ 引脚上(RL = 22 + 1.1 ≈ 23 cycles)
Burst Length = 8:连续 8 个时钟周期输出 8×8=64bits 数据
Cycle N+RL+7:最后一个数据字输出
DDR5 的 Read Latency:
DDR5-4800 CL40:
RL(ns) = CL × tCK + tDQSCK + tDQSQ
tCK(DDR5) = 0.417ns(2400MHz)
RL(ns) = 40 × 0.417 + 1.2 = ~17.9ns
加上 tRCD 的 14ns → ACT 到数据输出约 32ns2.3 写命令(WRITE)
WRITE 命令:
发送:CS#=低, RAS#=高, CAS#=低, WE#=低
伴随:A[17:0] = 列地址,BA[2:0] = 目标 Bank
同时:DQ 引脚携带写入数据
WL(Write Latency)的分解:
WL = CWL + tDQSS
CWL(CAS Write Latency):
→ WRITE 命令到第一个数据字出现在 DQ 的时钟周期数
→ DDR4-3200 CWL=11(写延迟比读 CL 低)
→ CWL = 11 × 0.625ns = 6.875ns
tDQSS(DQS to CK Setup):
→ DQS 选通信号和 CK 时钟的相对延迟
→ 要求 tDQSS ≥ 0.75×tCK 且 ≤ 1.25×tCK
→ 约 0.3~0.8ns
DDR4-3200 WRITE 完整时序:
Cycle N: 发送 ACT[Row=X, Bank=A]
Cycle N+tRCD:发送 WRITE[Col=Y, Bank=A](和 READ 一样需要 tRCD)
数据立即跟随 WRITE 命令发出(不需要等 WL)
WL = CWL = 11 cycles:WRITE 命令发出后 11 cycles 数据在 DQ 上
写操作的特点:
→ 数据方向和读相反(控制器→DRAM)
→ 数据和命令不同步发出(命令先,数据后)
→ 数据 Burst 长度 BL=82.4 预充电(PRE)和行关闭
PRE(Precharge)命令:
发送:CS#=低, RAS#=低, CAS#=高, WE#=低
伴随:A10=1 表示"对所有 Bank 预充电"(或 A[10]=0 + BA 选择特定 Bank)
A10=0 表示对特定 Bank 预充电
PRE 的作用:
→ 关闭当前打开的行(Row)
→ Sense Amp 断开与 Bit Line 的连接
→ 恢复 Bit Line 到 1/2 VDD 预充电电平
→ 为打开下一个行做准备
tRP(Row Precharge Delay):
→ PRE 命令到下一个 ACT 命令的最小延迟
→ DDR4-3200 标准:tRP = 13.75ns = 22 cycles
→ tRP 期间,Bank 不可用(等待预充电完成)
行冲突(Row Conflict)时延:
当前行:ACT[Row=X] ── tRCD ── READ ── PRE ── tRP ── ACT[Row=Y]
│
└─ 延迟:tRCD + tCCD + tRP + tRCD_new
连续访问不同行的总时间:
tRCD + CL + tCCD + tRP + tRCD_new + CL_new
≈ 13.75 + 13.75 + 3.4 + 13.75 + 13.75 + 13.75
≈ 72.15ns
连续访问同一行的总时间:
tRCD + CL + tCCD + ...(无 PRE 和新 ACT)
≈ 13.75 + 13.75 + N×tCCD
≈ 27.5ns(第一次访问)
≈ 3.4ns × N(后续访问同一行,连续读)3. 完整时序图:ACT + READ + PRE 分解
DDR4-3200(tCK=0.625ns)ACT → READ → PRE 的完整时序:
地址和命令:
Cycle: 0 1 2 3 4 5 6 ... N N+1 N+2 N+3 N+4 N+5
CK: ─┐ ─┐ ─┐ ─┐ ─┐ ─┐ ─┐ ─┐ ─┐ ─┐ ─┐ ─┐ ─┐ ─┐ ─┐ ─┐ ─┐ ─┐ ─┐ ─┐ ─┐ ─┐
└ ─┘ ─┘ ─┘ ─┘ ─┘ ─┘ ─┘ ─┘ ─┘ ─┘ ─┘ ─┘ ─┘ ─┘ ─┘ ─┘ ─┘ ─┘ ─┘ ─┘ ─┘
CS#: ─┐ ─┐ ─┐
└───────────┘ └──────────────────┘
RAS#: ─┐ ──────────────── ─┐
└┘ │ └
CAS#: ─────────────────────────────── ──────────────────────────────── ──────────── ─┐
│ │ └
WE#: ─────────────────────────────────────────────────────────────────────────────── ─┐
└
A[17:0]: RRRRRRRR ─────────────────── CCCCCCCC ────────────────────────── A10=1 ────────────
(行地址) (列地址) (precharge)
BA[2:0]: BBB ───────────────────────── BBB ──────────────────────────────── ─────────────────
说明:ACT @ t=0(行地址 RRRRRRRR,Bank BBB)
READ @ t=22(tRCD=22 cycles)→ 列地址 CCCCCCCC
数据在 READ 后 RL=22 cycles 开始输出
PRE @ t=数据结束后+4 cycles → A10=1(所有 Bank)
时序参数对应关系:
ACT → READ 间隔:tRCD = 22 cycles = 13.75ns
READ 命令 → 数据输出:CL = 22 cycles
READ → PRE(不需要等数据结束):tRTP = 8 cycles(Read to Precharge)
PRE → 下一个 ACT:tRP = 22 cycles = 13.75ns
Row Cycle Time(RC):
= tRCD + CL + tRTP + tRP + tRRD
= 22 + 22 + 8 + 22 + 4 cycles
= 78 cycles = 48.75ns4. 关键时序参数汇总表
DDR4 关键时序参数(DDR4-3200 CL22,tCK=0.625ns):
参数 全称 典型值(ns) 典型值(cycles) 说明
─────────────────────────────────────────────────────────────────────────
tCK Clock Period 0.625ns 1 时钟周期(1600MHz)
tCH Clock High 0.45×tCK CK 高电平宽度
tCL Clock Low 0.55×tCK CK 低电平宽度
tRCD RAS to CAS Delay 13.75ns 22 ACT 到 READ/WRITE
tRP Row Precharge 13.75ns 22 PRE 到下一个 ACT
tRC Row Cycle Time 45ns 72 连续访问同一行
tRAS RAS Active Time 32ns 52 ACT 保持时间
tRTP Read to Precharge 5ns 8 READ 后到 PRE
tWR Write Recovery 15ns 24 WRITE 后到 PRE
tCCD CAS to CAS Delay 3.4ns 5~6 列到列间隔
tRRD Rank to Rank Delay 4ns 6 不同 Rank 切换
tRFC Refresh Cycle Time 350ns 560 刷新一行时间
tREFI Refresh Interval 7.8µs 12480 刷新间隔
CL CAS Latency 13.75ns 22 READ 命令到数据
CWL CAS Write Latency 6.875ns 11 WRITE 命令到数据
RL Read Latency 14.4ns 23 实际读延迟
WL Write Latency 7.5ns 12 实际写延迟
tDQSCK DQS to CK Skew 0.5~1.0ns 数据选通延迟
tDQSQ DQS to DQ Setup 0.2~0.4ns 数据建立时间
tWPRE Write DQ Preamble 1×tCK 写前导码
tWPST Write DQ Postamble 0.5×tCK 写后导码
tRPRE Read DQ Preamble 2×tCK 读前导码(DBI/DM)
tRPST Read DQ Postamble 0.5×tCK 读后导码
DDR5 新增参数:
CAMD CAM Downlink 4~8 cycles DDR5 特有延迟
SCS Strobe Ctlr Setup 0.3×tCK 新时序
SCH Strobe Ctlr Hold 0.3×tCK 新时序5. 多 Bank 操作和 Bank 冲突
5.1 Bank 级流水操作
现代 DRAM 控制器会在多个 Bank 之间流水线化操作:
示例:Bank 流水线(Bank 0/1/2/3 并行)
Bank 0:ACT[Row=0] ─── READ ─── PRE ─── ACT[Row=5]
Bank 1: ACT[Row=2] ─── READ ─── PRE
Bank 2: ACT[Row=3] ─── READ ─── PRE
Bank 3: ACT[Row=7] ─── READ
tRRD(Rank to Rank Delay):
→ 同一个 Rank 内连续 ACT 命令的最小间隔
→ DDR4 tRRD = 4 cycles(最小)
→ 如果是不同 Rank,tRRD 可以更短(或并行)
Bank 冲突的代价:
Bank 0 和 Bank 1 访问同一个行(内部行冲突):
→ Bank 0 ACT[Row=X] ─── READ ─── PRE ─── ACT[Row=X](同一行重开)
→ tRP + tRCD + ... 开销重复
Bank 并行度对性能的影响:
- 8 个 Bank 的 DDR4 颗粒:内存控制器可以同时保持 8 个行打开
- 减少行冲突概率 → 提高带宽利用率
- DDR5 的 32 Bank 设计:进一步减少冲突5.2 命令序列和时序约束汇总
DDR4 标准命令序列及约束:
1. ACT(行激活)
→ 发送:ACT[Bank, Row]
→ 约束:同一 Bank 的上一个 ACT 后必须等 tRAS 才可 PRE
tRAS(RAS Active Time)= 32ns(DDR4-3200)
同一 Bank 的上一个 PRE 后必须等 tRP 才可 ACT
tRP = 13.75ns
同一 Rank 的上一个 ACT 后必须等 tRRD 才可另一个 ACT
tRRD = 4ns
2. READ(列读)
→ 发送:READ[Bank, Col]
→ 约束:上一个 ACT 后必须等 tRCD 才可发 READ
tRCD = 13.75ns
同一个 Bank 上一次 READ 后必须等 tCCD 才可发下一个 READ
tCCD = 4ns(BL8 模式)
同一个 Bank 上一次 READ 后必须等 tRTP 才可发 PRE
tRTP = 5ns
3. WRITE(列写)
→ 发送:WRITE[Bank, Col] + 数据
→ 约束:上一个 ACT 后必须等 tRCD 才可发 WRITE(和 READ 相同)
同一个 Bank 上一次 WRITE 后必须等 tCCD 才可发下一个 WRITE
同一个 Bank 上一次 WRITE 后必须等 tWR 才可发 PRE
tWR(Write Recovery)= 15ns
4. PRE(预充电)
→ 发送:PRE[Bank](或 PRE A10=1 所有 Bank)
→ 约束:上一个 ACT 后必须等 tRAS 才可发 PRE
tRAS = max(tRAS, tRTP)
PRE 后必须等 tRP 才可发下一个 ACT
tRP = 13.75ns
5. REF(刷新)
→ 发送:REF[Bank](或 REF All Bank)
→ 约束:每次 REF 后必须等 tRFC 才可发下一个命令
tRFC = 350ns(DDR4-8Gb)
每 64ms 必须完成所有 Bank 的 REF(64ms/tREFI 次)
命令优先级(时序约束越严格,越优先):
PRE > ACT > READ/WRITE > REF > NOP6. DDR5 时序的变化
DDR5 时序的新变化:
1. 命令速率不同
DDR4:命令在 CK 上升沿和下降沿都采样(DDR)
DDR5:命令只在 CK 上升沿采样(SDR),但 CK 频率更高(2400~3200MHz)
2. 双通道 per DIMM
DDR5 每个 DIMM 有两个独立的 40-bit 通道(≠ DDR4 的单 64-bit)
→ 每个通道独立时序,可以流水线化
3. 新命令:ACTab(Activate Two Banks)
DDR5 新增:一个 ACT 命令同时激活两个 Bank(一个行激活,一个预充电)
→ 减少 Bank 切换延迟
4. CAS 到 CAS 的约束变化
DDR5 tCCD = 8 cycles(BL16 模式,一次传 128 bits)
比 DDR4 的 tCCD=4 更长(因为每次传输更多数据)
5. Read Latency 分解(DDR5)
RL = CL + tDQSCK + tDQSQ + tCAD
多了 tCAD(CAM Downlink Delay)= 4~8 cycles
→ DDR5-4800 CL40 实际延迟 ≈ 18ns(和 DDR4-3200 CL22 差不多)
6. CKE 定时(Clock Enable)
DDR5 强化了 CKE 控制:
→ 更细粒度的时钟门控
→ 可以独立控制每个 Bank 的时钟
→ Self-Refresh 期间更省电
DDR5 时序参数示例(DDR5-4800 CL40):
tCK = 0.417ns(2400MHz 时钟)
tRCD = 14ns(33.6 cycles)
tRP = 14ns
CL = 40 cycles(16.7ns)
CWL = 32 cycles(13.3ns)
tCCD = 8 cycles(3.3ns)
tRRD = 4 cycles(1.67ns)7. 总结
- DRAM 命令:ACT(行激活)/ READ / WRITE / PRE(预充电)/ REF(刷新)/ MRS(模式配置)/ NOP,编码在 CS# + RAS# + CAS# + WE# 四根信号上
- 时序参数:tRCD(行到列延迟)/ CL(读延迟)/ CWL(写延迟)/ tRP(预充电延迟)/ tCCD(列到列间隔),单位是 ns 和 cycles
- 命令顺序:ACT → READ/WRITE → PRE → ACT(下一个),每一步都有最小时间约束
- 延迟计算:总读延迟 = tRCD + CL + tDQSCK + tDQSQ,DDR4-3200 CL22 约 28ns(ACT 到数据),实际总线延迟 60~80ns(含内存控制器开销)
- Bank 冲突:连续访问不同行(跨行)导致 tRCD + tRP + tRCD_new 额外开销,是行内访问延迟的 3~5 倍
- DDR5 变化:命令只在上升沿采样(SDR)、双通道 per DIMM(2×40-bit)、tCCD 更长(BL16)、新增 tCAD 延迟
下篇预告(S05):Bank、Row、Column——内存地址是怎么一步步映射到具体的 Cell 的?Bank Group、Rank、Channel 的层次结构,以及如何利用地址局部性避免行冲突。
关注公众号「AI不着急」,回复”资料”获取内存学习路线图。
评论