存储器基础:SDRAM与DDR SDRAM的工作原理、存储单元结构、bank/row/column寻址、读写时序基础
在FPGA工程中,DDR控制器设计之所以让许多工程师感到棘手,根源往往不在于控制器逻辑本身,而在于对底层DRAM芯片行为模型的理解不够扎实。SDRAM(Synchronous Dynamic Random Access Memory)与DDR SDRAM(Double Data Rate SDRAM)虽然接口速率差异巨大,但其核心存储原理一脉相承:电容电荷存储、行列寻址、预充电与刷新机制。本章将从存储单元物理结构出发,逐步拆解bank/row/column寻址模型,并建立读写时序的基本时间观——这是后续编写FPGA控制器状态机、调校时序参数、解决带宽瓶颈的必备认知基础。
2.1 存储单元结构:从电容到1T1C阵列
DRAM的核心存储单元由一个晶体管(MOSFET)和一个电容(Capacitor)构成,业界称为1T1C结构。电容用于存储电荷:充电代表逻辑"1",放电代表逻辑"0"。晶体管充当开关,由字线(Word Line, WL)控制,决定电容是否与位线(Bit Line, BL)连通。这种结构的优势在于面积极小、成本低、集成度高,但代价是电容电荷会通过漏电流逐渐流失,因此必须周期性刷新(Refresh)来维持数据。
理解1T1C结构对FPGA控制器设计有直接意义:读操作本质上是破坏性读出——当字线打开、电容电荷释放到位线上时,电容中原有的电荷状态被破坏,因此读后必须重写(Restore)。这也是为什么DRAM读操作后需要额外的"预充电"步骤来恢复位线电压,并为下一次访问做好准备。
2.2 Bank/Row/Column三维寻址模型
现代SDRAM/DDR将存储阵列划分为多个独立的Bank(通常为4个或8个)。每个Bank内部是一个二维矩阵:行(Row)与列(Column)。因此,一次完整的存储访问需要三个地址分量:Bank地址(BA)、行地址(Row Address)、列地址(Column Address)。
这种三维寻址模型的核心价值在于Bank级并行。由于不同Bank的存储阵列相互独立,控制器可以在一个Bank进行预充电的同时,对另一个Bank执行行激活或读写操作。FPGA控制器设计中的"Bank交错"(Bank Interleaving)策略正是基于这一特性,通过轮转访问不同Bank来隐藏预充电和激活延迟,从而提升有效带宽。
| 地址分量 | 信号线 | 典型位宽 | 作用 | FPGA控制器关注点 |
|---|---|---|---|---|
| Bank地址 | BA[1:0](DDR2为BA[2:0]) | 2~3 bit | 选择4或8个Bank之一 | Bank状态机管理、交错策略 |
| 行地址 | A[13:0](DDR3为A[15:0]) | 14~16 bit | 选择Bank内的行(页) | 行激活/预充电调度、页命中率 |
| 列地址 | A[9:0](与行地址复用) | 10 bit左右 | 选择行内的列(突发起始点) | 突发长度、列地址递增 |
值得注意的是,行地址与列地址通过同一组地址线A[]分时复用。在激活命令(ACT)阶段,地址线传输行地址;在读写命令(RD/WR)阶段,地址线传输列地址。这种复用设计减少了芯片引脚数量,但要求控制器必须严格按照时序发送地址。
2.3 读写时序基础:从命令到数据
一次完整的读操作包含以下关键阶段,每个阶段都有严格的时序参数约束:
- 激活(ACTIVATE):发送Bank地址和行地址,打开指定行的字线,将整行数据(通常为1KB~2KB)从存储电容放大到位线缓存(Sense Amplifier)中。此阶段对应时序参数tRCD(Row-to-Column Delay),即从激活命令到读写命令的最小间隔。
- 读命令(READ):发送列地址,从已激活的行中选取指定列开始的数据。此阶段对应CAS延迟(tCL, CAS Latency),即从读命令发出到第一批数据出现在数据总线上的时钟周期数。
- 数据传送(Data Transfer):按突发长度(Burst Length, BL)连续输出数据。DDR的突发长度通常为4或8,意味着一次读命令会连续传送4或8个数据字。
- 预充电(PRECHARGE):关闭当前行,将位线恢复到预充电状态,为下一次行激活做准备。此阶段对应tRP(Row Precharge Time)。
- 刷新(REFRESH):周期性对所有行进行重新充电,防止数据丢失。刷新操作需要tRFC(Refresh Cycle Time),期间所有Bank均不可访问。
2.4 案例拆解:DDR2-800读操作时序分析
以DDR2-800(数据速率800MT/s,核心时钟400MHz)为例,假设控制器配置为CL=5、tRCD=5、tRP=5(单位:核心时钟周期),突发长度BL=4。我们来分析一次单Bank连续读操作的时钟周期消耗:
| 阶段 | 时钟周期 | 累计周期 | 说明 |
|---|---|---|---|
| 激活命令 | 1 | 1 | 发送ACT,行地址有效 |
| tRCD等待 | 5 | 6 | 行激活到读命令的最小间隔 |
| 读命令 | 1 | 7 | 发送RD,列地址有效 |
| tCL等待 | 5 | 12 | CAS延迟,数据尚未出现 |
| 数据传送 | 2 | 14 | BL=4,DDR双沿,2个时钟周期传完 |
| 预充电 | 1 | 15 | 发送PRE命令 |
| tRP等待 | 5 | 20 | 预充电完成,可激活新行 |
从上述分析可见,一次单Bank读操作从激活到可再次激活共需20个核心时钟周期,而实际数据传送仅占2个周期,有效带宽利用率仅为10%。这就是为什么FPGA控制器必须采用Bank交错、深度流水线等技术来隐藏时序开销。
2.5 常见误区与设计复盘
在FPGA DDR控制器开发中,以下误区最为常见:
- 误区一:忽略tRAS约束。tRAS(Active to Precharge Delay)要求行激活后必须保持至少一定时间才能预充电。如果控制器在tRAS未满足时发送PRE命令,将导致数据损坏。FPGA实现中,tRAS通常由计数器或延迟链保证。
- 误区二:刷新与读写冲突处理不当。刷新操作会阻塞所有Bank的访问。控制器必须提前规划刷新时机,避免在带宽高峰期刷新导致数据断流。常用的做法是采用"刷新批处理"或"分布式刷新"策略。
- 误区三:Bank状态跟踪不完整。每个Bank都有独立的状态(空闲、激活、预充电中),控制器必须为每个Bank维护状态机。如果状态跟踪错误,可能向未激活的Bank发送读写命令,导致命令被忽略或数据错误。
- 误区四:忽略读写转换延迟。DDR总线从读转向写或从写转向读时,需要额外的总线周转时间(tWTR, tRTW)。频繁切换读写方向会显著降低带宽,控制器应尽量将读操作和写操作分别批量调度。