6.4 内存总线
内存总线用于连接处理器和主存储器。
前面章节我们介绍了目前使用的主存储器——DRAM芯片,以及内存条、内存控制器的一些概念。内存控制器和内存芯片(或者说内存条)的接口就是内存总线。内存总线规范是由JEDEC(Joint Electron Device Engineering Council)组织制定的,它包含了一般总线的三个层级:机械层、电气层和协议层。
在机械层,JEDEC规定了内存芯片的封装方式、封装大小和引脚排布,内存条生产厂家可以据此设计内存条PCB板,可以使用不同DRAM厂家的芯片。同时,JEDEC也制定了内存条和计算机主板连接的规范,也就是内存插槽规范,规定了内存条的引脚个数、排布和内存条的长度、厚度、机械形式。这样不同厂家的内存条就可以在同一块主板上使用。图6.10是台式机使用的DDR3内存条和对应的内存插槽的图片。DDR3内存条使用双列直插式设计,每列分布了120个引脚,共240个引脚。中间的缺口不是位于内存条的正中心,目的是防止将内存条插反。图6.11是台式机使用的DDR2内存条的图片。DDR3内存条和DDR2内存条的长度相同,但内存条上的缺口位置是不同的,可以防止DDR2和DDR3内存条之间误插。
图6.10 台式机的DDR3内存条和内存插槽
图6.11 台式机的DDR2内存条
在电气层,JEDEC组织规定了DRAM芯片的电气特性。例如,DDR2内存使用1.8V电压,而DDR3内存使用1.5V电压。另外,规范还规定输入电压高低电平的标准、信号斜率、时钟抖动的范围等信号电气特性。
在协议层,JEDEC组织规定了DRAM芯片的操作时序。协议规定了DRAM芯片的上电和初始化过程、DRAM工作的几种状态、状态之间的转换,以及低功耗控制等内容。比如,DRAM初始化完成后,进入空闲态,通过激活(Activate)命令进入“打开一行”的激活态,只有在激活态,才可以读写DRAM的数据,单纯的读写操作后,DRAM仍会处于激活态,等待下一次读写。如果想要读写其他行,需要首先发送预充(Precharge)命令将DRAM转回空闲态,然后再发送激活命令。这些命令不是在任意时刻都可以发送的,需要满足协议规定的时序要求。图6.12给出了DDR2内存的状态转换图。
图6.12 DDR2内存各状态转换图
DDR3内存条的接口信号见表6.2。内存条将多个DDR3 SDRAM存储芯片简单地并列在一起,因此表中所列的信号主要是DDR3 SDRAM的信号。此外,表中还包含了一组I2C总线信号(SCL、SDA)和I2C地址信号(SA0~SA2)用来支持内存条的软件识别。内存条将自身的一些设计信息(包括SDRAM类型、SDRAM的速度等级、数据宽度、容量以及机械尺寸标准等信息)保存在一个EEPROM中,该EEPROM可以通过I2C总线访问,称为SPD(Serial Present Detect)。计算机系统可以通过I2C总线来读取内存条的信息,从而自动匹配合适的控制参数并获取正确的系统内存容量。组装电脑时,用户可以选用不同容量、品牌的内存条而无须修改软件或主板,就离不开SPD的作用。值得一提的是,表中给出的信号是按照双面内存条带ECC功能列出来的,如果只有单面,或者不带ECC校验功能,只需将相应的引脚位置悬空。
表6.2 双面DDR3 UDIMM内存条的接口信号列表
DRAM存储单元是按照Bank、行、列来组织的,因此对DRAM的寻址是通过bank地址、行地址和列地址来进行的。此外,计算机系统中可以将多组DRAM串接在一起,不同组之间通过片选(CS)信号来区分。在计算机系统中,程序的地址空间是线性的,处理器发出的内存访问地址也是线性的,由内存控制器负责将地址转换为对应于DRAM的片选、Bank地址、行地址、列地址。
DDR3 SDRAM读操作时序如图6.13所示。图中命令(Command,简称CMD)由RAS_n、CAS_n和WE_n三个信号组成。当RAS_n为高电平,CAS_n为低电平,WE_n为高电平时,表示一个读命令。该图中,列地址信号延迟(CL)等于5个时钟周期,读延迟(RL)等于5个时钟周期,突发长度(Burst Length,BL)等于8。控制器发出读命令后,经过5个时钟周期,SDRAM开始驱动DQS和DQ总线输出数据。DQ数据信号和DQS信号是边沿对齐的。在DQS的起始、DQ传输数据之前,DQS信号会有一个时钟周期长度的低电平,称为读前导(Read Preamble)。读前导的作用是给内存控制器提供一个缓冲时间,以开启一个信号采样窗口,将有用的读数据采集到内部寄存器,同时又不会采集到数据线上的噪声数据。
图6.13 DDR3 SDRAM读时序
DDR3 SDRAM写操作的协议如图6.14所示。当RAS_n为高电平,CAS_n为低电平,WE_n为低电平时,表示一个写操作。读写操作命令的区别是WE_n信号的电平不同,读操作时该信号为高,写操作时该信号为低。写操作使用额外的数据掩码(Data Mask,DM)信号来标识数据是否有效。当DM为高时,对应时钟沿的数据并不写入SDRAM,当DM为低时,对应时钟沿的数据才写入SDRAM。DM信号与DQ信号同步。在写操作时,DQS信号和DQ信号是由内存控制器驱动的。同样,在DQS的起始、DQ传输数据之前,DQS信号也存在一个写前导(Write Preamble)。DDR3 SDRAM的写前导为一个周期的时钟信号,DDR2 SDRAM的写前导为半个时钟周期的低电平信号。
图6.14 DDR3 SDRAM写时序
前面讲过SDRAM的基本操作包括激活(Activate)、读写(Read/Write)和预充电(Precharge)。当SDRAM接收到一个操作后,它需要在固定的时钟周期之后开始进行相应的动作,并且这些动作是需要经过一定的时间才能完成的。因此,对DRAM不同操作命令之间是有时间限制的。例如,对于DDR3-1600内存来说,当软件访问的两个地址正好位于内存的同一个Bank的不同行时,内存控制器需要首先针对第一个访问地址发出激活操作,经过13.75ns的时间,才可以发出读写操作。如果第一个访问是读操作,则需要经过至少7.5ns(此外还需满足tRASmin的要求,这里进行简化说明)的时间才可以发送预充电操作。预充电操作发送后,需要经过13.75ns的时间才可以针对第二个访问的行地址发送新的激活操作,然后经过13.75ns的时间,发送读写操作。因此,对SDRAM的同一个Bank的不同行进行读写存在较大的访问延迟。为了掩盖访问延迟,SDRAM允许针对不同Bank的操作并发执行。上述访问过程如图6.15所示。
图6.15 SDRAM的访问时序图
提高内存总线访问效率的两个主要手段是充分利用行缓冲局部性和Bank级并行度。行缓冲局部性是说,当两个访存命令命中SDRAM的同一行时,两个命令可以连续快速发送;Bank级并行度是说,针对SDRAM的不同Bank的操作可以并发执行,从而降低后一个操作的访存延迟。下面以一个简单的例子来说明对SDRAM的不同访问序列的延迟的差别。
假定处理器发出了三个访存读命令,地址分别命中SDRAM的第0个Bank的第0行(列地址为0)、第0个Bank的第1行和第0个Bank的第0行(与第一个命令的列地址不同,假定列地址为1)。如果我们不改变访问的顺序,直接将这三个命令转换为对应SDRAM的操作发送给内存。则需要的时间如图6.16所示。图中,<B0,R0>表示第0个Bank的第0行,<B0,R1>表示第0个Bank的第1行。每一个读命令都会转换出对应于SDRAM的<激活,读数据,预充电>序列。假定使用的是DDR2-800E规格的内存,它对应的时序参数为:tRCD=15ns,tRP=15ns,tRASmin=45ns,tRC=60ns,tRL=15ns,tRTP=7.5ns,tCCD=10ns(4个时钟周期)。则读数据分别在第30ns(tRCD+tRL)、90ns(tRC+tRCD+tRL)和150ns(tRC+tRC+tRCD+tRL)返回给处理器。
图6.16 调度前的命令序列
假定我们改变命令发给内存的顺序,我们将第3个命令放到第1个命令之后发送,将第2个命令最后发送,则得到的访存序列如图6.17所示。在该图中,针对第0个Bank第0行第1列的命令不需要发送预充电和激活操作,而是在针对第0个Bank第0行第0列的命令之后直接发送。则处理器得到读数据的时间变为第30ns、第40ns和第90ns。相比上一种访存序列,第3个访存命令的读数据的访存延迟降低了110ns(40ns相比于150ns)。
图6.17 调度后的命令序列
对内存总线的控制是由内存控制器实现的。内存控制器负责管理内存条的初始化、读写、低功耗控制等操作。内存控制器接收处理器发出的读写命令,将其转化为内存芯片可以识别的DRAM操作,并负责处理时序相关问题,最终返回数据(对于读命令)或者返回一个响应(对于写命令)给处理器。内存控制器一般还包括命令调度功能,以提高内存总线的访问效率。对于处理器来说,它只需要发送读写命令给内存控制器就可以了,而不必关心内存的状态以及内存是如何被读写的。