电子说
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口。
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是一个系统工程,在如下方面需要着重关注:
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。
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芯片上单个比特数据时:
2) 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。
物理地址的bank映射
审核编辑:刘清
全部0条评论
快来发表一下你的评论吧 !