(1) 半导体存储器:TTL 、MOS,易失 (2) 磁表面存储器:磁头、载磁体 (3) 磁芯存储器:硬磁材料、环状元件 (4) 光盘存储器:激光、磁光材料
在CPU和主存之间加一个缓存,主要是解决CPU和主存速度不一致的问题,主存速度比CPU慢很多,增加一个较快的缓存可以解决这个问题。而在主存后面增加一个外存是为了解决容量不足的问题,外存比较便宜且容量大,但是速度慢,可以存放一些暂时不用的数据。
存放一个机器字的存储单元,通常称为字存储单元,相应的单元地址叫字地址。而存放一个字节的单元,称为字节存储单元,相应的地址称为字节地址。如果计算机中可编址的最小单位是字存储单元,则该计算机称为按字寻址的计算机。
主要技术指标有:
对于上述概念我们可以这样来记忆: 存储体呢,相当于一栋大楼,大楼内有很多房间(存储单元),每个房间内又有很多床位(存储元件),那么0代表床上无人,1代表床上有人。
比如有16个存储单元,而存储单元的地址是用二进制表示的,那么用4位二进制数就可以表示。MAR的位数就是4位。那么相反,如果我们知道MAR有4位,那么存储单元就有24个,16个存储单元。所以MAR反映存储单元的个数。
要想完成一个完整的取或存操作,CPU(控制器)还得给主存加以各种控制信号(读命令、写命令、地址译码驱动信号等)。
现代计算机中: 1.主存由半导体集成电路构成 2.驱动器、译码器和读写电路均在存储芯片中 3.MAR和MDR在CPU芯片中 4.存储芯片和CPU芯片可以通过总线(系统总线)连接 5.地址总线用来指出存储单元地址号。
上图中的表格,一小格代表一个存储单元,大方块是主存中的存储体。以8位二进制作为一个存储单元,也就是一个字节。通常,字由字节组成,图中,4个存储单元又构成了1个字,每个字有字地址(左边的0、4、8)。如果字的高有效位放在内存的低地址端,称为大端(大尾)方式,反之称为小端(小尾)方式。
1.地址线24根,一共可以寻找到 2^{24} 个字节的地址,故寻址范围为 2^{24}B = 16MB(B表示字节)。 2.字长为16位,也就是说一个字由两个字节组成,如果同样是24根地址线,那么按照字寻址,可以找到 16 / 2 = 8MW 的字,W = word。 3.同样的,32位说明一个字由4个字节组成,一共有16/4 = 4 MW。
用8片存储芯片组成一个 16K×8位 的芯片组,一个芯片输出一位,8个同时进行读写,同时受一个片选线控制。再用四组上述芯片组,构成一个容量为64K的存储器。当地址为65535(2^64-1)时 应该对最后一组芯片进行读写操作,则最后一组片选线低电平有效,其他的片选线保持高电平无效。
如上图所示,用8个1K* 4位的存储芯片组成 4K * 8位的存储器,将两个芯片作为一组,片选线连在一起,受同个信号控制,地址线需要12根,其中10根作为芯片的地址线, A_{10} 和 A_{11} 作为片选译码器,用于选择哪个具体的芯片组。
线选法:
用一个地址译码器来寻址,例如输入0000,则表示寻找地址为0的存储单元,对其进行读写操作。这种驱动方式的缺点是,如果地址线很多,比如有20条,那么就能表示1M条地址,相应地译码器的输出也就有1M条线,近百万条的电路是很不现实的,所以在大规模存储元件就无法使用线选法。
重合法:
将存储单元排列成一个二维矩阵,X地址译码器表示二维矩阵的第一维,Y地址译码器表示二维矩阵第二维,比如X输入0000,Y输入0000,表示对坐标为(0,0)的存储单元进行读写。
静态RAM(Static Random Access Memory,SRAM)
如图为静态RAM的基本电路:
T1−T4为一个触发器,两端为输入端,A^’为触发器非原端(即反相输入,输入信号为0,触发器内记录为1),A为触发器原端,对应地,左边的写放大器做了取反处理,就是因为左边为触发器的非原端。
T_5、T_6 为行开关,同时打开表示这一行打通,信号可以在这一条路上流通(就是一个三极管,看成一个闸门,控制左右两端的连通)
T_7、T_8 为列开关,类似行开关,同时打开表示此列打通。
上述的一个个单元按照列阵的形式排列成下图的形式,构成了静态存储元阵列。如下图所示,有6条地址线,指定了存储器的存储容量为 2^{6} = 64 个存储单元,四条数据线表示存储器的字长为4位,故存储位元的总数为 64 * 4 = 256 个。R/W线控制读写。
分别打开行列选择线,对应图中紫色的线路打通,数据从A端向下从 D_{out} 流出。
分别打开行列选择线,使得紫色的线路打通,数据从写输入端流入,左边经过取反后流入A^’, 右边流入A。
每一个刷新周期中集中一段时间对DRAM的所有行进行一次刷新,对于一次刷新周期来说,一般前半段时间由来读写操作,后面留出一部分时间专门用于刷新,且刷新和读写互斥,故会出现一段时间无法进行读写,称为死区。
刷新时间被均匀地分配到刷新周期里面,无死区,但是刷新次数过多,产生很大无用刷新。
将刷新时间划分成几块,每小块进行集中刷新,宏观开起来又是分散式刷新,虽然还是存在死区,但是将刷新安排在指令译码阶段,就不会出现 “死区”。
SRAM采用6个晶体管和1个触发器作为一个存储单元,设计复杂,集成度低,价格高,功耗大,由于SRAM不需要刷新所以速度较快,速度快的要求导致其使用单行译码,行译码的限制使其存储容量小,以上特点使其一般用于缓存。
DRAM采用一个晶体管和一个电容作为一个存储单元,需要刷新,存储容量大但是速度较慢,一般作为主存。
提高访存速度的措施主要有:采用高速器件、采用层次结构 Cache-主存、 调整主存结构。 主要介绍调整主存结构。
主要用来扩容,增加存储器的带宽。在存储体和CPU之间增加数据寄存器,数据先存在数据寄存器中,每次需要数据直接从数据寄存器中取即可。但是存在一定问题:
出现上述问题的原因是,每次存取数据都是一块一块地拿,不够灵活,于是出现了多体并行系统。
如图,有多个存储体,编号为 M_0 到 M_3 ,从某个存储题开始顺序编址,,每个存储体有各自的控制电路,各个体并行工作,CPU给出地址格式为:体号+体内地址。但是存在问题:
其实这种方式很像存储器的扩容操作,(见3.2.5.2),所以这种方式也就适合存储器的扩容,不能实现程序的并行运行。
如图,按照横向编码,那么一个程序的指令会被拆分在多个存储器中,实现了并行。再观察地址,可以发现规律:前四位表示体内地址,后两位表示体号。在不改变存取周期的前提下,增加存储器的带宽。
解释:M_0 先进行存取,经过 τ 后 M_1 ,开始进行存取,经过 τ 后 M_2 ,开始进行存取,依次进行下去,我们发现,除了第一个字需要 T 的时间存取完成,后面都只需要 τ 的时间就可以完成一次存取操作,故读取4个字需要的时间为 T + (4-1)τ。
CPU速度快,主存速度慢,且每年CPU速度的提升比主存快,CPU和主存的速度差距越来越大,但是CPU再快,没有主存数据的输入也只能空等,故在CPU和主存之间设置一个缓存,其速度比主存快,容量比主存小,利用的局部性原理,将必要的一块数据存进缓存,CPU需要数据时先访问缓存,如果没有找到再去主存中读取,这种方式使得CPU的效率得到很大的提升。
如图,缓存和主存的地址都分为两部分,其中两者的块内地址相等,块内地址的大小决定了块的大小,比如块内地址为4位,并且编址方式为字节,则每块大小为16字节。另外,cache中还存在一个标记,用于标识当前cache块对应的主存块号。
主存和缓存按块存储,块的大小相同,若缓存共有 C 块,主存共有 M 块,那么 M 远远大于 C,CPU在主存中申请数据,如果这一块数据已经在缓存中了,则直接从缓存中调入CPU,这称为命中,否则表示未命中。如果命中,说明主存块和缓存块之间建立了对应关系,用 标记记录与某缓存块建立了对应关系的 主存块号。
CPU 欲访问的信息在 Cache 中的 比率,设 N_c 表示通过cache完成存取的总次数,N_m 表示通过主存完成存取的总次数,h 定义为命中率,则:h = N_c/(N_c + N_m)
命中率与 Cache 的 容量 与 块长 有关。容量越大越容易命中。块如果太小,则装不下一条指令,需要多个块;块太大,则总块数太少,块的大小适中,命中率越高,一般每块可取 4 ~ 8 个字,块长取一个存取周期内从主存调出的信息长度。
t_c 表示命中时的cache访问时间, t_m 表示未命中时的主存访问时间, 1-h 表示未命中率,则平均访问时间 t_a = ht_c+(1-h)t_m,若e表示访问效率,则:e = t_c/t_a,可以知道访问效率介于 :t_c/t_m — 1。
CPU通过地址总线发送主存块号,由于Cache和主存的块内地址编号相同,可以直接转换。主存块号先经过主存Cache地址映射变换机构判断是否命中:
主存Cache地址映射变换机构: 地址映射用于判断主存的数据可以存入到哪些Cache块中,变换机构用于查找某个主存块号所对应的Cache地址块号。
主要解决问题:Cache 和主存的一致性。
将主存的字块进行分区,每个分区的大小和cache的大小相同,主存的第j块字块只能放在cache的第i块中,i = j mod C,C为cache的块数。如主存储体中蓝色部分只能放在Cache中的蓝色部分。
CPU给出的主存地址由三部分组成:主存字块标记,Cache字块地址,字块内地址。
主存字块标记就是主存的分区号;分区内的块号就是cache字块地址;字块内地址就是字块内的偏移地址,在Cache和主存中相同,不用处理。以第0块为例:由于cache中的第0块装的可能是主存中任意一个分区的第0块,所以需要比较主存字块标记和cache上的标记是否相同,如果相同则说明命中。
该方式的缺点是cache的利用率不高,可能会反复换出同一个cache字块而其他字块空闲。
Cache利用率高,只要Cache中有空余则就可以装入。由于可以装入到任意的位置,所以要和Cache所有的块比较判断是否命中,比较次数多。同时主存字块标记要存m位(即主存块号),比较的位数也多,时间慢,电路复杂。
直接映射和全相联映射方式是两个极端,一个只能放在固定位置,一个可以放在所有位置,各自的优缺点也很明显,组相连映射是一种中庸的思路。首先将cache分为Q组,同时将主存进行分区,每个区的块数等于cache的组数,每个区的第i块只能放在cache的第i组中,但是在组中的位置可以任意。
某一主存块 j 按模 Q 映射到缓存的第 i=j mod Q 组中的任一块,其中主存块第 j 块只能放在 特定的第 i 组中,属于直接映射的思想,而可以放在特定组中任意一块,属于全相连映射的思想。
主存地址的组成如图所示,在cache中查找时,先根据组地址(即j mod Q)找到cache对应的组,然后通过若干个并行的比较器(个数由每组块数决定)比较主存字块标记(即主存的分区号),只要有一个命中则命中。
第一问: 由于不考虑Cache的一致性维护和替换算法的控制位,总容量就是:行数 * 每行容量,即 8 * 64 = 512B 第二问: 根据题目可知,一个int类型数据占32位,cache每行容量和主存每行容量相同,故主存一行容量为64B,那么一行可以放 64/(32/8) = 16 个数字。由于数组的首地址为320,对应的是主存的第5行,说明数组从主存的第5行开始存储,每行存16个数字。又因为按照行优先存储,a[0][31] 前有31个元素,由于每行放16个数字,所以a[0][31] 在第二行,即主存的第6块,按照直接映射,行号为 6 mod 8 = 6。
a[1][1]同理,该元素前面有257个元素,对应块号为21块,直接映射后的行号为 21 mod 8 = 5。
第三问: 两个程序都是两层循环,如果只考虑一次内循环,每次遍历256个数字,由于是按照行优先存储,数字在行方向是连续的,已知每次按照块来交换Cache和内存中的数据,每块16个数字,对于程序A,按照行来遍历,其中第一个数字未命中(交换),剩下的15个元素都可以命中,所以命中率为15/16,而程序B的命中率为0。所以A快。
虚存空间的用户程序按照虚地址编程并存放在辅存中。程序运行时,由地址变换机构依据当时分配给该程序的实地址空间把程序的一部分调入实存。每次访存时,首先判断该虚地址所对应的部分是否在实存中:
由此可见:
从虚存的概念可以看出,主存-辅存的访问机制与Cache-主存的访问机制是类似的。这是由Cache存储器、主存和辅存构成的三级存储体系中的两个层次。Cache-主存是为了提高速度,主存-辅存则是为了扩容。
相同点:
不同点:
在操作系统的控制下,硬件和系统软件为用户解决了上述问题,从而使应用程序的编程大大简化。
页式虚拟存储系统中,虚地址空间被分成等长大小的页,称为逻辑页;主存空间也被分成同样大小的页,称为物理页。相应地,虚地址分为两个字段:高字段为逻辑页号,低字段为页内地址(偏移量);实存地址也分两个字段:高字段为物理页号,低字段为页内地址。通过页表可以把虚地址(逻辑地址)转换成物理地址,过程如下图所示:
由于虚存地址空间可以很大,因而每个进程的页表有可能非常长。例如,如果一个进程的虚地址空间为2G字节,每页的大小为512字节,则总的虚页数为 2^{31}/2^9=2^{22} 。如此一来,页表本身就要占用大量内存,并且还是连续的空间,这好吗?这不好。于是,一些系统把页表存储在虚存中,因而页表本身也要进行分页。当一个进程运行时,其页表中一部分在主存中,另一部分则在辅存中保存。
另一些系统采用二级页表结构。每个进程有一个页目录表,其中的每个表项指向一个页表。因此,若页目录表的长度(表项数)是m,每个页表的最大长度(表项数)为n,则一个进程最多可以有m×n个页。
在页表长度较大的系统中,还可以采用反向页表(反置页表) 实现物理页号到逻辑页号的反向映射。页表中对应每一个物理页号有一个表项,表项的内容包含该物理页所对应的逻辑页号。访存时,通过逻辑页号在反向页表中逐一查找。如果找到匹配的页,则用表项中的物理页号取代逻辑页号;如果没有匹配表项,则说明该页不在主存中。这种方式的优点是页表所占空间大大缩小,但代价是需要对反向页表进行检索,查表的时间很长。有些系统通过散列(哈希)表加以改进,但需要解决地址冲突的问题,这在操作系统中得以完成。
由于页表通常在主存中,因而即使逻辑页已经在主存中,也至少要访问两次物理存储器才能实现一次访存,这将使虚拟存储器的存取时间加倍。为了避免对主存访问次数的增多,可以对页表本身实行二级缓存,把页表中的最活跃的部分存放在更高速的存储器中(局部性原理),组成快表。这个专用于页表缓存的高速存储部件通常称为转换后援缓冲器(TLB)。保存在主存中的完整页表则称为慢表。
页表是虚地址到主存物理地址的变换表,通常称为内页表。与内页表对应的还有外页表,用于虚地址与辅存地址之间的变换。当主存缺页时,调页操作首先要定位辅存,而外页表的结构与辅存的寻址机制密切相关。例如对磁盘而言,辅存地址包括磁盘机号、磁头号、磁道号和扇区号等。
段是按照程序的自然分界划分的长度可以动态改变的区域。通常,程序员把子程序、操作数和常数等不同类型的数据划分到不同的段中,并且每个程序可以有多个相同类型的段。在段式虚拟存储系统中,虚地址由段号和段内地址(偏移量)组成。虚地址到实主存地址的变换通过段表实现。每个程序设置一个段表,段表的每一个表项对应一个段。每个表项至少包含下面三个字段:
段表本身也是一个段,可以存在辅存中,但一般是驻留在主存中。
段式虚拟存储器有许多优点:
段式虚拟存储器也有一些缺点:
段页式虚拟存储器是段式虚拟存储器和页式虚拟存储器的结合。实存被等分成页。每个程序则先按逻辑结构分段,每段再按照实存的页大小分页,程序按页进行调入和调出操作,但可按段进行编程、保护和共享。
例题:
假设有三道程序,基号用A、B和C表示,其基址寄存器的内容分别为SA、SB和SC。程序A由4个段构成,程序C由3个段构成。段页式虚拟存储系统的逻辑地址到物理地址的变换过程如图所示。在主存中,每道程序都有一张段表,A程序有4段,C程序有3段,每段应有一张页表,段表的每行就表示相应页表的起始位置,而页表内的每行即为相应的物理页号。请说明虚实地址变换过程。
解:地址变换过程如下:
假如计算机系统中只有一个基址寄存器,则基号可不要。多道程序切换时,由操作系统修改基址寄存器内容。实际上,上述每个段表和页表的表项中都应设置一个有效位。只有在有效位为1时才按照上述流程操作,否则需中断当前操作先进行建表或调页。可以看出,段页式虚拟存储器的缺点是在由虚地址向主存地址的映射过程中需要多次查表,因而实现复杂度较高。