主存储器主要有三个部件?:存储体、MAR(地址寄存器)和MDR(数据寄存器)
存储器的逻辑就是通过一个时序控制逻辑控制
地址寄存器用来存储要放入或取出的地址
存储体用来存放数据
数据寄存器用来存放要放入或取出的数据
当要取出时,时序控制逻辑会给上面那个开关一个信号,让他打开(同样的,存入的时候时序控制逻辑也会给一个信号,当然是不同的信号)
多个存储元合并起来就是存储单元
多个存储单元合并起来就是存储体
这种形式的存储器有一个坏处,一次只能读一行存储单元,因此需要一个译码器来帮助分析地址
因此总容量=存储单元个数*存储字长
这就是总的电路图
片选线:用来控制控制电路的开关(低电平有效/高电平有效)
读/写控制线:因为一次只能执行一个操作,因此读和写操作可以放在一根线上
然后地址线把地址存入MAR,经过译码器读取或写入
读取的话就把数据放入MDR再到数据线,写入的话就把MDR中的数据写入
上面有n条地址线,说明有n位地址→ 2 n 2^{n} 2n个存储单元
有n条数据线,说明有存储单元为n位字长
总容量=存储单元个数*存储字长
存储芯片的描述:
8*8位
常见的描述:
8K8位→ 2 13 ∗ 8 b = 8 K B 2^{13}*8b=8KB 213∗8b=8KB
8K1位→ 2 13 ∗ 1 b = 8 K b = 1 K B 2^{13}*1b=8Kb=1KB 213∗1b=8Kb=1KB
64K*16位→ 2 16 ∗ 16 b = 128 K B 2^{16}*16b=128KB 216∗16b=128KB
K : 2 10 M : 2 20 G : 2 30 T : 2 40 K:2^{10} \qquad M:2^{20} \qquad G:2^{30} \qquad T:2^{40} K:210M:220G:230T:240
因此就可以的出8K= 2 3 ∗ 2 10 2^{3}*2^{10} 23∗210
总容量是1KB
因此地址线有10根
按字节寻址:1K个单元,每个单元1B
按字寻址:256个单元,每个单元4B
按半字寻址:512个单元,每个单元2B
按双字寻址:128个单元,每个单元8B
这个应该不是很难理解
易失性存储器(就是断电以后东西就没了)
这其实就是上面的讲的逻辑图
1.存储矩阵:由大量相同的位存储单元阵列构成。
2.译码驱动:将来自地址总线的地址信号翻译成对应存储单元的选通信号,该信号在读写电路的配合下完成对被选中单元的读/写操作。
3.读写电路:包括读出放大器和写入电路,用来完成读/写操作。
4.读/写控制线:决定芯片进行读/写操作。
5.片选线:确定那个存储芯片被选中,可用于容量扩充
6.地址线:是单向输入的,其位数与存储字的个数有关。
7.数据线:是双向的,其位数与读出或写入的数据位数有关。
8.数据线数和地址线数共同反映存储芯片容量的大小。
如地址线10根,数据线8根,则芯片容量-210X8-8K位。
一般存储器都是用半导体做的,但是会有不同的形式,有SRAM(静态存储器)和DRAM(动态存储器)
剩余的就是他们的参数对比表
存储信息:这是存储模式,SRAM利用双稳态,DRAM利用电容(当然这两种都需要插电,没电直接GG)
破坏性读出:触发器的状态可以直接查看,查看时并不会改变;电容是利用有没有电来判别的,检测的时候回导致电荷流失,会破坏
需要刷新:触发器的状态是稳定的,电容是不稳定,会流失的,因此触发器不需要刷新,电容需要
送行列地址:SRAM中并不是行=列矩阵,行列不一定位数相等,因此需要一次性全部送进去;DRAM中是行=列矩阵,因此可以分两次送
运行速度:这就不用讲了
集成度:触发器需要6个逻辑元件,电容只需要1个或者3个,因此集成度高低立刻就出现了
发热量:不需要多讲了吧,快的肯定热
存储成本:这个也不用讲了吧,集成度低的肯定要更多的钱嘛
经过参数对比,也可以看出SRAM更适合做Cache(高速缓存器),DRAM更适合做主存
多久需要刷新一次?
刷新周期:一般为2ms
每次刷新多少存储单元?
以行为单位,每次刷新一行存储单元
(为什么要用行列地址?减少选通线的数量)
可以看出,如果是一个译码器直接连接的话,当n大到一定的程度以后,可能会需要很多很多的线
当使用行列的方式的话,会少很多,一个是 2 n 2^{n} 2n根,行列的话就是 2 n 2 ∗ 2 2^{\frac{n}{2}}*2 22n∗2
会少将近一半,大大节省了材料
如何刷新?
有硬件支持,读出。行的信 息后重新写入,占用1个读/写周期
在什么时刻刷新?
存取周期
假设DRAM内部结构排列成128X 128的形式,读/写周 期0.5us
2ms共2ms/0.5us = 4000个周期
有三个思路
思路一:每次读写完都刷新一行
→系统的存取周期变为1us
前0.5us时间用于正常读写
后0.5us时间用于刷新某行
思路二: 2ms内集中安排时间全部刷新
→系统的存取周期还是0.5us
有一-段时间专门用于刷新,
无法访问存储器,称为访存“死区”
思路三: 2ms内每行刷新1次即可
→2ms内需要产生128次刷新请求
每隔2ms/128= 15.6us - . 次
”
每15.6us内有0.5us的“死时间
这三种应该挺好理解(1、读出来直接刷新2、同一刷新3、在这个时间端内刷新就行)
这次主要是片选线( C S ‾ \overline{CS} CS低电平有效),因此有效时间的地址被读入,然后进行数据处理,但是会有一定的延后,因为需要进行数据输出和恢复
只读存储器,用来存放一些固定的指令(就好比电脑的启动指令之类的)
这是所有的存储器,可以分为高速缓冲存储器、主存储器和辅助存储器
这里只有半导体存储器具有易失性,也就是断电则数据消失;
速度是硬件自动完成的
容量是硬件+操作系统完成的
这是逻辑结构图
由于存储器是8K*1位,因此地址线有13位(因为8K= 2 13 2^{13} 213b),数据线是1根,因为只有1位,CS是片选线、WE是读写控制线
而PCU则是16位的地址线和8位的数据线
当然,由于数据线是8位,因此就需要8块存储器,所以模式就和上面相似,都用13位地址线去控制,然后提出各自的数据,放入数据线中
位扩展就是使用多个位(就比如这里使用了8个)
字扩展不同的是他用多的不是数据位,而是传入的数据字(就是传进去几个)
如上图所示,用13位控制地址,用13、14位来控制目标存储器
这里用的是线选法,也就是13、14只能是01或者10,也就是n条线n个信号(也可以用一根线控制两个,如果是1的时候可以是取非以后送入另一个,叫做译码片选法)
译码片选法:一个地址就是0xxx……,另一个就是1xxx……,这里就是n条线 2 n 2^{n} 2n个信号(也就是通过译码器实现)
这个就是字扩展
而低电平有效和高电平有效的差距就是是否取非
而是否工作是通过使能端进行实现的(使能端也分高低电平工作模式)
而实际中两种扩展可能会同时出现,因此就会出现
设CPU有16根地址线,8根数据线,井用MREQ作为访存控制信号(低电平有效),用WR作为读/写控制信号(高电平为读,低电平为写)。现有下列存储芯片: 1KX 4位RAM, 4KX 8位RAM, 8K x 8位RAM,2KX 8位ROM, 4K x 8位ROM, 8K X 8位ROM及74LS1 38译码器和各种门电路。画出CPU与存储器的连接图,要求:
1)主存地址空间分配: 6000H~ 67FFH为系统程序区; 6800H~6BFFH为用户程序区。
2)合理选用上述存储芯片,说明各选几片?
3)详细画出存储芯片的片选逻辑图。
(系统程序区用ROM,用户程序区用RAM)
步骤:
确认地址线、数据线,选择存储芯片
CPU数据线8根因此存储器就是8位
地址分配:6000H~67FFH→67FFH-6000H+1=800H, 8 ∗ 1 6 2 = 2 11 = 2 K 8*16^{2}=2^{11}=2K 8∗162=211=2K→用1片2K8位ROM(地址线11根)
6800~6BFFH→6BFFH-6800H+1=400H, 4 ∗ 1 6 2 = 2 10 = 1 K 4*16^{2}=2^{10}=1K 4∗162=210=1K→用2片1K4位RAM,进行位扩展(地址线10根)
地址线:
6000H ~67FFH→0110 0000 0000 0000 ~ 0110 0111 1111 1111
6800H~6BFFH→0110 1000 0000 0000 ~ 0110 1011 1111 1111
地址线就是后面11/10根,(当然是用多的,也就是11根)
然后就是用3位做译码器输入(因为这里是74LS138译码器,因此用3个)
还可以用前面两位作为使能端,另一个 M R E Q ‾ \overline{MREQ} MREQ作为使能端(当然这里需要同一种电平有效模式)
这里解释一下这个与门的作用:因为程序区的 A 10 A_{10} A10其实是没有用,并且必须是0才可以,因此就是和 Y 5 ‾ \overline{Y_{5}} Y5与后取非才行
用来提高存储器的工作速度(为了匹配上CPU的工作速度)
这是逻辑结构图,其实就是多了一套端口和一个CPU来进行读写,但是会有以下一些情况
1.两个端口不同时对同–地址单元存取数据。
2.两个端口同时对同一地址单元读出数据。
3.两个端口同时对同一地址单元写入数据。(这会导致写入错误,不知道哪个写入成功)
4.两个端口同时对同一地址单元,一个写入数据,另一个读出数据。(这回导致读出错误,可能是先写入,再读出)
解决的方法是:
做一个“忙”信号,当一边的端口被访问时,另一个端口不允许被访问
有两种形式,单体多字存储器和多体并行存储器
每个存储单元存储m个字,总线宽度也为m个字,一次并行读出m个字
指令和数据在主存内必须是连续存放的
(如要只要一列数据,就会导致读取时极大的浪费,很少使用)
每个模块都有相同的容量和存取速度。
各模块都有独立的读写控制电路、地址寄存器和数据寄存器。
它们既能并行工作,又能交叉工作。
多体并行存储体的编址模式
很明显其实就是高低位的区别,一个体号在前面,一个体号在后面,这也会导致一部分的区别
高低位会导致有所不同,最明显的就是连续取n个存储字的时候耗时不同
如上图所示就是高位交叉编址明显就是扩容的作用,而低位交叉编址可以起到加速的作用
例题:
流水线(低位交叉编址的多提存储器)
微观(计算题)
模块数m=4,存储周期为T,字长W,数据总线宽度为W,总线传输周期为r,连续存取n个字,求交叉存储器的带宽。
有m个存储体,存储周期为T,字长W,每隔r时间启动下一个存储体,连续存取n个字,求存储器的存取速率。
连续存取n个字耗时=T+(n-1)r (条件是m≥T/r,一般是m=T/r)
带宽= n ∗ W T + ( n − 1 ) r \frac{n*W}{T+(n-1)r} T+(n−1)rn∗W
宏观(概念题)
一个存储周期内。交叉存储器可以提供的数据量为单个模块的m倍。
(可以并行工作如总线宽度为mW时,可以同时取出长度为mW的数据)
空间局部性:在最近的未来要用到的信息(指令和数据),很可能与现在正在使用的信息在存储空间上是邻近的。
时间局部性:在最近的未来要用到的信息,很可能是现在正在使用的信息。
每次CPU从主存取出一个数据需要1000ns,做一个运算需要5ns,因此一个数据的处理就需要1000*2+5ns
而当使用一个Cache(高速缓存存储器)的时候,读入一块数据需要1000ns,CPU取出一个数据需要5ns,运算5ns以及写入5ns,因此一个数据的处理就需要1000+53=1015(但是他读入的是一块,如果是十个,其实十个的数据就是1000+35*10=1150ns,就会比只有主存的时间少很多)
属性:
命中率H:CPU欲访问的信息已在Cache中的比率
设一个程序执行期间,Cache的总命中次数为 N c N_{c} Nc,访问主存的总次数为 N m N_{m} Nm,则H= N c N c + N m \frac{N_{c}}{N_{c}+N_{m}} Nc+NmNc
缺失率M=1-H
设 t c t_{c} tc为命中时的Cache访问时间, t m t_{m} tm为未命中时的访问时间(这个其实是访问主存时间+访问Cache时间,因为我的教课书上对于 t m t_{m} tm的定义是访问主存时间,注意昂!!!)
Cache-主存 系统的平均访问时间 T a T_{a} Ta为
T a = H ∗ t c + ( 1 − H ) ∗ t m T_{a}=H*t_{c}+(1-H)*t_{m} Ta=H∗tc+(1−H)∗tm
例题:
[例3-2]假设Cache的速度 是主存的5倍,且Cache的命中率为95%,则采用Cache后 ,存储器性能提高多少(设Cache和主 存同时被访问,若Cache 命中则中断访问主存) ?
设Cache的存取周期为1,则主存的存取周期为5t
Cache和主存同时访问,不命中时访问时间为5t
故系统的平均访问时间为 T a T_{a} Ta=0.95t+ 0.055t= 1.21t(系统的效率 e = t / 1.2 t = 83.3 % e=t/1.2t=83.3\% e=t/1.2t=83.3%)
设每个周期可存取的数据量为S,
则存储系统带宽为S/1.21t,
不采用Cachel时带宽为S /51t,
故性能为原来的 S / 1.2 t S / 5 t = 5 t 1.2 t \frac{S/1.2t}{S/5t}=\frac{5t}{1.2t} S/5tS/1.2t=1.2t5t≈4.17倍,即提高了3.17倍。
若采用先访问Cache再访间主存的方式
不命中时,访问Cache耗时为t,发现不命中后再访问主存耗时为5t,总耗时为6t
故系统的平均访问时间为 T a = 0.95 ∗ t + 0.05 ∗ 6 t = 1.25 t T_{a}=0.95*t+0.05*6t=1.25t Ta=0.95∗t+0.05∗6t=1.25t(系统的效率 e = t / 1.25 t = 80 % e=t/1.25t=80\% e=t/1.25t=80%)
故性能为原来的 5 t 1.25 t = 4 倍 \frac{5t}{1.25t}=4倍 1.25t5t=4倍,即提高了3倍
主存当中一块数据是如何移到Cache上的
(1)空位随意放:全相联映射
他这个就是随意放进去,然后在放进去的位置前面放上他在主存里面的位置,在主存里面放在Cache里面的位置,相互对应(这个位置可以从地址位数里面表现出来)
主存地址对Cache的映射
(2)对号入座:直接映射
这个就类似于哈希表,按照一定的算法,将数据按位置放入,所以他需要在主存内的具体位置(防止撞车),然后在主存内放入Cache字块地址和字块内地址
这个就是主存地址对Cache的映射
举例:
假定数据在主存和Cache间的传送单位为512B
Cache大小 2 13 = 8 K B = 16 行 ∗ 512 B / 行 2^{13}=8KB=16行*512B/行 213=8KB=16行∗512B/行
主存大小 2 20 = 1024 K B = 2048 块 ∗ 512 B / 块 2^{20}=1024KB=2048块*512B/块 220=1024KB=2048块∗512B/块
如何对0220CH单元进行访问
化开为0000 0010 0010 1100
因为Cache传送单位是512B,所以Cache块内地址为9位
Cache大小是16*512,所以Cache行号为4位
剩余前面的7位都是主存地址,即标记
(3)按号分组,组内随意放:组相联映射
第一种方法对Cache的利用率很高,但是不是很好找
第二种方法很好找,但是由于算法的固定位置,可能对Cache的利用率不是很高
第三种直接采用了他们两种方法的优点,既分组,又相互映射
在Cache里面存入主存位置,在主存里面放入Cache组位置和具体地址(类似于2-1第二组第一个位置)
替换算法,就是Cache满了怎么办(或者就是相应的地址映射方式的可用空间满了,咋办)
写策略,Cache的内容被修改后与主存保持一致
替换算法
1.随机算法(RAND):随机地确定替换的Cache块。它的实现比较简单,但没有依据程序访问的局部性原理,故可能命中率较低。
2.先进先出算法(FIFO):选择最早调入的行进行替换。它比较容易实现,但也没有依据程序访问的局部性原理,可能会把-些需要经常使用的程序块( 如循环程序)也作为最早进入Cache的块替换掉。
3.近期最少使用算法(LRU):依据程序访间的局部性原理选择近期内长久未访问过的存储行作为替换的行,平均命中率要比FIFO要高,是堆栈类算法。
LRU算法对每行设置一一个计数器,Cache每命中一次, 命中行计数器清0,而其他各行计数器均加1,需要替换时比较各特定行的计数值,将计数值最大的行换出。
4.最不经常使用算法(LFU):将- -段时间内被访问次数最少的存储行换出。每行也设置一个计数器,新行建立后从o开始计数,每访问一次,被访问的行计数器加1,需要替换时比较各特定行的计数值,将计数值最小的行换出。
这四种方式应该挺好理解的,就是第一种方式极其傻,所以只需要了解,很少使用
例题:
设Cache由8个块构成,CPU依次访问的主存地址块号为: 4, 6, 12, 4, 8, 14, 22, 6, 4, 11, 5,2(十进制),求:
1)假设地址映射方式为全相联映射,在采用FIFO、LRU、LFY替换算法时,分别求Cache命中次数。
这就是依照顺序,把Cache中没有的放入,就是
放入4,放入6,放入12,命中4(因为4已经在Cache中,因此命中),放入8,放入14,放入22,命中6,命中4,放入11,放入5,这时候2没有地方放,因为满了,就要用到对应的替换算法
FIFO:先进先出,把4替换成2
LRU:近期最少访问,会出现歧义(是0的太多了,因此在操作系统中会有解释)
LFU:最不经常访问,会出现歧义(这个也是0的太多了)
因此命中次数就是3
2)假设地址映射方式为直接映射,求Cache命 中次数。
可以从图中看出直接映射的方式就是对8取模(并且替换也是直接替换)
因此过程如下
放入4(位置4),放入6(位置6),12替换4(位置4),4替换12(位置4),放入8(位置0),14替换6(位置6),22替换14(位置6),6替换22(位置6),命中4,放入11(位置3),放入5(位置5),放入2(位置2)
所以命中次数为1
3)假设地址映射方式为二路组相联映射,在采用FIFO、 LRU、 LFU替换算法时,分别求Cache命中次数。
二路组相联映射
就是两个块一组,根据题目就是分成4组,然后放入
因此过程如下
放入4(0-0),放入6(2-0),放入12(0-1),命中4,8替换(FIFO:4,0-0;LRU:12,0-1;LFU:12,0-1),放入14(2-1),22替换(FIFO:6,2-0;LRU、LFU),6替换/命中,4替换/命中,放入11(3-0),放入5(1-0),2替换
可以具体看出,命中次数因算法不同而不同,因此不做具体分析(其实就是懒)
这里当Cache的内容被修改的时候需要和主存保持一致,因此我们需要把Cache内容协会主存
有以下策略
命中时:
(1)写回法(write-back):当CPU对Cache写 命中时,只修改Cache的内容,而不立即写入主存,只有当此块被换出时才写回主存
(2)全写法(写直通法,write-through): 当CPU对Cache写命中时,必须把数据同时写入Cache和主存,一般使用写缓冲(write buffer)(当然会有一个写入缓存器,慢慢写入,释放CPU去工作;这也会有问题,如果写的太频繁,会导致写缓冲溢出)
未命中时:
(1)写分配法:把主存中的块调入Cache,在Cache中修改。搭配写回法使用
(2)非写分配法:只写入主存,不调入Cache,搭配全写法使用
设主存地址空间大小为1KB,按字节编址,Cache由8个块构成,每个Cache块大小为16B, CPU依次访问以下地址:
0001001110、1001110010、 0001001111、 001 1000010、0101001000、1011110010、1111010000、0011001001 (十进制为78、626、79、194、 328、 754、 976、201), 求:
1)假设地址映射方式为全相联映射,在采用FIFO、LRU、 LFU替换算法时,分别求Cache命中次数。
可以看出主存空间是1KB= 2 10 B 2^{10}B 210B,因此就是10位地址,然后Cache大小是16B,因此大小为 2 4 2^{4} 24,地址位数为4位
因此主存字块标记就是6位,字块内地址就是4位
因此每次放进去的有16B数据,不是我们理解时候的一位
可以看第一张图发现命中次数为2
2)假设地址映射方式为直接映射,求Cache命中次数。
直接映射的方式,这里需要有一个Cache字块地址,为什么是3位呢(因为每个Cache块地址是16B,但是有8块,所有还有一个 2 3 2^{3} 23),最后主存字块地址标记就是10-3-4=3
可以看出,第一个其实是用Cache字块地址来定位,标记是主存字块地址,放入的是16B的数据
3)假设地址映射方式为二路组相联映射,在采用FIFO、LRU、 LFU替换算法时,分别求Cache 命中次数。
这里和第二种方法不同的就是Cache字段地址变成了组地址,组地址长度就是(8/2=块数/x路)= 2 2 2^{2} 22,两位
最终填充也是如下所示
4)假设其它配置同3),采用写回法和直写法时,Cache的总容量分别为多少?
是一个逻辑模型
功能:用户给出一个地址,叫做虚地址或逻辑地址,虚拟存储器要给出该地址对应的数据
实现:由辅助硬件将虚地址映射到主存当中的某个单元,主存单元地址称为实地址或物理地址
虚拟存储器的种类:
(1)页式虚拟存储器
虚拟空间与主存空间都被划分成同样大小的页,主存的页称为实页,虚存的页称为虚页
这里其实就是一个映射关系,虚页号+页表基址寄存器可以合成一个页表项地址,经过查表得到实页号,然后通过页内地址进行数据的存取
(2)段氏虚拟存储器
段式虚拟存储器中的段是按程序的逻辑结构划分的,各个段的长度因程序而异。
虚拟地址分为两部分:段号和段内地址。
段表:每一行记录了与某个段对应的段号、装入位、段起点和段长等信息。
由于段的长度可变,所以段表中要给出各段的起始地址与段的长度。
这个和页式的区别就是,他没有直接对应的页内地址,所以他可以根据数据的长度来分配,而页式虚拟存储器的页大小固定,会造成浪费
(3)段页式虚拟存储器
把程序按逻辑结构分段,每段再划分为固定大小的页
主存空间也划分为大小相等的页
程序对主存的调入、调出仍以页为基本传送单位。
每个程序对应一个段表, 每段对应一个页表。(这边会因为页表过大而出现一个多级页表的概念,这块内容在操作系统里面会详细解释)
虚拟地址:段号+段内页号+页内地址
快表
页表、段表存放在主存中,收到虚拟地址后要先访问主存,查询页表、段表,进行虚实地址转换。(其实就是放在Cache中叫快表,放在主存中叫慢表)
放在主存中的页表称为慢表(Page)。
访问过程:
不过一般是两边同时访问,如果命中就中断对主存的操作
例题:
这里就直接上图了,因为文字比较苍白,顺便解释一下地址的由来
主存地址:实页号16位+页内地址12位
虚拟地址:虚页号20位+页内地址12位
首先是页内地址:4KB= 2 12 2^{12} 212B,因此页内地址就是12位
然后是实页号:256MB= 2 28 2^{28} 228B,因此实页号=28-12=18位
然后是虚页号:4GB= 2 32 2^{32} 232B,因此虚页号=28-12=20位
然后是地址变换,有效位表示表内的数据是否有意义,标记表示实页号,页框号表示虚页号,直接转换就行