1, 简介
DDR SDRAM(Double Data Rate Synchronous Dynamic Random Access Memory,双数据率同步动态随机存储器)通常被我们称为DDR,其中的“同步”是指内存工作需要同步时钟,内部命令的发送与数据传输都以它为基准。DDR是一种掉电就丢失数据的存储器件,并且需要定时的刷新来保持数据的完整性。
DDR是我们嵌入式系统使用比较多的硬件,但是平时我们在做软件开发或者优化的时候,对它的组成及工作原理了解却很少。主要原因是对于DDR的软件开发主要是配置参数,而这些参数由芯片厂商已经提供好了。其实,要想对系统做深度的功耗优化和性能优化,是很有必要深挖DDR的组成与工作原理的细节。
现在嵌入式系统设计或者计算机设计,考虑到存储性能、存储容量、成本等因素,通常采用存储金字塔式的设计,比如CPU后面紧接着寄存器,寄存器后面跟着cache,cache后面紧接着DDR,然后DDR后面跟着SSD、EMMC等非易失。通过利用程序的时间及空间局部性原理,可以在尽可能少的影响性能的前提下,增加存储容量,降低存储成本。
随着CPU 发展,内存也发生了巨大的变革,DDR从诞生到现在已经经历了多代,分别是第一代SDR SDRAM(Single Data Rate SDRAM,同步型动态存储器),第二代的DDR SDRAM,第三代的DDR2 SDRAM,第四代的DDR3 SDRAM,现在已经发展到DDR5 SDRAM。为了实现容量增加和传输效能增加,规范的工作电压越来越低,DDR容量越来越大,IO的速度越来越高。
历代ddr特性对比
- Voltage(VDDQ):存储芯片的输出缓冲供电电压。
- Device Width:颗粒位宽,常见为4/8/16bit。一个Memory Array中由行地址和列地址的交叉选中一个位,若2个Array叠加在一起,就同时选中了2个Bit,位宽是X2。若4个Array叠加到一起,就能够同时选中4个Bit,位宽则是X4。也就是说,对一个X4位宽的DDR 颗粒,如果给出行地址和列地址,就会同时输出4个Bit到DQ(数据输入、输出:双向数据总线)数据线上。
- Die Density:颗粒密度,也就是容量,随着DDR迭代,容量越来越大。
- Data rates:MT/s指每秒传输多少个数据(Mega-transfer per second),和时钟频率是两个不同的概念。DDR(dual data rate)是双边沿传输数据。因此MT/s是IO时钟频率的两倍。
- Prefetch:在一个时钟周期中,同时将相邻列地址的数据一起取出来,并行取出DRAM数据,再由列地址0/1/2(DDR1使用列0,DDR2使用列0和列1,DDR3/DDR4使用列0,1和2)选择输出。2n/4n/8n。这里的数字指的就是并行取出的位数。这里的n,就是DQ位宽,即上面的device width(x4/x8/x16)。所以DDR3 16bit SDRAM内存颗粒,16bit指的是位宽,其一次读写访问的数据量是8*16=128bit
- Bank:DDR4以前是没有Bank Group的,所以该值就表示整个颗粒中Bank数量。但是在DDR4和DDR5中,就表示每个Bank Group中Bank的数量,整个颗粒Bank数量 = Bank Group * Bank。
- Bank Group:Bank分组数量,该特性只存在于DDR4和DDR5中。
- Burst Length:指突发长度,突发是指在同一行中相邻的存储单元连续进行数据传输的方式,连续传输所涉及到存储单元(列)的数量就是突发长度,在DDR SDRAM中指连续传输的周期数。一般对应预取bit数目。
- Core frequency:颗粒核心频率,即内存cell阵列的工作频率,它读取数据到IO Buffer的频率。它是内存频率的基础,其他频率都是在该频率的基础上得出来的。
- IO clk Frequency:内存的数据传输速率。它和内存的prefetch有关。对于DDR,一个时钟周期的上升沿和下降沿都在传输数据,即一个时钟周期传输2bit的数据,所以DDR的prefetch为2bit。对于DDR2,IO时钟频率是其核心频率的两倍,同时也是双沿传输数据,因此DDR2的prefetch为2×2bit=4bit。对于DDR3,IO时钟频率是其核心频率的四倍,同时也是双沿传输数据,因此DDR3的prefetch为4×2bit=8bit。
DDR SDRAM是由威盛等公司提出的第二代SDRAM标准,主要它允许在时钟脉冲的上升沿和下降沿都能传输数据,这样不需要提高时钟频率就能实现双倍的SDRAM提速。DDR2 SDRAM是由电子设备工程联合委员会开的第三代SDRAM内存技术标准,相比上一代提供了更高运行效能(拥有两倍与上一代的预读取能力,4bit数据prefetch)和更低的电压(1.8v)。DDR3 SDRAM相比上一代,电压更低(1.5v),效能更高(支持8bit prefetch),只需133MHz就能实现1066MHz的总线频率。DDR4相比上一代,工作电压更低(1.2v),效能更高(16bit prefetch),同样的频率下,理论速度是上一代的两倍。
2, 框架
DDR子系统框图
DDR SDRAM子系统包含DDR controller、DDR PHY和DRAM存储颗粒三部分。我们分别看一下各部分的组成,然后讲述一下数据的读写过程。
2.1 DDR controller
内存控制器负责初始化DRAM,并重排读写命令,以获得最大的DRAM带宽。它通过多端口与其他用户核进行连接,这些端口的类型包含AXI4/AXI3/AHB/CHI。每个端口有可配置的宽度、命令和数据FIFO。
内存控制器接收来自于一个或者多个CPU、DSP、GPU的请求,这些请求使用的地址是逻辑地址,由仲裁器来决定这些请求的优先级,并将其放入内存控制器中。如果一个请求处于高优先级(赢得仲裁),会被映射到一个DRAM的物理地址并被转换为一个DRAM命令序列。这些命令序列被放置在内存控制器中的队列池(Queue pool)中,内存控制器会执行队列池中这些被挂起的命令,并将逻辑地址转化为物理地址,并由状态机输出符合DRAM访问协议的电信号,经由PHY驱动DRAM的物理IO口。
- Arbitration CMD priority:仲裁器,仲裁CMD的优先级。会对来自各端口的请求进行仲裁,并将请求发送给控制器,仲裁其从端口收到的每个事务,每个事务都有一个相对应的优先级。端口仲裁逻辑会根据优先级进行处理,从而确定如何向控制器发出请求。以Cadence Denali内存控制器为例,它有几种仲裁策略:
- Round Robin:每个端口对应一个独立的计数器,当端口上有请求被接受的时候,计数器就会增加,然后仲裁器会针对计数器非0的端口的请求进行轮流仲裁,每仲裁执行一次,相应端口的计数器减一,直到端口接受请求计数器变为0。
- 带宽分配/优先级轮流操作:结合轮流操作、优先级、带宽和端口带宽保持等,根据用户分配的命令优先级,将传入的命令按优先级分组。在每个优先级组内,仲裁器评估请求的端口、命令队列和请求的优先级,从而确定优先级。当控制器繁忙时,超过其带宽分配的端口,可能会接受较低的优先级服务。
- 加权优先级循环:是一种面向服务质量的算法,结合了循环操作、优先级、相对优先级、端口排序的功能。根据命令的优先级或该类型命令的相关端口的优先级,将传入的命令分成优先级组。具有较高权重的端口可能会更频繁的接受仲裁,从而更容易被运行到。
- DDR SDRAM Control:DDR SDRAM的控制。包含了一个命令队列,接受来自仲裁器的命令。该命令队列使用一个重排算法来决定命令的放置顺序。重排逻辑遵循一些规则,通过考虑地址碰撞、源碰撞、数据碰撞、命令类型和优先级,来确定命令插入到命令队列的位置。重排逻辑还通过命令分组和bank分割,来提高控制器的效率。当命令进入命令队列后,选择逻辑扫描命令队列中的命令进行运行。若较高优先级的命令还没有准备好运行,较低优先级的命令不与命令队列中排在前面的命令冲突,那么这个较低优先级的命令,可以先于该没准备好的高优先级命令运行。此外,控制器还包含一个仲裁块,支持软件可编程接口、外部引脚及计数器的低功耗控制。另外,控制器支持调频功能,用户可以通过操作寄存器组,调整ddr的工作频率。
- Transaction Processing:事务处理用于处理命令队列中的命令。该逻辑会重排命令,使DRAM的读写带宽吞吐最大化。
- 2.2 DDR PHY DDR PHY是连接DDR颗粒和DDR Controller的桥梁,它负责把DDR Controller发过来的数据转换成符合DDR协议的信号,并发送到DDR颗粒。相反地,它也负责把DRAM发送过来的数据转换成符合DFI(DDR PHY Interface)协议的信号并发送给内存控制器。DDR PHY和内存控制器统称为DDR IP,他们保证了SoC和DRAM之间的数据传输。 目前在DDR IP的市场上,国际厂商占据较高的市场份额,而国内IP企业占比很小,究其原因,主要是由于DDR PHY具有较高的技术门槛,要在这类PHY上实现突破并不容易。DDR PHY是一个系统工程,在如下方面需要着重关注:
- DDR PHY的数据传输采用并行多位、单端突发的传输模式,对电源完整性PI(Power Integrity,电源完整性)和信号完整性SI (Signal Integrity,信号完整性)的要求很高。
- 为了能够补偿不确定的延时,针对不同信号,DDR PHY有个灵活配置的延时电路及对应的辅助逻辑,这些延时电路可能会随着电压及温度变化而变化。因此PHY针对这些电路要有校准(Training),可以说DDR PHY是对Training要求最多的接口。
- 2.3 DDR DRAM颗粒 从DDR PHY到内存颗粒的层次关系如下:channel->DIMM->rank->chip->bank->row/column组成的memory array。例如,i7 CPU 支持两个Channel(双通道),每个Channel上可以插2个DIMM(dual inline memory module,双列直插式存储模块),每个DIMM由2个rank构成,8个chip组成一个rank。由于现在多数芯片的位宽是8bit,而CPU的位宽是64bit,因此经常是8个芯片可以组成一个rank。
- Channel:简单理解一个通道对应一个DDR控制器,每个通道拥有一组地址线、控制线和数据线。
- DIMM:是主板上的一个内存插槽,一个channel可以包含多个DIMM。
- Rank:一组可以被一个内存通道同时访问的芯片组合称作一个rank,一个rank中的每个芯片都共用内存通道提供的地址线、控制线和数据线,同时每个芯片都提供一组输出线,这些输出线组合起来就是内存条的输出线。简单来说rank是一组内存芯片集合,当芯片位宽*芯片数=64bit(内存总位宽)时,这些芯片组成一个Rank,存储64bit的数据。一般每个芯片位宽是8bit,然后内存条每面8个芯片,那么每面就构成了一个Rank,这两面的Rank通过一根地址线来区分当前要访问的是哪一面。同一个Rank中所有的芯片协作来读取一个地址(1个Rank,8个芯片*8bit=64bit),这个地址的不同bit,每8个一组分散在这个Rank上的不同芯片上。设计Rank的原因是为了减少每个芯片的位宽(在CPU总位宽确定的前提下,比如64bit),降低复杂度。
- Chip:是内存条上的一个芯片,由多个bank组成,大多数是4bit/8bit/16bit,多个chip做成一个rank,配合完成一次访问的位宽。
- Bank:是一个逻辑上的概念。一个bank可以分散到多个chip上,一个chip也可以包含多个bank。
- Row、Column组成的memory array:可以简单的理解bank为一个二维bit类型的数组。每个bank对应一个bit,8个bank组成8bit的数据。
- 3, DRAM剖析 接下来深入的剖析一下DRAM的组成及工作原理。对于DRAM的原理,看到一篇很不错的文章《深入内存/主存:解剖DRAM存储器 - 知乎 (zhihu.com)》,以下内容基本上来自于这篇文章。3.1 基本结构1)DRAM的基本单元 基本的DRAM单元(cell),是一个电容加一个CMOS晶体管组成的电路。通过给晶体管最上面的一端(称作栅极)加上电压或是取消电压,就可以控制CMOS晶体管的开、关。一旦打开就可以读出电容上存储的电量,或者向电容写入电量。这样电容上的电荷有无就对应着存储1bit的1或0。DRAM cell 为了存储更多的bit,可以用如上的DRAM单元组成存储阵列。行对应的是word line,即字线。列对应的是bit line,即位线。当某一行的字线上通电后,这一行的cell上的电容就会经过位线进行充放电。通过读取位线上的电压变化,就能判断存储的是0,还是1。由于电容很小,打开字线后产生的电压波动也很小,所以在读取的时候,要经过sense amplifier进行放大。 每个位线都接在一个放大器上,由于每个cell的电容太小了,在读某一bit前,先对bit line进行precharge。预充的电压为工作电压的一半。这样在打开字线后,位线上的轻微变化也能被放大器捕捉到,并在本地还原、暂存字线对应整行cell的电压。其实,当读了位线(电容放电)后,电容上的电荷就会发生了改变,这是一种破坏性读出。为了解决这个问题,就需要放大器在读取cell存储的数据后,利用暂存的cell电压写回字线单元行。cell存储阵列2)DRAM刷新 由于cell的电容很小,并且CMOS晶体管在关闭的时候,也存在漏电,这样电容上的电荷也在随着时间的变化,逐渐变少。时间一长,存储的信息就会丢失。为了解决这一问题,具体做法是对于每个单元行,每过一段时间就自主地进行读取,等放大器暂存好信息后就立刻将其写回行。关于单元行的刷新时机也很有讲究,一般每64ms内就要对cell阵列进行一次全面刷新。3.2 DRAM的读写cell阵列+外围逻辑1) DRAM读过程 在读取DRAM芯片上单个比特数据时:
- 读取前,先给各条位线预充电(也称为precharge),即把位线电压拉高到供电电压的一半。拉高到一半的目的是和cell电容电压形成电压差,从而在打开单元行时,可利用电容的微弱充放电产生电压波动。预充电完成后,就可以断开位线与预充电电源的连接,此时位线处于悬空态,电压会保持为供电电压的一半。
- 开始读取,首先在地址总线上输入行地址,稍后立刻置“行地址选通”(即RAS)有效,置RAS有效后,DRAM芯片就把行地址缓存下来。
- 缓存好行地址之后,就把行地址送入译码模块,译码模块把行地址译码成独热码,独热码的每一位都接到对应的字线,然后把其中一条字线的电压值拉高。
- 把地址线上的地址从行地址转换成列地址,转换成列地址之后,外界会置“列地址选通”有效,然后DRAM会把列地址缓存起来。
- 拉高的字线所对应的单元行被打开,即单元行的所有晶体管导通,单元行的各个cell电容和位线连通。如果cell保存比特信息1,即cell电容的电压等于供电电压,此时cell电容电压高于位线电压,电容放电,位线的电压稍稍上升。如果cell保存比特信息0,即cell电容的电压等于地电压,即0电压,此时位线电压高于cell电容电压,位线向cell电容充电,位线电压稍稍下降。
- 放大器捕捉位线上的微弱电压波动,通过“差分感测”在本地生成并暂存cell电容电压。如果cell电容等于供电电压,那么位线电压稍稍上升,放大器比较此位线和另一条基准线的电压,通过模拟电路的反馈来放大两者的电压差,最终在本地生成一个等于供电电压的输出电压,并用锁存器把输出电压锁存下来。如果cell电容电压等于0,放大器最终生成等于0的输出电压,并用锁存器把0电压锁存下来。
- 放大器锁存好行数据之后,把行数据送往多到一选择器。
- 列地址缓存就把列地址送到多到一选择器,多到一选择器根据列地址,把单元行中的某一位送到输出线。
- 输出之后,还需要把放大器的数据写回到单元行,即根据放大器的锁存值,把位线拉高到供电电压或是0电压,位线向cell电容充放电,充放电结束之后,就可以关闭字线。
- 写回数据并关闭字线之后,连接位线和预充电电源,给位线预充电到供电电压的一半,为下一次读写做好准备。
- 2) DRAM写过程 写过程和读过程比较类似,就不详细描述,主要描述有差异的地方:
- 位线预充电到供电电压的一半。
- 输入、缓存行地址,译码行地址,开通单元行,开通单元行后位线产生电压波动,放大器捕捉电压波动并还原、暂存行数据到本地。
- 输入、缓存列地址,与此同时置写使能有效,并在Data Buffer存进写入比特,注意,Data Buffer在读取DRAM时用来暂存输出比特,而在写DRAM时则用来暂存写入比特。
- 把写入比特送到一到多分配器,分配器根据列地址把写入比特送到对应的放大器中,放大器根据写入比特改写本地暂存值。
- 放大器根据暂存的电压值刷新单元行,刷新完毕后断开单元行的字线。
- 刷新完毕后,重新给位线预充电,为下一次读写做好准备。
- 总的来说,读取一个比特的总体过程:获得行号,译码行号,开启单元行,放大位线电压波动并暂存数据到放大器,获得列号并根据列号选择一位进行输出,写回数据,关闭字线,重新预充电。写一个比特的总体过程是:获得行号,译码行号,开启单元行,放大位线电压波动并暂存数据到放大器,获得列号并输入写入数据,根据列号把写入数据送到放大器并改写暂存值,写回数据,关闭字线,重新预充电。 你可能会疑问,要访问的一个字节的其他7bit是不是也存在这些单元行里,答案是否定的。其实,还存在7个这样的bit存储阵列,其中相同的行列地址在这7个bit存储阵列相同位置取出相应的bit,这样便得到了完整的8bit(一个字节)数据。 另外,在读写过程中,时间主要消耗在“开启单元行”与“放大电压波动并暂存数据”。单元行的栅极可以抽象成一个个电容的并联,因此字线的拉高就是给这么多电容充电的一个过程,这将是很耗时及耗电的。由于放大器大部分是模拟电路,所以他的工作也不快。那么怎么提高DRAM的读写速度呢?关键点在放大器的缓存区(row buffer),它缓存了单元行,但是一般我们只取出了其中的一个bit。如果要想提升速写速度,那就还访问这个单元行的其他bit,这时会直接从row buffer中取出相应的数据,不需要经历开启单元行、放大、读写数、写回的耗时过程。3.3 DRAM系统层次 DRAM的系统层次如下:channel->DIMM->rank->chip->bank->row/column组成的memory array->存储cell。1)bank 如下是一个8阵列bank。其中每个rank中的行列定位到的小方块,是一个cell,对应一个bit。行、列组成了一个memory array,即一个bank。8个bank组成了8 bank的阵列,通过行、列地址可以得到8 bit的输出。8阵列bank 一个8阵列bank一次读写8个比特,一颗存储芯片上一般含有多个bank。下图是一颗含有8个bank的存储芯片的示意图。芯片每次读写都只针对一个bank,因此读写地址必须包含一个bank号,bank号用于开启目标bank,目标bank之外的bank是不工作的。包含8个8阵列bank的存储芯片2)Rank和DIMM 电脑用的内存芯片都嵌在一个电路板上,把这个电路板插入内存插槽后,就可增加电脑内存。电路板和板上的芯片,就是所谓的内存条,也称为DIMM条。内存条通过“内存通道”连接到内存控制器,一组可以被一个内存通道同时访问的芯片称作一个rank。一个rank中的每个芯片,都共用内存通道提供的地址线、控制线和数据线,同时每个芯片都提供一组输出线,这些输出线组合起来就是内存条的输出线。 对于一个包含8颗芯片的DIMM条。这8颗芯片被一个内存通道同时访问,所以它们合称为一个rank。有的DIMM条有两面,即两面都有内存芯片,这种DIMM条拥有两个rank。 若每个芯片都包含8个bank,每个bank都包含8个阵列,那么这条内存条就可以一次读写8×8=64比特,其中第一个8是指每个芯片输出8位,第二个8是指这个rank总共有8颗芯片,因为这8颗芯片被同一个内存通道访问,所以其被访问的bank和bank内的行地址、列地址都是完全一致的。下图是一个描述这个过程的简图:显然,我们在读写8颗芯片同一个bank同一个位置的cell。注意,图中没有显示不在工作状态的bank。对一个rank读写,即同时读写rank内8个存储芯片内的同一位置的bank。rank读写 电脑有时候可以插入多个内存条,多个内存条有助于提升电脑的内存容量,但是未必能提高电脑的速度。电脑的速度受“内存通道”数限制,如果电脑有四个插槽,却只有一个内存通道,那么CPU仍然只能一次访问一个rank。但如果电脑有四个插槽的同时还有四个内存通道,那么CPU就可以一次访问四个rank,很显然,四并行访问明显比串行访问快,假设每个rank可以输出64比特,那么四通道就可以一次访问4×64=256比特,而单通道只能访问64比特。3.4 DRAM访问加速1)burst模式 由于现在的处理器,CPU与DDR之间基本上都有cache,CPU在访问内存单个字的时候,不仅需要访问这个字,还需要把这个字所在的缓存行全部搬进cache中,因此内存不仅要一次提供一个字,还要提供一个缓存行(cache line)。缓存行一般比较大,比如8个64比特,因此内存要一次提供8×64=512比特数据。但如果前面介绍的方式访问内存,那么一次只能提取出64比特,即提取一个字,这并不满足缓存行的要求。为此,我们提出对内存使用“burst模式”。 由于缓存行内的各个字在内存上是紧邻的,我们就可以灵活地使用cell阵列中的行缓存(row buffer)。前面说到单元行进入放大器的行缓存之后,并不会在读写一个比特后立刻写回cell阵列,而是待在行缓存里等待下一个读写命令。如果下一个读写命令仍然发生在该单元行,那就可以行命中,直接操作row buffer。 在burst模式里,每当我们读取cell阵列中的一个比特,不仅把这个比特送到输出缓存中,而且紧接着把这个比特所在缓存行的各个比特都送到输出缓存,这样就完成了一次burst,即把目标比特周围的多个比特连续地读出。2)bank并行和内存交错 前面我们比较详细地聊了在一个cell阵列中读取数据的过程,而CPU在访问内存时,还需要一些别的操作。总的来说,CPU访存大概要经过5个步骤:1, CPU发送指令给内存控制器。2, 内存控制器解析指令,并把“解析到的控制信息”发送到控制总线。3, bank接收控制信息,并读取数据。4, 内存芯片把读取出的数据放到数据总线。5, 内存控制器收取数据,并将其交给CPU。 如果CPU连续访问同一bank,那么CPU、内存控制器、总线和bank就必须串行操作,串行操作会让访存效率下降。我们假设CPU不可以在一个bank工作时,再给它发送新的指令。如果CPU连续不断地给一个bank发送指令,那么很可能前一个指令还没完成,后一个指令就改变了bank内的row buffer、列地址缓存或输出缓冲。 为了说明cpu访存过程中带来的时间消耗和造成的效率下降,下面以“总线延迟”为例: 光速是3×10^8m/s,而高性能CPU的频率可达3GHz,即3×10^9Hz。那么在CPU的一个时钟周期内,光可以运动10cm。但是电在硅中的传播距离大约是光的五分之一,经过测量,在电子线路中 电在一个CPU时钟周期内只能运动20mm左右。而CPU和内存芯片之间的距离远不止20mm,因此数据在总线上移动需要花费多个CPU时钟周期。 上面的计算说明,在CPU访存的5个步骤中,第2、第4步是要花很多时间的,而没有详细讨论的第1、第5步,大概率比这两步还要慢。因此让CPU、内存控制器、总线和bank串行操作是不明智的。实际上,我们完全可以在一个bank进行第3步时,让CPU、内存控制器、总线去操作新的bank,以此隐藏起它们的工作时间,从而营造起一种CPU、内存控制器和总线不需要消耗时间的假象。上面这种做法实现了“bank间并行”。 所谓在“bank间并行”就是让一个chip内的不同bank并行工作,让它们各干各的。为此CPU要连续、依次向不同的bank发送读取指令,这样在同一时间很多bank都在工作,第一个bank可能在输出,第二个bank可能在放大电压,第三个bank可能在开启单元行。当第一个bank burst输出完毕,第二个bank刚好可以输出。当第二个bank burst输出完毕,第三个bank刚好可以输出.......通过这样让“bank读取”和“CPU、内存控制器、总线工作”在时间上相互重叠的方式,我们可以成功地把CPU、内存控制器和总线的工作时间隐藏起来,从而打造出一种CPU无延迟访问内存、多个bank连续、依次“泵”出数据的理想情况。这种通过“bank间并行”实现“连续泵出数据”的方法,就是所谓的“内存交错”。 内存交错不仅隐藏了CPU、内存控制器和总线的工作时间,还隐藏了对单个bank而言row缺失所造成的多余访问时间(所谓“多余”是相对“row 命中”情况而言的),连续两次对同一个bank的访问,它们访问的row相同或者不同,对延迟的影响是相当显著的。 如果第二个命令是对同一个row访问,那么memory controller只需要发出Rd/Wr读写命令即可,称为行命中。如果第二个命令是对不同的row进行访问,那么memory controller需要发出PRE,ACT,Rd/Wr命令序列,称为行缺失。从命令序列的对比来看,可以看出行缺失的情形对性能的影响是糟糕的。下图显示了连续的行缺失的情形下的访存序列:行缺失的访问序列 然而,如果我们有多个bank,然后将 A0,A1,A2...的访存序列,通过memory controller的address interleaving, 映射到多个bank上,也就是所谓banking。避免了连续访问同一个bank的不同row,造成的大量行缺失,就能够得到下面的访存序列:流水线化的访问序列 显然,上图中的类似流水化的访问能够很大程度上掩盖访问DRAM的访存延迟,这也就是banking能够提高memory throughput的原因。 另外,memory controller的address interleaving是什么呢? 我们都知道在OS层面,有着从virtual address到physical address的地址映射。类似地,在memory controller层面,我们需要将physical address映射为对DRAM chip中具体的位置的访问,通过将bank映射到物理地址的相对低位(相对于row),可以使得对连续地址的访存请求被映射到不同的bank。