很久没有在优快云上面发文章了,最近复习机组的存储器,感慨自己这两年把知识都还给老师了,便做个笔记好好整理一下,也有了一些新收获。转载请注明来源:https://leerw.github.io
存储系统和结构
存储系统
将两个或来两个以上速度、容量和价格各不相同的存储器用硬件、软件或硬件软件结合的方式连接起来形成存储系统。这个系统对应用程序员是透明,即从应用程序员角度来看,它是一个大的存储器,这个存储器的速度接近于速度最快的那个存储器,存储容量与容量最大的那个存储器接近或相等,单位容量的价格接近于最便宜的那个存储器
实际上,存储系统层次结构主要是体现在缓存-主存和主存-辅存这两个存储层次上
- 缓存-主存层次主要解决的是CPU和主存速度不匹配问题
- 主存-辅存层次主要解决的是存储系统的容量问题
存储器
主要结构是译码驱动电路、存储单元矩阵、读写电路和与CPU相连的地址线、数据线、片选线、读写允许线
半导体存储芯片的译码驱动方式有两种:线选法和重合法
主存的技术指标
- 容量: 按位或者字节计算,默认是值总的位数
- 速度
- 存取时间:启动一次存储器操作(读或者写)到完成所需的全部时间(蒋本珊:从地址传送给主存开始到数据能够被使用为止所用的时间间隔)
- 存取周期:存储器进行连续两次独立的存储器操作(读或写)所需的最小间隔时间
- 存储器带宽: 单位时间内存储器存取的i信息量, 存取周期/存取周期内访问的位数,决定了以存储器为中心的机器获取信息的传输速度,它是改善机器瓶颈的关键因素,为了提高存储器的带宽:
- 缩短存取周期
- 增加存储字长,使每个存取周期可以访问到更多的位数
- 增加存储体
你可能会纳闷,为什么没有价格这个指标,因为标题上写了是技术指标,so….
RAM
RAM是可读、可写的存储器,CPU可以对RAM的内容随机进行读写访问。
SRAM
SRAM是用触发器工作原理存储信息,因此即使信息读出后,仍然保持原有的状态不需要再生(再生是什么?实际上是相对于DRAM而言的,这里是对DRAM的比较,之后会讲到)。但是电源掉电之后,原存的信息丢失,是易失性半导体存储器
SRAM存储元
以A点的电位表示该存储元所存储的位,高电平为1,低电平为0
- 写:以写1为例,则置 I/O I / O 为高点平,当 I/O I / O 为高电平的时候, Y Y 地址选通为高电平,则 T7 T 7 导通, C2 C 2 为高电平, A1 A 1 为高电平,X地址线选通, A2 A 2 为高电平, T5 T 5 导通, A A 为高电平,导通, D1 D 1 为高电平, T8 T 8 导通, D2 D 2 被拉为低电平, B1 B 1 被拉为低电平,行选通则 B2 B 2 为高电平, T6 T 6 导通, B B 被拉为低电平,截止, T2 T 2 导通,保持被强迫写入的状态不变,从而将1保存起来。写0的情况类似,只是将I/O置为低电平而已。
- 读:读出存储元中保存的信息,实际上就是读 A A 和点的电平,由图可以看出, A A 点和位线相连, B B 点和连接,那么读的信息实际上就是 I/O I / O 线上的电平信息,当 X X 和选中这个单元之后,既可以让 I/O I / O 与 I/O¯ I / O ¯ 接着一个差分读出放大器,从其电流方向判断所读信息是1还是0,也可直接将 I/O I / O 接上一个读出放大器,根据其有无电流判断所读信息是1还是0.
SRAM的读写时序
tA
t
A
:读出时间:从给出有效地址后,经过译码电路、驱动电路的延迟、到读出所选内容,在经过
I/O
I
/
O
电路延迟后在外部数据总线上稳定地出现所读出的数据时间
DRAM
DRAM是靠电容存储电荷的原理来寄存信息,若电容上有足够多的电荷表示存1,若无电荷表示存0,电容上的电荷一般只能维持1~2ms,因此即使电源不掉电,存储的信息也会很快消失。所以需要在消失之前对所有存储单元进行恢复,也就是再生和刷新过程。
DRAM存储元
- 三管
读出时,先对 T4 T 4 置一个预充电信号打开 T4 T 4 ,那么读数据线就和 VDD V D D 一样具有高电平了,此时读选择线置高电平,打开 T2 T 2 ,若该存储元存的信息是1,也就是电容 Cg C g 有足够的电荷,那么 T1 T 1 将会打开,由于 T1 T 1 的源极接地,将会把读数据线拉成低电平,读出来的就是0,如果存储元存储的是0,即 Cg C g 上没有电荷,那么 T1 T 1 截止,读数据线上维持高电平,读出来的就是1。由此可见,读出的信息和存储元中真正存储的信息是反相的。
写入时,如果写1,那么将写数据线和写选择线置高电平,则 T3 T 3 导通,对 Cg C g 充电,也就是写1。 - 单管
单管DRAM是对三管DRAM的简化,读出时,字线置高电平, T T 导通,若上有足够的电荷,也就是存储的信息为1,电容放电,那么读数据线上会出现高电平,读出为1,若 Cs C s 上没有电荷,也就是存储的信息为0,数据线上无电流,读出为0,。由于无论读出的是1还是0,最终电容上都会因为放电或者原本就没有电荷致使读后没有电荷,所以是破坏性读出,需要对存储元进行恢复状态,也就是再生。注意,再生和刷新不一样,再生是对于单个存储元而言的,而刷新则是对存储矩阵中的某一行存储元而言的。
三管电路的缺点是管子多,占用的芯片面积大,优点是外围电路简单,读出过程就是再生过程,故在再生时不需要另加外部逻辑
单管电路的优点是管子少,占用的芯片面积少,集成度高,相对便宜,但因读1和读0时,数据线上的电平差别很小,需要有鉴别能力强的读出放大器配合工作,外围电路比较复杂
DRAM的读写时序
DRAM的刷新
为什么需要刷新?
DRAM存储单元是通过栅极电容上存储的电荷来暂存信息的,由于电容上的电荷会随着时间的推移被逐渐泄漏掉,因此每隔一段时间必须向栅极电容补充一次电荷,这个过程就叫做刷新。
三种刷新方式:
1. 集中刷新: 读写操作时不受刷新工作的影响,系统的存取速度较高,但是有死区,而且存储容量越大,死区越长
2. 分散刷新:没有死区,但是加长了系统的存取周期,降低了整机的速度,且刷新过于频繁,没有充分利用所允许的最大刷新间隔
3. 异步刷新:虽然也有死区,但是比集中方式的死区小得多,而且减少了刷新次数
对赖老师做的一个比喻印象深刻,假设人有24颗牙,人刷一颗牙需要1分钟,那么集中刷新就是一天内,前23小时36分钟在正常地吃,最后的24分钟一次性集中刷完牙,但是在这24分钟内没办法吃东西,对于没一颗牙来说,死区就是24分钟;分散刷新就是吃一分钟的东西,刷一颗牙,那么48分钟就可以把24颗牙给刷一遍,但是一天要刷太多遍了;而异步刷新就是每个小时刷一颗牙,那么一天24小时刚好把24颗牙刷一遍,对每一个牙来说,死区就是一分钟
DRAM和SRAM的区别
- DRAM存储元采用栅极电容存储信息,SRAM存储元利用双稳态触发器存储信息
- DRAM集成度高,功耗小(MOS管少),但存取速度慢(电容充放电没有触发器翻转快),一般用来组成大容量主存系统;SRAM的存取速度快,但集成度低,功耗也较大,所以一般用来组成高速缓冲存储器和小容量主存系统
- SRAM芯片需要有片选信号;DRAM芯片可以不设片选信号,而用行选通信号和列选通信号兼做片选信号
- SRAM芯片的地址线直接与容量相关,而DRAM芯片常采用地址复用技术,以减少地址线的数量,所以一般DRAM的地址引脚数为地址位数的一半,分时复用,先传一半的行地址,再传一半的列地址,当引脚数增加一个,地址位数增加两位,DRAM芯片的容量是原来的4倍
ROM
ROM
MOS型掩膜ROM,采用重合法进行驱动,行选择线和列选择线交叉处有MOS管,也可没有。用行、列交处是否有耦合元件MOS管,即可区分出原存的是1还是0,生产时就已经写死了,制成后不可能改变原行、列交叉处的MOS管是否存在,所以,用户是无法改变原始状态的。
PROM
Programmable ROM,可实现一次性编程的只读存储器。
EPROM EEPROM
Erasable Programmable ROM,可擦除可编程只读存储器,它可以由用户对其所存信息作任意次的改写。EPROM的改写可用两种方法,一种用紫外线照射,但是擦除时间比较长,而且不能对个别需改写的单元进行单独擦除和改写。另一种方法是用电气方法将存储内容擦除,然后重写,也就是电可擦除,EEPROM。
Flash
快擦型存储器,性能价格比好、可靠性更高的可擦写非易失性存储器,既有EPROM价格便宜、集成度高的特点,又有EEPROM的电可擦除重写的特性。适合作为一种高密度、非易失的数据采集和存储器件。
Cache
cache存储器的目的是使存储器的速度逼近可用的最快存储器的速度,同时以较便宜的半导体存储器的价格提供一个大的存储器容量
cache的设计要素:
1. cache地址
- 逻辑地址
- 物理地址
2. cache容量
3. 映射功能
- 直接相联
- 全相联
- 组相联
4. 替换算法
- 最近最少使用(LRU)
- 先进先出(FIFO)
- 最不经常使用(LFU)
- 随机
5. 写策略
- 写直达法
- 写回法
- 写一次
6. 行大小
7. cache数目
- 一级或两级
- 统一或分立
原理
局部性:CPU从主存取指令或者取数据,在一定时间内,只是对主存局部地址区域的访问。这是因为指令和数据在主存内都是连续存放的,并且有些指令和数据往往会被多次调用(如子程序、循环程序和一些常数),即指令和数据在主存中的地址分布不是随机的,而是相对的簇聚,使得CPU在执行程序时,访存具有相对的局部性,这就成为程序访问的局部性。
局部性分为两种,时间局部性和空间局部性:
1. 时间局部性
2. 空间局部性
比如这样的一个求数组和小程序:
int sumvec(int v[N] {
int i, sum = 0;
for (i = 0; i < N; i++) {
sum += v[i];
}
return sum;
)
对于变量v,在for循环中以步长为1进行访问,有很好的空间局部性,一般来说,随着步长的增加,空间局部性下降,v的时间局部性比较差,因为v中的每一个元素在循环中只访问了一次,而相对地sum的时间局部性就比较好,但是空间局部性很差。
总之,评价一个程序中局部性的简单原则是:
1. 重复引用同一个变量的程序有良好的时间局部性
2. 对于步长为k的引用模式的程序,步长越小,空间局部性越好,具有步长为1的引用模式的程序有良好的空间局部性,在存储器中以大步长跳来跳去的程序空间局部性会很差
3. 对于取指令来说,循环有很好的时间和空间局部性。循环体越小,循环迭代次数越多,局部性越好
原理: 当CPU试图访问主存中的某个字时,首先检查这个字是否在cache中,如果在,即为命中,则把这个字传送给CPU,如果不是,即为不命中,则将主存中包含这个这个字的固定大小的块读入cache中,同时将这个字传送给CPU。因为访问的局部性,当把某一块数据存入cache,以满足某次存储器的访问,CPU将来还很有可能访问同一存储位置或该数据快中的其他字。
地址映射
考虑一个计算机系统,其中每个存储器地址有
m
m
位,形成个不同的的地址,这样一个机器的高速缓存被组织为一个
S=2s
S
=
2
s
个高速缓存组的数组,每个组包含
E
E
个高速缓存行,每个行是由一个字节的数据块组成的,一个有效位指明这个行包含的数据是否有意义(有些教材中还会包有一个脏位,指明该行的数据是否是脏数据),还有
t=m−(b+s)
t
=
m
−
(
b
+
s
)
个标记位(是当前块的存储地址的子集),他们唯一地标识存储在这个高速缓存行中的块。
以上将cache概括为一个四元组
<S,E,B,m>
<
S
,
E
,
B
,
m
>
<script type="math/tex" id="MathJax-Element-136">
</script>
直接相联: E=1 E = 1
m位的地址被划分为了三个部分,高 t t 位是标记位,中间位是组索引位,低 b b 位是快内偏移索引位
- 组选择:cache从的地址中间抽取
s
s
位作为cache组的索引,选通这位对应的cache组
- 行匹配:在直接映射中,每个cache组中只有一个高速缓冲行,所以当且仅当这一组中唯一的高速缓冲行中的标记与 w w 中的标记,也就是的高 t t 位相匹配时,这一行中包含的一个匹配
- 字抽取:块偏移位,也就是 w w 中的低位,向我们提供了所需要字的第一个字节的偏移,所以命中,选择出了起始字节
全相联: S=1 S = 1 , E=C/B E = C / B
因为只有一个组,所以 m m 位的地址被分为了两个部分,高位的标记位和低 b b 位的块偏移索引位
- 高速缓冲行的有效位必须被设置
- 高速缓冲行的标记位必须匹配地址的标记位
- 高速缓冲命中,根据块内偏移,选出起始字节
组相联:
因为直接相联不够灵活,每个主存块只能固定地对应某个缓冲块,即使cache中有许多空闲的位置也不能占用,使缓存的存储空间得不到充分利用,而且,如果程序恰好要重复访问对应同一缓存位置的不同主存块,就要不停地进行替换,从而降低了命中率;全相联需要的逻辑电路很多,成本较高;所以组相联是直接相联和全相联的一个折中
组相联同样是将 m m 位的地址划分为三个部分,高 t t 位的标记位,中间位的组索引位,低 b b 位的块内偏移索引位
- 组选择,根据中间的位选中cache的某一组
- 行匹配,选中的这一组中有 E E <script type="math/tex" id="MathJax-Element-162">E</script>行,根据有效位和标记位匹配到其中的一行
- 字抽取:高速缓存命中,然后块偏移选择起始字节
替换算法
上面我们讲的都是直接命中的情况,那么在cache中没有找到我们要访问的字,也就是没有命中的情况时,该怎么办呢?
一旦cache行被占用,当新的数据块需要装入cache时,原存在的块必须要被替换掉
对于直接相联,任意主存块对应的cache都只有唯一的行可以使用,没有选择的可能。直接替换掉就可以了。
而对于全相联和组相联则需要一种替换算法决定那一块被替换掉
- LRU:最近最少使用
- FIFO:先进先出
- LFU:最不经常使用
- 随机
写策略
为了保持cache和主存的数据一致性问题,常用的有两种写策略:
- 写直达法:写入数据时,既写入cache又写入主存,它能随时保证主存中的数据和cache中的数据一致,但是增加了访存次数
- 写回法:增加一个脏位,只更新cache中的数据,当更新操作发生时,需要设置与该行相关的脏位,当一个块被替换时,当且仅当脏位被置位时才将它写回主存,可以减少访存的次数,但在读操作cache失效时要发生数据替换,引起被替换的块写回主存的操作,增加了cache的复杂性
磁盘
下面是一个youtube上面一个希捷公司的视频,你可能无法看到,但是我强烈推荐你去看一看,很直观详细地解释了磁盘。
width="560" height="315" src="https://www.youtube.com/embed/NtPc0jI21i0?rel=0" allowfullscreen="">《未完待续》