精华内容
下载资源
问答
  • 内存工作原理

    千次阅读 2015-11-29 14:18:51
    现代的PC(包括NB)都是以存储器为核心的多总线结构,即CPU只通过存储总线与主存储器交换信息(先在Cache里找数据,如果找不到,再去主存找)。输入输出设备通过I/O总线直接与主存储器...内部存储器简称内存,也可称
    现代的PC(包括NB)都是以存储器为核心的多总线结构,即CPU只通过存储总线与主存储器交换信息(先在Cache里找数据,如果找不到,再去主存找)。输入输出设备通过I/O总线直接与主存储器交换信息。在I/O设备和主存储器之间配置专用的I/O处理器。CPU不直接参与I/O设备与主存储器之间的信息传送。
    
        存储器分为内部存储器和外部存储器(或者叫主存储器和辅助存储器)。内部存储器简称内存,也可称为主存。从广义上讲,只要是PC内部的易失性存储器都可以看作是内存,如显存,二级缓存等等。外部存储器也称为外存,主要由一些非易失性存储器构成,比如硬盘、光盘、U盘、存储卡等等。
    内存作为数据的临时仓库,起着承上启下的作用,一方面要从外存中读取执行程序和需要的数据,另一方面还要为CPU服务,进行读写操作。所以主存储器快慢直接影响着PC的速度。下面我就从内存的原理开始谈起。
        一、原理篇
        内存工作原理
        1.内存寻址
        首先,内存从CPU获得查找某个数据的指令,然后再找出存取资料的位置时(这个动作称为“寻址”),它先定出横坐标(也就是“列地址”)再定出纵坐标(也就是“行地址”),这就好像在地图上画个十字标记一样,非常准确地定出这个地方。对于电脑系统而言,找出这个地方时还必须确定是否位置正确,因此电脑还必须判读该地址的信号,横坐标有横坐标的信号(也就是RAS信号,Row Address Strobe)纵坐标有纵坐标的信号(也就是CAS信号,Column Address Strobe),最后再进行读或写的动作。因此,内存在读写时至少必须有五个步骤:分别是画个十字(内有定地址两个操作以及判读地址两个信号,共四个操作)以及或读或写的操作,才能完成内存的存取操作。
        2.内存传输
        为了储存资料,或者是从内存内部读取资料,CPU都会为这些读取或写入的资料编上地址(也就是我们所说的十字寻址方式),这个时候,CPU会通过地址总线(Address Bus)将地址送到内存,然后数据总线(Data Bus)就会把对应的正确数据送往微处理器,传回去给CPU使用。
        3.存取时间
        所谓存取时间,指的是CPU读或写内存内资料的过程时间,也称为总线循环(bus cycle)。以读取为例,从CPU发出指令给内存时,便会要求内存取用特定地址的特定资料,内存响应CPU后便会将CPU所需要的资料送给CPU,一直到CPU收到数据为止,便成为一个读取的流程。因此,这整个过程简单地说便是CPU给出读取指令,内存回复指令,并丢出资料给CPU的过程。我们常说的6ns(纳秒,秒-9)就是指上述的过程所花费的时间,而ns便是计算运算过程的时间单位。我们平时习惯用存取时间的倒数来表示速度,比如6ns的内存实际频率为1/6ns=166MHz(如果是DDR就标DDR333,DDR2就标DDR2 667)。
        4.内存延迟
        内存的延迟时间(也就是所谓的潜伏期,从FSB到DRAM)等于下列时间的综合:FSB同主板芯片组之间的延迟时间(±1个时钟周期),芯片组同DRAM之间的延迟时间(±1个时钟周期),RAS到CAS延迟时间:RAS(2-3个时钟周期,用于决定正确的行地址),CAS延迟时间 (2-3时钟周期,用于决定正确的列地址),另外还需要1个时钟周期来传送数据,数据从DRAM输出缓存通过芯片组到CPU的延迟时间(±2个时钟周期)。一般的说明内存延迟涉及四个参数CAS(Column Address Strobe 行地址控制器)延迟,RAS(Row Address Strobe列地址控制器)-to-CAS延迟,RAS Precharge(RAS预冲电压)延迟,Act-to-Precharge(相对于时钟下沿的数据读取时间)延迟。其中CAS延迟比较重要,它反映了内存从接受指令到完成传输结果的过程中的延迟。大家平时见到的数据3—3—3—6中,第一参数就是CAS延迟(CL=3)。当然,延迟越小速度越快。
        二、外观篇
        由于笔记本的空间设计要求,笔记本内存比台式机内存条要窄,通常采用SO-DIMM模组规范,布线也比较紧凑,针脚也为标准的200Pin。我们经常看到的内存上,一般的元件有内存颗粒、电路板、SPD芯片、排阻(终结电阻)和针脚。下面我来分别介绍一下。
        1.颗粒
        内存颗粒就是大家平时见到内存上一个个的集成电路块。颗粒是内存的主要组成部分,颗粒性能可以说很大程度上决定了内存的性能,常见的颗粒有以下一些参数。
        A.厂商
        市场上生产内存颗粒的厂商主要有Hynix(现代电子),Samsung Electronics(***电子),Micro(美光),Infineon(英飞凌),Kingmax(胜创)等等。不过需要注意的一点是,“内存颗粒”和“内存条”是完全不同的两回事。能够生产内存颗粒的厂商全球没几个,而有了内存颗粒后内存条的生产就要简单得多,生产者自然要多得多。充斥市场的杂牌内存条与品牌内存条有着根本的区别,它们在成本上也有很多不同。Kingston、Kingmax、金邦等大的品牌内存条采用的都是符合Intel规定的6层PCB板和现代、***等内存大厂的内存颗粒,按照严格的工艺进行生产;而那些杂牌内存条虽然号称“***”、“现代”,其实就是一些小厂和作坊,他们拿来大厂内存颗粒的切割角料,焊到劣质的PCB板上就下了线,品质完全没有保证,而且经常与一些大的经销商结成联盟来生产和销售,价格波动也更容易受到渠道因素的影响。
        B.内存芯片类型
        内存芯片类型分SDRAM,DDR SDRAM,DDRⅡ SDRAM、SDRAM、DDR SDRAM和DDR SDRAM同出一门,都属SDRAM系,因此三者的颗粒在外观上不容易分辨,。但是由于采用的物理技术不同,三者在电路,延迟,带宽上还是有很大区别的,区分三者一般都是看颗粒的参数或者针脚和缺口位置,后面我会重点讲DDR和DDRⅡ技术。
        C.内存工艺和工作电压
        SDRAM内存工艺主要以CMOS为主,内存的工作电压和内存的芯片类型有很大关系,在JEDEC(Joint Electron Device Engineering Council 电子元件工业联合会)的规范中,SDRAM的工作电压是3.3V,DDR是2.5V,DDRⅡ是1.8V。
        D.芯片密度
        位宽及刷新速度芯片的密度一般都会用bit为单位进行表示(1B=8bit),比如16Mbit是16Mbit÷ 8bit=2MB也就是单颗芯片是2MB的。还有一个参数就是位宽,SDRAM系的位宽是64bit,采用多少个颗粒(一般为偶数)组成64bit也是不一样的。比如一个芯片是4bit的,那么要用16个同样的芯片才能组成64bits的,如果芯片是16bit那么只须4个就可以了。举个例子,256MB的内存可以用512bits÷8×4颗=256MB,4颗×16bit=64bit来组成,一般表示为512Mbits×16bit或64MB×16bit。刷新速度,内存条是由电子存储单元组成的,刷新过程对以列方式排列在芯片上的存储单元进行充电。刷新率是指被刷新的列的数目。两个常用的刷新率是2K和4K。2K模式能够在一定的时间内刷新较多的存储单元并且所用时间较短,因此2K所用的电量要大于4K。4K模式利用较慢的时间刷新较少的存储单元,然而它使用的电量较少。一些特殊设计的SDRAM具有自动刷新功能,它可自动刷新而不借助CPU或外部刷新电路。建立在DRAM内部的自动刷新,减少了电量消耗,被普遍应用于笔记本电脑。
        E.Bank
        内存的Bank一般分为物理Bank和逻辑Bank。物理Bank体现在SDRAM内存模组上,"Bank 数"表示该内存的物理存储体的数量。(等同于"行"/Row)。逻辑Bank表示一个SDRAM设备内部的逻辑存储库的数量。(现在通常是4个bank)。此外,对于主板,它还表示DIMM连接插槽或插槽组,例如Bank 0 或 Bank A。这里的Bank是内存插槽的计算单位,它是电脑系统与内存之间数据总线的基本工作单位。只有插满一个BANK,电脑才可以正常开机。举个例子,1个SDRAM线槽一个Bank为64bit,而老早以前的EDO内存是32bit的,必须要安装两根内存才能正常工作。主板上的Bank编号从Bank 0开始,必须插满Bank 0才能开机,Bank 1以后的插槽留给日后升级扩充内存用。
        F.电气接口类型
        般的电气接口类型与内存类型对应,如SDRAM是SSTL_3(3.3V)、DDR是 SSTL_2(2.5V)、DDRⅡ是SSTL_18(1.8V)。
        G.内存的封装
        现在比较普遍的封装形式有两种BGA和TSOP两种,BGA封装分FBGA,μBGA,TinyBGA(KingMAX)等等,TSOP分TSOPⅠ和TSOPⅡ。BGA封装具有芯片面积小的特点,可以减少PCB板的面积,发热量也比较小,但是需要专用的焊接设备,无法手工焊接。另外一般BGA封装的芯片,需要多层PCB板布线,这就对成本提出了要求。此外,BGA封装还拥有芯片安装容易、电气性能更好、信号传输延迟低、允许高频运作、散热性卓越等许多优点,它成为DDRⅡ官方选择也在情理之中。而TSOP相对来说工艺比较成熟,成本低,缺点是频率提升比较困难,体积较大,发热量也比BGA大。
        H.速度及延迟
        一般内存的速度都会用频率表示。比如大家常常看到的SDRAM 133、DDR 266、DDRⅡ 533其实物理工作频率都是133MHz,只是采用了不同的技术,理论上相当于2倍或4倍的速率运行,还有一种表示速度方法是用脉冲周期来表示速度,一般是纳秒级的。比如1/133MHz=7ns,说明该内存的脉冲周期是7ns。内存延迟我前面说过了,参数一般为4个,也有用3个的,数字越小表示延迟越小,速度越快。

        I.工作温度
        工作温度:工业常温(-40 - 85度);扩展温度(-25 - 85度)
        2.电路板
        电路板也称PCB版,是印刷电路板电子板卡的基础,由若干层导体和绝缘体组成的平板。电路图纸上的线路都蚀刻在其上,然后焊接上电子元件。由于所有的内存元件都焊在电路版上,因此电路板的布线是决定内存稳定性的重要方面,跟据Intel的规范,DDR内存必须使用6层PCB版才能保证内存的电气化功能和运行的稳定性。所以建议大家购买大厂的产品,不要使用来历不明的山寨货。
        3.SPD及SPD芯片
        SPD(Serial Presence Detect)— 串行存在侦测,SPD是一颗8针的EEPROM(Electrically Erasable Programmable ROM 电子可擦写程序式只读内存), 容量为256字节~2KB,里面主要保存了该内存的相关资料,如容量、芯片厂商、内存模组厂商、工作速度、是否具备ECC校验等。SPD的内容一般由内存模组制造商写入。支持SPD的主板在启动时自动检测SPD中的资料,并以此设定内存的工作参数。当开机时PC的BIOS将自动读取SPD中记录的信息,如果没有SPD,就容易出现死机或致命错误的现象。建议大家购买有SPD芯片的内存。

        4.排阻

        排阻,也称终结电阻(终结器)是DDR内存中比较重要的硬件。DDR内存对工作环境提出很高的要求,如果先前发出的信号不能被电路终端完全吸收掉而在电路上形成反射现象,就会对后面信号的影响从而造成运算出错。因此目前支持DDR主板都是通过采用终结电阻来解决这个问题。 由于每根数据线至少需要一个终结电阻,这意味着每块DDR主板需要大量的终结电阻,这也无形中增加了主板的生产成本,而且由于不同的内存模组对终结电阻的要求不可能完全一样,也造成了所谓的“内存兼容性问题”。由于DDR II内部集成了终结器,这个问题上得到了比较完美的解决。

        5.针脚(Pin)

        Pin-针状引脚,是内存金手指上的金属接触点。由于不同的内存的针脚不同,所以针脚也是从外观区分各种内存的主要方法。内存针脚分为正反两面,例如笔记本DDR内存是200Pin,那么正反两面的针脚就各为200÷2=100个。此外,有些大厂的金手指使用技术先进的电镀金制作工艺,镀金层色泽纯正,有效提高抗氧化性。保证了内存工作的稳定性

    三、技术篇

        1.DDR
    DDR技术

        DDR
    技术

        DDR SDRAM
    是双倍数据速率(Double Data RateSDRAM的缩写。从名称上可以看出,这种内存在技术上,与SDRAM有着密不可分的关系。事实上,DDR内存就是SDRAM内存的加强版。DDR运用了更先进的同步电路,使指定地址、数据的输送和输出主要步骤既独立执行,又保持与CPU完全同步;DDR使用了DLL(Delay Locked Loop,延时锁定回路提供一个数据滤波信号)技术,当数据有效时,存储控制器可使用这个数据滤波信号来精确定位数据,每16次输出一次,并重新同步来自不同存储器模块的数据。DDL本质上不需要提高时钟频率就能加倍提高SDRAM的速度,它允许在时钟脉冲的上升沿和下降沿读出数据,理论上使用原来的工作的频率可以产生2倍的带宽。同速率的DDR内存与SDR内存相比,性能要超出一倍,可以简单理解为133MHZ DDR="266MHZ" SDR。从外形体积上DDRSDRAM相比差别并不大,他们具有同样的尺寸和同样的针脚距离。DDR内存采用的是支持2.5V电压的SSTL2标准,而不是SDRAM使用的3.3V电压的LVTTL标准。但是DDR存在自身的局限性DDR只是在SDRAM基础上作简单改良,并行技术与生俱来的易受干扰特性并没有得到丝毫改善,尤其随着工作频率的提高和数据传输速度加快,总线间的信号干扰将造成系统不稳定的灾难性后果;反过来,信号干扰也制约着内存频率的提升——当发展到DDR400规范时,芯片核心的工作频率达到200MHz,这个数字已经非常接近DDR的速度极限,只有那些品质优秀的颗粒才能够稳定工作于200MHz之上,所以DDR标准就成了一种进一步提高内存速度的解决方法。

        DDR 
    技术

        DDR
    相对于DDR有三大技术革新,4位预取(DDR2位)、Posted CAS、整合终结器(ODT)、FBGA/CSP封装。要解释预取的概念,我们必须从内存的频率说起。大家通常说的内存频率其实是一个笼统的说法,内存频率实际上应细分为数据频率、时钟频率和DRAM核心频率三种。数据频率指的是内存模组与系统交换数据的频率;时钟频率则是指内存与系统协调一致的频率;而DRAM核心频率指的是DRAM内部组件的工作频率,它只与内存自身有关而不受任何外部因素影响。对SDRAM来说,这三者在数字上是完全等同的,也就是数据频率=时钟频率=核心频率;而DDR技术却不是如此,它要在一个时钟周期内传输两次数据,数据频率就等于时钟频率的两倍,但核心频率还是与时钟频率相等。由于数据传输频率翻倍(传输的数据量也翻倍),而内部核心的频率并没有改变,这意味着DDR芯片核心必须在一个周期中供给双倍的数据量才行,实现这一任务的就是所谓的两位预取(2bit Prefect)技术;DDR采用的4位预取。这项技术的原理是将DRAM存储矩阵的位宽增加一(两)倍,这样在一个时钟周期内就可以传输双(四)倍的数据,这些数据接着被转化为宽度为1/214)的两道数据流、分别从每个时钟周期的上升沿和下降沿传送出去。Posted CASDDR通过引入Posted CAS功能来解决带宽利用变低的问题,所谓Posted CAS,指的是将CAS(读/写命令)提前几个周期、直接插到RAS信号后面的一个时钟周期,这样CAS命令可以在随后的几个周期内都能保持有效,但读/写操作并没有因此提前、总的延迟时间没有改变。这样做的好处在于可以彻底避免信号冲突、提高内存使用效率,但它只有在读写极其频繁的环境下得到体现,若是普通应用,Posted CAS功能反而会增加读取延迟、令系统性能下降,因此我们可以根据需要、通过BIOSPosted CAS功能开启或关闭(关闭状态下DDR的工作模式就与DDR完全相同)。  芯片整合终结器,提高了内存工作的稳定性,增强的内存的兼容性。FBGA封装和CSP封装,封装虽然无法直接决定内存的性能,但它对内存的稳定工作至关重要。 FBGA封装是DDR的官方选择,FBGA属于BGA体系(Ball Grid Array,球栅阵列封装),前面已经讲过了。CSP封装最大的特点在于封装面积与芯片面积异常接近,两者比值仅有1.141,它也是目前最接近11理想状况的芯片封装技术。这样在同样一条模组中就可以容纳下更多数量的内存芯片,有利于提升模组的总容量。 

        2.
    双通道内存控制器技术

        所谓双通道
    DDR,简单来说,就是芯片组可以在两个不同的数据通道上分别寻址、读取数据。这两个相互独立工作的内存通道是依附于两个独立并行工作的,位宽为64-bit的内存控制器下,因此使普通的DDR内存可以达到128-bit的位宽,如果是DDR333的话,双通道技术可以使其达到DDR667的效果,内存带宽陡增一倍。双通道DDR有两个64bit内存控制器,双64bit内存体系所提供的带宽等同于一个128bit内存体系所提供的带宽,但是二者所达到效果却是不同的。双通道体系包含了两个独立的、具备互补性的智能内存控制器,两个内存控制器都能够在彼此间零等待时间的情况下同时运作。例如,当控制器B准备进行下一次存取内存的时候,控制器 A就在读/写主内存,反之亦然。两个内存控制器的这种互补天性可以让有效等待时间缩减50%,双通道技术使内存的带宽翻了一翻。双通道DDR的两个内存控制器在功能上是完全一样的,并且两个控制器的时序参数都是可以单独编程设定的。这样的灵活性可以让用户使用三条不同构造、容量、速度的DIMM内存条,此时双通道DDR简单地调整到最低的密度来实现128bit带宽,允许不同密度/等待时间特性的DIMM内存条可以可靠地共同运作。双通道DDR技术带来的性能提升是明显的,DDR266能够提供2.1GB/s的带宽,而双通道DDR266则能提供4.2GB/s的带宽。以此类推,双通道DDR333DDR400能够达到5.4GB/s6.4GB/s

        3.CPU
    集成内存控制器技术

        这是
    AMD公司提高CPU与内存性能的一项技术,这项技术是一种将北桥的内存控制器集成到CPU的一种技术,这种技术的使用使得原来,CPU-北桥-内存三方传输数据的过程直接简化成CPU与内存之间的单项传输技术,并且降低了它的延迟潜伏期,提高了内存工作效率。这么做得的目的是为了解放系统的北桥,众所周知,显卡也是通过北桥向CPU传输数据的,虽然说早在GeForce256时代就有了GPU的说法,但是随着现在游戏的进步,画面的华丽,不少数据还是需要CPU来做辅助处理的。这些数据传输到CPU必然要经过系统的北桥,由于AMD64系统将内存控制集成到主般中来了,所以压力减小的北桥便可以更好地为显卡服务。另外,缺少了中间环节,内存和CPU之间的数据交换显得更为流畅。但是这项技术也有缺点,当新的内存技术出现时,必须要更换CPU才能支持。这在无形间增加了成本。

        4.
    其他技术

        A.ECC
    内存

        全称
    Error Checkingand Correcting。它也是在原来的数据位上外加位来实现的。如8位数据,则需1位用于Parity检验,5位用于ECC,这额外的5位是用来重建错误的数据的。当数据的位数增加一倍,Parity也增加一倍,而ECC只需增加一位,当数据为64位时所用的ECCParity位数相同(都为。在那些Parity只能检测到错误的地方,ECC可以纠正绝大多数错误。若工作正常时,你不会发觉你的数据出过错,只有经过内存的纠错后,计算机的操作指令才可以继续执行。当然在纠错时系统的性能有着明显降低,不过这种纠错对服务器等应用而言是十分重要的,ECC内存的价格比普通内存要昂贵许多。

        B.
    UnBuffered Memory 内存

        (
    UnBuffered Memory,(不)带有缓存的内存条。缓存能够二次推动信号穿过内存芯片,而且使内存条上能够放置更多的内存芯片。带缓存的内存条和不带缓存的内存条不能混用。电脑的内存控制器结构,决定了该电脑上带缓存的内存还是上不带缓存的内存。

    展开全文
  • 计算机原理(3)-内存工作原理

    千次阅读 2018-01-19 22:21:48
    1. 内存工作原理   CPU和内存是计算机中最重要的两个组件,前面已经知道了CPU是如何工作的,上一篇也介绍了内存采用的DRAM的存储原理。CPU工作需要知道指令或数据的内存地址,那么这样一个地址是如何...

    转载自:http://blog.csdn.net/cc_net/article/details/11097267

    1. 内存工作原理


     

    CPU和内存是计算机中最重要的两个组件,前面已经知道了CPU是如何工作的,上一篇也介绍了内存采用的DRAM的存储原理。CPU工作需要知道指令或数据的内存地址,那么这样一个地址是如何和内存这样一个硬件联系起来的呢?现在就看看内存到的是怎么工作的。


     

    1.1 DRAM芯片结构

    上图是DRAM芯片一个单元的结构图。一个单元被分为了N个超单元(可以叫做cell),每个单元由M个DRAM单元组成。我们知道一个DRAM单元可以存放1bit数据, 所以描述一个DRAM芯片可以存储N*M位数据。上图就是一个有16个超单元,每个单元8位的存储模块,我们可以称为16*8bit 的DRAM芯片。而超单元(2,1)我们可以通过如矩阵的方式访问,比如 data = DRAM[2.1] 。这样每个超单元都能有唯一的地址,这也是内存地址的基础。

     

    每个超单元的信息通过地址线和数据线传输查找和传输数据。如上图有2根地址线和8根数据线连接到存储控制器(注意这里的存储控制器和前面讲的北桥的内存控制器不是一回事),存储控制器电路一次可以传送M位数据到DRAM芯片或从DRAM传出M位数据。为了读取或写入【i,j】超单元的数据,存储控制器需要通过地址线传入行地址i 和列地址j。这里我们把行地址称为RAS(Row Access Strobe)请求, 列地址称为(Column Access Strobe)请求。


    但是我们发现地址线只有2为,也就是寻址空间是0-3。而确定一个超单元至少需要4位地址线,那么是怎么实现的呢?

    解决这个问题采用的是分时传送地址码的方法。看上图我们可以发现在DRAM芯片内部有一个行缓冲区,实际上获取一个cell的数据,是传送了2次数据,第一次发送RAS,将一行的数据放入行缓冲区,第二期发送CAS,从行缓冲区中取得数据并通过数据线传出。这些地址线和数据线在芯片上是以管脚(PIN)与控制电路相连的。将DRAM电路设计成二维矩阵而不是一位线性数组是为了降低芯片上的管脚数量。入上图如果使用线性数组,需要4根地址管脚,而采用二维矩阵并使用RAS\CAS两次请求的方式只需要2个地址管脚。但这样的缺点是增加了访问时间。

     

     

    1.2 内存模块

     

    内存模块也就是我们常说的内存条。我们在购买内存是经常会听到我这个内存采用的是什么颗粒,如下左图,我们看到内存PCB上的一块块的就是内存颗粒。也就是我们DRAM芯片。通过管脚和PCB连接。不同厂商,不同类型的内存可以的大小,管脚,性能,封装都不一样,但是原理都是一样。这里我们就不展开介绍了。而下有图展示了一个1M*4bit的DRAM芯片的管脚图。

      

    对于一个内存颗粒来说,它的容量和字长是有限的,所以我们使用内存是会把多个颗粒组成内存模块来对内存进行字长和容量的扩展。目前的内存一般内存条上面会有多颗内存颗粒,比如一条64M的内存可能是由8个8M*8bit 的SDRAM内存颗粒组成。

     


    1.2.1 字长位数扩展 

    位扩展的方法很简单,只需将多片RAM的相应地址端、读/写控制端 和片选信号CS并接在一起,而各片RAM的I/O端并行输出即可。 如上图,我们采用了8个DRAM芯片分,别编号为0-7,每个超单元中存储8位数据。在获取add(row=i,col=j)地址的数据的时候,从每个DRAM芯片的【i, j】单元取出一个字节的数据,这样传送到CPU的一共是8*8b = 64b的数据。我们通过8个8M*8b的内存颗粒扩展为了8M*64b的内存模块。

     

     

    1.2.2 字存储容量扩展

     

    RAM的字扩展是利用译码器输出控制各片RAM的片选信号CS来实现的。RAM进行字扩展时必须增加地址线,而增加的地址线作为高位地址与译码器的输入相连。同时各片RAM的相应地址端、读/写控制端 、相应I/O端应并接在一起使用。下图是我们通过4个2M*8b的内存颗粒,将内存容量扩展到了8M,字长为8位。

     

    最后,内存通过主板上的内存插槽DIMM和内存总线相连接。对于不同内存比如SDRAM和DDR他们内存金手指的定义是不同的。这里就不需要详细介绍了。

     


    2. 内存编址

     

    前面我们知道了DRAM颗粒以及内存模块是如何扩展字长和容量的。一个内存可能是8位,也可能是64位,容量可能是1M,也可能是1G。那么内存是如何编地的呢?和地址总线,计算机字长之间又有什么关系呢?

     

     

    2.1 字长

     

    计算机在同一时间内处理的一组二进制数称为一个计算机的“字”,而这组二进制数的位数就是“字长”。。通常称处理字长为8位数据的CPU叫8位CPU,32位CPU就是在同一时间内处理字长为32位的二进制数据。 所以这里的字并不是我们理解的双字节(Word)而是和硬件相关的一个概念。一般来说计算机的数据线的位数和字长是相同的。这样从内存获取数据后,只需要一次就能把数据全部传送给CPU。

     


    2.2 地址总线

     

    前面我们已经介绍过地址总线的功能。地址总线的数量决定了他最大的寻址范围。就目前来说一般地址总线先字长相同。比如32位计算机拥有32为数据线和32为地线,最大寻址范围是4G(0x00000000 ~ 0xFFFFFFFF)。当然也有例外,Intel的8086是16为字长的CPU,采用了16位数据线和20位数据线。

     


    2.3 内存编址

     

    从前面我们知道一个内存的大小和它芯片扩展方式有关。比如我们内存模块是采用 16M*8bit的内存颗粒,那么我们使用4个颗粒进行位扩展,成为16M*32bit,使用4个颗粒进行字容量扩展变为64M*32bit。那么我们内存模块使用了16个内存颗粒,实际大小是256MB。

     

    我们需要对这个256M的内存进行编址以便CPU能够使用它,通常我们多种编址方式:

    1. 按字编址:    对于这个256M内存来说,它的寻址范围是64M,而每个内存地址可以存储32bit数据。
    2. 按半字编址:对于这个256M内存来说,它的寻址范围是128M,而每个内存地址可以存储16bit数据。
    3. 按字节编址:对于这个256M内存来说,它的寻址范围是256M,而每个内存地址可以存储8bit数据。


    对于我们现在的计算机来说,主要都是采用按字节编址的方式。所以我们可以把内存简单的看成一个线性数组,数组每个元素的大小为8bit,我们称为一个存储单元。这一点很重要,因为后面讨论的所有问题内存都是以按字节编址的方式。 这也是为什么对于32位计算机来说,能使用的最多容量的内存为4GB。如果我们按字编地址,能使用的最大内存容量就是16GB了。

     

    于是很容易想到一个问题,为什么我们要采用字节编址的方式呢?关于这个问题,我在网上基本没有找到答案,甚至都找不到问这个问题的。所以这里没法给出答案,为什么为什么呢? 麻烦知道的朋友告诉我哈。

     

    另一方面的问题是,内存编址方式和DRAM芯片是否有关呢? 我认为还是有一定关系。比如我DRAM的芯片是8M*8bit,那么芯片最小的存储单位就是8bit,那么我们内存编址就不能按照半个字节来编址。否则内存取出8bit,根本不知道你要那4bit传给CPU。也有一种说法是现在的DRAM芯片cell都是8bit,所以采用按字节编址。另一方面应该也和数据总线位宽有关。

     

     

    3. 内存数据

     

    前面我们知道了,内存是按字节编址,每个地址的存储单元可以存放8bit的数据。我们也知道CPU通过内存地址获取一条指令和数据,而他们存在存储单元中。现在就有一个问题。我们的数据和指令不可能刚好是8bit,如果小于8位,没什么问题,顶多是浪费几位(或许按字节编址是为了节省内存空间考虑)。但是当数据或指令的长度大于8bit呢?因为这种情况是很容易出现的,比如一个16bit的Int数据在内存是如何存储的呢?

     


    3.1 内存数据存放

     

    其实一个简单的办法就是使用多个存储单元来存放数据或指令。比如Int16使用2个内存单元,而Int32使用4个内存单元。当读取数据时,一次读取多个内存单元。于是这里又出现2个问题:

    1. 多个存储单元存储的顺序?
    2. 如何确定要读几个内存单元?

     

    3.1.1 大端和小端存储

    1. Little-Endian 就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。
    2. Big-Endian 就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。

    需要说明的是,计算机采用大端还是小端存储是CPU来决定的, 我们常用的X86体系的CPU采用小端,一下ARM体系的CPU也是用小端,但有一些CPU却采用大端比如PowerPC、Sun。判断CPU采用哪种方式很简单:

    [cpp]  view plain  copy
    1. bool IsBigEndian()    
    2. {    
    3.     int vlaue = 0x1234;    
    4.     char lowAdd =  *(char *)&value;     
    5.     if( lowAdd == 0x12)    
    6.     {    
    7.         return true;    
    8.     }    
    9.     return false;    
    10. }  


    既然不同计算机存储的方式不同,那么在不同计算机之间交互就可能需要进行大小端的转换。这一点我们在Socket编程中可以看到。这里就不介绍了,对以我们单一CPU来说我们可以不需要管这个转换的问题,另外我们目前个人PC都是采用小端方式,所以我们后面默认都是这种方式。

     


    3.1.2 CPU指令


    前面我们多次提到了指令的概念,也知道指令是0和1组成的,而汇编代码提高了机器码的可读性。为什么突然在这里介绍CPU指令呢? 主要是解释上面的第二个问题,当我读取一个数据或指令时,我怎么知道需要读取多少个内存单元。

     


    3.1.2.1 CPU指令格式


    首先我们来看看CPU指令的格式,我们知道CPU质量主要就是告诉CPU做什么事情,所以一条CPU指令一般包含操作码(OP)和操作

      操作码字段   地址码字段

     

     

    根据一条指令中有几个操作数地址,可将该指令称为几操作数指令或几地址指令。

     操作码 A1 A2 A3

     

    三地址指令: (A1) OP (A2) --> A3

     操作码 A1 A2

     

    二地址指令: (A1) OP (A2) --> A1

     操作码  A1

     

    一地址指令: (AC) OP (A) --> AC   

     操作码 

     

        零地址指令

    A1为被操作数地址,也称源操作数地址; A2为操作数地址,也称终点操作数地址; A3为存放结果的地址。 同样,A1,A2,A3以是内存中的单元地址,也可以是运算器中通用寄存器的地址。所以就有一个寻址的问题。关于指令寻址后面会介绍。

    CPU指令设计是十分复杂的,因为在计算机中都是0和1保存,那计算机如何区分一条指令中的操作数和操作码呢?如何保证指令不会重复呢?这个不是我们讨论的重点,有兴趣的可以看看计算机体系结构的书,里面都会有介绍。从上图来看我们知道CPU的指令长度是变长的。所以CPU并不能确定一条指令需要占用几个内存单元,那么CPU又是如何确定一条指令是否读取完了呢?

     


    3.1.2.2 指令的获取


    现在的CPU多数采用可变长指令系统。关键是指令的第一字节。 当CPU读指令时,并不是一下把整个指令读近来,而是先读入指令的第一个字节。指令译码器分析这个字节,就知道这是几字节指令。接着顺序读入后面的字节。每读一个字节,程序计数器PC加一。整个指令读入后,PC就指向下一指令(等于为读下一指令做好了准备)。

    Sample1:

    [plain]  view plain  copy
    1. MOV AL,00  机器码是1011 0000 0000 0000  


    机器码是16位在内存中占用2个字节:

    【00000000】 <- 0x0002

    【10110000】 <- 0x0001


    比如上面这条MOV汇编指令,把立即数00存入AL寄存器。而CPU获取指令过程如下:

    1. 从程序计数器获取当前指令的地址0x0001。
    2. 存储控制器从0x0001中读出整个字节,发送给CPU。PC+1 = 0X0002.
    3. CPU识别出【10110000】表示:操作是MOV AL,并且A2是一个立即数长度为一个字节,所以整个指令的字长为2字节。
    4. CPU从地址0x0002取出指令的最后一个字节
    5. CPU将立即数00存入AL寄存器。


    这里的疑问应该是在第3步,CPU是怎么知道是MOV AL 立即数的操作呢?我们在看下面一个列子。

     

    Sample2:

    [plain]  view plain  copy
    1. MOV AL,[0000] 机器码是1010 0000 0000 0000 0000 0000  

     

    这里同样是一条MOV的汇编指令,整个指令需要占用3个字节。

    【00000000】 <-0x0003

    【00000000】 <- 0x0002

    【10100000】 <- 0x0001

     

    我们可以比较一下2条指令第一个字节的区别,发现这里的MOV  AL是1010 0000,而不是Sample1中的1011 000。CPU读取了第一个字节后识别出,操作是MOV AL [D16],表示是一个寄存器间接寻址,A3操作是存放的是一个16位就是地址偏移量(为什么是16位,后面文章会介绍),CPU就判定这条指令长度3个字节。于是从内存0x0002~0x0003读出指令的后2个字节,进行寻址找到真正的数据内存地址,再次通过CPU读入,并完成操作。

     

    从上面我们可以看出一个指令会根据不同的寻址格式,有不同的机器码与之对应。而每个机器码对应的指令的长度都是在CPU设计时就规定好了。8086采用变长指令,指令长度是1-6个字节,后面可以添加8位或16位的偏移量或立即数。 下面的指令格式相比上面2个就更加复杂。

     

    • 第一个字节的高6位是操作码,W表示传说的数据是字(W=1)还是字节(W=0),D表示数据传输方向D=0数据从寄存器传出,D=1数据传入寄存器。
    • 第二个字节中REG表示寄存器号,3位可以表示8种寄存器,根据第一字节的W,可以表示是8位还是16位寄存器。表3-1中列出了8086寄存器编码表
    • 第二个字节中的MOD和R/M指定了操作数的寻址方式,表3-2列出了8086的编码

    这里没必要也无法更详细介绍CPU指令的,只需要知道,CPU指令中已经定义了指令的长度,不会出现混乱读取内存单元的现象。有兴趣的可以查看引用中的连接。

     


    3.1.3  内存数据

     

    3.1.3.1 内存数据的操作

     

    从上面我们可以知道,操作数可以是立即数,可以存放在寄存器,也可以存放在内存。对于第一个例子,指令已经说明,操作时是一个字节,于是CPU可以从下一个内存地址读取操作时,而对于第二个列子,操作数只是地址偏移,所以当CPU获得这个数据后,需要转换成实际的内存地址,在进行一次内存访问,把数据读入到寄存器中。这里就出现我们前面提到的问题,这个数据我们要读几个存储单元呢?

    [cpp]  view plain  copy
    1.     MyClass cla;  
    2. 008C3EC9  lea         ecx,[cla]    
    3. 008C3ECC  call        MyClass::MyClass (08C1050h)    
    4. 008C3ED1  mov         dword ptr [ebp-4],0    
    5.     cla.num5 = 500;  
    6. 008C3ED8  mov         dword ptr [ebp-6Ch],1F4h    
    7.     int b1 = MyClass::num1;  
    8. 008C3EDF  mov         dword ptr [b1],64h    
    9.     int b2 = MyClass::num2;  
    10. 008C3EE6  mov         dword ptr [b2],0C8h    
    11.     int b3 = MyClass::num3;  
    12. 008C3EF0  mov         eax,dword ptr ds:[008C9008h]    
    13. 008C3EF5  mov         dword ptr [b3],eax    
    14.     int b4 = cla.num4;  
    15. 008C3EFB  mov         eax,dword ptr [cla]    
    16. 008C3EFE  mov         dword ptr [b4],eax    
    17.     int b5 = cla.num5;  
    18. 008C3F04  mov         eax,dword ptr [ebp-6Ch]    
    19. 008C3F07  mov         dword ptr [b5],eax    


    让我们看一段C++代码和对应的汇编代码,操作很简单,创建一个Myclass对象后,对成员变量赋值。而赋值都是试用Mov操作符。对于这些变量我们有赋值操作和取值操作,那么是如何确定要读取或写入数据的大小呢?

    [cpp]  view plain  copy
    1. cla.num5 = 500;  
    2. 08C3ED8  mov         dword ptr [ebp-6Ch],1F4h    


    我看先看看赋值操作,往dword ptr [ebp-6Ch]内存存入一个立即数, [ebp-6Ch]是num5的内存地址,而前面的dword ptr 表示这是进行一个双子操作。还记得上面指令格式中第一个字节的W字段吗? 在8086中只能进行字节或字操作,而现在CPU都可以进行双字操作。

    [cpp]  view plain  copy
    1. int b5 = cla.num5;  
    2. 08C3F04  mov         eax,dword ptr [ebp-6Ch]    


    同样,当我们要从一个内存读取数据的时候,也要指定读取数据的操作类型,这里也是双字操作。这样以来,就能从内存中正确的读出需要的长度了。就这么一个简单的赋值操作,获取你从来没想过在内存中怎么存放,又是怎么读取的。这一切都是编译器和CPU在背后为我们完成了。

     


    3.1.3.2 内存对齐

     前面我们清楚了CPU是如何正确读取数大小不同的数据的,最后一部分来看看有关内存对齐的问题。对于大部分程序员来说,内存对齐应该是透明的。内存对齐是编译器的管辖范围。编译器为程序中的每个数据单元安排在适当的位置上。

     


    3.1.3.2.1 对齐原因

    从前面我们知道,目前计算机内存按照字节编址,每个地址的内存大小为1个字节。而读取数据的大小和数据线有关。比如数据线为8位那么一次读取一个字节,而如果数据线为32位,那么一次需要读取32个字节,这样是为了一次更多的获取数据提高效率。否则读取一个int变量就需要进行4次内存操作。对于内存访问一般有以下两个条件:

    1. CPU进行一次内存访问读取的数据和字长相同。
    2. 有些CPU只能对字长倍数的内存地址进行访问。

    对于第一个条件一般来说,目前存储器一个cell是8bit,进行位扩展使他和字长还有数据线位数是相同,那么一次就能传送CPU可以处理最多的数据。而前面我们说过目前是按字节编址可能是因为一个cell是8bit,所以一次内存操作读取的数据就是和字长相同。

    也正是因为和存储器扩展有关(参考1.2.1的图),每个DRAM位扩展芯片使用相同RAS。如果需要跨行访问,那么需要传递2次RAS。所以以32位CPU为例,CPU只能对0,4,8,16这样的地址进行寻址。而很多32位CPU禁掉了地址线中的低2位A0,A1,这样他们的地址必须是4的倍数,否则会发送错误。

    如上图,当计算机数据线为32位时,一次读入4个地址范围的数据。当一个int变量存放在0-3的地址中时,CPU一次就内存操作就可以取得int变量的值。但是如果int变量存放在1-4的地址中呢? 根据上面条件2的解释,这个时候CPU需要进行2次内存访问,第一次读取0-4的数据,并且只保存1-3的内容,第二次访问读取4-7的数据并且只保存4的数据,然后将1-4组合起来。如下图:

    所以内存对齐不但可以解决不同CPU的兼容性问题,还能减少内存访问次数,提高效率。当然目前关于这个原因争论很多,可以看看CSDN上的讨论:http://bbs.csdn.net/topics/30388330

     

    3.1.3.2.2 如何对齐内存

    内存对齐有一个对齐系数,一般是2,4,8,16字节这样。而不同平台上的对齐方式不同,这个主要是编译器来决定的。

    具体的规则可以参考之前转的一篇文章,这里就不详细写了: http://blog.csdn.net/cc_net/article/details/2908600

     



    总结



    通过这一篇对内存工作的介绍,我们从内存的硬件结构,存储方式过渡到了内存的编址方式,然后又探讨了按字节编址带来的问题和解决的办法。这里就涉及到了CPU的指令格式,编译器的支持。最后我们也是从硬件和软件方面讨论了内存对齐的问题。

    展开全文
  • 专家详解:内存工作原理及发展历程 http://memory.zol.com.cn/47/474952.html 内存基本存储原理: cpu先要从RAM中获取数据,需要首先给地址总线传递数据的定位地址,在若干个时钟周期之后,数据总线就会把数据传送给...

    专家详解:内存工作原理及发展历程 http://memory.zol.com.cn/47/474952.html


    内存基本存储原理:

    cpu先要从RAM中获取数据,需要首先给地址总线传递数据的定位地址,在若干个时钟周期之后,数据总线就会把数据传送给CPU.当地址解码器收到地址总线送来的地址数据后,它就会根据这个地址数据找到相对应的存储单元,然后数据总线会将其中的数据传递给CPU.

    上图中如果CPU每次调用需要64bits的数据(数据总线为64bits),那么CPU会在一个时间中存取8个字节的数据,但是因为每次还是存取一个1个字节的数据,所以64bits总线在这种使用中将不带来任何优势.


    从’线’到’矩阵’

    将RAM制作成一条线,或者是当作一个数组,在实际制造芯片的时候,尤其是大容量RAM(目前貌似有64GB的内存)的时候,这是在设计上无法实现的.因此我们可以将其排成阵列.在存储1024bits的时候(寻址单位为字节),那么我们需要32*32的矩阵就可以实现.一个32*32的二维矩阵比1024bits的一维更紧凑.

    在二维的数据存储中,对于x86处理器,想要读取的数据地址(一个22位二进制数字的地址编码,11位行地址,11位列地址,寻址范围为4M,2的22次)在传递给地址总线后,通过RAM地址接口进行分离(信号分离器).行地址译码器首先确定行地址,列地址译码器会确认列地址,这样可以确定唯一的数据位置,然后将其通过RAM数据接口传递到数据总线.实际上,RAM的内部存储数据并不是正方形的(行比列少,便于刷新).

    SRAM: 4-6晶体管实现,速度快,数据保存稳定,不会存在泄漏,但是成本昂贵,一般使用在CPU二级缓冲中.
    DRAM: 1个电容器+一个晶体管,但是因为存在泄漏,因此在64ms的周期内刷新充电,同时读取数据是需要放电的,因此需要在某一刻充电.充放电带来了延迟,同时放电电流太小需要信号放大器处理.


    RAM的封装技术

    一个16K x 1bit SRAM芯片的针脚功能示意图:

     

    早期SRAM芯片采用了20线双列直插封装技术.拥有这么多的针脚,是因为:每一个地址信号都需要一根信号线,一根数据输入线和一个数据输出线,部分控制线,电源线.
    A0-A13是地址输入信号引脚,CS是芯片选择引脚。在一个实际的系统中,一定具有很多片SRAM芯片,所以需要选择究竟从那一片SRAM芯片中写入或者读取数据.WE是写入启用引脚.当SRAM得到一个地址之后,它需要知道进行什么操作,究竟是写入还是读取,WE就是告诉SRAM要写入数据.Vcc是供电引脚.Din是数据输入引脚.Dout是数据输出引脚.GND是接地引脚

    Enable(OE):有的SRAM芯片中也有这个引脚,但是上面的图中并没有.这个引脚同WE引脚的功能是相对的,它是让SRAM知道要进行读取操作而不是写入操作.从Dout引脚读取1bit数据需要以下的步骤:
    SRAM读取操作:

    1)通过地址总线把要读取的bit的地址传送到相应的读取地址引脚(这个时候/WE引脚应该没有激活,所以SRAM知道它不应该执行写入操作).

    2)激活/CS选择该SRAM芯片.

    3)激活/OE引脚让SRAM知道是读取操作.第三步之后,要读取的数据就会从Dout引脚传输到数据总线.

    SRAM写入操作:

    1)通过地址总线确定要写入信息的位置(确定/OE引脚没有被激活).

    2)通过数据总线将要写入的数据传输到Din引脚.

    3)激活/CS引脚选择SRAM芯片.

    4)激活/WE引脚通知SRAM知道要尽心写入操作.

    经过上面的四个步骤之后,需要写入的数据就已经放在了需要写入的地方.

    DRAM因为存在数据刷新的过程,所以设计更加复杂.下面是DRAM芯片针脚的作用.

    下图是Intel的2188芯片 采用16K*1 DRAM 16线DIP封装. 16K*1 指的是这款芯片可以存储16*1024的字节数,可同时进行1字节的读取或者写入操作.

    虽然该芯片只有7根地址引脚,但是通过采用多路技术,通过DRAM接口把地址一分为二,然后利用两个连续的时钟传输地址数据,利用一半的针脚实现全部地址位的传输.

    为什么需要减少地址引脚呢?因为DRAM相比SRAM,因为成本低,体积小,因此使用在内存中,内存容量大,因此需要的地址线也比较多,需要在芯片中增加相对应的针脚数,但是芯片的针脚是十分宝贵的资源,这样做无疑会提高芯片的生产成本,所以需要采用多路复用技术.

    采用多路复用技术使得读写过程变得更加复杂.
    在上面的示意图中,你可以看到在DRAM结构中相对于SRAM多了两个部分:由/RAS (Row AddressStrobe:行地址脉冲选通器)引脚控制的行地址门闩线路(Row Address Latch)和由/CAS(Column Address Strobe:列地址脉冲选通器)引脚控制的列地址门闩线路(Column Address Latch)。

    DRAM读取过程:

    1)通过地址总线将行地址传输到地址引脚。

    2)/RAS引脚被激活,这样行地址被传送到行地址门闩线路中。

    3)行地址解码器根据接收到的数据选择相应的行。

    4)/WE引脚被确定不被激活,所以DRAM知道它不会进行写入操作。

    5)列地址通过地址总线传输到地址引脚。

    6)/CAS引脚被激活,这样列地址被传送到列地址门闩线路中。

    7)/CAS引脚同样还具有/OE引脚的功能,所以这个时候Dout引脚知道需要向外输出数据。

    8)/RAS和/CAS失活,这样就可以进行下一个周期的数据操作了。其实DRAM的写入的过程和读取过程是基本一样的,所以如果你真的理解了上面的过程就能知道写入过程了,所以这里我就不赘述了。(只要把第4步改为/WE引脚被激活就可以了)。

    DRAM被设计为有规律的读取DRAM内的内容.优点如下:

    1.仅仅使用/RSA激活每一行就可以达到全部刷新的目的.

    2.DRAM控制器来控制刷新,这样可以防止刷新操作干扰有规律的读写操作.因此DRAM芯片的行数量是比列数量多的.


    寻址单元的实现和扩展(bank)

    RAM单元只能存储一个bit的数据,但是CPU存取和地址寻址的时候是根据一个寻址单元(8比特)来操作的,RAM如何实现CPU读写和寻址单元的实现呢?

    最简单的是我们需要8个1位的RAM基本存储单元的芯片以并列的方式堆叠在一起,这8个芯片采用相同的地址.下图只给出了4个.

    通常这8颗1bit芯片是通过地址总线和数据总线在PCB(印刷电路板)上连接而成的,对于CPU来说它就是一颗8bit的RAM芯片,而不再是独立的8个1 bit芯片。在上图所示的地址总线位宽是22bit,这样这个地址总线所能控制的存储模块的容量应该是2的22次=4194304bit,也就是4Mb * 8(4MB)的容量;数据总线的位宽是8bit,就是通过刚才提到的8个1bit的基本存储单元的Dout并联在一起实现的--这样也能够满足CPU的要求了。(对于这种存储颗粒我们称之为4194304 x 8模块或者4Mx8,注意这里的“M”不是“MByte”而是“Mbit”)。为了举例说明,我们用一条TI(德仪公司)出品的TM4100GAD8 SIMM内存为例来说明,因为这种内存的构造相对比较简单,便于大家理解。TM4100GAD8基于4M x 8模块制造,容量4MB,采用30线SIMM封装。如果前面我说的东西你看明白了,就应该知道这条内存采用了4Mx1 DRAM颗粒。下面的数据是我在TI官方网站上找到的(目前很少有公司的网站还提供自己以前产品的数据):构造:4194304 × 8。工作电压:5-V。30线SIMM(Single In-Line Memory Module:SIMM)。采用8片4Mbit DRAM内存颗粒,塑料SOJs封装。长刷新期16 ms(1024周期)。

    在上面的示意图中,A0–A10是地址输入引脚。/CAS:行地址脉冲选通器引脚。DQ1–DQ8:数据输入/数据输出引脚。NC:空信号引脚。/RAS:列地址脉冲选通器引脚。VSS:接地引脚。/W:写入启用引脚。VCC 5V供电引脚。

    上面的电路示意图应该能够让我们更加清楚的理解这个问题,TM4100GAD8由8片4096x1bit芯片组成,VCC和VSS为所有的芯片提供5v的电压。每个芯片都具有/RAS、/CAS、/W引脚同内存相应的引脚连通。每个芯片都具有不同的数据输出/输出接口。这样我们应该就能够知道RAM是如何满足CPU存取数据的需要的了。

    上面实现8bit的读取,但是在32bit和64bit的读取中,这种方法是不够的,我们需要扩展.这里引入bank的概念.

    这里将4M*8当作一个bank,4个bank以类似并联的方式相连,组成位宽为32bit的bank,64bit的则需要8个bank,存储数据时候,第一个bank存储第一个字节,第二个bank存储第二个字节,以此类似.每个bank容量为4M字节.

    通过两种方式增加这类内存的容量,第一种增加每个bank的容量,第二个是增加bank的数量.
    上面的内存用于486级别的电脑,奔腾系列的内存与486不同的.


    SIMM和DIMM封装

    SIMM(single in-line memory module,单边接触内存模组)
    因为内存颗粒无法直接和计算机连接并且通讯的,同时因为数据位传输位宽等方面的原因,所以内存厂商通过封装的方式把他们组织到一起.
    下图中是30线DIMM和72线DIMM.

    在DIMM内存中的颗粒采用DIP封装(双列直插封装.PCBA的流程中有DIP).SIMM内存根据引脚分为30线和72线.
    SIMM中一般容量为1,4,16MB的SIMM内存是单面.当容量的SIMM是双面的.
    一条72线SIMM内存的数据总线位宽是32bit,所以它的数据传输能力大大提高了.

    DIMM是目前的内存主要封装模式.比如SDRAM,DDR SDRAM, RDRAM,其中SDRAM具有168根引脚并且提供了64bit的数据寻址能力.现在高密度的DRAM可以有不只一个Din和Dout引脚,并且可以根据需有在DRAM芯片上制造4,8,16或64根数据引脚.

    上图上面的内存就是168线的SDRAM,而下面的内存是72线的SIMM。

    如果一个DRAM芯片具有8个数据引脚,那么当我们想实现一个4MB的内存,我们以前的方法是4M*1的8个芯片并连.但是现在就可以通过1M*8的4个芯片实现.减少了芯片的个数.4M的寻址空间需要11根地址线引脚复用地址数据.


    FPM DRAM (现代内存已经不使用)

    理解FPM DRAM和EDO DRAM对后面的延迟的理解有很好的帮助

    FPM DRAM是优先于动态随机存取存储器(DRAM)的新形式,快速页面模式的动态随机存取存储器(Fast Page Mode DRAM,FPM DRAM)是一种动态随机存取存储器。是一种在486时期被普遍应用的内存。有30线和72线、5V电压、带宽32bit、基本速度60ns以上。
    页面模式动态随机存取存储器可以直接访问RAM的某一行而不必频繁的重新指定这一行。当列地址控制器(CAS)信号变为要读取一系列邻近的记忆单元时,行地址控制器(RAS)信号仍然保持有效。这样减少了访问时间并且降低了电能需求。FPM DRAM的典型时序是6-3-3-3.

    之所以称之为快页内存,因为它以4字节突发模式传送数据,这4个字节来自同一列或者说同一页。如何理解这种读取方式呢?FPM DRAM如果要突发4个字节的数据,它依然需要依次的读取每一个字节的数据,比如它要读取第一个字节的数据,这个时候的情况同前面介绍的DRAM读取方式是一样的(我们依然通过读取下面的FPM读取时序图来了解它的工作方式):

    1、首先行地址被传送到行地址引脚,在/RAS引脚被激活之前,RAS处于预充电状态,CAS也处于预充电状态,当然/WE此时依然是高电平,FPM至少知道自己不会进行写操作。

    2、/RAS引脚被赋予低电平而被激活,行地址被送到行地址选通器,然后选择正确的行送到传感放大器,就在/RAS引脚被激活的同时,tRAC开始计时。

    3、CAS一直处于预充电状态,直到列地址被传送到列地址引脚并且/CAS引脚得到一个低电平而被激活(tCRC时间开始计时),然后下面的事情我们也应该很清楚了,列地址被送到列地址选通器,然后需要读取的数据位置被锁定,这个时候Dout引脚被激活,第一组数据就被传送到数据总线上。

    4、对于原来介绍的DRAM,这个时候一个读取周期就结束了,不过对于FPM则不同,在传送第一组数据期间,CAS失活(RAS依然保持着激活状态)并且进入预充电状态,等待第二组列地址被传送到列地址引脚,然后进行第二组数据的传输,如此周而复始直至4组数据全部找到并且传输完毕。

    5、当第四组数据开始传送的时候,RAS和CAS相继失活进入到预充电状态,这样FPM的一个完整的读取周期方告结束。FPM之所以能够实现这样的传输模式,就是因为所需要读取的4个字节的行地址是相同的但是列地址不同,所以它们不必为了得到一个相同的列地址而去做重复的工作。

    6、这样的工作模式显然相对于普通的DRAM模式节省了很多的时间,特别是节省了3次RAS预充电的时间和3个tRAC时间,从而进一步提高的效率。

    从第4步不同,不同在于不用重复的激活RSA,故后面的只需要3个时钟.6-3-3-3其中的6表示从最初状态读取第一组数据需要6个时钟周期,而读取另外三个数据仅仅需要3个时钟周期就能达到目的了。需要特别指出的是,在上面的时序图中,我们并没有标注出 FPM DRAM进行第二个、第三个、第四个数据输出的前进行新的列地址选通的时间,但是从上面的示意图中我们可以看到Col.2同Data1和D2之间都没有重叠,所以这三个数据的输出是进行完毕一个再进行的另一个,因此再上一次数据传输完毕到下一次列地址传输之间还有一点小小的延迟。


    EDO DRAM ( Extended Data Out DRAM:扩展数据输出DRAM)现代内存已经不使用
    EDO DRAN可以在输出数据的同时进行下一个列地址选通.
    下面通过EDO读取时序图来理解EDO DRAM读取数据的过程.

    1、RAS在结束上一次的读取操作之后,进入预充电状态,当接到读取数据的请求之后,行地址首先通过地址总线传输到地址引脚,在这个期间CAS依然处于预充电状态。

    2、/RAS引脚被激活,列地址开始经过行地址选通电路和行地址解码器进行行地址的选择,就在这个同时tRAC周期开始,因为是读取操作/WE引脚一直没有被激活,所以内存知道自己进行的是读取操作而不是写操作。

    3、在CAS依然进行预充电的过程中,列地址被送到列地址选通电路选择出来合适的地址,当/CAS被激活的同时tCAC周期开始,当tCAC结束的时候,需要读取的数据将会通过数据引脚传输到数据总线。

    4、从开始输出第一组数据的时候,我们就可以体会到EDO同FPM之间的区别了:在tCAC周期结束之前,CAS失活并且开始了预充电,第二组列地址传输和选通也随即开始,第一数据还没有输出完毕之前,下一组数据的tCAC周期就开始了--显然这样进一步的节省了时间。就在第二组数据输出前,CAS再次失活为第三组数据传输列地址做起了准备……

    5、如此的设计使得EDO内存的性能比起FPM的性能提高了大约20-40%。

    6、正是因为EDO的速度比FPM快,所以它可以运行在更高的总线频率上。所以很多的EDO RAM可以运行在66MHz的频率上,并且一般标注为5-2-2-2。


    SDRAM 内存工作原理(不涉及硬件实现,just 简单原理)
    SIMM :我们需要把多个芯片放在一个bank或多个bank中满足8bit,32bit或者64位bit数据总线的要求,初始DRAM因为只有一个数据输入引脚和数据输出引脚.
    DIMM :发展DRAM芯片引脚数量变多,有较多的数据输入输出引脚,因此一个4M*8的封装DIMM就可以相当于SIMM的8个4M*1芯片,芯片数量减少.

    SDRAM则可以实现在单个的DIMM中存在多个bank,在满足数据总线的前提下进一步的提高数据总线的性能.

    前面讨论的DRAM读取方式中,当一个读取周期结束后,/RAS和/CAS都必须停止激活然后有一个短暂的预充电期才能进入到下一次的读取周期中。但是一个具有两个bank的SDRAM的模组中,其中一个bank在进行预充电的期间另一个bank却可以被调用--这样当你需要读取已经预充电的bank的数据时,就无需等待而是可以直接调用了。为了实现这个功能,SDRAM就需要增加对于多个bank的管理,这样就可以实现控制其中的bank进行预充电,并且在需要使用的时候随时调用了。这样一个具有两个bank的SDRAM一般会多一根叫做BA0的引脚,实现在两个bank之间的选择--一般的BA0是低电平表示Bank0被选择,而BA0是高电平Bank1就会被选中。

    可见,虽然SDRAM在基本的原理上比如基本存储的结构都是基本一样的,但是在整个内存架构的组织上是不同的,而且在存储单元的控制上也是有着相当大的区别的。因为异步DRAM同处理器和芯片的时钟并没有什么关系,所以芯片组只能按照DRAM内存的时序要求“被动”的操作DRAM控制引脚。SDRAM因为要同CPU和芯片组共享时钟,所以芯片组可以主动的在每个时钟的上升沿发给引脚控制命令。

    异步DRAM的读取过程:
    异步DRAM的运行并不需要同处理器同频,它的时序信号控制、寻址等操作基本上说是独立控制的,也就是由内存芯片本身所控制.
    1) 行地址通过地址总线传输到地址引脚。
    2)/RAS引脚被激活,列地址就会被放入行地址选通电路( Row Address Latch:在文章的前面部分我们把它翻译为行地址门闩电路)。
    3) 行地址解码器( Row Address Decoder)选择正确的行然后送到传感放大器( sense amps)。4) /WE引脚此时不被激活,所以 DRAM知道它们不是进行写操作。
    5) 列地址通过地址总线传输到地址引脚。
    6) /CAS引脚被激活,列地址就可以被送到列地址选通器( Column Address Latch)。
    7) /CAS引脚也被当作输出启动信号( Output Enable),因为一旦/CAS信号被放到传感放大器,就因为这时需要的数据已经找到,所以Dout针脚开始有效,数据可以从内存中传输到系统了。
    8)/RAS和 /CAS引脚停止激活,等待下一个读取命令

    内存读取的过程中,我们需要考虑两种类型的延迟.
    1.两次读操作之间的延迟.因为DRAM的读取操作包括电容器的充电和放电另外还包括把信号传送出去的时间,所以在两个读取操作中间至少留出足够的时间让让内存进行这些方面的操作。同时两次读之间的延迟包括RAS和 /CAS预充电延迟时间。在/RAS被激活并且失活之后,你必须给它足够的时间为下次激活做好准备.当一次读取操作周期结束之后,我们必须让/RAS和/CAS引脚都失活。实际上,在你让它们失活之后,必须等待预充电过程结束之后才能开始下一个操作(或者还是读取操作、或者是写入操作、或者是刷新操作),如下图.


    2.内部的延迟包括从/RAS被激活后到数据总线出现数据,/CAS被激活到数据总线出现数据,即tRAC(行存取时间)和tCAC(列存取时间),如下图(1).

    图(1) tRAC与tCAC

    图(2) DRAM读写时序图

    上面这张图(2)详细的介绍了DRAM读写数据的详细流程.

    1) 首先看上图第一行,在预充电期间行地址通过地址总线传输到地址引脚,这个期间RAS未被激活,在第三行Address BUS中我们看到数据在这个期间正在行地址总线上,这个期间CAS也处于预充电状态;
    2) 依然看上图第一行, /RAS引脚被激活(RAS Active,灰色的部分),行地址就会被放入行地址选通电路(第三行Address Bus中所示),这个期间CAS依然处于预充电状态;在/RAS被激活的同时,tRAC(行存取时间)开始--如上图最后一行Data Bus所示。
    3) 在/RAS被激活以后,行地址解码器( Row Address Decoder)选择正确的行然后送到传感放大器( sense amps)。
    4) 在这个期间/WE引脚一直处于不激活的状态,所以 DRAM知道它们不是进行写操作--这个状态将一直持续到开始执行写操作才结束。
    5) 列地址通过地址总线传输到地址引脚。
    6) /CAS引脚被激活(如上图第三行),列地址就可以被送到列地址选通器( Column Address Latch)。这个时候tCAC(列地址访问时间)开始计时。
    7) 在/CAS处于激活状态期间的末尾,/RAS停止激活--也就大约在这个时间附近找到的数据被传送到数据总线进行数据传送(如图data Bus),在数据总线进行数据传输的过程中,地址总线是处于空闲状态的,它并不接受新的数据--在数据开始创送的同时tRAC和tCAC都结束了。
    8)就在数据在数据总线上传输期间,/CAS引脚也被停止激活--就是得到一个高电平,从而开始进入到预充电期。RAS和CAS会同时处于预充电期,直到下次/RAS被激活进入到下一个读取操作的周期

    SIMM和DIMM中的潜伏期(latency)类型为两种: 访问时间(access time)和周期时间(cycle time).
    潜伏期的时间是很短的,只有几纳秒.
    访问时间: 即tRAC和tCAC
    周期时间: 两次读取周期之间,即/RAS失活到预充电结束,/CAS失活到预充电结束的时间.

    对于异步DRAM,访问时间就是从(行地址到达行地址引脚时起)到(数据被传输到数据引脚的时间段).访问时间为60纳秒的DIMM意味着当我们下达读取数据的命令后,地址数据被送到地址引脚之后要等待60纳米才能达到数据输出引脚。
    周期时间为:在第一次读完以后,到下一次操作开始之前的这段时间间隔.
    我们平时说的DRAM内存多少纳米指的是访问时间.访问时间越短,意味这内存工作频率越高.内存频率越高,意味这可以适应外频更高的处理器.

    展开全文
  • 本文主要介绍内存工作原理,常用的内存相关的概念,以及内存发展历程,用于大家了解内存相关的知识。希望能对大家有所帮助。
  • 详解内存工作原理及发展历程 RAM SRAM SDRAM
  • 内存工作原理,讲得很详细,很不错,通俗易懂,是学习嵌入式的好资料。
  • 前言   转载自... ...我们还有内存这一个很重要的部分没有介绍。这一章不仅仅介绍内存工作原理,还会介绍内存的编址、内存数据存放。逐渐从硬件过渡到软件上来。为后面介绍程序运行打下基础。

    前言

     

    转载自http://blog.csdn.net/cc_net/article/details/11097267


    前面两篇文章介绍了计算机硬件是如何工作的。而从这一章开始将逐渐的转到软件上面来。我们还有内存这一个很重要的部分没有介绍。这一章不仅仅介绍内存的工作原理,还会介绍内存的编址、内存数据存放。逐渐从硬件过渡到软件上来。为后面介绍程序运行打下基础。



     

    1. 内存工作原理


     

    CPU和内存是计算机中最重要的两个组件,前面已经知道了CPU是如何工作的,上一篇也介绍了内存采用的DRAM的存储原理。CPU工作需要知道指令或数据的内存地址,那么这样一个地址是如何和内存这样一个硬件联系起来的呢?现在就看看内存到的是怎么工作的。


     

    1.1 DRAM芯片结构

    上图是DRAM芯片一个单元的结构图。一个单元被分为了N个超单元(可以叫做cell),每个单元由M个DRAM单元组成。我们知道一个DRAM单元可以存放1bit数据, 所以描述一个DRAM芯片可以存储N*M位数据。上图就是一个有16个超单元,每个单元8位的存储模块,我们可以称为16*8bit 的DRAM芯片。而超单元(2,1)我们可以通过如矩阵的方式访问,比如 data = DRAM[2.1] 。这样每个超单元都能有唯一的地址,这也是内存地址的基础。

     

    每个超单元的信息通过地址线和数据线传输查找和传输数据。如上图有2根地址线和8根数据线连接到存储控制器(注意这里的存储控制器和前面讲的北桥的内存控制器不是一回事),存储控制器电路一次可以传送M位数据到DRAM芯片或从DRAM传出M位数据。为了读取或写入【i,j】超单元的数据,存储控制器需要通过地址线传入行地址i 和列地址j。这里我们把行地址称为RAS(Row Access Strobe)请求, 列地址称为(Column Access Strobe)请求。


    但是我们发现地址线只有2为,也就是寻址空间是0-3。而确定一个超单元至少需要4位地址线,那么是怎么实现的呢?

    解决这个问题采用的是分时传送地址码的方法。看上图我们可以发现在DRAM芯片内部有一个行缓冲区,实际上获取一个cell的数据,是传送了2次数据,第一次发送RAS,将一行的数据放入行缓冲区,第二期发送CAS,从行缓冲区中取得数据并通过数据线传出。这些地址线和数据线在芯片上是以管脚(PIN)与控制电路相连的。将DRAM电路设计成二维矩阵而不是一位线性数组是为了降低芯片上的管脚数量。入上图如果使用线性数组,需要4根地址管脚,而采用二维矩阵并使用RAS\CAS两次请求的方式只需要2个地址管脚。但这样的缺点是增加了访问时间。

     

     

    1.2 内存模块

     

    内存模块也就是我们常说的内存条。我们在购买内存是经常会听到我这个内存采用的是什么颗粒,如下左图,我们看到内存PCB上的一块块的就是内存颗粒。也就是我们DRAM芯片。通过管脚和PCB连接。不同厂商,不同类型的内存可以的大小,管脚,性能,封装都不一样,但是原理都是一样。这里我们就不展开介绍了。而下有图展示了一个1M*4bit的DRAM芯片的管脚图。

      

    对于一个内存颗粒来说,它的容量和字长是有限的,所以我们使用内存是会把多个颗粒组成内存模块来对内存进行字长和容量的扩展。目前的内存一般内存条上面会有多颗内存颗粒,比如一条64M的内存可能是由8个8M*8bit 的SDRAM内存颗粒组成。

     


    1.2.1 字长位数扩展 

    位扩展的方法很简单,只需将多片RAM的相应地址端、读/写控制端 和片选信号CS并接在一起,而各片RAM的I/O端并行输出即可。 如上图,我们采用了8个DRAM芯片分,别编号为0-7,每个超单元中存储8位数据。在获取add(row=i,col=j)地址的数据的时候,从每个DRAM芯片的【i, j】单元取出一个字节的数据,这样传送到CPU的一共是8*8b = 64b的数据。我们通过8个8M*8b的内存颗粒扩展为了8M*64b的内存模块。

     

     

    1.2.2 字存储容量扩展

     

    RAM的字扩展是利用译码器输出控制各片RAM的片选信号CS来实现的。RAM进行字扩展时必须增加地址线,而增加的地址线作为高位地址与译码器的输入相连。同时各片RAM的相应地址端、读/写控制端 、相应I/O端应并接在一起使用。下图是我们通过4个2M*8b的内存颗粒,将内存容量扩展到了8M,字长为8位。

     

    最后,内存通过主板上的内存插槽DIMM和内存总线相连接。对于不同内存比如SDRAM和DDR他们内存金手指的定义是不同的。这里就不需要详细介绍了。

     


    2. 内存编址

     

    前面我们知道了DRAM颗粒以及内存模块是如何扩展字长和容量的。一个内存可能是8位,也可能是64位,容量可能是1M,也可能是1G。那么内存是如何编地的呢?和地址总线,计算机字长之间又有什么关系呢?

     

     

    2.1 字长

     

    计算机在同一时间内处理的一组二进制数称为一个计算机的“字”,而这组二进制数的位数就是“字长”。。通常称处理字长为8位数据的CPU叫8位CPU,32位CPU就是在同一时间内处理字长为32位的二进制数据。 所以这里的字并不是我们理解的双字节(Word)而是和硬件相关的一个概念。一般来说计算机的数据线的位数和字长是相同的。这样从内存获取数据后,只需要一次就能把数据全部传送给CPU。

     


    2.2 地址总线

     

    前面我们已经介绍过地址总线的功能。地址总线的数量决定了他最大的寻址范围。就目前来说一般地址总线先字长相同。比如32位计算机拥有32为数据线和32为地线,最大寻址范围是4G(0x00000000 ~ 0xFFFFFFFF)。当然也有例外,Intel的8086是16为字长的CPU,采用了16位数据线和20位数据线。

     


    2.3 内存编址

     

    从前面我们知道一个内存的大小和它芯片扩展方式有关。比如我们内存模块是采用 16M*8bit的内存颗粒,那么我们使用4个颗粒进行位扩展,成为16M*32bit,使用4个颗粒进行字容量扩展变为64M*32bit。那么我们内存模块使用了16个内存颗粒,实际大小是256MB。

     

    我们需要对这个256M的内存进行编址以便CPU能够使用它,通常我们多种编址方式:

    1. 按字编址:    对于这个256M内存来说,它的寻址范围是64M,而每个内存地址可以存储32bit数据。
    2. 按半字编址:对于这个256M内存来说,它的寻址范围是128M,而每个内存地址可以存储16bit数据。
    3. 按字节编址:对于这个256M内存来说,它的寻址范围是256M,而每个内存地址可以存储8bit数据。


    对于我们现在的计算机来说,主要都是采用按字节编址的方式。所以我们可以把内存简单的看成一个线性数组,数组每个元素的大小为8bit,我们称为一个存储单元。这一点很重要,因为后面讨论的所有问题内存都是以按字节编址的方式。 这也是为什么对于32位计算机来说,能使用的最多容量的内存为4GB。如果我们按字编地址,能使用的最大内存容量就是16GB了。

     

    于是很容易想到一个问题,为什么我们要采用字节编址的方式呢?关于这个问题,我在网上基本没有找到答案,甚至都找不到问这个问题的。所以这里没法给出答案,为什么为什么呢? 麻烦知道的朋友告诉我哈。

     

    另一方面的问题是,内存编址方式和DRAM芯片是否有关呢? 我认为还是有一定关系。比如我DRAM的芯片是8M*8bit,那么芯片最小的存储单位就是8bit,那么我们内存编址就不能按照半个字节来编址。否则内存取出8bit,根本不知道你要那4bit传给CPU。也有一种说法是现在的DRAM芯片cell都是8bit,所以采用按字节编址。另一方面应该也和数据总线位宽有关。

     

     

    3. 内存数据

     

    前面我们知道了,内存是按字节编址,每个地址的存储单元可以存放8bit的数据。我们也知道CPU通过内存地址获取一条指令和数据,而他们存在存储单元中。现在就有一个问题。我们的数据和指令不可能刚好是8bit,如果小于8位,没什么问题,顶多是浪费几位(或许按字节编址是为了节省内存空间考虑)。但是当数据或指令的长度大于8bit呢?因为这种情况是很容易出现的,比如一个16bit的Int数据在内存是如何存储的呢?

     


    3.1 内存数据存放

     

    其实一个简单的办法就是使用多个存储单元来存放数据或指令。比如Int16使用2个内存单元,而Int32使用4个内存单元。当读取数据时,一次读取多个内存单元。于是这里又出现2个问题:

    1. 多个存储单元存储的顺序?
    2. 如何确定要读几个内存单元?

     

    3.1.1 大端和小端存储

    1. Little-Endian 就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。
    2. Big-Endian 就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。

    需要说明的是,计算机采用大端还是小端存储是CPU来决定的, 我们常用的X86体系的CPU采用小端,一下ARM体系的CPU也是用小端,但有一些CPU却采用大端比如PowerPC、Sun。判断CPU采用哪种方式很简单:

    [cpp]  view plain  copy
     print ? 在CODE上查看代码片 派生到我的代码片
    1. bool IsBigEndian()    
    2. {    
    3.     int vlaue = 0x1234;    
    4.     char lowAdd =  *(char *)&value;     
    5.     if( lowAdd == 0x12)    
    6.     {    
    7.         return true;    
    8.     }    
    9.     return false;    
    10. }  


    既然不同计算机存储的方式不同,那么在不同计算机之间交互就可能需要进行大小端的转换。这一点我们在Socket编程中可以看到。这里就不介绍了,对以我们单一CPU来说我们可以不需要管这个转换的问题,另外我们目前个人PC都是采用小端方式,所以我们后面默认都是这种方式。

     


    3.1.2 CPU指令


    前面我们多次提到了指令的概念,也知道指令是0和1组成的,而汇编代码提高了机器码的可读性。为什么突然在这里介绍CPU指令呢? 主要是解释上面的第二个问题,当我读取一个数据或指令时,我怎么知道需要读取多少个内存单元。

     


    3.1.2.1 CPU指令格式


    首先我们来看看CPU指令的格式,我们知道CPU质量主要就是告诉CPU做什么事情,所以一条CPU指令一般包含操作码(OP)和操作

      操作码字段   地址码字段

     

     

    根据一条指令中有几个操作数地址,可将该指令称为几操作数指令或几地址指令。

     操作码 A1 A2 A3

     

    三地址指令: (A1) OP (A2) --> A3

     操作码 A1 A2

     

    二地址指令: (A1) OP (A2) --> A1

     操作码  A1

     

    一地址指令: (AC) OP (A) --> AC   

     操作码 

     

        零地址指令

    A1为被操作数地址,也称源操作数地址; A2为操作数地址,也称终点操作数地址; A3为存放结果的地址。 同样,A1,A2,A3以是内存中的单元地址,也可以是运算器中通用寄存器的地址。所以就有一个寻址的问题。关于指令寻址后面会介绍。

    CPU指令设计是十分复杂的,因为在计算机中都是0和1保存,那计算机如何区分一条指令中的操作数和操作码呢?如何保证指令不会重复呢?这个不是我们讨论的重点,有兴趣的可以看看计算机体系结构的书,里面都会有介绍。从上图来看我们知道CPU的指令长度是变长的。所以CPU并不能确定一条指令需要占用几个内存单元,那么CPU又是如何确定一条指令是否读取完了呢?

     


    3.1.2.2 指令的获取


    现在的CPU多数采用可变长指令系统。关键是指令的第一字节。 当CPU读指令时,并不是一下把整个指令读近来,而是先读入指令的第一个字节。指令译码器分析这个字节,就知道这是几字节指令。接着顺序读入后面的字节。每读一个字节,程序计数器PC加一。整个指令读入后,PC就指向下一指令(等于为读下一指令做好了准备)。

    Sample1:

    [plain]  view plain  copy
     print ? 在CODE上查看代码片 派生到我的代码片
    1. MOV AL,00  机器码是1011 0000 0000 0000  


    机器码是16位在内存中占用2个字节:

    【00000000】 <- 0x0002

    【10110000】 <- 0x0001


    比如上面这条MOV汇编指令,把立即数00存入AL寄存器。而CPU获取指令过程如下:

    1. 从程序计数器获取当前指令的地址0x0001。
    2. 存储控制器从0x0001中读出整个字节,发送给CPU。PC+1 = 0X0002.
    3. CPU识别出【10110000】表示:操作是MOV AL,并且A2是一个立即数长度为一个字节,所以整个指令的字长为2字节。
    4. CPU从地址0x0002取出指令的最后一个字节
    5. CPU将立即数00存入AL寄存器。


    这里的疑问应该是在第3步,CPU是怎么知道是MOV AL 立即数的操作呢?我们在看下面一个列子。

     

    Sample2:

    [plain]  view plain  copy
     print ? 在CODE上查看代码片 派生到我的代码片
    1. MOV AL,[0000] 机器码是1010 0000 0000 0000 0000 0000  

     

    这里同样是一条MOV的汇编指令,整个指令需要占用3个字节。

    【00000000】 <-0x0003

    【00000000】 <- 0x0002

    【10100000】 <- 0x0001

     

    我们可以比较一下2条指令第一个字节的区别,发现这里的MOV  AL是1010 0000,而不是Sample1中的1011 000。CPU读取了第一个字节后识别出,操作是MOV AL [D16],表示是一个寄存器间接寻址,A3操作是存放的是一个16位就是地址偏移量(为什么是16位,后面文章会介绍),CPU就判定这条指令长度3个字节。于是从内存0x0002~0x0003读出指令的后2个字节,进行寻址找到真正的数据内存地址,再次通过CPU读入,并完成操作。

     

    从上面我们可以看出一个指令会根据不同的寻址格式,有不同的机器码与之对应。而每个机器码对应的指令的长度都是在CPU设计时就规定好了。8086采用变长指令,指令长度是1-6个字节,后面可以添加8位或16位的偏移量或立即数。 下面的指令格式相比上面2个就更加复杂。

     

    • 第一个字节的高6位是操作码,W表示传说的数据是字(W=1)还是字节(W=0),D表示数据传输方向D=0数据从寄存器传出,D=1数据传入寄存器。
    • 第二个字节中REG表示寄存器号,3位可以表示8种寄存器,根据第一字节的W,可以表示是8位还是16位寄存器。表3-1中列出了8086寄存器编码表
    • 第二个字节中的MOD和R/M指定了操作数的寻址方式,表3-2列出了8086的编码

    这里没必要也无法更详细介绍CPU指令的,只需要知道,CPU指令中已经定义了指令的长度,不会出现混乱读取内存单元的现象。有兴趣的可以查看引用中的连接。

     


    3.1.3  内存数据

     

    3.1.3.1 内存数据的操作

     

    从上面我们可以知道,操作数可以是立即数,可以存放在寄存器,也可以存放在内存。对于第一个例子,指令已经说明,操作时是一个字节,于是CPU可以从下一个内存地址读取操作时,而对于第二个列子,操作数只是地址偏移,所以当CPU获得这个数据后,需要转换成实际的内存地址,在进行一次内存访问,把数据读入到寄存器中。这里就出现我们前面提到的问题,这个数据我们要读几个存储单元呢?

    [cpp]  view plain  copy
     print ? 在CODE上查看代码片 派生到我的代码片
    1.     MyClass cla;  
    2. 008C3EC9  lea         ecx,[cla]    
    3. 008C3ECC  call        MyClass::MyClass (08C1050h)    
    4. 008C3ED1  mov         dword ptr [ebp-4],0    
    5.     cla.num5 = 500;  
    6. 008C3ED8  mov         dword ptr [ebp-6Ch],1F4h    
    7.     int b1 = MyClass::num1;  
    8. 008C3EDF  mov         dword ptr [b1],64h    
    9.     int b2 = MyClass::num2;  
    10. 008C3EE6  mov         dword ptr [b2],0C8h    
    11.     int b3 = MyClass::num3;  
    12. 008C3EF0  mov         eax,dword ptr ds:[008C9008h]    
    13. 008C3EF5  mov         dword ptr [b3],eax    
    14.     int b4 = cla.num4;  
    15. 008C3EFB  mov         eax,dword ptr [cla]    
    16. 008C3EFE  mov         dword ptr [b4],eax    
    17.     int b5 = cla.num5;  
    18. 008C3F04  mov         eax,dword ptr [ebp-6Ch]    
    19. 008C3F07  mov         dword ptr [b5],eax    


    让我们看一段C++代码和对应的汇编代码,操作很简单,创建一个Myclass对象后,对成员变量赋值。而赋值都是试用Mov操作符。对于这些变量我们有赋值操作和取值操作,那么是如何确定要读取或写入数据的大小呢?

    [cpp]  view plain  copy
     print ? 在CODE上查看代码片 派生到我的代码片
    1. cla.num5 = 500;  
    2. 08C3ED8  mov         dword ptr [ebp-6Ch],1F4h    


    我看先看看赋值操作,往dword ptr [ebp-6Ch]内存存入一个立即数, [ebp-6Ch]是num5的内存地址,而前面的dword ptr 表示这是进行一个双子操作。还记得上面指令格式中第一个字节的W字段吗? 在8086中只能进行字节或字操作,而现在CPU都可以进行双字操作。

    [cpp]  view plain  copy
     print ? 在CODE上查看代码片 派生到我的代码片
    1. int b5 = cla.num5;  
    2. 08C3F04  mov         eax,dword ptr [ebp-6Ch]    


    同样,当我们要从一个内存读取数据的时候,也要指定读取数据的操作类型,这里也是双字操作。这样以来,就能从内存中正确的读出需要的长度了。就这么一个简单的赋值操作,获取你从来没想过在内存中怎么存放,又是怎么读取的。这一切都是编译器和CPU在背后为我们完成了。

     


    3.1.3.2 内存对齐

     前面我们清楚了CPU是如何正确读取数大小不同的数据的,最后一部分来看看有关内存对齐的问题。对于大部分程序员来说,内存对齐应该是透明的。内存对齐是编译器的管辖范围。编译器为程序中的每个数据单元安排在适当的位置上。

     


    3.1.3.2.1 对齐原因

    从前面我们知道,目前计算机内存按照字节编址,每个地址的内存大小为1个字节。而读取数据的大小和数据线有关。比如数据线为8位那么一次读取一个字节,而如果数据线为32位,那么一次需要读取32个字节,这样是为了一次更多的获取数据提高效率。否则读取一个int变量就需要进行4次内存操作。对于内存访问一般有以下两个条件:

    1. CPU进行一次内存访问读取的数据和字长相同。
    2. 有些CPU只能对字长倍数的内存地址进行访问。

    对于第一个条件一般来说,目前存储器一个cell是8bit,进行位扩展使他和字长还有数据线位数是相同,那么一次就能传送CPU可以处理最多的数据。而前面我们说过目前是按字节编址可能是因为一个cell是8bit,所以一次内存操作读取的数据就是和字长相同。

    也正是因为和存储器扩展有关(参考1.2.1的图),每个DRAM位扩展芯片使用相同RAS。如果需要跨行访问,那么需要传递2次RAS。所以以32位CPU为例,CPU只能对0,4,8,16这样的地址进行寻址。而很多32位CPU禁掉了地址线中的低2位A0,A1,这样他们的地址必须是4的倍数,否则会发送错误。

    如上图,当计算机数据线为32位时,一次读入4个地址范围的数据。当一个int变量存放在0-3的地址中时,CPU一次就内存操作就可以取得int变量的值。但是如果int变量存放在1-4的地址中呢? 根据上面条件2的解释,这个时候CPU需要进行2次内存访问,第一次读取0-4的数据,并且只保存1-3的内容,第二次访问读取4-7的数据并且只保存4的数据,然后将1-4组合起来。如下图:

    所以内存对齐不但可以解决不同CPU的兼容性问题,还能减少内存访问次数,提高效率。当然目前关于这个原因争论很多,可以看看CSDN上的讨论:http://bbs.csdn.net/topics/30388330

     

    3.1.3.2.2 如何对齐内存

    内存对齐有一个对齐系数,一般是2,4,8,16字节这样。而不同平台上的对齐方式不同,这个主要是编译器来决定的。

    具体的规则可以参考之前转的一篇文章,这里就不详细写了: http://blog.csdn.net/cc_net/article/details/2908600

     



    总结



    通过这一篇对内存工作的介绍,我们从内存的硬件结构,存储方式过渡到了内存的编址方式,然后又探讨了按字节编址带来的问题和解决的办法。这里就涉及到了CPU的指令格式,编译器的支持。最后我们也是从硬件和软件方面讨论了内存对齐的问题。


    我自己感觉,内存的访问管理是计算机中最重要的部分,也是计算机硬件和软件之间交互的过渡的一个地方。所以理解了内存的工作原理,对于后面理解不同的内存模型很有帮助。


    展开全文
  • 内存与cpu工作原理

    千次阅读 2017-05-03 22:25:47
    内存:通电状态下进行数据存储   cpu内部大致结构 程序控制器(CPU的控制中心) 职责: 1 分析或解释 指令 2 根据或析与解释结果向其他组件发出命令 3 控制cpu的工作进度和工作方式   当一条指令进入...
  • 49页的PDF介绍了内存工作原理及发展历程,看完后相信你会对内存有一个很全面的认识
  • 虚拟内存原理

    千次阅读 2019-10-05 10:36:58
    虚拟内存:为了更加高效并且少出错,现代操作系统提供了一种对主存的抽象概念,叫做虚拟内存。虚拟内存是硬件异常,硬件地址翻译,主存,磁盘文件和内核软件的完美交互,他为每个进程提供了一个大的,一致和私有的...
  • 共享内存实现原理

    万次阅读 2018-09-28 18:02:39
    共享内存的使用实现原理(必考必问,然后共享内存段被映射进进程空间之后,存在于进程空间的什么位置?共享内存段最大限制是多少?) nmap函数要求内核创建一个新额虚拟存储器区域,最好是从地质start开始的一个...
  • 深入理解内存原理简介

    万次阅读 多人点赞 2016-12-27 23:21:04
    在了解CPU和存储器工作原理之前,先来了解一下CPU指令和我们编程语言之间的一些关系。   2.2.1.1 CPU指令 因为在计算机中指令和数据都用二进制来表示,也就是说它只认识0和1这样的数字。最早期的计算机...
  • linux共享内存原理剖析

    千次阅读 2017-05-08 16:41:14
    linux共享内存原理剖析共享内存区域是被多个进程共享的一部分物理内存。如果多个进程都把该内存区域映射到自己的虚拟地址空间,则这些进程就都可以直接访问该共享内存区域,从而可以通过该区域进行通信。共享内存是...
  • 深入解析内存原理:DRAM的基本原理

    千次阅读 2019-11-25 16:34:32
    前面我们知道了在一个简单的SRAM 芯片中进行读写操作的步骤了,然后我们来了解一下普通的DRAM 芯片的工作情况。DRAM 相对于SRAM 来说更加复杂,因为在DRAM存储数据的过程中需要对于存储的信息不停的刷新,这也是它们...
  • 内存工作原理

    2013-07-15 16:01:19
    内存工作原理
  • DDR工作原理

    万次阅读 多人点赞 2018-06-21 18:57:44
    DDR SDRAM全称为Double Data Rate SDRAM,中文名为“双倍数据流SDRAM”。...本文只着重讲讲DDR的原理和DDR SDRAM相对于传统SDRAM(又称SDR SDRAM)的不同。 DDR的核心频率、时钟频率和数据传输频率: ...
  • 内存工作原理及时序介绍

    千次阅读 2012-12-21 11:09:40
    并且,内存原理、结 构与时序多年不会改变,无论将来内存技术如何进步,相信这篇文章的存在价值都不会打折扣。本文亦希望能通过对DRAM 基本原理以及时序的介绍,在内存设置以及XMP的制作上有所帮助。 =========...
  • Java内存模型与Java线程的实现原理

    万次阅读 2016-07-15 23:52:18
    Java内存模型与Java线程的实现原理
  • 内存】ECC内存简介

    千次阅读 2020-07-01 00:23:43
    ECC内存简介。
  • 深入浅出DDR系列(二)--DDR工作原理

    千次阅读 多人点赞 2020-08-02 20:52:58
    学习完了DDR的基本组成和硬件结构原理之后,从整体上了解了DDR的特性和静态图,包括原理、管脚图等。那么本章就要从动态的角度来分析时序结构,包括read/write的整个过程到数据返回发生了什么,其中包括以下内容 ...
  • 内存基本知识
  • 内存屏障底层原理

    千次阅读 2019-05-23 08:44:16
    我写这个系列的博客主要目的是解析Disruptor是如何工作的,并深入了解下为什么这样工作。理论上,我应该从可能准备使用disruptor的开发人员的角度来写,以便在代码和技术论文[Disruptor-1.0.pdf]之间搭建一座桥梁。...
  • 10分钟看懂内存的实现原理

    千次阅读 2019-11-06 13:57:46
    内存最小单位是一些类似于二极管这样的东西,它能存储一个电状态,高或低,可表示1或0; -这些单元经过组织起来保存数据,组织的方法是8个编成一个字节,4个字节一个字,每组数据都可以读写; -这些单元按照顺序排放...
  • 几周前,我们新开了一系列文章,旨在深入 JavaScript,探寻其工作原理。我们认为通过了解 JavaScript 的构建方式和其运行规则,我们能写出更好的代码和应用。 第一篇文章重点介绍了引擎、运行时和调用栈的概述。...
  • 内存(DRAM)的工作原理及时序介绍

    万次阅读 多人点赞 2015-09-20 23:05:29
    第一部分:工作原理 DRAM基本组成 内存地址 寻址 内存cell的基本操作 硅晶体中的“电容” MOSFET的控制原理——水库模型 储存数据 写入数据 读取数据 第二部分:时序介绍 时序及...
  • 共享内存原理

    千次阅读 2015-04-08 22:54:12
    共享内存区域是被多个进程共享的一部分物理内存。如果多个进程都把该内存区域映射到自己的虚拟地址空间,则这些进程就都可以直接访问该共享内存区域,从而可以通过该区域进行通信。共享内存是进程间共享数据的一种最...
  • 认识CPU的工作原理

    万次阅读 多人点赞 2018-08-01 11:40:18
    学习CPU的工作原理 在了解CPU的工作原理之前,先简单谈谈CPU是如何生产出来的。 CPU是在特别纯净的硅材料上制造的。一个CPU的芯片包含上百万个精巧的晶体管。人们在一块指甲盖大小的硅片上,用化学的方法蚀刻或...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 487,610
精华内容 195,044
关键字:

内存的工作原理