内存是我们平常嵌入式系统中接触的比较频繁的硬件之一,但是我们对这个器件的了解却知之甚少。主要的原因是作为嵌入式工程师的我们,这部分主要是配置参数,而这些参数都是由芯片厂商已经提供好了,硬件工程师都会基于厂商认证的DDR选型,减少开发周期。其实对于内存,有很多的细节和知识点可以深挖,本章的内容包括如下内容:
小张有一定的计算机背景知识,最近他在京东上买了两条DDR3的内存,打算把笔记本升级成8G。可是一拆开包装到就傻眼了:
4GB看起来很好,两根刚好8GB。2Rx8是啥,PC3又是啥,10600似乎和他想买的1333的差好远,后面那串数字又代表什么呢?于是乎对于这些细节,我们越看越傻眼。后面讲会详细的介绍这些细节。
在回归DDR的发展过程之前,我们先来了解下储存器的主要功能,其主要是储存程序和各种数据,并能在计算机运行过程中高速、自动完成程序或数据的出存取。
首先,要了解下储存的基本部分,ROM和RAM。
类型 | 作用 | 特点 | 发展 |
---|---|---|---|
RAM(random access memory):随机存取存储器 | 是与CPU直接交换数据的内部存储器,也叫主存(内存)。它可以随时读写,而且速度很快,通常作为操作系统或其他正在运行中的程序的临时数据存储媒介。 | 电源关闭时RAM不能保留数据 | SDRAM、DRAM、DDR |
ROM:只读存储器 | ROM所存数据,一般是装入整机前事先写好的,整机工作过程中只能读出,而不像随机存储器那样能快速地、方便地加以改写 | ROM所存数据稳定,断电后所存数据也不会改变。 | flash、HDD、SSD |
从上面的可以看出,其主要的区别有两点
而对于RAM,可分为SRAM(静态随机存储器)和DRAM(动态随机存储器)
类型 | 作用 | 特点 |
---|---|---|
SRAM(Static Random Access Memory,静态随机存储器) | 它是一种具有静止存取功能的内存,不需要刷新电路即能保存它内部存储的数据 | 优点是速度快,不必配合内存刷新电路,可提高整体的工作效率。缺点是集成度低,功耗较大,相同的容量体积较大,而且价格较高,少量用于关键性系统以提高效率。 |
DRAM(Dynamic Random Access Memory,动态随机存储器) | DRAM只能将数据保持很短的时间。为了保持数据,DRAM使用电容存储,所以必须隔一段时间刷新(refresh)一次,如果存储单元没有被刷新,存储的信息就会丢失 | 必须刷新,后面衍生出DDR,DDR2,DDR3,DDR4 |
但回顾内存容量的发展,从最初KB到GB的跃进,从单条1GB到如今单条16GB或者32GB的进化,经历了漫长的过程。
从最初的时候,个人电脑和嵌入式系统对于功能的实现都比较简单,内存的容量和储存容量都比较小,只有64K到256KB,对于嵌入式系统上甚至更小。
那我们以PC的过程来讲解发展过程,由于第一代DIP的芯片难以扩展,而随着CPU的数据总线的宽度达到64bit,一根DDR就难以满足处理需要,所以就需要两根、4根,内存容量也有所增加,它的出现很快就替代了30pin SIMM内存,386、486以及后来的奔腾、奔腾Pro、早期的奔腾II处理器多数会用这种内存。
EDO DRAM【扩展数据输出内存】
它拥有更大的容量和更先进的寻址方式,这内存简化了数据访问的流畅,读取速度DRAM快不少,主要用在486、奔腾,奔腾Pro、早期的奔腾II处理器的电脑上面。
在1991到1995年EDO内存盛行的时候,凭借着制造工艺的飞速发展,EDO内存在成本和容量上都有了很大的突破,单条EDO内存容量从4MB到16MB不等,数据总线依然是32位,所以搭配拥有64位数据总线的奔腾CPU时基本都成对的使用。
SDR SDRAM【同步型动态存储器】
然而随着CPU的升级EDO内存已经不能满足系统的需求了,内存技术也发生了大革命,插座从原来的SIMM升级为DIMM(Dual In-line Memory Module),两边的金手指传输不同的数据,SDR SDRAM内存插座的接口是168Pin,单边针脚数是84,进入到了经典的SDR SDRAM(Single Data Rate SDRAM)时代。
SDRAM其实就是同步DRAM的意思,“同步”是指内存工作需要同步时钟,内部命令的发送与数据的传输都以它为基准。内存频率与CPU外频同步,这大幅提升了数据传输效率,再加上64bit的数据位宽与当时CPU的总线一致,只需要一根内存就能让电脑正常工作了,这降低了采购内存的成本。
DDR
SDRAM从发展到现在已经经历了四代,分别是:第一代SDR SDRAM,第二代DDR SDRAM,第三代DDR2 SDRAM,第四代DDR3 SDRAM,现在已经发展到DDR5 SDRAM。
在80286时代,内存颗粒(Chip)是直接插在主板上的,叫做DIP(Dual In-line Package)。到了80386时代,换成1片焊有内存颗粒的电路板,叫做SIMM(Single-Inline Memory Module)。那么这样有带来哪些好处呢?
由阵脚形态变化成电路板带来了很多好处:模块化,安装便利等等,造就了我们现在的DIY市场的产生,我们就可以针对我们现在的PC进行内存的升级工作。
当时SIMM的位宽是32bit,即一个周期读取4个字节,到了奔腾时,位宽变为64bit,即8个字节,于是SIMM就顺势变为DIMM(Double-Inline Memory Module)。这种形态一直延续至今,也是内存条的基本形态。现在的DIMM分为很多种:
- RDIMM: 全称(Registered DIMM),寄存型模组,主要用在服务器上,为了增加内存的容量和稳定性分有ECC和无ECC两种,但市场上几乎都是ECC的。
- UDIMM:全称(Unbuffered DIMM),无缓冲型模组,这是我们平时所用到的标准台式电脑DIMM,分有ECC和无ECC两种,一般是无ECC的。
- SO-DIMM:全称(Small Outline DIMM),小外型DIMM,笔记本电脑中所使用的DIMM,分ECC和无ECC两种。
- Mini-DIMM:DDR2时代新出现的模组类型,它是Registered DIMM的缩小版本,用于刀片式服务器等对体积要求苛刻的高端领域。
从DDR到DDR4主要的区别是在于传输速率的不同,随着时钟周期的不断降低,传输率也不断提高。还有电压也越来越低。有趣的是命名规则,大部分台式机DIMM厂商都会标注DDRx-yyy,x代表第几代,yyy代表数据传输率。而大部分的SO-DIMM和RDIMM等则标注PCx-zzzz,x还代表第几代,zzzz则代表最大带宽。因为DDR位宽为64位,8个字节,所以zzzz=yyy * 8,而yyy又是时钟的两倍。
所以小张的内存条上的PC3-10600S代表DDR3,1333MHz的SO-DIMM。小张又问,那2R*8啥意思呢?
DDR到DDR5的主要变化,我们可以看到,为了配合整体行业对于性能,容量和省电的不断追求,规范的工作电压越来越低,芯片容量越来越大, IO的速率也越来越高。
除了电压,容量和IO的速率变化之外,还列出了Bank, Bank Group,Prefetch和Burst Length的演进,bank数越来越多,到DDR4出现bank group,prefetch也从2n增加到4n,8n。虽然我们说现在DDR4的最大速率是3200MT/s, 但是这是指的DDR4的IO频率,即DDR4和memroy controller之间的接口数据传输速率。那么DRAM是怎么实现用比较低的核心传输频率来满足日益高涨的高速IO传输速率的需求呢?这就是靠prefetch来实现的。
其实从外观上就可以看出来小张的内存条由很多海力士的内存颗粒组成。从内存控制器到内存颗粒内部逻辑,笼统上讲从大到小为:channel>DIMM>rank>chip>bank>row/column,如下图:
一个现实的例子是:
在这个例子中,一个i7 CPU支持两个Channel(双通道),每个Channel上可以插俩个DIMM,而每个DIMM由两个rank构成,8个chip组成一个rank。由于现在多数内存颗粒的位宽是8bit,而CPU带宽是64bit,所以经常是8个颗粒可以组成一个rank。所以小张的内存条2R X 8的意思是由2个rank组成,每个rank八个内存颗粒(为啥我们以后讲)。由于整个内存是4GB,我们可以算出单个内存颗粒是256MB。
这次我们来看看rank和Chip里面有什么,如下图:
这是个DDR3一个Rank的示意图。我们把左边128MB Chip拆开来看,它是由8个Bank组成,每个Bank核心是个一个存储矩阵,就像一个大方格子阵。这个格子阵有很多列(Column)和很多行(Row),这样我们想存取某个格子,只需要告知是哪一行哪一列就行了,这也是为什么内存可以随机存取而硬盘等则是按块存取的原因。
实际上每个格子的存储宽度是内存颗粒(Chip)的位宽,在这里由8个Chip组成一个Rank,而CPU寻址宽度是64bit,所以64/8=8bit,即每个格子是1个字节。选择每个格子也不是简单的两组信号,是由一系列信号组成,以这个2GB DDR3为例:
其引脚按照功能可以分为7类:前3类为电源、地、配置
PIN分类 | 名称 | 方向 | 功能描述 |
---|---|---|---|
电源 | VDD | PI | 芯片主电源输入(1.2V) |
电源 | VDDQ | PI | DQ信号线电源供电(1.2V) |
电源 | VPP | PI | DRAM激活电压(2.5V) |
电源 | VREFCA | PI | 控制/命令/地址信号参考电平 |
地 | VSS | - | 主地 |
地 | VSSQ | - | DQ信号参考地 |
配置 | ZQ | - | 阻抗匹配(ODT)校准参考,接240欧电阻到地 |
后4类为:控制信号、时钟信号、地址信号、数据信号
PIN分类 | 名称 | 方向 | 功能描述 |
---|---|---|---|
控制信号 | ALERT_N | OUT | 报警信号,若命令/地址出现奇偶校验错误或者CRC错误,该PIN脚拉低,告知DDR Controller |
控制信号 | TEN | IN | 测试模式使能信号,高电平使能测试模式。正常操作过程中,必须拉低。 |
控制信号 | RESET_N | IN | DDR复位信号,低电平有效。正常操作过程中,保持高电平。 |
控制信号 | PAR | IN | 命令/地址信号的奇偶校验使能,可通过寄存器禁用或者使能。 |
控制信号 | CS_N | IN | DDR芯片使能,用于多个RANK时的RANK组选择。 |
控制信号 | ODT | IN | 阻抗匹配使能 |
控制信号 | CKE | IN | 时钟信号使能。通过此电平,可以控制芯片是否进入低功耗模式。 |
控制信号 | ACT_N | IN | 命令激活信号,这个信号为低电平时,可以通过A[14:16]地址信号线选择激活命令的行地址。为高电平时,Address信号线正常使用。 |
PIN分类 | 名称 | 方向 | 功能描述 |
---|---|---|---|
时钟信号 | CK_N/CK_P | IN | 差分时钟信号,由DDR Controller输出。 |
地址信号 | BG0 | IN | Bank Group地址选择 |
地址信号 | BA[0:1] | IN | Bank地址选择 |
地址信号 | A[0:16] | IN | 地址选择信号,其中A16还有RAS_N功能,A15有CAS_N功能,A14有WE_N功能,A12有BC_N功能,A10有AP功能。 |
数据信号 | DQ[0:15] | IN/OUT | 低8位数据和高8位数据信号线,共16位数据信号线。 |
数据信号 | LDM/LDBI | IN/OUT | 低8位数据掩码 |
数据信号 | UDM/UDBI | IN/OUT | 高8位数据掩码 |
数据信号 | LDQS_N/LDQS_P | IN/OUT | 低8位数据选通信号 |
数据信号 | UDQS_N/UDQS_P | IN/OUT | 高8位数据选通信号 |
电源、地、配置信号的功能很简单,在此不赘述。控制信号主要是用来完成DDR4与DDR4 Controller之间的状态切换。DDR4中最重要的信号就是地址信号和数据信号。
如上DDR4芯片有20根地址线(17根Address、2根BA、1根BG),16根数据线。在搞清楚这些信号线的作用以及地址信号为何还有复用功能之前,我们先抛出1个问题。假如我们用20根地址线,16根数据线,设计一款DDR,我们能设计出的DDR寻址容量有多大?
Size(max)=(2^20) * 16=1048576 * 16=16777216bit=2097152B=2048KB=2MB。
但是事实上,该DDR最大容量可以做到1GB,比传统的单线编码寻址容量大了整整512倍,它是如何做到的呢?答案很简单,分时复用。我们把DDR存储空间可以设计成如下样式:
首先将存储空间分成两个大块,分别为BANK GROUP0和BANK GROUP1,再用1根地址线(还剩19根),命名为BG,进行编码。若BG拉高选择BANK GROUP0,拉低选择BANK GROUP1。(当然你也可以划分成4个大块,用2根线进行编码)
再将1个BANK GROUP区域分成4个BANK小区域,分别命名为BANK0、BANK1、BANK2、BANK3。然后我们挑出2根地址线(还剩余17根)命名为BA0和BA1,为4个小BANK进行地址编码。
此时,我们将DDR内存颗粒划分成了2个BANK GROUP,每个BANK GROUP又分成了4个BANK,共8个BANK区域,分配了3根地址线,分别命名为BG0,BA0,BA1。然后我们还剩余17根信号线,每个BANK又该怎么设计呢?这时候,就要用到分时复用的设计理念了。
剩下的17根线,第一次用来表示行地址,第二次用来表示列地址。现在修改为传输2次地址,在传输1次数据,寻址范围最多被扩展为2GB。虽然数据传输速度降低了一半,但是存储空间被扩展了很多倍。这就是改善空间。
所以,剩下的17根地址线,留1根用来表示传输地址是否为行地址。
- 在第1次传输时,行地址选择使能,剩下16根地址线,可以表示行地址范围,可以轻松算出行地址范围为2^16=65536个=64K个。
- 在第2次传输时,行地址选择禁用,剩下16根地址线,留10根列地址线表示列地址范围,可以轻松表示的列地址范围为2^10=1024个=1K个,剩下6根用来表示读写状态/刷新状态/行使能、等等复用功能。
- 这样,我们可以把1个BANK划分成67108864个=64M个地址编号。如下所示
- 所以1个BANK可以分成65536行,每行1024列,每个存储单元16bit。
所以1个BANK可以分成65536行,每行1024列,每个存储单元16bit。
每行可以存储1024*16bit=2048bit=2KB。每行的存储的容量,称为Page Size。
单个BANK共65536行,所以每个BANK存储容量为65536*2KB=128MB。
单个BANK GROUP共4个BANK,每个BANK GROUP存储容量为512MB。
单个DDR4芯片有2个BANK GROUP,故单个DDR4芯片的存储容量为1024MB=1GB。
至此,20根地址线和16根数据线全部分配完成,我们用正向设计的思维方式,为大家讲解了DDR4的存储原理以及接口定义和寻址方式。
但是细心的同学发现一个问题,对于每一个bank,按照正常的10位数据,那么col应该是1024,而现在是128,是什么原因呢?
那么问题又来了,为什么Column Address的寻址能力只有128呢?请继续看下图
在上图中,可以清晰地发现,10bits的Column Address只有7bits用于列地址译码!列地址0,1,2并没有用!!!列地址0,1,2,这3bits被用于什么功能了?或者是DDR的设计者脑残,故意浪费了这三个bits?在JESD79-3规范中有如下的这个表格:
可以发现,Column Address的A2,A1,A0三位被用于Burst Order功能,并且A3也被用于Burst Type功能。由于一般情况,我们采用的都是顺序读写模式(即{A2,A1,A0}={0,0,0}),所以此时的A3的取值并无直接影响,这个后面章节中重点介绍。
CA[2:0]的值决定了一次Burst sequence的读写地址顺序。
比如一次Burst Read的时候如果CA[2:0]=3’b001表示低三位从地址1开始读取,CA3=0的时候按顺序读取1,2,3,0,5,6,7,4,CA3=1的时候交错读取1,0,3,2,5,4,7,6。
- 对于Prefetch而言,正好是8N Prefetch,对于Burst而言对应BL8。
- BC4其实也是一次BL8的操作,只是丢弃了后一半的数据。
更形象地理解就是对于一个Bank里面的Memory Array,每个Memory Cell可以看作是一个Byte的集合体。CA[9:3]选中一行中的一个特定Byte,再由CA[2:0]选择从这个Byte的哪个位置开始操作。CA3既参与了列地址译码,也决定Burst是连续读取还是交错读取。Prefetch也决定了I/O Frequency和SDRAM Core Frequency之间的关系。
本章主要是针对DDR的发展和原理进行了学习,主要集中在硬件的组成原理,其中涉及到Channel > DIMM > Rank > Chip > Bank > Row/Column,其组成如下图所示
《内存的故事》外一篇–Rambus之战
从诞生到三足鼎立格局,DRAM到底经历了什么?
内存系列二:深入理解硬件原理
LPDDR4协议规范