引言 Introduction
如今,DDR4 SDRAM 是基于 FPGA 或者 ASIC 的设备中非常流行的存储介质。本文我们将探寻 DDR4 的一些的基础知识:
- DDR4 SDRAM 的内部结构是怎么样的
- DDR4 的基础操作:读写操作是如何进行的,以及
- 高层次的 SDRAM 子系统概述,比如 FPGA/ASIC 与 DDR4 SDRAM 通信的整个系统
物理结构 Physical Structure
从 DRAM 必要的 IO 管脚及其功能来开始本文是个不错的主意。本章我们将从 DRAM 外部的 IO 开始,一直向底层讨论到 DRAM 内部的基础电路单元。
顶层 Top Level
正如你预期的那样,DRAM 拥有时钟、复位、片选、地址以及数据输入。下文中的表格有关于各个引脚更详细的信息。表格中并没有列出所有的 IO,只列出了其中基础的部分。读者可以花一些时间来了解各个 IO 的功能,尤其是那些拥有复用功能的地址信号。
图-1 顶层 IO 信息
BankGroup,Bank,Row,Column
上节中的 DRAM 顶层结构展示了提供给外部的 IO 管脚。而下图则展示了 DRAM 内部的构造,以 bank 以及 bankgroup 为单元组织起来。
图-2 BankGroup 以及 Bank
当从存储介质中读取数据时,需要提供读数据的地址;在写入数据时,除地址外还需提供写数据。由用户提供的地址,一般称为“逻辑地址”(logical address)。逻辑地址在传输给 DRAM 前,会转换为物理地址(Physical address 译注:转换工作通常由 MMU 完成)。物理地址由以下几个域(field)组成:
- Bank Group
- Bank
- Row
- Column
这些域将用于区分读取或者写入数据的存储介质单元的位置。
如果再深入一个层次,看看单个 Bank 的组成部分。
- 存储阵列 Memory Arrays
- 行译码 row decoder
- 列译码 column decoder
- Sense Amplifiers
图-3 行&列译码
在确定了待读取地址的 Bank 组与 Bank 后,地址中的行部分将激活(activate)存储阵列中的一行(line),这被称为 Word line。在该行被激活后,其数据被从存储阵列中读出,写入 Sense Amplifiers。随后,DRAM 根据列地址从 Sense Amplifiers 中缓存的 Word line 再读取出属于该列的数据,这部分数据的长度与 DRAM 列数据位宽相同,称为 Bit line。
DRAM 协议规定了列数据位宽,包括 4 bit,8 bit 和 16 bit 三种,DRAM 也因此分为三类:x4,x8 以及 x16 。此外请注意:DRAM 颗粒的 DQ 宽度与列数据位宽相同。所以也可以说 DRAM 是根据 DQ 总线宽度划分的,为了简便起见。
[备注] x16 DRAM 仅有 2 个 Bank Group 而 x4 以及 x8 DRAM 有 4 个 Bank Group,如图 2 所示。
举例时间:一个 DRAM 芯片好比就是一个装满着文件柜的建筑
BankGroup 地址用于找到楼层
Bank 地址用于找到你所需的那个文件柜
Row 地址用于在这个文件柜里找到你所需的抽屉
Col 地址则用来标记抽屉里第几份文件是你需要的
而在更低的层次上,每个比特实际上由一个保持电荷的电容,以及一个用作开关的晶体管组成。
图-4 比特层组成
由于电容中保持的电荷会随着时间流逝而放电,DRAM 中保持的信息会逐渐丢失除非周期性地对电容充电,即重刷新。这也就是 DRAM 中 'D' 的由来,代表 Dynamic,对应于 SRAM (Static Random Access Memory)。
DRAM 容量与地址 DRAM Sizing & Addressing
DRAM 采用标准容量,由 JEDEC 标准制定。JEDEC 是决定 DDR 设计与发展路线的标准委员会。下文的内容来自 JEDEC DDR4 标准(JESD79-4B)的 2.7 节。
图-5 不同容量的 DRAM 颗粒的地址映射
DRAM 容量计算 DRAM Size Calculation
接下来让我们通过手工计算 2 个颗粒的大小来更深入地理解上一份表格的内容。
/* 4Gb x4 Device */ 4Gb x4 颗粒
Number of Row Address bits: A0-A15 = 16 bits
行地址信号位宽:16bit
Total number of row = 2^16 = 64K
总行数:64k
Number of Column Address bits: A0-A9 = 10 bits
列地址信号位宽:10bit
Number of columns per row = 1K
总列数:1k
Width of each column = 4 bits
每列的数据位宽:4bit
Number of Bank Groups = 4
Bank Group 数量:4
Number of Banks = 4
Bank 数量:4
Total DRAM Capacity =
Num.Rows x
Num.Columns x Width.of.Column x
Num.BankGroups x Num.Banks
DRAM 容量计算 = 行数 x 列数 x 列的数据位宽 x Bank Group 数量 x Bank 数量
Total DRAM Capacity =
64K x 1K x 4 x 4 x 4 = 4Gb
/* 4Gb x8 Device */
Number of Row Address bits: A0-A154 = 15 bits
Total number of row = 2^15 = 32K
Number of Column Address bits: A0-A9 = 10 bits
Number of columns per row = 1K
Width of each column = 8 bits
Number of Bank Groups = 4
Number of Banks = 4
Total DRAM Capacity =
Num.Rows x
Num.Columns x Width.of.Column x
Num.BankGroups x Num.Banks
Total DRAM Capacity =
32K x 1K x 8 x 4 x 4 = 4Gb
DRAM Page 大小计算 DRAM Page Size
在上文的表格中,提到了 Page Size 这一概念,指的是每一行中的 bit 数量。换句话说,是当一行被激活时,载入到 Sense Amps 的比特数量。考虑到列地址的位宽为 10bit,每一行有 1k 个列。
所以对于 x4 器件而言,每一行的 bit 数量为 1k x 4 = 4k bit(512B)。
同理,x8/16 器件的 page size 分别为 1k/2k Byte
Rank (Depth Cascading)
DRAM 中有 single/Dual/Quad Rank 等术语。Rank 是 DRAM 中的最高层次的逻辑单元,一般用于增加整个系统的存储容量。
比如说你需要 16Gb 存储,根据市场上的供应情况、价格以及你自己口袋里的银子,你可能会选择单个 16Gb 的芯片,那么此时你拥有的就是 Single Rank 的系统,因为你只需要单个片选信号(CS_n,毕竟你只有单个 chip),就可以读取整个 16Gb 空间。
你也可以选择两个单独的 8Gb 的颗粒来组成 16Gb 空间,这两个颗粒一起焊在一块 PCB 上,一般来说这比单个 16Gb 的颗粒要便宜。此时,这两个颗粒共享同一组地址与数据总线,因此你需要控制 2 个片选信号来分时选中这两个颗粒,此时即为 Dual Rank。
[备注] 你可能会遇到另一种形式的 Dual Rank DDR——Dual-Die Package,即 DDP。DDP 将两个 DDR 颗粒封装在一起,此时你看见的就只有单个芯片了,但其实这两个颗粒还是共享总线,是一种 Dual Rank 器件。
图-6 Rank 的组成
Width Cascading
再举个多芯片系统的例子,但与 RANK 无关。假设你需要一个 8Gb 存储,并且你的借口是 x8 位宽的,即位宽为 8 bit。此时,你可以选择单个 8Gb x8 的颗粒,或者两个’位宽串联‘的 4Gb x4 的颗粒。在位宽串联(Width Cascading)模式中,两个颗粒连接到同一个片选信号、地址以及数据总线。但不同的是,连接至数据总线的不同部分,在下图中,第一个 x4 颗粒连接到 DQ[3:0],而第二个颗粒则连接至 DQ[7:4]。(译注:此时两者都是 single rank )
图-7 位宽串联的 DRAM 颗粒
存储访问 Accessing Memory
- DDR4 的读写访问都基于 Burst 形式(译注:Burst 一般译作突发传输或者猝发传输)。突发传输起始时,由用户指定传输的起始地址,以及本次传输的长度,在 DDR4 中这个长度为 8 或者 4,后者是一个 chopped 的传输。(译注:chopped burst ,即提利昂·兰尼斯特式短小的传输)
- 读写操作分为两个阶段,以 ACTIVATE 激活命令(保持一个周期的 ACT_n & CS_n 低电平信号)开始,其后是具体的读或者写命令。
- 与激活命令同时发出的地址信号,用于确定所需激活的 BankGroup,Bank,Row,这项步骤称为 RAS 阶段,Row Address Strobe。
- 而在第二阶段,与读写命令同步发出的地址信号用于确定突发传输的起始列地址。这项步骤称为 CAS 阶段,Column Address Strobe。
- 由于单个 Bank 只有一个 Sense Amps,只能缓存单个行的内容。因此在激活某行后,访问同一 Bank 不同行之前,需要使用 PRECHARGE 命令关闭(de-activate)当前激活行。PRECHARGE 命令好比关上当前打开的文件柜抽屉,命令发出后当前 Sense Amps 中缓存的行会被写回原地址。
- 相较于直接使用 PRECHARGE 命令关闭某个行,也可以使用 RDA (Read with Auto-Precharge)或者 WRA (Write with Auto-Precharge)命令,在当前传输结束后自动关闭当前行。因为列地址只需要使用 A0-A9 10bit,因此 CAS 阶段使用 A10 比特表示当前是否启用自动关闭(Auto-Precharge)。
命令真值表 Command Truth Table
至今为止,我们一直在使用 ”命令“ (Command)这一说法,激活命令,读写命令等等。但在本文开始的时候,我们并没有提到 DRAM 有"命令" IO,那么这些命令都是如何通过 IO 发送给 DRAM 的呢?
事实上,DRAM 使用 ACT_n, RAS_n, CAS_n & WE_n ,这几个信号 IO 的组合来发出命令。
表-部分命令的真值表
上表是 DRAM 部分命令的子集,完整的命令真值表可以在 JEDEC 标准 JESD79-4B 4.1 节中获得。
读命令 Read
图-8 读命令操作
上图是读命令的时序图,此时突发传输长度为 8,称为 BL8。
- 第一步是 ACT 命令,当时在地址总线上的是 row 地址
- 第二步发出了 RDA 命令,此时地址总线上为 column 地址
- RDA 命令指示 DRAM 在读操作完成后自动关闭当前 Bank
写命令 Write
图-9 写命令操作
上图是写命令的时序图。
- 第一步是发出 ACT 命令激活 ROW 行
- 第二步发出了写命令,第一次突发传输写入 COL 起始的地址中,第二次突发传输写入 COL+ 8 地址
- 第二次突发传输之前无需再发出 ACT 命令,因此所操作的 ROW 行此前已经被打开,数据缓存于 Sense Amps 中
- 此外,第一次发出的是纯粹的 WR 命令,所以传输结束后,该行仍处于激活状态。第二次发出的是具有自动关闭功能的 WRA 命令,因此在传输结束后自动关闭了该行。
[备注:本文对一些内容并没有做出详细的解释,比如 A16&A15&A14 这些具有复用功能的地址信号中,自动关闭功能通过 A10发出,而 A12 则用于选择突发传输的长度:4/8, 如果模式寄存器中相应的配置位使能的话]
DRAM 子系统 DRAM sub-system
在前面的章节中,我们已经讨论了很多关于 DRAM 本身的内容,在本节中,我们将讨论 ASIC 或者 FPGA 与 DRAM 通信时所需的系统组件,由 3 部分组成:
- DRAM
- DDR PHY
- DDR Controller(译注:一般简称为 MC,即 Memory Controller)
图-10 DRAM 子系统组成
上图中的信息量很大,让我们一点点拉扯来看:
- 一般来说,DRAM 是一个焊接在 PCB 上的独立芯片,而 PHY 与 MC 则是 FPGA 或者 ASIC 用户逻辑的一部分
- 用户逻辑与 MC 之间的接口是由用户定义的,并没有被标准化
- 用户逻辑向 MC 发出读写命令时,其中的地址使用的是逻辑地址
- MC 再将逻辑地址转换为物理地址,将用户逻辑的命令转换后向 PHY 发出
- MC 与 PHY 之间采用标准化接口进行通信,一般为 DFI (DDR PHY Interface),DFI 标准可从以下链接得到 http://www.ddr-phy.org/
- PHY 将 MC 的命令转换为具体的底层信号,驱动 DRAM 的物理 IO 接口
- PHY 与 DRAM 之间的接口由 JEDEC 标准化
由此看来,MC 好比是读写 DDR 的大脑,而 PHY 则是做出反应的肌肉
- 当用户激活一行时,整个行被缓存至 Sense Amps 中。后续用户对该缓存行读写的代价会相对较低,因为可以省略第一阶段的激活命令。MC 一般可以对访问 DRAM 的请求进行重排序,来高效地利用行缓存机制。为了实现重排序,MC 一般具有一小块 cache 或者 TCAM,并始终返回最新的数据(译注:and always returns the lastest data 这里没有搞懂)。所以用户逻辑无需担心数据丢失或者冲突,因为控制器会负责重排序功能
- PHY 中包括了模拟电路的部分,用于驱动 DRAM 的 IO。并负责调整寄存器以增大驱动能力或者调节端接电阻,以提高信号完整性
言而总之 In a netshell
让我们最后总结下本文:
- DRAM 以 Bank Groups Bank Row Columns 的形式组织
- 用户发出的地址称为逻辑地址,由 DRAM 控制器转换为物理地址后发送给 DRAM
- DRAM 根据其 DQ 数据总线宽度,划分为 x4、x8 以及 x16 三类
- 可以通过 depth/width 串联多个 DRAM 颗粒实现所需的大小
- 读写命令分为两个阶段进行,第一步激活某行,第二步读写该行
- DRAM 子系统由 DRAM 颗粒、PHY 以及 控制器三部分组成