概括:
本文介绍80x86存储器组成的基本原理,会隐藏一些硬件细节。
一、基本组成
1.1、计算机系统由CPU,memory,I/O组成,如下图,时钟驱动CPU处理(读、写、运算)memory里的程序或者数据,以及控制I/O。
1.2、当然现的计算机系统不会如此简单,因为memory有很多种,I/O设备的种类更是繁多,由于CPU,memory,I/O的时钟频率不匹配,以及memory的成本等因素,现代计算机系统的基本组成如下(以Pentium为例):
二、存储器的层次结构
比较图2和图1,主要的区别在于系统对于存储器的组织,首先对于各种存储器进行说明。
1、寄存器
1个32bit的寄存器需要32个锁存器或者触发器构成,访问速度和cpu的时钟频率相匹配。
2、SRAM (static ram)
一个存储位需要六个晶体管,可以稳定在两种状态,所以不需要对SRAM进行刷新,所以叫静态ram,由于是晶体管的结构而且不需要刷新,所以其访问速度极快,几乎可以和cpu的时钟频率相匹配。
3、DRAM(dynamic ram)
1个存储位由一个电容和一个访问晶体管组成,因为电容的不稳定性,需要定期对其进行刷新(可以理解为冲电),由于是电容的结构而且需要刷新,所以其访问速度稍慢,一次访问需要几十至几百到cpu周期。
4、硬盘
由磁介质组成,容量巨大,但是访问速度比较慢。
5、磁带等更慢的存储设备
容量更巨大,访问速度巨慢。
典型的SRAM,DRAM,磁盘的造价以及访问时间如下(仅供参考)
SRAM DRAM 磁盘
造价 100$/MB 1$/MB 0.01$/MB
访问时间 3ns 60ns 8000ns
以上可以看出访问速度越快的存储器或者造价很高或者占用空间较大,所以我们需要通过特定的存储器组织方式来实现时间(访问速度)和空间(存储器大小)的平衡,这个特定的组织方式就是层次结构,见下图。
三、程序的局部性与缓存机制
现在说明计算机系统如何利用图3的的层次结构实现时间和空间的平衡的。
3.1、程序的局部性体现为时间局部性和空间局部性。
时间局部性:当某一内存地址被访问后,很有可能在不久的将来还会被访问。
空间局部性:当某一内存地址被访问后,其附近的内存地址很有可能在不久的将来被访问。
3.2、缓存机制
缓存机制就是利用程序的局部性特征实现存储器访问的时空平衡,通俗的说就是既要大存储空间,又要快速访问。
那么如何对大容量的存储器进行快速访问呢?答案只可能是把底层的大容量存储器的最近很有可能被频繁访问的内存(程序的局部性)缓存到它的上一级的具有较高访问速度的存储器当中去。
四、不同的缓存机制详述
不同层次存储器之间的缓存机制是不同的,有的是由硬件完成,有的是由软件完成,有的是有软硬件共同完成,所以说硬件的发展和软件的发展是相辅相成的,即将出现的虚拟内存的概念就有力的说明了这一点。下面以实例说明Pentium的缓存机制。
4.1、主存与L2高速缓存(以下简称L2)缓存机制
▲为了便于描述假设地址空间为4G(32根地址线),主存大小为16MB。
▲Pentium的L2大小为512KB
主存的大小是L2大小的32倍,也就是说在某一时刻,主存最多有1/32被缓存到L2中,因为L2和主存在存储器结构中是访问速度较快的,为了提升效率,系统采用硬件缓存的机制,就是由硬件来决定主存的某个特定的内存单元缓存到L2的什么位置。
4.1.1、L2的组织见下图
由上图可知,L2除了512KB的缓存空间外,还另外附加了32KB的有效位和标志位,这个位的作用是辅助实现缓存机制。
4.1.2、缓存规则
当寻址16MB的地址空间(L2本身支持的最大地址空间为4G)被分解成了524288个(512K,2的15次方)block,每个block32字节,我们利用如下规则把这512k个block和L2的16K个block进行映射,见下图。
如上图所示,当寻址一个32bit的地址时,组索引决定此地址所在的block会被缓存到L2的哪一组,标记位决定此地址所在的block会被映射到哪一行(取余规则),最低的5位决定地址在L2某一行的block内的偏移。
4.1.3、缓存步骤
当访问主存的一个地址时,首先会按照地址的组索引找到L2中相应的组(组匹配),然后在组中根据标记位查找到相应的行(行匹配),然后根据偏移找到对应的地址。如果上述步骤出现未找到匹配的情况,就是未命中,则从主存中读取相应地址所在的block到L2中,并按照此规则缓存到L2当中。
4.1.4、关于组索引的补充
把组索引放到地址的中间也是由于程序的局部性,组索引放到中间可以把较大的连续的地址空间映射到L2的不同block内,这样不至于导致缓存的未命中很高。
4.2、L2与L1之间的缓存
由于L1具有更高的访问速度,为了更好的匹配cpu读取,把L1缓存分为L1-i chache(指令高速缓存)和L1-d chache(数据高速缓存),L1-i chache和L1-d chache的结构相同,都是16KB,128组,每组4行,每行32字节。
缓存规则也主存与L2的缓存规则相同。
结构如下图所示:
4.3、硬盘与内存之间的缓存(虚拟内存来了)
现在的操作系统提供多进程,多线程支持,对于32位的cpu来说,每一个进程都4GB的虚拟空间,各进程之间的虚拟空间互不影响,CPU为此机制提供了硬件支持,CPU和操作系统密切合作实现了硬盘到内存的缓存机制。
4.3.1、虚拟地址的概念
程序再被编译链接之后,变量或者函数的地址都是虚拟地址,操作系统会为此虚拟地址分配合适的物理地址的映射。
4.3.2、虚拟地址的主要作用
●使各进程的地址空间隔离,互不影响。
●为操作系统和用户程序分配不同的虚拟地址空间,并设置相应的访问权限也就是所谓的保护模式。
●实现内存映射等其他功能。
4.3.3、缓存规则
和上述的高速缓存规则类似,也需要把虚拟地址空间分成block,把内存也分成block,然后按照一定的规则进行块映射,程序的虚拟地址空间是存储在硬盘上的,所以虚拟地址和主存的缓存也就是硬盘和主存的缓存。
操作系统采用段表和页表来实现虚拟内存对物理内存的映射。
段表结构如下图:
页表结构如下图:
虚拟寻址规则如下图:
4.3.4、缓存步骤
因为页表和页面的物理机制都是4KB对齐的,所以低12bit就可以设置一些段或者页面的属性。
段表当中的每一项指向一个页表,页表中的每一项指向一个4KB的物理内存区域。
当寻址一个虚拟地址时,MMU根据虚拟地址的高10位段表中的页表起始地址,然后根据接下来的10位确定页表中的那一项,读出页面物理地址的高20位,和虚拟地址的低12位结合获得虚拟地址对应的物理地址,之所以使用二级页表提高了查找效率,80386以上的提供了硬件级的支持。
4.3.5、TLB
通过以上可知,查找虚拟对应的物理地址需要查表,而查表是比较费时的操作,如果把每次查表的结果缓存到一个高速缓存中,TLB出现了,TLB也分为指令TLB和数据TLB,让MMU首先会查找TLB,能大大提高系统效率。
指令TLB(32个字,8组,4行)结构图如下:
数据TLB类似,64个字,16组,4行,图略。
4.4、L1与寄存器之间的缓存机制由编译器决定。
总结:至此,计算机系统存储器层次访问的任督二脉已经打通,程序的局部性和存储的缓存机制是核心内容。