[计组]3.存储系统
存储系统
主存储器的基本组成
基本的半导体元件及原理
一个主存储器可分为 存储体、MAR地址寄存器、MDR数据寄存器 三个部分,这三个部分会在时序控制逻辑得控制下有条不紊得进行工作
而一个存储体 由多个存储单元构成
而每个存储单元 又由多个存储元构成,一个存储元可以存储一位 0 或 1
一个存储元涉及到两个半导体元器件:
- MOS管:MOS管可理解为一种电控开关,输入电压达到某个阈值时,MOS管就可以接通
- 电容:一个电容有两个金属板和中间的绝缘体构成
- 我们可以通过电容是否保存了电荷来判断0还是1
- 若我们规定有电流是1,无电流是0,则通过合理的链接多个存储元,即可输入输出多个二进制位的信息了
这边需要注意,多个存储元组成的存储单元就是存储字,而它与字节是不同的,一个字节一定等于8bit,而一个存储字等于多少比特主要看它的存储体的结构
存储芯片的基本原理
如果通过地址来决定我们要读或写哪个存储字呢?
这就涉及到了译码器的作用
- 译码器通过对MAR中的地址处理,一个地址信号会被转换成译码器的高电平信号
- 当字选线(上图红线)被接通后,我们可以通过数据线(上图绿色)把每一位的二进制信息传送到MDR当中
- 然后CPU会通过数据总线从一个MDR中取走这一整个字的数据,
- 我们还需要增加一个控制电路,用于控制MAR,译码器,MDR
- 由于我们传送的是电信号,所以只有当电信号稳定时,才会移交下一步处理
我们将其抽象后就变为下图这样
为了保证电信号稳定,我们通常会在译码器后面添加一个驱动器
另一方面,存储芯片还需要对外提供片选线和读写控制线
- 驱动器是一个放大电信号的部件
- 读写信号包括了控制电路和字选线和数据线
- 一个存储芯片需要接收来自外界的地址信息,这个地址信息通常是通过CPU通过地址总线给传过来的
- 需要通过数据线进行数据传输
- 还需要通过片选线来判断这个芯片此时是否可用
- 片选线对应则内存条中存储芯片,一个内存条中有多个存储芯片,那么片选线就用于选择用哪个存储芯片工作
- 需要提供读写控制线,这个读写控制线可以一条或两条
- 存储芯片下方有金属引脚,其中每一条线对应一个金属引脚
- n位地址对应n条地址线
寻址技巧
SRAM和DRAM
SRAM和DRAM是两种特殊的存储芯片
- DRAM:Dynamic Random Access Memory 即动态RAM
- DRAM芯片:使用栅极电容存储信息
- DRAM用于主存
- SRAM:Static Random Access Memory 即静态RAM、
- SRAM芯片:使用双稳态触发器存储信息
- SRAM用于Cache高速缓存器
- 核心区别:存储元不一样
栅极电容
栅极电容是DRAM芯片中的存储元件,DRAM通过栅极电容的充放电来存储和读取信息的,DRAM主要用于制造主存
- 如果存储的信息是二进制1:则电容内存储了电荷
-
如果存储的信息是二进制0:则电容内未存储电荷
双稳态触发器
双稳态触发器是SRAM芯片中的存储元件,它具有6个MOS管和两根数据线用于读出0或1,当字选线被接通后,其通过A阀和B阀的电平高低来决定读或写入0还是1
双稳态
- 若读、写入1:A高B低
- 若读、写入0:A低B高
栅极电容与双稳态触发器的区别
读出时
- 栅极电容读出时:在读出数据1时,实际上是给电容放电,而电容放电会导致信息被破坏,是破坏性读出,读出后应有重写操作,也称为再生
- 双稳态触发器读出时:读出数据,触发器状态保持稳定,是非破坏性读出无需重写
成本与功耗
介于上述两存储元件读出时的区别,栅极电容的读写速度更慢,而双稳态触发器的读写速度更快
而通过图片也能得知,栅极电容只需一个MOS管,而双稳态触发器则需要六个MOS管,则
- 栅极电容:每个存储元制造成本更低,集成度高,功耗低
- 双稳态触发器:每个存储元制造成本更高,集成度低,功耗大
是否刷新
- 栅极电容:电容内的电荷只能维持2ms,即便不断电,2ms后信息也会消失,所以2ms之内必须刷新一次(给电容充电)
- 双稳态触发器:只要不断电,触发器的状态就不会改变
DRAM与SRAM的对比
DRAM的刷新
-
刷新周期:一般为2ms
-
刷新数量:以行为单位,每次刷新一行存储单元
-
为什么采用行列地址:减少选通线的数量
-
如何刷新:有专门的刷新电路,读出一行信息后重新写入,占用1个读/写周期
-
什么时刻刷新:
- 分散刷新:每次读写完都刷新一行
- 集中刷新:2ms内集中安排时间全部刷新,在刷新时期内无法访问存储器,这个时期称为访存”死区“
- 异步刷新:2ms内每行刷新1次即可
*假设DRAM内部结构排列成128 128 的形式,读/写周期0.5微秒**
2ms共2ms/0.5微秒 = 4000个周期,则三种刷新方案如下所示
DRAM的地址线复用技术
分两次传入行、列地址,可使得地址线更少,芯片引脚更少
先接收行地址、再接收列地址
只读存储器ROM
- RAM芯片——易失性,断电后数据消失
- ROM芯片——非易失性,断电后数据不会丢失
常用ROM芯片
- 很多ROM芯片虽然名字是“Read-Only”,但很多ROM也可以“写”
- 闪存得写速度一般比读速度更慢,因为写入前要先擦除
- RAM芯片是易失性得,ROM芯片是非易失性得,很多ROM也具有“随机存取”的特性
计算机内重要的ROM
计算机的主存是用来存放一系列的指令和数据的,CPU的作用是到主存中取指令并执行指令
然而主存RAM芯片是一种易失性的芯片,关机后,RAM内的所有数据都会丢失
也就是说,当我们再次开机的时候,需要把操作系统还有相关的指令数据,重新调入到主存中
- 而在开机时,主存中完全没有数据没有指令,所以CPU就需要从主板上的BIOS芯片(ROM)来读取开机所需要的指令
- 在BIOS芯片中,存储了"自举装入程序",负责引导装入操作系统(将辅存中的操作系统放入主存)
- 在逻辑上,BIOS虽然是集成在主板上的ROM芯片,但我们应该把它看作主存的一部分
- 也就是说,RAM(内存)和ROM(BIOS)二者结合,才是一套完整的主存,且二者统一编址
主存储器与CPU的链接
我们知道 单块存储芯片需要对外暴露:
- 数据总线:与CPU建立链接用于传输数据,
- 地址总线:与CPU建立链接用于传送访问地址
- 控制总线:片选线与读、写控制线,CPU通过控制总线发送控制信号
字扩展:扩展主存的字数,使得存储能力增加
位扩展:扩展主存的字长,使得读写速率增快
存储芯片的输入输出信号
位扩展
- 如果数据总线宽度大于存储芯片的字长,CPU传输能力就会有冗余
- 我们可以通过链接多块存储芯片来扩展主存字长,让其与CPU的数据总线宽度一样
抽象出来后,就成了下面这样
字扩展
字扩展的方法可以使得存储容量的增加,增加了CPU的寻址能力
线选法
- 使用一根专门的地址线,作为片选信号,链接存储芯片的片选线,n条线可以扩展n个片选信号
- n条线对应n个选片信号
- 电路简单
- 地址空间不连续
译码片选法
- 使用一个译码器来处理CPU的高位地址部分,将其转换为十进制来决定使用哪个存储芯片
-
n条线对应2^n个选片信号 -
电路复杂
- 地址空间可连续
字位同时扩展
译码器
- CPU可以使用译码器的使能端控制片选信号的生效时间
- 只有当译码器的使能信号有效时,其才能正常工作
- 常见带多个使能信号的译码器:74ls138,也是下图中的逻辑结构
- MREQ:主存储器请求的信号
双端口RAM与多模块存储器
- 存取周期:可以连续读/写的最短时间间隔
- DRAM芯片的恢复时间比较长,有可能是存取时间的好几倍
- 如存取时间为r,存取周期为T,则T=4r,其中3r都是恢复时间
- SRAM的恢复时间比较短
双端口RAM
- 作用:优化多核CPU访问一根内存条的速度
- 需要有两组完全独立的数据线、地址线、控制线
- CPU、RAM中也要有更加复杂的控制电路
双端口RAM可以进行:
- 两个端口同时对不同的地址单元存取数据
- 两个端口同时对统一地址单元读出数据
双端口RAM不可以进行:
-
两个端口同时对同一地址单元写入数据(产生写入覆盖冲突)
-
两个端口同时对同一地址,一个写入数据,一个读出数据(产生读取错误)
-
解决方法:置”忙“信号为0,由判断逻辑决定暂时关闭一个端口(即被延迟)
未被关闭的端口正常访问,被关闭的端口延长一个很短的时间再被访问
-
多体并行存储器
- 即便对于一个单核的CPU,CPU的读取速度也比内存条快得多,而内存每一次读取之后有需要一段恢复时间,但CPU想要连续读取一些数据的时候,就必须等待这段恢复时间,如何解决这个问题就可以用多体并行存储器
- 我们可以把其看作四根(多根)内存条
- 这就分为了高位交叉编址的多体存储器与低位交叉编址的多体存储器
- 高位交叉:采用CPU传入地址的高位bit来判断访问哪个存储体
- 低位交叉:采用CPU传入地址的低位bit来判断访问哪个存储体
- 看这种情况,假设每个存储体的存取周期为T,存取时间为r,假设T=4r
- 对于高位交叉编制,如果说我们需要连续访问一段内存的话,我们在读取完第一个存储字后,需要等待该存储体的恢复时间后才能继续访问,采用高位交叉存储,相当于单纯的扩容
- 而对于低位交叉编制,则访问完第一个存储字后,直接访问的是下一个存储体,则不需要等待第一个存储字所属存储体的恢复时间
- 在我们实际应用当中,有很多数据就是存放在地址连选的空间,比如说数组
- 既然低位交叉存储能使得我们的读取效率变高,我们应该取多少个体呢?
- 采用”流水线“的方式并行存储(宏观上并行,微观上串行),宏观上,一个存储周期内,m体交叉存储器可以提供的数据量为单个模块的m倍
- 存取周期为T,存取时间为r,为了使流水线不间断,应该保证模块数m>=T/r
多模块存储器
小结
番外:双通道存储
Cache的基本概念和原理
之前我们知道可以通过双端RAM、多模块存储器提高存储器的工作速度,但即便是优化后,速度与CPU的差距依然很大,这个时候,我们可以利用Cache来缓和CPU和主存之间的速度矛盾
Cache的工作原理
- 我们先看没有Cache的情况
- 在打开软件的时候,需要将辅存中的软件以及相关数据调入主存,然后CPU能一条一条的从主存当中读取指令以及相关数据
- 但主存相对于CPU来说,是很慢的,这个时候就会导致CPU的执行效率被内存的读取速度所拖累
-
- 模拟一个场景,假设我们现在利用微信在和女朋友聊天,这个时候若CPU是直接从内存当中一条一条读取指令以及相关速度,你的视频就会卡出天际,然后你的女朋友就会生气,你就会很难受
- 那么如何解决呢?我们可以将视频聊天相关的数据以及代码复制一份,放入一个更高速,读写速度更快的Cache当中
- 这个时候,CPU就可以从Cache当中读取指令以及速度,大大缓和了CPU和内存直接的速度矛盾
- 实际上,Cache被集成在CPU内部,Cache用SRAM实现,速度块,成本高
局部性原理
- 空间局部性:在最近的未来要用到的信息(指令和数据),很可能与现在正在使用的信息在存储空间上是邻近的
- 例如:行优先遍历二位数组,我们知道在C语言中,二维数组每一行的数据存储是连续的,这满足了空间局部性、
- 指令和数据在内存里面通常是顺序存储的,而我们访问这些数据的时候通常是需要顺序访问
- 时间局部性:在最近的未来要用到的信息,很可能是现在正在使用的信息
- 例如:C语言当中的循环结构,循环累加时,加法指令在未来很短的时间内会被再次访问
- 在程序中会有大量的循环结构,除了对指令的访问有时间局部性外,有时候对某些变量也具有时间局部性
- 基于局部性原理,不难想到,可以把CPU目前访问的地址"周围"的部分数据放到Cache中
- 接下来CPU就可以直接从Cache中读取这些数据!
性能分析
-
设t_c为访问一次Cache所需时间,t_m为访问一次主存所需时间\\ 命中率H:CPU欲访问的信息已在Cache中的比率\\ 缺失率M:M=1-H\\
-
下列给出Cache—主存 系统的平均访问时间,假设平均访问时间为t,则:
-
先访问Cache,若Cache未命中再访问主存
t=Ht_c+(1-H)(t_c+t_m) - 同时访问Cache和主存,若Cache命中则立即停止访问主存
t=Ht_c+(1-H)t_m
例题:
常见问题
- 基于局部性原理,不难想到,可以把CPU目前访问地址“周围”的部分数据放到Cache中,如何界定"周围"?
- 将主存的存储空间“分块”,如:每1KB为一块,主存与Cache之间以“块”为单位进行数据交换
- 操作系统中,通常将主存中的“一个块”也称为“一个页\页面\页框”,Cache中的“块”也称为“行”
小结
Cache和主存的映射方式
如何区分Cache与主存的数据块对应关系?
- 全相联映射:主存块可以放在Cache的任意位置
- 直接映射:每个主存块只能放到一个特定的位置
- Cache块号=主存块号%Cache总块数
- 组相联映射:Cache块分为若干组,每个主存块可放到特定分组中的任意一个位置
- 组号=主存块号%分组数
- 给每个Cache块增加一个“标记”,记录对应的主存块号,同时需要增加有效位,代表该块是否有效
假设某个计算机的主存地址空间大小为256M,按字节编制,其数据Cache有8个Cache行,行长为64B
全相联映射(随意放)
访存操作
- 对比Cache所有的标记位,找到对应的主存块号
- 若找到,且有效位为1,则命中,访问Cache中的块内地址
- 若没找到,或有效位为0,则正常访问主存块
直接映射(只能放固定位置)
-
缺点:若其对应位置有主存块,则不能使用,这缩减了Cache的使用度
-
若Cache总块数=2^n,则主存块号末尾n为直接对应它在Cache中的位置
访存操作
- 根据主存块的行号确定Cache行
- 若主存块号除去行号与标记相对应,且有效位为1,则命中
- 若不对应,或有效位为0,且正常访问主存
组相联映射(可放特定分组)
访存操作
- 根据后几位确定所属分组号
- 匹配前几位,若对应且有效位为1,则命中
- 若不对应或有效位为0,则正常访问主存
小结
Cache的替换算法
Cache很小,主存很大,如果Cache满了怎么办?
- 随机算法(RAND,Random):若Cache已满,则随机选择一块替换
- 先进先出算法(FIFO):若Cache已满,则替换最先被调入的Cache块
随机算法(RAND)
- 核心思路:若Cache已满,则随机选择一块替换
- 缺点:实现简单,但完全没考虑局部性原理,命中率低,实际效果不稳定
先进先出算法(FIFO)
- 核心思路:若Cache已满,则替换最先被调入的Cache的块
- 缺点:未考虑局部性原理,最先调入的Cache块也有可能被频繁访问的
近期最少使用算法(LRU)★
- 核心思路:为每个Cache设置一个计数器,用于记录每个Cache块已经有多久没被访问,当Cache满后替换计数器最大的
- 缺点:若被频繁访问的主存块数量>Cache行的数量,则会不断地进来、出去,发送“抖动”
计数器的变化
- 命中时,所命中的行的计数器清零,比其低的计数器加一,其余不变
- 未命中且还有空闲时,新装入的计数器置零,其余非空闲行全加1
- 未命中且无空闲行时,计数值最大的行的信息块被淘汰,新装行的计数器置零,其余全部加1
最不经常使用算法(LFU)
- 核心思路:为每一个Cache块设置一个计数器,用于记录每个Cache块被访问过几次,当Cache满后替换计数器最小的
- 缺点:未遵循局部性原理,曾经被多次访问的块在未来并不一定用到,这会导致计数器很大,未来一段时间无法被替换
小结
Cache写策略
CPU修改了Cache中的数据副本,如何确保主存中数据母本的一致性?
- 注意:每次访问主存块一定会被调入Cache
- 读不会修改Cache内的副本,只有写有可能回修改
写命中的情况
写回法(write-back)
- 写回法(write-back):当CPU对Cache写命中时,只修改了Cache的内容,而不立即写入主存,只有当此块被换出时才写回主存
- 缺点:减少的访存次数,但存在数据不一致的隐患
全写法(写直通法)
- 全写法(写直通法,write-through):当CPU对Cache写命中时,必须把数据同时写入Cache和主存,一般使用写缓存(SRAM芯片)
- 写缓存:采用SRAM制造,可看作FIFO队列,CPU在将数据写入Cache的同时,也会同时写入写缓存内,当写入完毕,会有专门的电路将写缓存中的信息逐一写入主存中,这样提高了CPU的使用率
写不命中的情况
写分配法(write-allocate)
- 写分配法(write-allocate):当CPU对Cache写不命中时,把主存中的块调用Cache,在Cache中修改,通常搭配写回法使用
- 写回法(write-back):当CPU对Cache写命中时,只修改了Cache的内容,而不立即写入主存,只有当此块被换出时才写回主存
非写分配法(not-write-allocate)
- 非写分配法(not-write-allocate):当CPU对Cache写不命中时只写入主存,不调入Cache,搭配全写法使用
- 全写法(写直通法,write-through):当CPU对Cache写命中时,必须把数据同时写入Cache和主存,一般使用写缓存(SRAM芯片)
- 此操作代表只有”读“未命中的情况,才调入Cache
多级Cache
小结
页式存储器
建议搭配OS的第三章结合复习
-
页式存储系统:一个程序在逻辑上被分为若干个大小相等的”页面“
- ”页面“大小与”块“的大小相同,每个页面可以离散的放入不同的主存块中
虚地址与实地址
- 虚地址(逻辑地址):程序员视角看到的地址
- 实地址(物理地址):实际在主存中的地址
看这个情况,我们自己写了某个程序,大小为4kb,操作系统将为程序分页(操作系统完成,我们不可见),每页会被离散的放到主存的不同地方
由于程序是我们自己写的,我们肯定可以知道其地址范围是多少
这就是程序员视角
既然这个程序是我们自己写的,我们肯定可以知道其中一些数据存放的位置
对于12bit的逻辑地址来说,我们可以用后面10个bit来表示每个页面的页内地址,前面两个bit来表示这个逻辑地址属于那个页面
- 对于x来说,其前面两个bit是00,这代表其存放在0号页面当中
- 对于y来说,其前面两个bit是11,这代表其存放到3号页面当中
- 主存块号+页内地址=物理地址
综上所述,对于我们程序员,我们只能给出这个程序的逻辑地址,而操作系统会将这个逻辑地址映射为其实际的物理地址
- 那么这个转换过程最重要的就是把逻辑页号转换成与之相对应的主存块号
页表
- 为了记录逻辑页号到主存块号的对应关系,操作系统对建立一张页表,页表中记录了逻辑页号与主存块号的映射关系
- 操作系统在执行及其指令中,使用的是”逻辑地址“,因此需要通过”页表“将逻辑地址转为物理地址
- 页表相关的数据存放在主存中,CPU在进行地址转换的适合需要查询页表,意味着CPU需要进行访存操作
- 页表是一行一行存储的,我们把每一行叫做页表项
如果系统采用的是页式存储,CPU执行指令的时候,会指明需要访问的是那个逻辑地址
- 逻辑地址又分为页号和页内地址,这个页内地址的大小取决于页面的大小
- CPU里面还包含着页表基址寄存器,这个寄存器包含了页表的首地址
- 页表项的大小相同,只要给定了基地址即可访问任何一个页表项
TLB快速页表
- 块表(TLB)采用的是SRAM实现,所以速度很快
- 初始情况块表为空
- 每次到页表中命中后,会将该页表项加入快表
- 快表加快了地址转换的速度
- 快表为相联存储器,CPU可以通过内容来寻访
- 块表加快了地址转换速度,而Cache是加快了访存速度
- 快表也包含了替换算法
小结
a