按在计算机中的作用对存储器分类:
按存储介质分类:
按存取方式分类:
存储器的性能指标,有3个主要的性能指标,存储容量,单位成本和存储速度
存取时间:存取时间时指从启动一次存储器操作到完成该操作所经历的时间,分为读出时间和写入时间。
存取周期:它是指存储器进行一次完整的读写操作所需的全部时间,即连续两次独立访问存储器操作(读或写操作)之间所需的最小时间间隔。
主存带宽:主存带宽又称数据传输率,表示每秒从主存进出信息的最大数量,单位为字/秒,字节/秒
存取时间不等于存储周期,通常存储周期大于存取时间。因为任何一种存储器,在读写操作之后,总要有一段恢复内部状态的复原时间。
缓存的功率大于主存,速度高于主存,缓存和主存之间,通过硬件技术进行连接。
为了解决CPU和主存速度的不匹配问题,使用硬件技术 提升速度。
主存辅存之间通过软硬件结合进行连接,辅存用于解决主存容量问题。
存储体由若干个存储单元组成,存储单元由多个存储元件组成
存储体 ----> 存储单元(存储一串二进制串)----> 存储元件(存储一个0/1)
存储单元按照地址进行寻址
MAR:存储器地址寄存器,反应存储单元个数。保存了存储体的地址(存储单元的编号),反应了存储单元的个数。所以MAR的位数和存储单元的个数有关。
MDR:存储器数据寄存器,反应存储字长(存储单元长度)。保存了要送入CPU中的数据或要保存到存储体中的数据或者刚刚从存储体中取出来来的数据。这个寄存器的长度和存储单元的长度相同。
寻址方式及寻址范围计算:
地址线24根,按字节寻址,地址个数 = 2^24 * 1B = 16MB
如果字长16位,按字寻址,地址个数 = 8MW
如果字长32位,按字寻址,地址个数 = 4MW
让某一组芯片同时进行工作。如下图所示,使用32片 16K * 1位的存储器组成 64K * 8 位的存储器。16 K * 1说明每个存储器的数据线为1根,要组成64K * 8 位的存储器,只需使得每次读数据是从8个16 K * 1存储器中各读取一位即可,这时候就可以使用片选线同时选中8个 16K * 1的存储器。
1、线选法
从上图可以看出,地址总线为4,数据总线为8,按照字节进行寻址,内存大小为16 * 8 b。
通过地址线判断从那个字节进行数据的读取,换句话说,如果地址输入为0000,在只有字线0有效,其他字线无效。
线选法存在的问题:
如果容量稍大,比如为1M * 1 ,则此时有20根地址线,相应的有2^20 = 100万根字线,这样导致芯片字线非常密集,并且很难把芯片的密集程度做的很高。
2、重合法
对于重合法,同样如果有1M * 1的容量,此时X(行)、Y(列)各有十根地址线,对应的字线各有1024条,则公有2048跟字线。
静态RAM使用的是触发器进行存储数据,触发器由四根晶体管构成,属于双稳态触发器,具有源端和非端用于存储数据,一方为0,另一方为1,一方为1,另一方为0。
图中是保存一个0位或者1位的电路。
行地址线选择:相当于重合法图中的Xn,每行有多个基本单元电路,行地址选中一行中所有的基本单元电路。
列地址线选择:相当于重合法图中的Yn,每列有多个基本单元电路,列地址选中一列中所有的基本单元电路。
每次读取数据,需要行和列同时被选中。
T1 ~ T4为触发器,T1和T4用于存储0和1,T5和T6用于控制读取哪一端数据。
在实际的芯片中,会将虚框中的内容(T1 ~ T 4, T5和T6)进行列分布而非单独一个,T7和T8属于列开关,行列交叉点会有多个基本单元电路,能读出多位数据。
读数据时,虽然T5开,T7开,但是非端数据到写放大器就终止了。
写数据时,左边的写放大器把右边的写放大器的值取非后进行输出,保证A和非A端的值相反。
以Intel 2114芯片举例,Intel 2114 外特性如下图:
Intel 2114 芯片是由64 * 64位矩阵构成。由图中可知,芯片地址线9根,数据线4根,那芯片内部具体布局如下图:
如图所示,地址线共10位,其中行地址线6位,列地址线4位,行字线2^ 6 = 64,列字线 2^ 4 = 16。读取数据时如下所示:
将64列数据分为四组,每组16列。数据读取的时候,如,行地址为000000,列地址为0000,此时,行位线选中第一行中所有的元件,列
地址选中每组中的第一列,这样就从每组中读取一位,共读取四位数据。写数据和读数据同理。
动态RAM使用电容,电容中保存了电荷为1,电容没有被充电为0。
动态RAM基本电路有两种,如上图左(三管动态RAM)、右(单管动态RAM)。
(1)左侧电路读写操作
读操作: T4为预充电信号,如果预充电信号有效,T4会被打开,Vdd通过T4对读数据线进行充电,使得读数据线成为高电平,如果是进行读操作,则读选择信号有效,T2打开,如果此时CG中保存的数据是0,也就是CG没有充电,则T1不会导通,则读数据线就会保持高电平,所以,如果保存的数据是0,则在读数据时候,读出的数据是1。如果CG电容中保存的数据是1,T1导通,此时读数据线上的电平通过T2,T1线路进行放电,读数据线低电平,读出的数据为0。所以电容读出的信息和原存的信号是相反的。
写操作: 写入和输入信息相同。如果是写操作,写选择线有效,T3导通 写数据线会通过T3向CG充电,或者CG通过T3进行放电,如果写入的数据是1高电平,写数据线会通过T3向CG充电,CG写入1.如果写入是0,则CG通过T3进行放电,CG放电为0。
(2)右侧电路读写操作
读操作: 如果相应的行被选中,字线连接的T被打开,电容就会通过T进行充电或者放电,如果CG中有电位1,此时放电,则数据线有电流,如果CS中没有充电,则数据线无电流,通过数据数据线有无电流判断CS中保存的是1还是0。
写操作: 写入时,写入1,数据线有电流,进行充电为1。写入0,数据线无电流,放电为0。
(1) 三管动态RAM(Intel 1103)
三管动态RAM读写操作:
(2)单管动态RAM(Intel 4116)
单管动态RAM外特性:
上图中,大小为16k X 1,所以有14根地址线,图中地址线只有A0 – A6共7根线,此时行地址和列地址分为两次传输,将行地址和列地址分别保存早缓存器中。
单管动态RAM读写操作:
图中的读放大器的工作原理像一个撬撬板电路,一端为0,另一端就是1,一端为1,另一端就是0。
读操作: 如果选中63行,0列。则63行中所有的开关都被打开,如果电容中有电,则读放大器左端为1,则右端为0,此时读出的数据为0。如果电容中没有电,读放大器左端为0,则右端为1,此时读出数据为1。
写操作: 如果如果选中63行,0列。写入1,读放大器右端为1,左端为0,写入0。如果写入0,读放大器右端为0,左端为1,写入1。
以上电容中实际数据和写入读出数据相反,但是读出和写入的数据相同。
三管动态RAM和单管动态RAM电路比静态RAM电路多出放大器,放大器所用:电容存在漏掉,需要刷新放大器没过一段时间对每一列上的电容进行刷新重现。
由于动态RAM使用电容存储信息,电容容易漏电,经过一段时间,电容漏电,会导致数据有1变为0,。
动态RAM刷新只和行地址有关,和列地址无关,每次刷新的是一行中的所有基本电容电路。给出行地址,某一行被全部选中,这个行上所有电容中的信息都会被送到读电路,如果在读数据线和写数据线之间增加一个刷新放大器(每一列都加),就会完成对一行数据的刷新。
(1) **集中刷新:**以128 * 128矩阵为例
主存储器的存储周期 为0.5us
上图中的集中式刷新:每隔2ms对128行进行全部刷新,存取周期为0.5us,所以刷新每行也需要0.5us,2ms内,刷新需要64us。在这段死区内,CPU无法对动态RAM进行读写操作。
(2)分散刷新:以128 * 128矩阵为例
上图的分散式刷新:延长存取周期为正常存取周期的两倍(0.5us * 2 = 1us)。每1us对其中的一行进行刷新,128us刷新全部的128行。虽然没有死区,但是刷新过于频繁,并且延长了CPU的读写周期。
(3)分散集中相结合:以128 * 128矩阵为例
这种方式存取周期为0.5us,在集中式刷新中,每隔2ms对128行进行全部刷新,2ums= 2000us,即如果平均分到每行,则每15.6um刷新一行。若将刷新安排在指令译码阶段,就不会出现死区。
DRAM用于做主存,SRAM用于主存和CPU之间的缓存。这样就可以降低成本同时加快访问速度。
行列选择线交叉处有 MOS 管为“1”
行列选择线交叉处无 MOS 管为“0”
熔丝断为 “0”
熔丝未断为 “1”
G:栅极 S:源 D:漏
使用紫外线进行擦洗
D 端加正电压形成浮动栅,S 与 D 不导通为 “0”。
D 端不加正电压不形成浮动栅,S 与 D 导通为 “1”。
使用电擦写,可局部擦写,也可全部擦写。
第三种EPROM价格便宜,集成度高。
第四种EEPROM,电可擦洗重写。
Flash Memory比 EEPROM快,具备 RAM 功能。
上图为用两个 1k * 4 位存储芯片组成一个1K * 8位的存储芯片。在读取数据的时候,通过cs片选线同时选中两个芯片,将每个芯片中的四位组成8位传送到数据线上。
图中是将连个1k * 8的存储芯片组成一个2k * 8的存储芯片。共需要11根地址线 ,8根数据线,其中10根地址线选中具体的一个地址,第十根地址线用作片选线,当第十根为0时候,使用芯片1,当第十根为1时候,使用芯片2。
用8片 1K * 4位的芯片组成4K * 8位的芯片。其中有12根地址线,8根数据线,其中两根地址线作为片选线,一个片选地址选中两片芯片。
集合 | 检错位数与纠错位数 |
---|---|
{000,001,010,011,100,101,110,111} | 检0位错、纠0位错 |
{000, 011,101,110} | 检1位错,纠0位错 |
{000,111} | 检1位错,纠1位错 |
{0000,1111} | 检2位错,纠1位错 |
{00000,11111} | 检2位错,纠2位错 |
第一行: 列举出来的8个编码都是合法编码,只要改变其中任何一个编码中的任意某几位,就能够将其转变成集合中的另一个合法编码,这种情况下,即使发生了错误,结果依然是合法代码,所以不能检错也不能纠错。
第二行: 列举出四个编码为合法编码,其他的为不合法编码。需要改变任意一个编码中的两位,才能使其变成其中的另一个合法代码,如果只是改变一个合法编码中的一位,生成的为不合法编码。如果检测都集合中有一个为不合法编码,则其实通过那个合法编码发生的错误无法得知,如000,101,110都可以发生一位错而变成100。所以这种这种情况能检测一位错误而无法纠正错误。
第三行: 列举出两个编码为合法编码,其他的为不合法编码。这样,需要一个合法编码同时改变三位,才能变成另一个合法编码。此时如果检测到这个集合中有一个不合法编码,如果是100,则他可能是通过000改变一位到的,也可能是通过111改变两位得到的,通过概率,一位发生错误的概率更大,所以这种情况都认定是000改变一位得到的,所以可以将100纠正为000。如果这个不合法编码是101,则判定是通过111改变一位得到的,则纠正其为111。
第四行: 列举出两个编码为合法编码,其他的为不合法编码。这样,需要一个合法编码同时改变四位,才能变成另一个合法编码。此时如果检测到这个集合中有一个不合法编码,如果是1000,则判定为通过0000改变一位得到的,纠正其为0000;如果是1100,则判断是两位发生错误的不合法代码,无法判断是0000还是1111发生了错误;如果是1110,则判断是通过1111改变一位得到的,纠正其为1111。所以这种情况下能检测两位错误,纠正一位错误。
第五行: 列举出两个编码为合法编码,其他的为不合法编码。这样,需要一个合法编码同时改变五位,才能变成另一个合法编码。此时如果检测到这个集合中有一个不合法编码,如果是10000,则判定为通过00000改变一位得到的,纠正其为00000;如果是11000,则判断通过00000改变两位得到的,纠正其为00000;如果是11100,则判断是通过11111改变两位得到的,纠正其为11111;如果是11110,则判断是通过11111改变一位得到的,纠正其为11111。所以这种情况下能检测两位错误,纠正两位错误。
编码最小距离是任意两组合法代码之间二进制位数的最少差异, 既一个合法编码改变n位能够变成另一个合法编码,则这个n就是最小距离。
由前面的举例可知,编码的纠错 、检错能力与编码的最小距离有关。
最小距离越大,纠错 、检错能力越强。
通过前面的举例可以得到如下公式:
汉明码采用奇偶检验和分组校验
奇偶检验和分组校验: 将一个二进制编码划分为不同的组,通过添加检验位,使得每组中包含奇数个或者偶数个1。这里采用偶数校验进行举例,即添加校验位使得每组中包含偶数个1。
添加校验位:
校验位添加的位置:将校验位添加在编码的0,2,4,8…位置。
需要添加校验位的位数:设原数据有n位,需要添加K位校验位。
分组策略如下:
将位置 XXXX1分为一组,XXX1X分为一组…,位置从1开始。分组之前,是先放置好校验位,放置好之后再进行分组,分组是将校验位和原数据一起进行分组划分。
如果有一个编码为0101,对其进行添加校验码,并分组结果如下:
此时将数据分为三组如下:
第一组 位置编码 0001 0011 0101 0111 将位置为0001的数分为一组
代表位置 1 3 5 7 即将1,3,5,7分为一组
实际编码 0 0 1 1
第二组 位置编码 0010 0011 0110 0111 将位置为0010的数分为一组
代表位置 2 3 6 7
实际编码 1 0 0 1
第三组 位置编码 0110 0101 0110 0111 将位置为0100的数分为一组
代表位置 4 5 6 7
实际编码 0 1 0 1
添加检测位之后,形成新的检测位 Pi ,其位数与增添的检测位有关,如增添 3 位 (k = 3),得到新的检测位为 P4 P2 P1
以 k = 3 为例,Pi 的取值为:
校验结果如下:
P4 P2 P1 | 检测结果 |
---|---|
0 0 0 | 无差错 |
0 0 1 | 位置1发生错误 |
1 0 1 | 位置5发生错误 |
1 1 0 | 位置6发生错误 |
1 1 1 | 位置7发生错误 |
即P4 P2 P1是多少,那就是哪位发生错误。
对于这种单体多字系统,把存储器的存储字长加长
如CPU字长为16位,存储器字长设为64位,CPU每次访问存储字,都可以取出四个存储字,这四个机器字,每个都可以是一条机器指令,或者是长度为16的数据,CPU一次把这四个值从内存中取出,放到数据寄存器中,下次再用的时候,直接从数据寄存器中取出相应的数据或者指令,这样可以增加存储器的带宽。
缺点:
各个体并行工作
使用高两位区分访问的是哪个存储体,第四位表示访问某个存储体的具体地址
当一个存储体正与CPU交换信息时,另一个体可同时与外部设备进行直接存储器访问,实现两个体并行工作,提升效率。各个体分别响应不同请求源的请求,实现多体并行。
**缺点:**这种存储体存放信息时顺序存储,上一个存储体存满后才存储下一个存储题,由于程序运行过程一般是顺序存储访问,就会导致程序运行过程中,一个存储体会被频繁访问,而其他的存储体闲置。而上图的方式也是存储题容量的扩展方式,所以这种方式更适合存储体容量的扩展,而不适合用于提升存储体的带宽和访问速度。
上面这种方式进行低位交叉,高四位确定具体某个存储体中的地址,低两位确定具体是哪个存储体,保存按照横向顺序进行编码存放指令。
当执行一个程序的时候,CPU给出地址(体内地址和体号),如果访问的是M0,M0把内部地址和读写命令进行锁存,然后M0自己去完成读操作,之后,在这个存取周期内,CPU还可以继续给M0,M1,M2发出命令, 如果M0准备好了数据,在一个存储周期要结束的时候,就可以想CPU进行数据传送,这种方式就是第三章中的分离式通信。这种方式各个体分别可以响应相同请求源的请求,实现多体并行。
低位交叉的特点:在不改变存取周期的前提下,增加存储器的带宽
设四体低位交叉存储器,存取周期为T,总线传输周期为τ,为实现流水线方式存取,应满足 T = 4τ。
所以,连续读取 4 个字所需的时间为 T+(4 -1)τ。
CPU和**主存(DRAM)**的速度差异,避免 CPU “空等” 现象
为了充分发挥Cache的能力,使得机器的速度能够切实的得到提高,必须要保障CPU访问的指令或数据大多情况下都能够在Cache中找到,这样依靠程序访问的局部性原理。
所以放入cache中的数据是以块为单位的,块包含了当前正在使用的指令和数据和相邻的指令和数据,块的大小要通过实验的方式进行确定。
主存和缓存按块存储
块的大小相同,B 为块长,一般每块可取 4 ~ 8 个字
把主存储器和cache分成大小相等的块,主存中共有M块,cache中共育C块,Cache的容量要远远小于主存的容量,所以C要远远小于M
主存和Cache分为大小相等的块
对于块内地址部分,主存块和cache块大小是相同的,所以块内地址位数是完全相同的,另外一个块在内存和cache之间进行传送的时候,是整体进行传送的,块内字节的顺序不会发生任何变化,所以内存块内地址和cache块内地址部分的值是完全相同的。
Cache上的标记,用于标记贮存块和cache块之间的对应关系,如果一个主存块我们把他保存到了cache中了,我们就把主存块号写入到标记中,将来CPU如果再次访问这个地址数据的时候,先访问cache,用主存块号和cache中的标记进行比较,看要访问的数据是否在cache中,如果和某一个标记正好相等,并且这个cache块是有效的,那这个cache块中就保存了他要访问的在内存中的信息,他就直接从cache中获取这些信息,这样速度就会得到很大的提升。
由于 M >> C,所以看存在访问的部分主存内容不存在于 Cache中的情况
命中: 主存块调入缓存,主存块与缓存块 建立 了对应关系,用 标记记录与某缓存块建立了对应关系的主存块号。
未命中: 主存块未调入缓存,主存块与缓存块 未建立对应关系。
CPU 欲访问的信息在 Cache 中的 比率
命中率 与 Cache的容量 与 块长 有关
一般每块可取 4 ~ 8 个字,块长取一个存取周期内从主存调出的信息长度,这个和前面讲的提高存储器的访问速度中的多体交叉有关。如:采用16体交叉,每个存储体保存一个字,块长就是16个存储字,在一个存储周期中,可以把16个存储字取出放到cache中。如:
CRAY_1 | 16体交叉 | 块长取 16 个存储字 |
---|---|---|
IBM 370/168 | 4体交叉 | 块长取 4 个存储字 |
CPU取若干次数据,从cache中读取了N1次,从主存中读取了N2次:
命中率 = N1 / (N1 + N2)
效率 e 与 命中率 有关:
分子是CPU去访问一次Cache需要的时间。分母是CPU访问访问数据的平均时间(有的访问的是cache,有的访问的是主存)。
设 Cache 命中率 为 h,访问 Cache 的时间为 tc ,访问 主存 的时间为 tm
对于上面的这个公式,效率e的范围;[tc/tm, 1]。对于分母的平均时间计算,是在访问cache和访问主存并行的情况下计算出来的,如果,每次先访问cache,cache未命中再访问主存,公式将会发生变化。分母为 tc + (1 - h)tm。
**地址映射:**将主存地址映射到缓存中定位
**地址变换:**将主存地址变换成缓存地址
当新的主存块需要调入缓存中,而它的可用位置又被占用时,需根据替换算法解决调入问题。
(一)读操作
(二)写操作
写直达法写回法(Write – through): 写操作时数据既写入Cache又写入主存,写操作时间就是访问主存的时间,Cache块退出时,不需要对主存执行写操作,更新策略比较容易实现。
写回法(Write – back): 写操作时只把数据写入 Cache 而不写入主存,当 Cache 数据被替换出去时才写回主存,写操作时间就是访问 Cache 的时间,Cache块退出时,被替换的块需写回主存,增加了Cache 的复杂性。
(一)增加Cache级数
片载(片内)Cache,片外 Cache
(二) 统一缓存和分立缓存
指令 Cache,数据 Cache
Pentium | 8K 指令 Cache | 8K 数据 Cache |
---|---|---|
owerPC620 | 32K 指令 Cache | 32K 数据 Cache |
现在的缓存可分为片载缓存和片外缓存两级,并将指令缓存和数据缓存分开设置。
以cache存储体容量为单位,将主存储体划分为若干个和cache存储体大小相等的区域。
每个区的大小和cache存储体的大小相等,每个区中包含的字块数和cache存储体中包含的字块数相等。每个区中的字块进行编号的时候,可以编号2的C次方减一个,在进行映射的时候,任何一个区的第0块只能存放在cache存储的第0块,任何一个区的第1块只能存放在cache存储的第1块中。即:每个缓存块 i 可以和 若干 个 主存块 对应,每个主存块 j 只能和 一 个 缓存块 对应。
对于这种方式,如果CPU给出一个地址,我们可以把地址分为三部分:主存字块标记,Cache字块地址,块内偏移
因为cache中的第0块,装载的可以是主存储体中任意一个区域的第0块,所以我们要把区号写在标记中。当CPU给出地址访问cache的时候,先通过Cache字块地址确定读取的是cache中的哪一个块,再通过比较器比较这个块的标记和CPU给定地址的主存字块标记是否相等,如果是,则表示要访问的数据已经被加载进了cache,可以直接从cache中进行获取。
**优点:**这种方式,可以直接根据块号确定cache ,根据区号判断要读取的块是否被加载进了cache。
**缺点:**由于任何一个区的第0块只能存放在cache存储的第0块,任何一个区的第1块只能存放在cache存储的第1块中,就算有其他空闲也不能存入,这种映射使得cache的利用率很低,cache在调入的时候,冲突的概率很大,命中率低。
主存储器的任何块,可以被放入到cache中的任意块中,这样,任何一个字块只要想调入cache,只要cache中有空闲就能被调入进来。
缺点:
组相联映射,是直接相连映射和全相联映射的折中。
先把cache分成块,再把这若干个块分成组,每组中可以包含2块,4块,8块等
然后把主存储器中的字块也进行分区,每个区的大小和cache中的组数是相同。也就是cache被分成了多少组,主存储器每个区就有多少个块。映像的时候,每个区的第0块,可以放到cache第0组的任何一个位置。也就是,区里面的编号,就直接决定了他被放入到了cache中的那个组中。
这种方式,和直接关联相比,对于主存储器中的每个块,可以放入到cache一组中的多个位置,只要这组中有一个位置空闲,就能被调入。和全关联相比,只需要确定这个块是否在当前组中即可。
对于这种方式,虽然结构比较复杂,但是cache利用率高,获取数据效率高,计算简单。对于这种方式,如果cache只有一组,就变成了全相联,如果cache每组只有一块,就变成了直接相联。
对于以上的三种方式,在多层次的cache中使用是不一样的,对于接近CPU的cache,因为需要高速度,所以使用的是直接相连或者是cache每组块个数比较少的组相联。中间的层次,采用组相联的方式,距离CPU最远的cache,可以采用全相联的方式,因为距离CPU越远,对速度的要求越低,对cache利用率的要求越高。
当使用全相联和组相联的时候,如果 要获取的数据不在Cache中,从主存中读取后,需要将数据写入缓存Cache,如果Cache中已经有数据需要将Cache中的数据替换出去,那替换策略该如何呢。
让最先进入到内存块的数据先退出。这种方式并不能很好的体现程序的局部性原理。
在最近的一段时间内,我们使用的最少的块。