一. 计算机习题概述
计算机概述:计算机系统硬件软件
硬件:计算机的物理性能,决定计算机性能天花板在哪
软件:计算机的虚拟性能,决定硬件性能可以发挥到什么程度。可分为系统软件和应用软件:
- 系统软件:用来管理整个计算机系统。如:操作系统,DBMS,服务程序等。
- 应用软件:按任务需要编制成的各种程序。如:微信,QQ等。
计算机功能好坏取决于"软","硬"件功能的总和。计算机组成原理重点讨论硬件内容。
计算硬件发展:

计算机目前的发展趋势:一方面向更微型、多用途方向发展;另一方面向更巨型,超高速方向发展。
1.计算机硬件的基本组成
1.1 冯诺依曼结构
提出设想:
提出"存储程序的概念":将指令以二进制的形式先输入计算机的主存储器,然后按其在存储中的首地址执行程序的第一条指令,以后就按该程序的规定顺序执行其他指令,直到程序执行结束。

冯诺依曼机
处理步骤:
- 输入设备:将信息转化成机器能识别的形式
- 存储器:存放数据和程序
- 运算器:算术运算和逻辑运算
- 控制器:指挥程序运行
- 输出设备:将结果输出
在计算机系统中,软件和硬件在逻辑上是等效的。对于同一个功能,既可以用软件实现也可以用硬件实现,但用软件实现成本低,效率也低;而用硬件实现成本高,效率也高。如:对于乘法运算,可以设计一个专门的硬件电路实现乘法运算也可以用软件的方式,执行多次加法运算来实现。
冯诺依曼计算机的特点:
- 计算机由五大部件组成
- 指令和数据以同等地位存于存储器,可按地址寻访
- 指令和数据用二进制表示
- 指令由操作码(如:加减乘除)和地址码组成
- 存储程序:会提前将指令和程序存放到存储器中
- 以运算器为中心:输入输出设备与存储器之间的数据传送通过运算器完成。由于运算器还要完成数据中转操作,所以执行效率会降低。
1.2 现代计算机结构
现代计算机结构本质上是冯诺依曼结构的优化。
优化后的冯诺依曼结构:

传统冯诺依曼结构是以运算器为中心,数据传输都需要通过运算器作为中转。而现代计算机通常以存储器为中心,同时运算器和控制器之间的联系也十分紧密,所以将其结合起来就是CPU。即CPU运算器控制器。
现代计算机结构:

设备会直接和主存储器进行数据交换。
控制器控制运算器进行数据操作(如:加减乘除),另外也会控制主存储对CPU的读写,及输入输出设备的停止和启动。
主存储器会和CPU之间进行数据交换:一种是参与运算的数据(如:之类的变量)。另一种是放在控制器中的指令,指令会由控制器解析其含义。
主存储器和CPU统称为主机。
现代计算机硬件结构:

上面比较混淆的是主存和辅存:这两个都是存储器,主存就是主存储器(如:运行内存),包含在主机内;而辅存指辅助存储器(如:机械硬盘),属于设备。
现代冯诺依曼结构
总结:
2.各个硬件功能概况
2.1 主存储器
主存储器由三个部分构成:
- 存储体:相当于"货架"部分,存储二进制数据,并根据发送的数据地址,取出数据。
- MAR(存储地址寄存器):CPU将想要的数据地址存放到MAR中,即数据地址。
- MDR(存储数据寄存器):将存储体中取出的数据,写入MDR中,CPU可以通过数据线路从MDR中拿走数据。

存储步骤是:CPU将数据地址放入MAR中,将数据放入MDR中,之后存储体根据CPU指令将MDR中数据放入MAR指定的存储体地址中。
读取步骤是:CPU将读取地址放入MAR,存储体根据CPU指令将MAR中对应地址在存储体中找到并写入MDR中,CPU再从MDR中读取数据。
重点在存储体上:数据按地址存放在存储体中。
存储体结构:

存储单元:每个存储单元存放一串二进制代码。
存储字(word):存储单元中二进制代码的组合。
存储字长:存储单元中二进制代码的位数(如:8bit,16bit,32bit,64bit)。
存储元:存储二进制的电子原件,每个存储元可存1bit。
数据在存储体中按地址存储,类似于Excel的一列表格。每个表格代表一个存储单元,每个存储单元存放一串二进制代码称为存储字,每个存储字包含多少个二进制位称为存储字长。
注:MAR位数反映存储单元的个数,MDR位数存储字长。
例1:MAR4位总共有个存储单元。(4位的排列组合:4!=4*
3*2*
1=24)
例2:MDR16位每个存储单元可存放,1个字(word) 。
计算机基本单位:
- 位字(bit):最小的数据单位
- 字节(Byte):如果计算机硬件是位,那么:个字(bit)组成一个字节(1B8b),存储空间的最小单位。
- B:1B=8b,K:1KB = 1024B,M:1MB=1024KB,G:1GB=1024MB,T,P,E
2.2 运算器
用于实现算术运算(如:加减乘除)、逻辑运算(如:与或非)
有四部分构成:
- ACC:累加器,用于存放操作数,或运算结果。
- MQ:乘商寄存器,在乘除运算时,用于存放操作数或运算结果。
- X:通用的操作数寄存器,用于存放操作数。
- ALU(核心部件):算术逻辑单元,通过内部复杂的电路实现算术运算、逻辑运算。是运算器的核心单元。

ACC、MQ、X在进行加减乘除操作区别:
| 加 | 减 | 乘 | 除 |
---|
ACC | 被加数、和 | 被减数、差 | 乘积高位 | 被除数、余数 |
MQ | | | 乘数、乘积低位 | 商 |
X | 加数 | 减数 | 被乘数 | 除数 |
2.3 控制器
指挥各个部件,使程序可以正常运行
主要有三部分构成:
- CU(核心元件):控制单元,分析指令,给出控制信号。是控制器核心元件。
- IR:指令寄存器,存放当前执行的指令
- PC:程序计数器,存放下一条指令的地址,有自动加的功能

代码相当于指令,每完成一条指令过程:
取指令(PC)
根据PC中所记录的指令地址,从内存中取出该指令。
分析指令(IR)
将取出的指令由IR进行分析这条指令可以干什么。
执行指令(CU)。
分析完成后CU会控制其他部件完成指令具体执行。
程序在计算机中的运行过程:
运行顺序:PCMARMDRIRCUIRMARMDRACC
例:给定以下高级语言分析其在计算机内执行过程。
代码在主存结构如下:

地址是y=a*b+c
这段程序对应的机器指令;地址是四个变量的的存储情况。这里存储字长为。
运行步骤:
首先PC,执行主存地址为的第一行的指令

(1)存放的内容会通过地址总线传送到中,即,此时。也就是控制器向主存指明接下来要访问的是号地址所对应的指令。同时控制器会通过控制总线向主存发送读操作指令。
(3)接着主存会根据记录的地址到存储体中取出号地址对应的二进制数据,并将二进制数据放入当中。即,此时
(4)中存放的数据就是指令,所以这条指令会通过数据总线放入中。即,导致
(5),将前六位的指令操作码()发送到中,分析后得知,这是取数指令。
(6),将中的数据地址码发送给,导致。因为转化十进制是
(8)主存,导致。主存根据地址找到数据放入中
(9)最后在控制单元的指挥下中的数据会被存放到中。,导致
上面七步操作完成后代码执行完毕。其中是取指令;是分析指令;执行取数指令。
在上述取指令动作完成后,由于具有自动加的功能,所以,即执行主存地址为的第二行的指令

此时,
(1),导致
(3)主存,导致
(4),导致
(5),将前六位指令操作码发送给,分析后得知,这是乘法指令
(6),将中数据的地址吗发送到,导致
(8)主存,导致
(9)主存,将中的值放入乘商寄存器当中
(10)将,将中的值放入通用寄存器当中。导致
(11)通过控制线向发送相乘指令。,导致,如果乘积太大,需要辅助存储。
上面九步操作完成后代码执行完毕。其中是取指令;是分析指令;执行乘法指令。
在上述取指令动作完成后,由于具有自动加的功能,所以,即执行主存地址为的第三行的指令

此时,
(1),导致
(3)主存,导致
(4),导致
(5),将前六位指令操作码发送给,分析后得知,这是加法指令
(6),将中数据的地址吗发送到,导致
(8)主存,导致
(9)当进行加法运算的时候中会先存入被加数,通用寄存器会存放加数。,
(10)向发送相加指令。将中的值与中的值相加,再放回。。导致。
上面八步操作完成后代码执行完毕。其中是取指令;是分析指令;执行相加指令。
自动加,所以,即执行主存地址为的第四行的指令

此时,
(1),导致
(3)主存,导致
(4),导致
(5),将前六位指令操作码发送给,分析后得知,这是存数指令
(6),将中数据的地址吗发送到,导致
(7)将中的结果通过数据总线送到中。,
(9)由于是存数指令,所以会将中的数据,存放在所指定的地址中。地址为的存储单元。故
上面七步操作完成后代码执行完毕。其中是取指令;是分析指令;执行存数指令。
自动加,所以,即执行主存地址为的第五行的指令

此时
(1),导致
(3)主存,导致
(4),导致
(5),将前六位指令操作码发送给,分析后得知,这是停机指令
利用中断机制通知操作系统终止该进程。
总结:

OP:操作码
AD:地址码
CPU区分指令和数据的依据:根据指令周期的不同阶段
运行汇总

汇总二
2.4 计算机层次结构
最底层:由传统机器(机器语言的机器)和微程序机器(微指令系统)组成。
这一层传统机器执行二进制机器指令,而机器指令可以分解为多个微指令,微程序机器就是执行这些微指令的。

再上一层是:虚拟机器(汇编语言机器)
汇编语言编写的代码需要翻译成机器码,所以是虚拟机器。

再上一层是:虚拟机器(高级机器语言)
需要用编译程序翻译成汇编语言。

而我们编写的程序往往需要用到操作系统的调用,向上提供广义指令。
所以总的计算机层次:

计算机层次结构特点:下层是上层的基础,上层是下层的扩展
计算机硬件层:微程序机器MO(微指令系统)------>传统机器M1(用机器语言的机器)
计算机软件层:虚拟机器M2(操作系统机器)------>虚拟机器M3(汇编语言机器)------>虚拟机器M4(高级语言机器)
硬件层位于最底层,具有下层是上层的基础,上层是下层的扩展的特点。
编译程序
汇编程序
解释型
高级语言
汇编语言
机器语言
JavaScript和python
编译型程序:将高级语言编写的源程序全部语句一次全部翻译成机器语言程序,而后再执行机器语言程序(只需翻译一次)
解释型程序:将源程序的一条语句翻译成对应于机器语言的语句,并立即执行。紧接着再翻译下一句(每次执行都要翻译)
注意:编译、汇编、解释程序可以统称为翻译程序。
3. 计算机的性能指标
3.1 存储器的性能指标
主寄存器的容量存储单元的个数存储字长bit

例:MAR为位,MDR为位,总容量
3.2 CPU的性能指标
CPU的主频:CPU内数字脉冲信号震荡的频率,很大程度上反映了CPU的性能。如:,
可以理解为指挥CPU内部部件工作的节奏。
CPU震荡图:

其中每个脉冲信号的时间称为CPU的时钟周期(微秒,纳秒)
CPU主频与时钟周期关系:CPU主频(时钟频率)时钟周期赫兹 。即时钟周期CPU主频的倒数
代表CPU在一秒可以执行个周期。
CPI
CPI:指执行一条指令所需的时钟周期数
CPI性能是变化的:不同的指令,CPI不同。甚至相同的指令,CPI也可能有变化。
执行一条指令的耗时 时钟周期
例:某CPU主频为1000Hz,某程序包含100条指令,平均来看指令的。该程序在该CPU上执行需要多久?
解:总耗时主频时钟频率 CPU执行时间(一个程序的耗时)指令条数主频时钟周期时钟周期数主频
IPS
每秒执行多少条指令
主频平均
单位:单位一般在指标名称前。如:KIPS、MIPS
FLOPS
每秒执行多少次浮点运算
单位:单位一般在指标名称前。如:KPS、MPS、KFLOPS…………
注:此处K、M、G、T为数量单位。即千、百万、十亿、万亿
3.3 系统整体性能指标
注:
- 主频高的CPU不一定比主频低的CPU快。如两个CPU,的主频为,平均;的主频,平均。所以虽然主频低,但是处理快,总体比快。
- 若两个CPU的平均CPI相同,频率高的CPU也不一定快。还要看指令系统,如不支持乘法指令,只能用多次加法实现乘法;而支持乘法指令。
- 基准程序(跑分软件)执行得越快也不能说明机器性能越好:基准程序中的语句存在频度差异,运行结果也不能完全说明问题
3.4 总结

计算机性能指标
二. 数据的表示与运算
1. 进位计数制
十进制
如:
其可以表示为:
由十进制可以推广到多进制。
1.1 进制转化为十进制
基数:每个数码位所用到的不同符号的个数,十进制基数是,进制的基数为。
下面是一些常见进制的基数:
二进制:
八进制:
十进制:
十六进制:
进制转化为十进制例题:
- 二进制():转换为十进制
- 八进制(O):转换为十进制
- 十进制():转换为十进制
- 十六进制():转换为十进制
计算机用二进制好处是:
- 可使用两个稳定状态的物理器件表示。
- ,正好对应逻辑值假、真。方便实现逻辑运算。
- 可很方便地使用逻辑门电路实现算术运算。
1.2 二进制转化为八进制和十六进制
二进制转化为八进制
从小数点开始向两端三位一组(因为最大排列为八),不够补零:小数点左边不够三位向左边补零;右边不够三位向右边补零。每组转换成十进制,再由十进制得到对应的八进制符号
例:1111000010.01101
001 111 000 010 . 011 010
1 7 0 2 . 3 2
八进制转化为二进制
每位八进制对应三位的二进制
转换为二进制(010 101 001.101)2
具体:二进制、二进制、二进制、二进制
二进制转化为十六进制
四位一组(最大的排列为十六),每组转换成十进制,再由十进制得到对应的十六进制符号
例子:1111000010.01101
0011 1100 0010 . 0110 1000
3 C 2 . 6 8
十六进制转化为二进制
每位十六进制对应四位二进制
转换为二进制(1010 1110 1000 0110.0001)2
具体是:转换为二进制、转换为二进制、转换为二进制、转换为二进制、转换为二进制
1.3 十进制转化任意进制
整数部分转换(除基取余法):十进制数进制商余数,之后一直除直到商为,再将余数倒叙排列即可。
75转二进制:

小数部分转化(乘基取整法):十进制数进制小数,再取走小数的整数部分再乘进制,直到最后小数原十进制数或者等于即可,最后正序排序取走整数部分即可。
注意:有的十进制小数无法用二进制精确表示,我们一般当原十进制数时停止。
转换为二进制:

也可以将十进制转换为二进制,然后二进制再转换为八进制或十六进制。
进制速查表:

1.4 真值和机器数
十进制转换为二进制需要再前面加一位符号位,正号用,负号用。所以二进制,转换为二进制
真值:实际的带正负号的数值(人类习惯的样子)。如上面的和
机器数︰把正负号数字化的数(存到机器里的样子)。如上面的和
2. BCD码
BCD码指:用二进制编码的十进制数。主要有:码、余码、码。
由于机器数(二进制)转换为真值(十进制)过程较为麻烦,而BCD码就是为了解决这个问题。
BCD码原理:可以用对应一个十进制位。因为对应有种状态,完全可以表示这十种情况。同时也会与六种状态是冗余的。
2.1 8421码
码是指四位二进制位,来表示一个十进制。这四个二进制位的权重分别是、、、。如表示码,因为从左至右第二位和最后一位相加等于
的码表:

根据上面表码。可以用三个码表示这个数字
码的加法运算:
码
计算机做法是首先将两个码二进制相加,显然已经超出码的范围,即不在映射表中。实际上当结果处于内是没有定义的,是一个非法码区间。解决做法是让结果码,由于加后这四个数肯定会向高位进,此时低位部分就是我们需要个位数。所以,低位转换为十进制。而高位我们只需要在前面补上个,即,最终正好可以表示这个数,所以上面用表示是。
再看一种情况:对于结果已经大于码定义的四位。处理方法同样是后四位加,即。低位的码十进制,即个位。前面高位前面补足三个。最终。所以码
总结:只要相加结果处于这个区间都需要加修正。如果在合法范围内无需修正。

2.2 其他码
余码
在码基础上每个数

余码每个进制位并没有权值。
码
和码一样是一个有权码,四位二进制码的权值分别是

需要注意的是对于码,其第一位都是,而第一位都是。这是因为要避免歧义性。
3. 无符号整数的表示和运算
无符号整数即自然数,有
无符号整数的表示:假设现在机器字长是位,那么其通用寄存器只能存位。
如:二进制,刚好八位,可以存放在机器字长是位的寄存器中。
但二进制,二进制是九位,而机器字长位,其在计算机中只能保存低八位,即。

而这八位都有权值,没有符号位,所以称为无符号整数。

无符号整数特点:
- 全部二进制位都是数值位,没有符号位,第位的位权是
- 比特的无符号整数表示范围是,超出则溢出,意味着该计算机无法一次处理这么多位
- 可以表示的最小的数是:所有位全是,最大的的数是:所有位全是。
无符号整数的加法:从最低位开始,按位相加,并往更高位进位。如:,其实二进制位相加即可。

无符号整数的减法:
- 首先"被减数"不变,"减数"全部位按位取反、最后一位,减法变加法
- 从最低位开始,按位相加,并往更高位进位
如:
首先减数按位取反,之后的最后一位,即
最后计算,由于计算结果是九位,寄存器只能存储八位,所以舍弃高位的,结果是

4. 带符号整数在计算机中应用
带符号整数,如:
带符号整数可以用原码、反码、补码三种不同编码方式来表示。
带符号整数的表示:假设现在机器字长是位,那么其通用寄存器只能存位。最多只能同时进行位运算
4.1 原码表示法
开头第一位是符号位:正号用,负号用,剩下后七位是数值位。
如:真值二进制,在寄存器中存储方式是
真值二进制,在寄存器中存储方式是

原码特性:
- 若机器字长是位,带符号整数的原码表示范围:
- 符号位对应正负,剩余的数值位表示真值的绝对值
- 真值有两种形式:和。原;原
原码缺点:符号位不能参与运算,需要设计复杂的硬件电路才能处理。
4.2 原码计算方式
原码加法计算方式是:先将原码转换反码转换补码。在进行正常二进制计算即可。
正数转换为补码不变
负数(原码)符号位不变数值位取反反码末位补码

原码转换为补码快速技巧:原码从右往左找到第一个,这个左边的数值位按位取反就可以变为补码。同样补码转换为原码方式一样。
如:原转换为补码补
计算机硬件如何做补码的加法:从最低位开始,按位相加(符号位参与运算), 并往更高位进位。

注意:负数补码的数值为不能解读成位权。我们需要将其转换为原码。
如上面补转换为原码,而十进制
而对应原码的减法计算,仍需要将其转换为补码再计算。不同的是计算机只能处理加法运算,所以将减法变为加法即可。如补补补补
所以只需要解决已知一个补码求其负值的补码。方法是:补全部位按位取反末位补

如:补全部位按位取反末位补补码
同样有快速转换的技巧:原码从右往左找到第一个,这个左边的全部位按位取反就可以变为负值补码。
可以看出有符号整数减法和无符号整数减法方法一样,这样就意味着可以用同一套电路就可以实现处理所有加减法。
所以有符号整数的减法:
- 首先"被减数"不变,"减数"全部位按位取反、最后一位,减法变加法
- 从最低位开始,按位相加,并往更高位进位
原码计算总结:

注意:计算机内部所有带符号整数的加减法都要先转换为补码形式。
4.3 移码
移码:在补码补基础上,符号位取反就可以得到移码移。

注意:移码只能表示整数,不能表示小数。且真值只有一种表示形式,若机器字长为位,移码整数的范围:
4.4 原码、补码、反码和无符号整数特性
| 合法表示范围 | 最大的数 | 最小的数 | 真值的表示 |
---|
带符号的整数:原码 | | | | 原 原 |
带符号整数:反码 | | | | 反 反 |
带符号整数:补码 | | | | 补 真指只有一种补码 |
带符号整数:移码 | | | | 移 真值只有一种移码 |
无符号整数 | | | | |
原码和反码的合法表示范围完全相同,都有两种方法表示真值
补码和移码的合法表示范围比原码多一个负数,只有一种方法表示真值
常见考点:两个数和进行某种运算后,是否发生溢出。可以手算做题可以带入十进制验证,是否超出合法范围
如:计算机是位。,如果其用原码表示会溢出。而用补码表示则不会溢出。
几种码的表示:

4.5 定点小数表示和运算
之前的定点整数,即带符号的整数,小数点隐含在数值部分末尾。

而定点小数小数点位置是在符号位和数值位中间

定点小数的编码有原码、反码和补码。没有移码。并且定点小数各个位权与定点整数不一样。除符号位,由高位到低位
如:原

定点小数原码、反码补码转换和定点整数一样。其计算方法也一样。
定点小数和定点整数对比:

4.6 奇偶校验码
数据在计算机内部进行计算存取过程中可能会发生错误,所以要用到校验。
奇校验码:整个校验码(有效信息位和校验位)中的个数为奇数。
偶校验码:整个校验码(有效信息位和校验位)中的个数为偶数。
一般高位是校验位,剩下位是信息位

如:奇校验码:,因为是奇校验而信息位的有个,所以在首位添加,整体个数位是奇数。
偶校验码:,信息位个数是,所以不用补,首位添加个即可。
如果是奇校验码,计算会校验个数,如果个数是偶数,则证明发生错误,会要求重新发送。如果是奇数,这没有问题。
奇偶校验码可能检测不出来错误。特别是在发生多位跳变时候。
偶校验的硬件实现:各信息进行异或 (模2加)运算,得到的结果即为偶校验位。
如:偶校验码,对校验码各个位两两进行异或,若结果为则说明正确。

5. 字符与字符串
字母,数字和字符等都是以ascll码的数字形式存储再电脑中
补充:字符数字转整型数字:'1'—'0'=1
整型数字转字符数字:1+'0'='1'
ASCLL码:

字母表示
字母加上各种符号,总共128个。具体如上ASCLL码
汉字表示
国标码:专门用于汉字的ASCLL码,为了防止与字母冲突ASCLL值从128开始。
输入(拼音):输入法会将输入的拼音转换为国标码,再将国标码转换为与之相对应的汉字内码。
输出:用到汉字字形码具体如下:
字形码:

总结:

6. 算术逻辑单元
主要是算术逻辑单元的构成。
可以实现算术运算:加、减、乘、除等;逻辑运算:与、或、非、异或等;辅助功能:移位、求补等。

上图是ALU大致图像,和是输入信号,如要实现两个数加法,这两个数一个从输入,一个从输入。
是输出信号,运算结果从这里输出。
是控制信号,控制信号是由控制单元发出的,控制信号主要用于解析指令是加法减法等。
下面是实例图

右边五个控制单元就是上图的,是用于接收运算符号的。如:、时,做逻辑运算
由于上图有位,所以可以支持种运算状态。
最下方输入信号,可以反映机器字长。通常与上面输出信号位数保持一致。如上图都是位。
所以至少需要有控制信号、输入信号和输出信号。
6.1 最基本的逻辑运算
常见的有:与、或、非。与或非三种逻辑运算对应的门电路如下:

假设,端输入电信号代表,端输入电信号代表,两个信号做与运算结果为的。只有两端输入都是高电平信号时候结果才会是。
如果非门端输入高电平,则会输出低电平。
如果一个运算涉及到多个逻辑运算,那么执行顺序要看优先级。与
运算可以看作乘法, 而或
运算可以看作加法。
如:,要先算与运算;再算或运算。同样的这样的运算也符合分配律和结合律。
上面意义在于,设计门电路本质上逻辑表达式是对电路的数学化描述,简化逻辑表达式,就是在简化优化电路,就是在省钱。
如:实现。其门电路可以设计如下方式:

这里我们用两个与门,与进行与运算后,两个电信号再通过上面的或门做最后一次运算,最后输出。
同时由于运算遵循分配律,所以分配律。设计的门电路如下:

可以看到这里只用了一次或
运算计算;一次与
运算计算。所以这样设计相当于优化了门电路。
6.2 复合逻辑运算
常见的复合逻辑运算有:与非(先进行与
运算,再进行非
运算)、或非(先进行或
运算,再进行非
运算)、异或
其表达式表示如下:

其门电路符号如下:

上面运算遵循反演律(德摩根律):
重点介绍异或运算:即和不同时,输出。详细可以理解为且
或者且
时输出
表示式表示为。其电路图如下:

假设,的上路输入,下路经过非
运算后是;的上路经过非
运算后是,下路输入。所以上面的与门输入两个数是运算后是,下面的与门输入两个数是结果是,最后两个运算结果再做或
运算结果是。
组后补充一个复合逻辑:同或。其就是异或运算取反。

逻辑运算实现偶校验位
求的偶校验位
方法一:整体异或
方法二:部分异或再整体异或
与之对应电路如下:

方法三:

从上面三种方法可以看出逻辑表达式是对电路的数学化描述。
逻辑运算实现一位全加器
可以使用异或运算实现全加器。

上面表示两个数相加的第位,来自低位的进位,当前正在运算位称为本位。
计算步骤:
- 当输入和时,可以用异或运算,输入中有奇数个时为(异或),偶数异或为。
- 有两种情况会产生进位,如果表示都是,则要向高位进。另一种情况是两个本位中有一个,且来自低位的进位是,即。
综上其进位逻辑表示式为。对应门电路如下:

其简化图就是一位全加器:

上面门电路图可以理解为一个函数具体实现。而下面简化图可以理解为函数对外暴露的接口。
可以将多个一位全加器串联起来形成串行加法器:只有一个全加器,数据逐位串行送入加法器中进行运算。进位触发器用来寄存进位信号,以便参与下一次运算。

串行加法器本质是一位一位运算进位。所以如果操作数长位加法就要分次进行,每次只能产生一位和,并且串行逐位地送回寄存器。效率较低。
与之对应的是并行全加器。把个全加器串接起来,就可进行两个位数的相加。

这样特点是只有低位的运算结束后,才能进行高位的运算。电信号传递需要大量时间。其效率取决于每一位进位产生速度。
6.3 并行加法器优化
上面介绍的串行进位的并行加法器,特点是其速度依赖于来自低位的进位。接下来要探究的是如何让每个进位产生的更快。
进位,其中又可以进一步展开为
还可以进一步对进行展开,当展开到一定次数时会得到最后。而是一开拥有的信息。所以第位向更高位的进位可根据被加数、加数的第位信息,再结合即可确定。即可以利用刚开始被加数和加数每一位信息,和信息直接求。这就是其优化思路。
为了方便,记,,即
所以第一位进位:
第二位进位:
以此类推。可以算出位的进位信息。

从上面可以看出和值是经常用到的,只要是角标大于的进行都要用到。所以可以根据加数和被加数对应的两个比特位算出和,这两个信息可以通过线路送往更高位的运算中。所以我们在计算这一位进位信息时,其各个值都是确定的,只需要根据表达式设计出对应的线路,就可以在这里直接算出进位值。也就是说采用这种优化方式,每一位的进位信息几乎都是同时产生的。不需要像之前那样等待后一位进位信息往后传。
这种方式的加法器称为并行进位的并行加法器:各级进位信号同时形成,又称为先行进位、同时进位。
这种方案也有不足:可以看出到表达式已经很复杂了,再往后会更复杂,其对应的电路也会设计的更加复杂。所以要适可而止,通常到这个值就可以了,也就是可以同时支持位位的运算。在这个加法器内部,每个进位都是同时并行产生的。

7. 补码加减运算器
即从硬件的层面看,补码的加减运算是如何实现的。
7.1 补码加法器原理
加法器原理:

假设上面的是吗,即这个加法器实现的是的加法运算。计算,则结果是
计算机实现步骤:
- 首先数字通过两个输入进行输入。
- 由于,此时加法器做法是
- 输出,由于没有产生进位,所以
再看一个例子:计算,则计算结果
加法器实现步骤:
- 两个数字输入
- ,故加法器做法是
- 输出,由于产生了进位,所以
如果将两个如上图所示的加法器进行串联,即在一边再连接一个加法器。如果要实现两个加法器相加,在把两个加法器串联即可。
对上面加法器进行改造,使其能进行补码的加减运算。补码手算方式参考原码计算方式
改造后的加法器结构如下:

例1:补码,当,补,补
加法器实现步骤:
- 不变,直接输入,右侧输入读取操作所以
多路选择器(MUX)
右边线路会接受的值。 - 之后值会送入加法器中,接着向加法器传入,随后加法器会进行操作。
- 即
实现减法步骤:
- 首先多路选择器接收传入的减法信号
- 之后会从左侧进行非门取反操作后变为,最后通过多路选择器进入加法器中
- 值直接进入加法器,向加法器传入减法信号,即
- 由于字长有位,所以高位的会舍弃。即结果是。显然这个运算结果是错误的,发生位溢出现象。
同时这个加法器也可以实现无符号数的运算,因为无符号运算与补码运算一样。但是二者判断溢出方式不同,这涉及到标志位的产生。
7.2 标志位的生成
对上面的加法器的输出部分进行扩展:

的数相加,除了得到相加的结果之外,加法器还可以输出四个标志位信息、、、
:溢出标志,溢出时为,否则为
含义:判断有符数的加减运算是否发生溢出。其只在有符号数运算时才有意义。
硬件计算方法:最高位产生的进位次高位产生的进位
如:,其最高位进位信息是,次高位进位信息是,故,所以发生溢出。
:符号标志位
含义:有符号数加减运算结果为的正负性,表示运算结果为正数,表示运算结果为负数。
硬件计算方法:最高位的本位之和
如:最高位本位和是,即,结果为正数
:零标志位
含义:表示运算结果是否为,表示运算结果为,否则表示运算结果非
硬件计算方法:两个数的运算结果为,只有全为,
:进位借位标志
含义:进位借位标志,表示无符号数的加减法是否发生了进位或借位。当时,说明无符号数的加减运算发生了进位或借位,也即发生了溢出
硬件计算方法:最高位产生的进位,其中表示减法,否则表示加法。
如:运算,最高位进位是,减法,所以,即发生借位,这也就代表了,被减数比减数更小,所以才导致了进位。同时也意味着结果发生溢出。
总之,无符号数的运算是否发生溢出,要看。有符号加减运算是否溢出要看。
7.3 加减运算和溢出判断
位的补码所能表示的范围是,所以如果补码的加减运算结果值如果不在这个范围内,就会出现值溢出的现象。
如:位补码,位补码,则补,其真值。显然结果不正确,而其值,显然超出位补码所能表示的范围,所以出现值溢出现象,导致结果错误。
既然溢出的状况不可避免,计算机硬件必须要判断溢出问题。当进行补码加减运算时,都会转换为加法运算。所以我们只需要探讨加法运算即可。
首先,只有正数正数才会出现上溢出,导致正正负;只有负数负数才会出现下溢出,导致负负正。

例如下图:

计算的值,,按照上图表示,由于实际值为出现,显然这里出现了上溢,导致结果为负数,其实从枢轴上也可以看出向右走,会回到了负轴的位置。同样如果值会出现下溢,导致结果为。
基于这个规律计算机判断溢出方法如下:
方法一:
设加数的符号位,被加数的符号为,运算结果的符号为,则溢出逻辑表达式为:
若结果表示无溢出,若表示溢出。
注:表示符号位取反,相乘表示与
运算,相加表示或
运算。
如:补,真值
对其进行溢出判断:即发生溢出。
可以看出这里实现正正负,负负正这个逻辑时,设计的较为复杂。原因在于当逻辑表达式设计出来后相当于其门电路也背设计出来。
方法二:
根据数据位进位情况和符号位进位情况判断溢出
当符号位进位为,最高数值位进位为时,发生上溢
符号位进位为,最高数值位进位为时,发生下溢
例如:补,真值

此时,产生上溢。
即与不同时有溢出。处理"不同"的时候可以用逻辑符号:异或。溢出表达式判断为:
若表示无溢出,表示溢出。
方法三
采用双符号位。正数符号位,负数的符号为。
例如:补,上溢出
补,下溢出
上面两个运算结果符号位中,如,第一个符号位表示运算应该得到的正确符号,第二个符号位是运算得到的实际符号。如果没有溢出两个符号位一定是相同的。
逻辑表达式为:记两个符号为,则
若表示无溢出,表示溢出。
上面的双符号位又称:模补码
之前的单符号位又称:模补码
原因是将中的改为即,此时可以看作小数,小数点前位权为,显然这里保留两位符号位,相当于对取模运算,即保留位权为小于的右边所有位。所以称为模补码。同样模补码一样。
注意:虽然这里有两位的符号位,但实际存储时只存储一个符号位,运算时会复制一个符号位。并不会增加存储空间。
无论哪种方法其关键在于:同号同号异号,此时一定发生溢出。
符号扩展
符号溢出本质是所得的运算结果的位数不够表示。其解决办法是符号扩展。如扩展为,整数部分要在数值位和符号位中间补齐个;而小数部分要在右边补齐个。
如:扩展位
8. 移位运算
8.1 算数移位
指小数点前后移动。含义:通过改变各个数码位和小数点的相对位置,从而改变各数码位的位权。可用移位运算实现乘法、除法。
对于十进制数,小数点往后移位相当于;小数点前移位相当于
算数右移
高位补,低位舍弃。若舍弃的位,则相当于;若舍弃的位,则会丢失精度。
例如:的原码及位权如下:

每次往右移动位相当于,如果移动三次相当于,这里由于右移三次导致低位丢失所以失去精度。

算数左移
低位补,高位舍弃。若舍弃的位,则相当于;若舍弃的位,则会出现严重误差。
例如:的原码及位权如下:

每次往左移动位相当于,如果移动三次则,,因为移动三次位数值位只能表示这个区间,显然这个结果值溢出。所以出现严重误差。

同样,小数方法一样。
8.2 反码算数移位
反码的算数移位:正数的反码与原码相同,因此对正数反码的移位运算也和原码相同。
右移:高位补,低位舍弃。
左移:低位补,高位舍弃。
反码的算数移位:负数的反码数值位与原码相反,因此负数反码的移位运算规则如下:
右移:高位补1,低位舍弃。
左移:低位补1,高位舍弃。

8.3 补码算数移位
补码正数算数移位:正数的补码与原码相同,因此对正数补码的移位运算也和原码相同。
补码负数算数移位:负数补码反码末位。导致反码最右边几个连续的都因进位而变为0,直到进位碰到第一个为止。
规律:负数补码中,最右边的及其右边同原码。最右边的的左边同反码。
负数补码的算数移位规则如下:
- 右移(同反码):高位补,低位舍弃。
- 左移(同原码):低位补,高位舍弃。
负数补码右移:

总结:

由于位数有限,因此有时候无法用算数移位精确地等效乘除法。
例如:
相当于,计算机对原码,不左移、左移位、左移位。
8.4 逻辑移位
可以把逻辑移位看作是对"无符号数"的算数移位。
逻辑右移:高位补,低位舍弃。
逻辑左移:低位补,高位舍弃。

8.5 循环移位
循环左移:当原码左移时高位溢出的会移动到末位,进行循环补位。循环右移原理相同。
带进位位的循环左移:会有一位专门记录低位往高位进位信息。当循环左移一位时,进位信息会移动到原码最末尾。

循环移位主要用于把数据的低字节和高字节进行调换。
9. 原码与补码的运算
9.1 乘法运算
先看十进制乘法:
其中;
所以

扩展到二进制
乘数
被乘数
则

可以看出二进制原码实现方法比十进制更为简单,因为每一位不是就是。并且这样运算对于计算机也很简单相当于向右移动位即可。
原码乘法运算
如果用计算机实现原码乘法,要考虑的问题很多,实现步骤大致如下:
ACC内清空,MQ内存放乘数,X存放被乘数
MQ最低位与被乘数参与运算:
如果最低位是,内的值被乘数
如果最为位是,内的值
ACC与MQ中的值同时右移,ACC内低位称为MQ高位,此时MQ低位再次重复步
一直右移到MQ中剩符号位,此时运算结束
总结下来就是:先加法再移位,重复次
首先设机器字长位,其中一位是符号位,原,原,采用原码一位乘法求
符号处理相对简单:符号位,数值位取绝对值进行乘法计算原,原
机器实现上面原原相乘步骤:
首先ACC内清空,MQ内存放乘数,X存放被乘数

首先的最低位参与运算。由于当前位是,所以让,即当前运算值加上被乘数,如果当前位是,
,结果值放入ACC中

ACC与MQ同时右移,ACC高位补,其低位称为MQ高位

右移后MQ末位,同样。即,结果放入ACC中

ACC和MQ再次右移,下面红色部分可以称为"部分积"

当前末位值是,所以即可。所以此次ACC内结果不会变,接着右移

当前位是,,即。结果放入ACC接着右移

此时MQ末位是,但是这个不用参与运算,因为这一位是原本符号位
所以运算结果是,手算过程如下:

由于上面是绝对值乘法,所以最后还要对原本的符号位进行异或,添加到符号位。原,原,符号位是,所以最后结果是
这种方法叫原码一位乘法。因为每次参与运算只有一位。接下来用手算方式解题:
设机器字长为位(含位符号位,) ,,采用原码一位乘法求

由于补码乘法要用到双符号位,所以建议原码乘法也像上面题一样采用双符号位。
整数运算与上面小数运算类似,注意整数最后小数点位置是在末位前面的位置。

补码乘法运算
补码计算方法和原码十分相似。
原码补码计算对比:
原码 | 补码 |
---|
进行轮加法,移位。 | 进行轮加法,移位,最后再多来一次加法。 |
每次加法可能原码 | 每次可能补补 |
每次移位是逻辑右移 | 每次移位是算数右移 |
补码每次加的数值要根据MQ中最低位、辅助位来确定:
- 辅助位MQ中最低位时,补
- 辅助位MQ中最低位时,
- 辅助位MQ中最低位时,补
补码运算器与原码有差距:

因为MQ多一位辅助位,由于运算器内部部件位数相同,所以ACC和X都要扩展一位。
辅助位初始为。每次右移会使MQ的最低位顶替原本的辅助位。
用计算机实现步骤大致如下:
ACC内清空,MQ内存放乘数末位留一位当辅助位,X存放被乘数采用双符号位。
补码每次加的数值要根据MQ中最低位、辅助位来确定:
辅助位MQ中最低位时,补
辅助位MQ中最低位时,
辅助位MQ中最低位时,补
ACC与MQ中的值同时进行补码算术右移:
符号位不动,数值位右移,正数右移补,负数右移补
重复上面三步,直到乘数符号位,最后还要再进行中的一次加法,才能结束。最后将ACC中的值与MQ中除去符号位的前位拼接即可。所以说补码乘法符号位也会参与运算。
例:设机器字长为位(含位符号位,),,采用Booth算法求
补,补,补

最后结果是:补,即
注:上面的是辅助位,是MQ的最低位,是MQ符号位。
9.2 除法运算
首先从十进制出发,运算如下:

上面竖式可以转换为:,即余数
其本质是每上一位商要尽可能接近余数,但不超过余数。
对于二进制除法:,首先取绝对值狐狸小数点:

规律:忽略小数点,每确定一位商,进行一次减法,得到位余数,在余数末尾补,再确定下一位商。确定位商即可停止(机器字长为位)
原码的除法
设机器字长位位(含位符号位,),,,采用原码恢复余数的求法求
首先符号位,之后对数值位取绝对值进行除法计算
运算器实现大致步骤:
首先通用寄存器放入除数,ACC放入被除数,MQ清空用于存放商
默认MQ低位上商,此时通用寄存器,结果为余数放入ACC中。如果:
ACC高位是,则说明余数是负数表明默认商是不正确的。寄存器弥补做法是MQ中低位改为,之后通用寄存器,运算结果值放入ACC中
ACC高位是,说明余数正数,商正确进入。
之后ACC和MQ整体逻辑左移,左移之后ACC中的值就是余数。之后重复上述两步骤即可
这种恢复余数方法称为:恢复余数法
计算机实现:
首先通用寄存器放入除数,ACC放入被除数,MQ清空用于存放商

计算机并不能判断除数和被除数谁更大,所以默认MQ低位上商,之后再根据具体情况恢复余数

由于MQ低位是商,所以通用寄存器,即补,结果放入ACC中

由于ACC中高位代表除数负数,所以默认的商是错的。运算器将默认上的商改为,之后除数,即补

之后将逻辑左移

接着重复上述几步,由于这里机器字长是位,所以MQ中的商计算到位即可(还有一个符号位)。

手算做题方法如下:

注意:总共要左移次,上商次,最后一次上商余数不左移。
优化恢复余数法策略:

可以看到,将余数为负数的值设为,除数设为,则恢复操作为,之后的值左移:。最后再默认商,。所以当发现余数是负数(高位为),此时不用恢复余数,直接让余数左移位再加上除数即可。
基于这种思路的方法称为加减交替法,又称不恢复余数法。优化后的步骤如下:

注意:余数的正负性与商相同。加减法要进行次,最终可能由于余数为负数还要再多一次加。逻辑左移进行次(最后一次加减完不移位)。
定点小数运算中被除数一定要比除数小。因为如果大于除数,结果就是一个大于的数,定点小数无法表示大于的数。所以运算中第一步一定得到商是,如果商,则证明被除数比除数大,此时硬件电路会检测到这个问题,并且直接停止运算。
补码的除法
补码的除法与原码类似,同样是使用加减交替法。但不同在于:补码符号位要参与运算(不用绝对值),并且被除数、余数、除数采用双符号位。
具体做法如下:
首先根据被除数和除数符号进行运算
同号,则被除数减去除数
异号,则被除数加上除数
根据第一步得到的余数之后再根据余数和除数符号进行运算
同号,商,余数左移一位减去除数
异号,商,余数左移一位加上除数
重复第二步次,即可
最后一位直接横置为,这样不仅效率高而且误差不超过。
例:设机器字长为位(含有一位符号位),,,采用补码加减交替法求

结果:补,余数
原码与补码除法对比:

9.3 C语言强制类型转换
C语言中定点正数都是用补码形式存储的。用关键字unsigned
修饰的是无符号整数。
将有符号数转换为无符号数
上面在内存中以补码形式存储。由于将强制转换为无符号类型,所以
无符号数与有符号数转换:不改变数据内容,改变解释方式。
将长整型转换为短整型
类型占字节,类型占字节。假设在计算机中以十六进制,则转换短整型后是,即。
在计算机中十六进制是,则转换为短整型后是,即
将长整型转换为短整型:高位截断,保留低位。
短整型转换为长整型
- 首先补码是,将其赋值给类型的,由于是负数补码高位补,即,其真值。
- 之后将变为无符号类型赋值给,,真值为。
- 最后将的值赋值给无符号型,则,其真值为
10. 数据的存储与排列
多字节数据在内存中一定是占连续的几个字节。
10.1 大小端存储
如:字节类型:八进制,其最高有效字节;最低有效字节
其在计算机中二字节存储:
在计算机中存储方式有两种:大端存储和小端存储
10.2 边界对齐
现代计算机通常是按字节编址,即每个字节对应一个地址。
通常也支持按字,按半字,按字节寻址。假设存储字长为位,则个字,半字。 每次访存只能读写个字。

由于计算机每次只能读写个字,所以有的计算机会采取边界对齐方式,有的会用边界不对齐方式。
- 采用边界对齐方式存储,虽然空间上会有浪费,但是访问速度快。如要读取
半字1
,只需要一次读取就可以读取到。这是一种空间换时间的存储策略。 - 采用边界不对齐方式,虽然可以节省空间,将第一页没用完的空间充分利用,但会导致读取次数变多。如上图:对于边界不对齐方式要想读取
半字1
,需要分两次读取,最后还要进行拼接才能得到半字1
的完整表示。
补充:
计算机系统位数 | 单位 |
---|
16bit | 字(word)半字字节(byte)位(bit) |
32bit | 字(word)半字字节(byte)位(bit) |
64bit | 字(word)半字字节(byte)位(bit) |
无论操作系统的 位宽
是多少,1byte=8bite
,半字为字的一半,双字(double word)为字(word)的2倍永远不变。
一个ASCII字母占用 1 byte
,一个汉字占用 2 byte
11. 浮点数表示与运算
定点数可表示的数字范围有限,不能无限制地增加数据的长度,所以要用上浮点数。
计算机中的浮点数原理和科学计数法相似。如:科学计数法。由于后面的底数是不变的,所以也可以写作。其中左边称为阶码,阶码最前面一位是阶符,阶符为正小数点往后移动,阶符为负小数点往前移;后面的称为尾数,尾数最前面一位是数符,后面是数值部分,一般来说数值部分越短表示的精度就越低。

11.1 浮点数表示
以上是十进制科学计数法描述,接下来看二进制浮点数的科学计数法:
- 阶码:常用补码或移码表示定点整数
- 尾数:常用原码或补码表示定点小数
设阶码为,尾数为,则进制的浮点数真值
同样阶码反映浮点数的表示范围及小数点的实际位置;尾数的数值部分的位数反映浮点数的精度。
例如:阶码、尾数均用补码表示。,
的阶码对应真值;尾数对应真值;则的真值
最后真值部分相当于真题左移一位。对应内存中存储结构如下:

的阶码对应真值的,尾数对应真值;则的真值
对应内存中存储结构如下:

上面可以看到的尾数太长导致存储空间溢出,末位舍弃,精度降低。可以采用浮点数规格化方式提高精度。
11.2 浮点数尾数规格化
规格化方式:尾数最高值必须为有效值,即。
上面,小数点前的尾数是符号位不变,后面完全没有必要保留,所以将小数点后整体右移一位,即,得到,最后结果真值乘即可。的真值。其在内存中表示:

上面将尾数算数左移位,阶码减。直到尾数最高位是有效值,这种方式称为左规。
当浮点数运算的结果尾数出现溢出(双符号位为或)时,将尾数算数右移一位,阶码加,这种方法称为右规。
例:,,求
则,,则
由于双符号位异号,说明出现溢出。可以通过右规方式将浮点数规格化。将尾数右移一位,阶码加。即。这个尾数就是一个规格化尾数。其在内存中存储如下:

注:采用("双符号位"),当溢出发生时,可以挽救。更高的符号位是正确的符号位。
左规右规总结:
- 左规:当浮点数运算的结果为非规格化时要进行规格化处理,将尾数算数左移一位,阶码减。
- 右规:当浮点数运算的结果尾数出现溢出(双符号位为或)时,将尾数算数右移一位,阶码加。
规格化浮点数特点:
规格化的原码尾数,最高数值位一定是。
正数其最大值表示;最小值表示。尾数的表示范围是。
负数其最大值表示;最小值表示为。尾数表示范围是
规格化的补码尾数,符号位与最高数值位一定相反。正数为形式,负数为形式。
正数最大值表示;最小值表示。尾数表示范围是
负数最大值表示;最小值表示。尾数的表示范围是
例子:若某浮点数的阶码、尾数用补码表示,共位:。则如何规范化。
数值部分左移三位,变为,由于是左移所以阶码,则移动后阶码为。所以规范化后是
如果机器数超出浮点数正数范围称为正上溢。如果超出负数范围称为负上溢。而规格化后所表示的小数也有下限,如果表示的正数比浮点数还要小,则会出现正下溢情况。相反如果表示负数比浮点数所能表示的负数还要小,则会出现负下溢情况。如果有一个数值出现正下溢或负下溢计算机默认该数值为。如果出现正上溢或者负上溢,则计算机会中断程序。
11.3 浮点数标准IEEE 754
如果不能统一一个规格来表示浮点数阶码,尾数各占多少位,各自采用原码补码还是移码来表示,则计算机之间进行数据传输就会出现解析之间的问题。所以,IEEE754标准可以统一计算机规范。
先回顾一下移码,移码定义:移码真值偏置值。此处位移码的偏置值,即。指计算机位数。
如果真值,则移码。

根据以上定义可以得到之前结论:移码是补码符号位取反的值。上面偏置值是,但在IEEE754标准中,偏置值是,即。
改变偏置值后移码如下:

IEEE754标准规定阶码部分用移码表示,即,尾数部分用原码表示。

其中尾数部分为的原码隐藏了最高位的。下图是标准详细类型表示:

真值范围是,因为和有其他用途。
短浮点数
短浮点数确定真值方法:
例1:将十进制数转换为IEEE754的单精度浮点数格式表示
总位数:位
首先将十进制转换为二进制:二进制
其数符;尾数部分(规定隐藏最高位的);阶码真值;单精度浮点数偏移量,所以移码阶码真值偏移量,即二(要凑足位)。
从而可得单精度浮点数规格
例2:将IEEE754表示的单精度浮点数十六进制的真值是多少
转换为二进制
尾数部分(隐含最高位),即尾数真值二进制;移码,若看作无符号数,而单精度偏移量,所以,阶码真值移码偏移量二进制十进制
故转换为浮点数真值二进制
能表示浮点型最小绝对值:尾数全为,阶码真值最小,对应移码机器数,此时整体的真值
最大绝对值:尾数全为,阶码真值最大,对应移码机器数,此时整体的真值位
长浮点数
确定方法:
最小绝对值:尾数全为,阶码最小,所以最小值
最大绝对值:尾数全为,阶码最大,所以最大值
阶码全全的用途:
上面单精度浮点数最小能表示,如果还想表示比这更小的数此时就要用到阶码全和阶码全两种状态。

对于单精度来说上面阶码部分位,如果看作无符号数所能表示范围就是,其中二进制全,二进制全。所以取出这两种状态,阶码表示范围就是。
但如果阶码全,而尾数不全为时,这表示非规格化小数,此时默认小数点前面一位就是而不是,这种情况下所能表示浮点数对应真值是后面阶码真值也会固定为
如果阶码全,尾数也全,这表示
如果阶码全,尾数全,表示无穷大
如果阶码全,尾部不全为,表示非数值数"NaN"(Not a Number)。如:进行,等非法运算的结果就是
11.4 浮点数运算
浮点数加减运算步骤:
- 对阶。策略是阶数更小的向阶数更大的对齐。
- 尾数加减
- 规格化
- 舍入
- 判断溢出
先从十进制开始理解上述步骤。给定十进制数科学计数法:
由于后面阶数不一样,所以要先对齐。通常策略是阶数更小的向阶数更大的对齐。原因是定点小数前只有一位方便计算机处理。
所以变为:
两个尾数相加即可:
规格化是要保证尾数的第一个数值位是一个有效位。像就不需要规格化。如果是时需要左规,如果是就需要右规。
接着舍入,如果得到的新尾数长度过长就需要舍弃低位部分。若规定只能保留位有效尾数,则保留五位小数。也可以用其他方法如:四舍五入、舍去部分不为则像高位进等。
最后判断溢出。若规定阶码不能超过两位,则运算后阶码超出范围,则溢出。如:,规格化并用四舍五入的原则保留位尾数,得阶码超过两位,发生溢出。
注意:尾数溢出未必导致整体溢出,也许可以通过两步规范。
接着看二进制浮点数加减法。
例:已知十进制数、,则按机器补码浮点运算规则计算,结果用二进制表示,浮点数规格如下:阶符取位,阶码取位,数符取位,尾数取位。
解题步骤:
首先将十进制数转换为二进制。
二进制,二进制,所以
二进制,,所以
接着把尾数和阶码部分转换为补码
对于,其中补码,且由于阶符要两位,阶码要三位,所以是。尾数,且阶符要两位,尾数取位,所以是。即,
接着正式运算,首先使两个数的阶码相等小阶的向大阶看齐, 尾数每右移一位,阶码加
计算机判断阶数大小操作很简单,只需要将两个数的阶数进行相减的操作,如果是即负数,证明被减数要比减数阶数小。
阶码阶码,即结果为,所以需要让阶数更小的向右移动一位,因为阶差只有
向右移动一位
接着尾数相减,为了方便运算,先将数值位取反变为负值的补码。数值位取反末尾
规格化:可以看到结果溢出,且是负溢出可以进行右规操作进行补救。由于要结果进行算术右移,所以高位补什么要看双符号位更高位,因为更高位是本应该正确的符号。所以右移后结果:。同时右规后阶码要,即
最后规格化结果是:
再上一步进行右规算术右移时候已经抛弃一位,且最低位是,所以这里不用考虑舍入问题。
判断溢出:需要判断阶码是否越界。明显阶码位,无越界。所以上面补码转换为原码对应真值:
上面例子没有舍入,下面是需要舍入方法:
""舍""入法:类似于十进制数运算中的四舍五入法,即在尾数右移时,被移去的最高数值位为,则舍去;被移去的最高数值位为,则在尾数的末位加。这样做可能会使尾数又溢出,此时需再做一次右规。
恒置""法:尾数右移时,不论丢掉的最高数值位是""还是""都使右移后的尾数末位恒置""。这种方法同样有使尾数变大和变小的两种可能。
例如:加减运算结果为。由于数值符号异号,所以规格化。可以看到数值进行右规操作后整体右移,导致低位溢出。按照舍入策略,要在数值末位即。同样横置法类似。
当进行规格化和舍入操作时会导致阶码值改变,如果发生下溢,直接当作处理即可。如果发生上溢则会发生中断,这是必须要处理的错误。而有的计算机可能会把浮点数的尾数部分单独拆出去计算放入,算完了经过舍入后放入再拼回浮点数。
11.5 浮点数强制类型转换
系统位数对应的变量类型如下:

如果按照,如果按照这样的顺序转换则不会出现精度丢失问题。其中,double所能表示的位数是个数值位位阶码尾数还有一个隐含的位。
如果是位操作系统那么,这里型有,而有位。所以在位操作系统中,向转换是不会丢失精度的。但如果是位操作系统占位,而只有位。此时就会有精度的损失。
同样的尾数是位,是位。显然不会丢失精度。
再看,在位操作系统中,位数是个符号位个数值位;而是个符号位个阶码数值位个隐藏数值位,所以是数值位。那么可能会有精度的损失,但考虑到位的阶码所能表示的数肯定比更大,所以范围不会出现溢出。而,由于可能表示小数,小数在转变为类型时,小数点后的所有数值都会舍去,此时会有精度损失。而所能表示的范围比更大,所以会有溢出可能性。

三. 存储系统
存储器层次结构

上图底层至顶层的数据处理速度越来越快,容量也越来越小,同时价格也越来越高。最上的一层是寄存器,如:等。这些寄存器会比Cache缓存都快的多,所以CPU进行运算时,会把操作数放入寄存器中。
存储器层次结构图如下:

由于CPU运算速度很快,所以不能直接访问辅存。辅存中数据必须先调入主存中,才能进行访问。虽然数据被放入主存中,CPU访问速度可以大大提高,但速度还是不够快,所以就要用到高速缓冲存储器(Cache)。一些经常用到的数据会从主存中复制一份到缓存中,这样效率会大大提高。如:微信在视频通话时候,处理视频通话模块会在通话期间经常用到,所以这一处理模块会写入缓存中。
再详细一点,主存和辅存之间的数据交换是由硬件操作系统实现的,操作系统根据页面置换算法可以决定把哪些数据从主存置换到外存,这一层面需要系统程序员关系。主存和Cache之间的数据交换通常由硬件自动完成,这一部分由硬件工程师完成。
主存辅存:实现虚拟存储系统,解决了主存容量不够的问题
Cache主存:解决了主存与CPU速度不匹配的问题
存储器分类如下:

同时,存储器也可以按照存储介质分类:
- 半导体存储器:以半导体器件存储信息。常用在主存和Cache上。
- 磁表面存储器:以磁性材料存储信息。常用在磁盘和磁带上。
- 光存储器:以光介质存储信息。常见的有光盘。
也可以按存取方式分类:
- 随机存储存储器(RAM):读写任何一个存储单元所需时间都相同,与存储单元所在的物理位置无关。如:内存条。
- 顺序存取存储器(SAM):读写一个存储单元所需时间取决于存储单元所在的物理位置。如:磁带等。
- 直接存取存储器(DAM):既有随机存取特点,也有顺序存取特点。先直接选取信息所在位置,然后按顺序方式存取。如:机械硬盘。
后两种存储器由于读写某个存储单元所需时间与存储单元的物理位置有关,所以也可以一起称为串行访问存储器。
还有一种特殊存储器:相联存储器:一种可以按内容访问的存储器(CAM),按照内容检索到存储位置进行读写。快表就是一种相联存储器。即可以直接表明要查找的内容,根据内容找到数据存储位置。
也可以按照信息的可更改性进行分类:
- 读写存储器(RW M):既可以读也可以写。如:磁盘、内存、Cache
- 只读存储器(ROM):只能读,不能写。如:实体音乐专辑采用CD-ROM、实体电影采用蓝光光碟、BIOS通常写在ROM中集成在主板上。事实上很多ROM也可以进行写数据,只不过比较麻烦。
还可以按照信息可保存性分类:
- 断电后,存储信息消失的存储器:易失性存储器。如:主存、Cache。
- 断电后,存储信息依然保持存储器:非易失性存储器。如:磁盘、光盘。
- 信息读出后,原存储信息被破坏:破坏性读出。如:DRAM芯片,在读出数据后要进行重写。
- 信息读出后,原存储信息不被破坏:非破坏性读出。如:SRAM芯片、磁盘、光盘。
存储器性能指标:
- 存储容量:存储字长字长。如:位。MDR位数反映存储字长。
- 单位成本:每位价格总成本总容量
- 存储速度:数据传输率数据的宽带存储周期。数据的宽度即存储字长。

存取时间:存储时间是指从启动一次存储器操作到完成该操作所经历的时间,分为读出时间和写入时间。
存取周期:存取周期又称为读写周期或访问周期。它是指存储器进行一次完整的读写操作所需的全部时间,即连续两次独立地访问存储器操作(读或写操作)之间所学地最小时间间隔。即存取周期存取时间回复时间
主存带宽(Bm):主存带宽又称数据传输率,表示每秒从主存进出信息地最大数量,单位为字秒、字节秒(Bs)或位秒(bs)
1. 主存储器基本组成
一个存储体可以分为:存储体、MAR、MDR三大部分。其中MAR是地址寄存器,MDR是数据寄存器。这三个原件会在时序控制逻辑指挥下进行配合工作。

1.1 存储芯片基本原理
存储体就是存放实际地二进制数据。一个存储体由多个存储单元构成,而每个存储单元又由多个存储元构成。一个存储元可以存放一位地二进制或。

上面的MOS管可以理解为一种电控开关,输入电压达到某个阈值时,MOS管就可以接通。具体原理是:如在MOS管一端输入一个高电压,这个高电压会达到MOS管阈值,接着MOS管就是导电。而如果电压没有达到阈值,那这个MOS管元件就是一个绝缘体。这种在电压达到阈值后是导体,如果电压不够或没有电压情况下又是绝缘体的材料被称为半导体材料。
另一个元件是电容:一个电容由两个金属板和中间的绝缘体构成,下边的三条依次变短的线表示下边这个金属板是接地的,即接地端电压是。如果现在给上面的金属板加一个电压,由于与下面接地的金属板产生电压差,因此电容中的电荷就会开始移动,这个移动过程就是给电容充电的过程。即当我们输入一个电压后,这个电容中就会保存一定的电荷,而如果上面输入的是低电压的或,由于上下两个金属板的电压差很小,所以此时的电容并不会充电。可以根据电容是否保存电荷的两种状态信息来对用二进制的或。
假设下面电容中已经有一些电荷,即电容表示二进制,此时读取这个二进制办法是:给MOS管一端加一个高电压信号,也可以理解为对MOS管输入二进制,MOS管就会接通变为导体,接通后,电容中存储的电荷就可以顺着导线外流,当上图最右端的出口检测到电流时,就可以认为这个存储元输出一个二进制。而另一种情况如果电容中没有保存电荷,当MOS管接通后,输出端并不能检测到电荷流出,因此在这种情况下电容中保存的是二进制的,也即存储元输出一个二进制。
输入一个二进制位原理类似:在输出端加一个高电压,同时给MOS管也加一个高电压接通,接通后输出口的高电压顺着接线流入电容,此时上边金属板电压是,下边是,产生电压差,电荷会移动到电容中。也即电容存储了二进制。最后再将MOS管断开即可完成存储。
如果将多个存储元进行科学合理的连接,那么就可以一次性读出或写入多个二进制数据。存储单元构成如下:

上面存储单元中红色线称为字选线,其连接了存储元每一个MOS管,因此如果给这条红色的线加一个高电平,那么这一行的MOS管都可以被接通,当MOS管接通后,电容中存储电荷就会顺着绿色线数据线往外导出,此时只需要检测每条绿色的线有没有导出电流就可以知道每一个存储元存储的是对应的二进制或。
而多个存储单元就构成了存储体,也称存储矩阵。存储体结构如下:

一次可以读出的一行二进制位就是存储字,上面例子中一行有个存储元,所以存储字长是。所以在这个例子中一个存储字。
实际情况中要使用译码器,来解决如何根据地址决定要读或写的存储字位置。如下:

译码器使用原理:假定给出位地址信息,这位地址就会对应个存储单元,所以译码器会根据地址寄存器MAR中给出的这几位地址,将其转变成某一条选通线的高电压信号。
假如CPU给MAR的地址是,对应十进制是。所以移码器会把第根字选线给它一个高电平的输出,之后再根据上面存储单元读取数据原理,就可以读取第一行的二进制信息。
总之每一个地址会对应一条字选线,如果有个地址,就会对应条字选线。译码器根据地址选取字选线,给定该字选线一个高电平信号,这个线或接通对应一行的MOS管,之后再根据绿色的数据线读取到每一位的二进制信息。之后CPU会通过数据总线取走这一整个字的数据。所以数据总线的宽度存储字长。
对于上面例子,其总容量存储单元个数存储字长。这里的表示MAR给定的只有三个地址。
继续完善这个存储芯片构成,还需要增加一个控制电路,用于控制译码器、MAR和MDR。

如CPU通过地址总线把地址送入MAR中,但是由于使用的是电信号来传输二进制数据,而电信号难免有不稳定的时候。因此当MAR中电信号稳定之前这个地址信息是不能送到译码器中的。所以这就是控制电路作用,只有MAR稳定后才会打开译码器开关让译码器翻译这个地址。同样当数据输出时,输出电信号稳定后控制电路才会认为此时输出是正确无误的,所以控制电路也需要控制MDR在什么时候给数据总线送出数据。
另一方面存储芯片还需要对外提供:
片选线(用或表示)。这种头上画线表示该信号低电平有效。
读控制线和写控制线。
如果将两根线分开设计:允许写、允许读
如果两个线设计为一根:低电平表示写,高电平表示读。
至此存储芯片完整构造原理已经介绍完:

存储芯片逻辑图:

存储矩阵就是一个个的存储元。译码驱动电路分为:译码器和驱动器。译码器前面已经介绍,驱动器作用就是保证译码器输送到字选线的电信高稳定。读写电路包括自选先、数据线和控制电路。另外一个存储芯片通常还需要地址线来接受CPU通过地址总线传递的地址信息。还需要通过数据线进行数据的传输。除此之外还需要片选线电信号来确定这一块芯片此时是否可用。最后还需要读写控制线,读写控制线可能不止一条。
详细说一下片选线,给定一个内存条:

上面主存每一个黑色矩形就是一个存储芯片,所以一个内存条包含多个存储芯片。如果要读取的数据只存放在某一块存储芯片中,在提供一个读写地址之后,只能让存储数据那一块芯片工作,而其他芯片不参与工作。此时就需要片选线,发送一个低电平信号给要读取的芯片。而其他芯片都给一个高电平信号。这样就能保证此时读取的就是指定芯片的数据。
存储芯片逻辑图中每根线都会对应硬件的一个金属引脚。有的题目会让判断金属引脚最少数目。这种题其实就是判断地址线和数据线的总根数,再加上一定需要的一根片选线和至少一根的读写控制线的数目就是金属引脚的最少数目。另外还会有供电引脚、接地引脚。
地址线总数就是数,数据线总数就是数。
如果告诉一个地址芯片有位地址,则有个存储单元,意味着地址线有条。
常见描述:位,即存储单元个数有个,每个存储单元字长是,即
1.2 寻址方式实现

上图一个格子表示一个字节,一行表示一个存储字。假设总容量位,即行,个字。通常寻址方式是按字节编址的。也就是说每一个字节会对应一个地址。由于有个单元,那么地址总线就是根,因为。而整个地址空间是从:


如果想按字寻址,由于一个字占四个字节,所以会把一行合并看作一个字。当我们指定要读的是第几个字时,只需要把字地址进行算术左移两位,这样就可以把字地址转为与之对应的起始字节地址。如此时要读取号字,也就是要读第二行的字,我们将算术左移两位,此时这个对应的十进制是,这样我们就得到这个字的起始字节的地址。
其他寻址方式原理类似。
2. SRAM和DRAM
SRAM即静态RAM;DRAM即动态RAM。
DRAM主要用于主存,SRAM用于Cache。重点在于SRAM和DRAM的对比。
上一节中介绍的存储器基本原理是DRAM芯片。两个芯片核心区别在于:存储元不一样。
DRAM芯片:使用栅极电容存储信息。SRAM芯片使用双稳态触发器存储信息。
2.1 SRAM和DRAM区别
DRAM存储元(栅极电容):

SRAM存储元(双稳态触发器):

DRAM存储元在上一节介绍过,这里重点介绍SRAM存储元双稳态触发器原理。上图一个双稳态触发器中包含六个MOS管()表示。这中存储元可以呈现出两种稳定的状态:
- 第一种:上图点是高电平,是低电平。这种状态对应二进制
- 第二种:如果上图点是低电平,点是高电平,这种状态对应二进制

同时双稳态触发器还需要两根数据线,根据两条线哪条线输出低电平信号,就可以判断触发器中存放的是还是。
如果要写入一个,只需要左边线为低电压,右边线高电压,就可以变为低高,存入。
两中存储元区别:
栅极电容 | 双稳态触发器 |
---|
电容放电信息被破坏,是破坏性读出,读出后应有重写操作,读写速度更慢 | 读出数据,触发器状态保持稳定,是非破坏性读出,读写速度更快 |
每个存储元制造成本更低,集成度高,功耗低 | 每个存储元制造成本更高,集成度低,功耗大 |
更详细对比:

上面提到了刷新的概念:
- 在栅极电容中电容内的电荷只能维持,即便不断电,后信息也会消失。所以之内必须刷新一次(给电容充电)。
- 而双稳态触发器只要不断电,触发器的状态就不会改变。
2.2 DRAM的刷新
DRM刷新周期一般为,且以行为单位,每次刷新一行存储单元。
之前介绍的译码器,如果有位地址,那么选通线的数量为。所以给译码器一端接根线(一百万根)不太可能实现。

解决办法是把存储单元由一维的排列改为二维排列。改为由存储端元构成的矩阵。这样之前的位地址就会被拆分为行地址和列地址。分别送给行地址译码器和列地址译码器。这样每个译码器就需要处理个地址信息。即位,每个只用负责即可。

这种方式地址选址原理也很简单。假设MAR地址是,这个二进制地址信息会被拆分成一个分给行地址译码器,和另一个分给列地址译码器。两个译码器根据都会对应选择第行第列存储单元内信息。

上面地址是位,采用二维存储需要根选通线,其中行地址译码器负责个根,列地址译码器负责根。
DRAM刷新方式有硬件支持,读出一行的信息后重新写入,占用个读写周期。
假设DRAM内部结构排列成的形式,读写周期是微秒(us),共有个周期。则刷新方式如下:
方式一:每次读写完都刷新一行,则系统的存取周期变为。其中前时间用于正常读写,后时间用于刷新某行。这种方式称为分散刷新

按照这种方法内会有次刷新操作。
方式二:内集中安排时间全部刷新。系统的存取周期还是,有一段时间专门用于刷新,这段无法访问存储器的刷新时间,称为访问死区。这种方式称为集中刷新

方式三:内每行刷新次即可,内需要产生次刷新请求,每隔一次,每内有的死时间无法访问。这种方式称为异步刷新。

在实际操作中,可以利用CPU不需要访问存储器这段时间进行刷新。即可在译码阶段进行刷新。这个刷新由存储器独立完成,不需要CPU控制。
2.3 DRAM地址线复用技术
DRAM在行译码器和列译码器输送地址时候不是和SRAM那么同时发送,而是分两次发送。本来DRAM中需要个地址线同时送行和列地址,但是采用地址线复用技术后,可以将行地址和列地址通过前后两次进行传输,也就是只需要条地址线就可以。先将行地址送达行地址缓冲器,再将列地址送入列地址缓冲器,两个缓冲器再送给两个译码器。

这种行列地址分两次送,可以使地址线减半、芯片引脚减半。原本需要个地址线,现在只需要个地址线即可。
所以在题中如果问DRAM引脚数量要考到地址复用技术导致引脚数量减半这一因素。
现在DRAM芯片已经过时,现在主存通常是采用SDRAM芯片。如:主存DDR3和DDR4。
3. ROM
ROM芯片:非易失性,断电后数据不会丢失
几种ROM芯片:
MROM:掩模式只读存储器
厂家按照客户需求,在芯片生产过程中直接写入信息,之后任何人不可重写(只能读出)可靠性高、灵活性差、生产周期长、只适合批量定制。
PROM:可编程只读存储器
用户可用专门的PROM写入器写入信息,写一次之后就不能更改。
RPROM:可擦除可编程只读存储器
允许用户写入信息,之后用某种方式擦除数据,可进行多次重写
可以进一步分为:UVEPROM:用紫外线照射分钟后可擦除所有信息
EEPROM:可用电擦除方式,擦除特定的字。
Flash Memory(闪速存储器):在EEPROM基础上发展而来,断电后也能保存信息,且可进行多次快速擦除重写。如:U盘,SD卡等
注意:由于闪存需要先擦除再写入,因此闪存的"写"速度比"读"速度更慢。
每个存储元只需要单个MOS管,所以位密度比RAM高。也就是ROM内存要比RAM大。
SSD(固态硬盘):由控制单元存储单元(Flash芯片)构成,与闪速存储器的核心区别在于控制单元不一样,但存储介质都类似,可进行多次快速擦除重写。SSD速度快、功耗低、价格高。目前个人电脑上常用SSD取代传统的机械硬盘。
拓展:手机辅存也使用Flash芯片,但相比SSD使用的芯片集成度更高、功耗低、价格贵。
之前的学习可以知道主存中存放重要指令。CPU根据这些指令完成对应操作。由于主存是RAM芯片,这种芯片会在断电后数据丢失。当再次开机时会将辅存中指令数据调用到主存中。操作系统装在辅存中,由于开机时主存中没有指令所以CPU必须向主板上面的ROM芯片读取开机所需要执行的指令。这个主板上ROM芯片就是BIOS芯片,其内部存储了"自举装入程序",负责引导装入操作系统(开机)。
在逻辑上主存由:RAMROM(BIOS)组成。且二者统一编址。

统一编址指的是:如果ROM芯片的容量是,那么CPU会将的地址分配给主存中的ROM芯片,RAM地址从开始往后编号。
总结:
很多ROM芯片虽然名字是“Read-Only",但很多ROM也可以进行"写"操作。
闪存的写速度一般比读速度更慢,因为写入前要先擦除。
RAM芯片是易失性的,ROM芯片是非易失性的。很多ROM也具有"随机存取"的特性。
3. 主存优化
上面介绍过存取周期:存取周期存取时间恢复时间

存取周期是指可以连续读写的最短时间间隔。DRAM芯片的恢复时间比较长,有可能是存取时间的好几倍(如:存取时间为,存取周期为,则可能)。而SRAM的恢复时间较短。由于存取周期长,从而引发多核CPU访问内存难得问题。
3.1 双端口RAM
作用:优化多核CPU访问一根内存条的速度。

这里CPU两个内核可以通过内存RAM的两个端口进行访问。如果要支持双端口RAM必须要有两组完全独立的数据线、地址线、控制线。CPU、RAM中也要有更复杂的控制电路(主板)。
两个端口对同一主存操作有以下种情况:
- 两个端口同时对不同的地址单元存取数据。
- 两个端口同时对同一地址单元读出数据。
- 两个端口同时对同一地址单元写入数据。这种情况是不被支持的,会出现写入错误情况。
- 两个端口同时对同一地址单元,一个写入数据,另一个读出数据。这种情况不被支持,因为会出现读出错误。
后两种不支持的操作解决方法是置"忙"信号为,由判断逻辑决定暂时关闭一个端口(即被延时),未被关闭的端口正常访问,被关闭的端口延长一个很短的时间段后再访问。

对比操作系统的"读者写者"问题。
3.2 多体并行存储器
内存每次读写都要恢复操作,当CPU要想连续读取时必须等待恢复,这个问题解决可以用到多体并行存储器。

上面的可以理解为四根规格一样的内存条。这种方案有两种编址方式:高位交叉编址和低位交叉编制。
高位交叉编址
根据地址的高位区分是哪个存储体(内存条)。如果有四个内存条,可以采用高位的两位来区分,因为正好可以表示四种内存条。
上图每个存储体可以划分为个存储体,每个存储体由体号体内地址构成。体号是当前存储体的地址,体内地址是每个存储体编号。

可以观察到,高位交叉编址的存储地址转换为十进制是垂直编址的,即,。
假设每个存储体存取周期是,存取时间是,假设。要连续访问这五个地址。
那么对于高位交叉编址要连续访问这五个地址所需的时间是:。因为每次访问读取时间是,而又需要时间恢复等待,由于高位交叉编址地址是在同一个存储体中连续存放的所以需要。

低位交叉编址
与高位交叉编址相反,即采用低位区分存储体。

可以观察到低位交叉编址是横向编址起始地址是,其实地址是,起始地址是
而对于低位交叉编址连续访问这五个地址所需时间就是:。
即由于低位交叉编址连续存储地址不是在同一个存储体内部而是分开存储,所以在读写第一个地址时,读完可以直接读写第二个,此时第一个进入恢复期,当三个读完后,要读取第五个地址时第一个已经恢复可以读取。所以时间就是,但这里计算的是总耗时考虑到了最后第四次读取的恢复时间,所以总耗时是。

所以可以得出一个结论当访问连续存储的地址时,低位交叉编制更快,且连续读取个存储字耗时为。实际上数据在内存中存储就是连续的,所以低位交叉编址方式应用更广泛,而高位交叉编址方式相当于单纯的扩容,速度上提升不大。
低位交叉编址方式采用流水线的方式并行存取(宏观上并行,微观上串行):
在宏观上,一个存储周期内,个存储体交叉存储器可以提供的数量为单个模块的倍。而为了保证这种流水线式存取不间断,当存取周期为,存取时间为总线传输周期为,应保证模块数。最好的方案式存储体个数。
3.3 单体多字存储器
相当于将多体多体并行存储器中的存储体进行合并。整个存储器只用一套读写电路、地址寄存器和数据寄存器。

上面每一个方格代表一个字。每次可以读取一行数据,即个字。所以数据总线宽度也为个字。显然这种存储器要比多体并行存储器灵活性要差。每次能同时取个字,不能单独取其中某个字。所以要读取的指令和数据在内存必须连续存放。即如果指令和数据不在同样一行存储,就意味着要读取两行数据,这两行数据中有部分无用信息。所以灵活性差。
但从速度方面来说单体多字存储器和多体并行存储器速度一样。每读入一个字平均时间都是。都可以很大程度上提升主存读写速度。
4. 主存储器与CPU连接
先回忆一下单块存储芯片:

单块存储芯片需要对外暴露接口有:数据总线(绿色)、地址总线(红色)、片选线和读写控制线(褐色)。上图给出的存储芯片只有位,但现在数据总线宽度通常都有位。要尽可能保证数据总线宽度存储字长。并且现代计算机中MAR和MDR都在CPU中,而存储芯片只是一个普通的寄存器。现代计算机主存结构如下:

如果想扩展主存的字数,需要字扩展;如果存储芯片字长比数据总线宽度要小,要用到位扩展。
4.1 位扩展
为了描述方便可以给存储芯片输入信号和输出信号进行命名:

地址从低位到高位是,数据总线从低到高是。片选先开关是或。读写控制线开关是或有的地方会把两根读写线分开表示。
下面是一个位的存储芯片:

,即需要根地址总线,连接上就完成了地址线的连接。

表示如果是高电平CPU就会往里写数据,如果是低电平就会读数据。

由于存储芯片只有位,所以一次只能通过数据总线来传送一位数据。

片选信号,由于只有一块芯片所以直接输入一个高电平信号,高电平代表开启。

此时主存只有一块芯片,每次只能读写一位数据。所以存储字长就是比特。数据总线并没有被充分利用。为了解决这个问题可以给主存再加一块相同型号的存储芯片,同样也是位。

这两个存储芯片同时工作,整个存储器存储字长扩展为位。现在可以同时读写两位的数据。使用同样方法再增加个存储芯片。

这样存储器存储字长就扩展为。这种扩展方式称为位扩展。
4.2 字扩展
假设现在有一块位的存储器

上面的存储字长是位,能完美匹配CPU数据总线。地址总线需要根,可以看到CPU提供了根地址总线,还有根没有用上,也就说这个CPU寻址是,MAR有位。所以CPU寻址能力并没有完全发挥。解决方法是同样加一块同型号的存储器,连接的方法有两种:线选法和译码片选法
线选法

可以看到地址总线和数据总线连接方式与之前一样。但是需要分别连接到和两个CPU的地址总线。由于片选信号是高电平有效,所以当是,而是,则表明左边存储芯片可以进行读写,右边则不会工作。
采用这种方式连接时的信号只能是不相同的,如果相同(如:)则两个存储芯片会同时工作,造成读写错误。这种方法称为线选法。这种方法会导致和开头的地址不可用。
译码片选法
接着优化上面的线选法

在接线处用非门连接第二个存储寄存器。假设处的信号是,第一个寄存器会工作,第二个寄存器经过非门取反后信号是所以不会工作。增加这个非门之后,左边寄存器合法地址变为,而右边寄存器合法地址变为。这个非门可以称为译码器,这代表输入一位的地址信息,这一位的地址信息有可能呈现出两种不同状态。即如果输入端信号为位,那么会对应成种不同的状态。
之前见过译码器:

左边是输入信号,位代表种不同状态。右边是输出线对应编号是。之前接触过更复杂的译码器,所以可以顺着这个思路继续优化。

上面这个译码器是译码器。上图变为即接受低电平才有效。译码器输出线上的圆圈表示非门。如果输入信息是,第二块寄存器会被选中进行读写操作,其他都不会工作。
如果和接入译码器,那么中间的无论是或都不会影响。

如果这样的话会发现为的时候可能取得的地址有个,当为时,又有个空间,而一块存储芯片只有存储空间,但是会对应个地址,所以这种情况只会在考试出现,实际情况不可能出现。
如果想将都接入译码器,只需要换个译码器,在接入四块位的存储芯片即可。
字扩展的线选法和译码片选法对比:

实际情况应用最多的是译码片选法。
同时可以将二者结合产生新的方法:字位同时扩展法。

图中有八块芯片:由于数据总线有根,所以可以每两块芯片为一组实现了位扩展,因为每个芯片是位。
每个芯片有对应即有根地址总线可以用上,可以将CPU的全部连接。这样会多出两根地址总线,所以可以接入一个译码器,此时能产生四种不同状态,可以再连接三个存储芯片。此时字扩展为位的寄存器。整个存储空间从全到全不间断存储。
4.3 几种常见译码器
最常见的是高电平有效的译码器:

这种译码器输出的是高电平所以可以配合使用。
低电平有效的译码器

译码器的输出端加了小圆圈代表取反,即低电平会输出,可以配合使用。
有使能端的译码器

使能端是指当有高电压时候才能使用,类似于。与之对应的是加一个圆圈的使能端,即低电压才能使用,对应。
多个使能端的译码器(型号的译码器)

下面两个使能端画了小圆圈代表取反。即一个高电平两个低电平译码器才能工作。
如果使能端输入的全是低电平,那么译码器的输出总线会输出全,都是高电平,存储器接收到全就不会工作。

多个使能端作用是CPU可使用译码器的使能端控制片选信号的生效时间。实际上CPU中除了地址之外还有一个很重要的输出信号(主存储器请求信号),当CPU想要正式访问主存时,这个信号会发出低电平,译码器使能端接受到这个低电平就会开始工作。
即在实际中CPU会先通过地址总线送出地址信号,其中包括低位和高位地址。由于数据是由信号送出的,所以电信号可能不稳定,因此CPU需要等到电信号稳定再通过发出主存请求信号让译码器工作。这样就能保证当一块存储芯片选中时,这块芯片所接受的地址地址信息是稳定的。

5. 磁盘存储器
计算机的外存储器又称为辅助存储器,目前主要使用磁表面存储器。所谓"磁表面存储",是指把某些磁性材料薄薄地涂在金属铝或塑料表面上作为载磁体来存储信息。磁盘存储器、磁带存储器和磁鼓存储器均属于磁表面存储器。

这种磁表面存储器一次读写只能是。并且读写这两种状态不能同时进行。
磁表面存储器的优点:
- 存储容量大,位价格低
- 记录介质可以重复使用
- 记录信息可以长期保存而不丢失,甚至可以脱机存档
- 非破坏性读出,读出时不需要再生。
磁表面存储器的缺点:
- 存取速度慢
- 机械结构复杂
- 对工作环境要求较高(磁性材质易受强磁场的干扰)。
外存储器既可以作为输入设备,也可以作为输出设备。(既可以存数据,也可以读数据)
5.1 磁盘设备的组成

磁盘分为两部分:正面是左图的机器部分。背面是右图的电路部分。具体细分如下:
存储区域:
一块硬盘含有若干个记录面,每个记录面划分为若干条磁道,而每条磁道又划分为若干个扇区,扇区(也称块)是磁盘读写的最小单位,也就是说磁盘按块存取。
为了读取每个盘面(记录面)的数据,因此每个盘面都有读写磁头
- 磁头数:即记录面数,表示硬盘总共有多少个磁头,磁头用于读取写入盘片上记录面的信息,一个记录面对应一个磁头。
此面涂抹磁性材料方式是一圈一圈涂的每一圈的磁性材料称为磁道。而每个盘片都是同样被划分多个磁道,对于不同盘面上相对位置相同的磁道称为一个柱面。
- 柱面数:表示硬盘每一面盘片上有多少条磁道。在一个盘组中,不同记录面的相同编号(位置)的诸磁道构成一个圆柱面。
同时还会给每个盘面划分多个扇区。计算机每次对磁盘的读写操作都是以扇区位单位的
硬盘存储器
为了能让磁盘能动起来,一个磁盘中需要有机械部件。
这些机械部件有:磁盘驱动器、磁盘控制器和盘片组成。
磁盘驱动器:核心部件是磁头组件和盘片组件,温彻斯特盘是-种可移动头固定盘片的硬盘存储器
磁盘控制器:是硬盘存储器和主机的接口,主流的标准有IDE、SCSI、 SATA等。

值得一提的是在一个磁盘的盘面上,可以在正面和反面都涂抹上一圈一圈的磁性材料。最上面光盘和最下面光盘一侧没有磁头,剩下光盘都有两个磁头在其盘片的正面和背面。磁盘横切面图:

5.2 磁盘的性能指标
磁盘性能指标通常看以下几点:
磁盘的容量:一个磁盘所能存储的字节总数称为磁盘容量。磁盘容量有非格式化容量和格式化容量之分。
非格式化容量是指磁记录表面可以利用的磁化单元总数。即磁盘在物理上来看总共可以存储的二进制比特位上限。
格式化容量是指按照某种特定的记录格式所能存储信息的总量。即磁盘有的扇区可能会损坏,为了避免有的扇区损坏导致整个磁盘无法使用,因此很多厂商生产的磁盘需要格式化留下某些备用的扇区作为顶替使用。所以实际用量会减少。
所以对于一块磁盘来说格式化的容量要比非格式化的容量要小。
记录密度:记录密度是指盘片单位面积上记录的二进制的信息量,通常以道密度、位密度和面密度表示。
道密度是沿磁盘半径方向单位长度上的磁道数。如:道指的是磁盘上一厘米半径有个磁道。
位密度是磁道单位长度上能记录的二进制代码位数。如:如果某圈磁道的位密度是,指的是外圈每一厘米的磁道可以存储的信息。
注意:磁盘所有磁道记录的信息量一定是相等的,并不是圆越大信息越多,故每个磁道的位密度都不同。即越内测的磁道位密度越大。因此内测磁道会影响到磁盘的总体容量。


面密度是位密度和道密度的乘积。
平均存取时间:
平均存取时间寻道时间磁头移动道目的的磁道旋转延迟时间磁头定位到所在扇区传输时间传输数据所花费的时间 磁盘读取过程如下:

首先磁盘要先进行寻道(找到所读位置的磁道),通常来说寻道花销时间较长。接着会旋转盘片直到磁头靠近所读扇区的起始位置。最后盘片接着旋转,使得磁头划过所读扇形弧道长度。
通常来说寻道时间题目会给个平均时间,旋转延迟时间如果题目没给,一般取盘片转半圈的时间。最后扇区时间需要根据题中所给的磁盘转速算出。有的题目还需要加上磁盘控制器延迟时间(CPU传输读取指令的时间)。
数据传输率:磁盘存储器在单位时间内向主机传送数据的字节数,称为数据传输率。
假设磁盘转数为(转秒),每次旋转都会读取一整条磁道,而每条磁道容量为个字节,则数据传输率为。
5.3 磁盘工作原理
上面介绍过磁盘读取过程原理。主机为了指明要读取的扇区位置,需要给磁盘中的各个扇区编号,即地址。
磁盘地址一般如下图所示:

- 驱动器号:一台电脑又可能有多个硬盘,所以要指明哪个驱动器。
- 柱面号:根据柱面号,磁头臂可以移动到哪个位置。
- 盘面号:可以根据盘面号激活对应的磁头。
- 扇区号:激活对应磁头之后,盘面旋转在指明的扇区号停下。
例如:若系统中有个驱动器,每个驱动器带一个磁盘, 每个磁盘个磁道、个盘面,每个盘面划分为个扇区,则每个扇区地址要位二进制代码。

磁盘工作过程:硬盘的主要操作是寻址、读盘、写盘。每个操作都对应一个控制字,硬盘工作时,第一步是取控制字,第二步是执行控制字。硬盘属于机械式部件,其读写操作是串行的,每次只能读写一个比特位,不可能在同一时刻既读又写,也不可能在同一时刻读两组数据或写两组数据。因此需要加入一个并串电路,因为CPU发送信号是并行的,而磁盘一次只能接受一比特是串行的。

5.4 磁盘阵列
RAID(Redundant Array of Inexpensive Disks 廉价冗余磁盘阵列)是将多个独立的物理磁盘组成一个独立的逻辑盘,数据在多个物理盘上分割交叉存储、并行访问,具有更好的存储性能、可靠性和安全性。也就是可以用某些手段将多个磁盘组成磁盘阵列,再结合相应的算法和机制可以提高磁盘的读写速度,同时也能提升存储性能、可靠性和安全性。
RAID的分级如下所示。在的几种方案中,无论何时有磁盘损坏,都可以随时拔出受损的磁盘再插入好的磁盘,而数据不会损坏。
:无冗余和无校验的磁盘阵列。没有容错能力。
逻辑上相邻的两个扇区在物理上存到两个磁盘,类比之前的低位交叉编址的多体存储器。

上图两个磁盘,指的是逻辑上相邻的数据。原理是在读写第一个数据时,可以直接读写第二个磁盘的数据。所以该方案是无冗余数据,但没有校验。校验:磁盘会有扇区损坏情况,如果一个扇区损坏那么在这个扇区所有数据都会消失,也有可能读取扇区没有损坏,但由于其他干扰导致读取数据错误,这样问题都不能进行解决。所以该方案无校验。
:镜像磁盘阵列。有容错能力,但容量减少一半。
将统一数据存储在多个磁盘上。

统一可以在一号磁盘读取,在二号磁盘读取,这样也能提高读写速率。而这种方案也更靠谱,如果某些扇区损坏至少可以在另一个镜像磁盘中读取数据。不会全部消失。另外由于其他力量干扰导致读出数据产生跳变,可以对比两个磁盘信息找出错误。所以这种方案会有冗余信息产生,但也有校验的功能。磁盘利用率不高。
:采用纠错的海明码的磁盘阵列。
在逻辑上连续的几个物理上分散存储在各个盘中。而信息位海明校验位,可纠正一位错。

上面的指的是四个连续的比特数据。后面的中保存与之数据对应海明校验码。上面位信息位的海明校验码,就可以有发现一位错误的能力。
:位交叉奇偶校验的磁盘阵列。
:块交叉奇偶校验的磁盘阵列。
:无独立校验的奇偶校验磁盘阵列。
上面六种方案越往后可靠性越高,成本也越低。
6. 固态硬盘SSD
固态硬盘存储技术是基于闪存技术(Flash Memory),属于电可擦除ROM,即EEPROM。

SSD组成有两部分:
闪存翻译层:负责翻译逻辑块号,找到对应页(Page)。
存储介质层:有多个闪存芯片,每个芯片包含多个块(如:一个块大小是KB),每个块包含多个页。

固态硬盘的读写是以页位单位的,相当于磁盘的一个扇区。固态硬盘的一个块,相当于磁盘的磁道。即系统通过总线指明此次要读写的逻辑块号是多少,如果数据是存放在磁盘(机械硬盘)中,那么一个逻辑块对应的就是一个磁盘块磁盘扇区。
SSD读写性能:是以页为单位进行读写的。以块为单位进行擦除,擦干净的块,其中的每页都能写一次,被读无限次。且支持随机访问,系统给定一个逻辑地址,闪存翻译层可以通过电路迅速定位到对应的物理地址。
如果要写的页有数据,则不能写入,需要将有数据的块内其他页全部复制到一个新的(擦除过的)块中,再在新的块中写入想要写入的数据,最后将原来的块内所有页擦除。此时地址会放生改变,但闪存翻译层会修正写入块的地址。这就导致了SSD读的速度比写的速度快很多。
固态硬盘相较于机械硬盘特点:
- SSD读写速度快,随机访问性能高,用电路控制访问位置;机械硬盘通过移动磁臂旋转磁盘控制访问位置,有寻道时间和旋转延迟
- SSD安静无噪音、耐摔抗震、能耗低、造价更贵
- SSD的一个"块"被擦除次数过多(重复写同一个块) 可能会坏掉,而机械硬盘的扇区不会因为写的次数太多而坏掉
由于上面的SSD一个块擦除次数过多可能会坏掉,所以现代SSD都会使用磨损均衡技术。
磨损均衡技术思想:将"擦除"平均分布在各个块上,以提升使用寿命。原理还是闪存翻译层有逻辑映射的功能,所以其真实物理地址会变。这种磨损技术分为两种:
- 动态磨损均衡:写入数据时,优先选择累计擦除次数少的新闪存块。
- 静态磨损均衡:SSD监测并自动进行数据分配、迁移,让老旧的闪存块承担以读为主的储存任务,让较新的闪存块承担更多的写任务。如:假设电脑中存储一部电影,对于电影来说读的次数更多基本上不会进行修改。所以SSD会监测到,并将电影放入擦除次数多的块中。
SSD总结:

例题:某固态硬盘采用磨损均衡技术,大小为, 闪存块的擦写寿命只有次。平均每天会对该固态硬盘写数据。在最理想的情况下,这个固态硬盘可以用多久?
SSD采用磨损均衡技术,最理想情况下,SSD中每个块被擦除的次数都是完全均衡的。,所以平均每天,每个闪存块需要擦除一次。而每个闪存块可以被擦除次,因此,经过天,约年后,该固态硬盘会坏。
7. Cache缓存
之前运用双端口RAM、多模块存储器提高存储器的工作速度,但优化后主存与CPU速度差距依然很大,所以可以增加一个Cache层缓和CPU与主存之间的速度矛盾。
7.1 Cache基本原理与概念
Cache工作原理

假设启动一个微信并使用视频聊天功能,首先会将视频聊天的代码放入Cache中,CPU可以直接从缓存中读取。而Cache读写速度非常快可以更好配合CPU工作。
注意:实际上Cache被集成在CPU中。Cache使用SRAM实现,速度快,成本高,但集成度低所以Cache芯片不能做的大,现在一般CPU的Cache缓存只有。
Cache的局部性:
- 空间局部性:在最近的未来要用到的信息(指令和数据),很可能与现在正在使用的信息在存储空间上是邻近的
- 时间局部性:在最近的未来要用到的信息,很可能是现在正在使用的信息。常见的是循环结构。
看一段代码:

上图是代码翻译成指令后,与数据一起存放在主存中。这个程序会一行一行访问数组中的元素:
根据空间局部性当我们访问完后,在接下来的一段时间内与它相邻的其他元素也有可能被访问到。
根据时间局部性,由于循环内部执行了sum
加法后,在这一段时间内这个加法指令还会被使用到。另外由于循环结构代码内的sum,i,j
这些变量在短时间内也会被循环访问。
基于这些局部性原理,可以把CPU目前访问的地址"周围"的部分数据放到Cache中。再看下面一段程序:
上面一段程序将会按照列来访问数组,显然这种按列优先的方式访问二维数组,其空间局部性会更差。所以这段代码在执行时间上要慢于第一段代码。
性能分析
假设CPU访问一次Cache所需时间为,而访问主存时间为,命中率为,即CPU能在Cache中找到想要的数据的概率。与之对应的缺失率。CPU读取可以分为两个策略:
例题:假设Cache的速度是主存的倍,且Cache的命中率为,则采用Cache后,存储器性能能提高多少?(设Cache和主存同时被访问,若Cache命中则主存中断访问)。
设Cache的存取周期为,则主存的存取周期为。且由于主存和Cache同时访问,所以命中时访问时间为,未命中时访问时间为。则平均访问时间为。故性能为原来的倍。
若先访问Cache再访问主存,命中时访问时间为,未命中时访问时间为,则平均访问时间为故性能为原来的倍。
有待解决的问题
基于局部性原理,不难想到,可以把CPU目前访问的地址"周围"的部分数据放到Cache中。关于这个"周围"可以用以下方法确定:
将主存的存储空间"分块",如:每为一块。主存与Cache之间以"块"为单位进行数据交换。

如上图,假设现在访问了这个元素,就可以将到这样一块存储中的数据放入Cache中。而为了方便存储,Cache内部也会被分为大小相等的块。

如上图,内存中每块大小是,即主存被分割成块内存。另外主存共有位,那么块号可以用位表示,块内地址可以用位表示。
注意:操作系统中,通常将主存中的"一个块"称为"一个页页面页框"。而Cache中的"块"也称为"行"
同时每次被访问的主存块,一定会被立即复制进Cache中。从而还有以下几个问题要解决:
7.2 Cache主存映射方式
映射方式可以解决Cache与主存的数据块对应关系这一问题。
映射方式有三种:全相联映射、直接映射、组相联映射。

对于如何区分Cahce中存放的是哪个主存块内容,可以通过一个标记一个有效位方式解决。
第一个标记用于标记Cache块内存放的信息是主存哪个位置,有效位标记用于确认第一个标记主存位置信息是否能用,即和。因为计算机只能区分和,所以第一个标记中不用的Cache块会被默认标记,显然这个默认标记并不是指这个Cache块存放的是主存中号地址的信息,所以要用到第二个标记有效位来确认这个指向主存地址信息是否可用。

如上图,Cache中号存储块有效位是,表示标记为可用用,即号块存储的是主存中号块的信息。下面会介绍每种映射方式细节。
全相联映射
假设某个计算机主存地址空间大小为,按字节编址,其数据Cache有个Cache行,行长
由于Cache行长是,所以为了保持全相联,主存行长也要是。主存对应即主存地址共位。而大小,每行行长是,所以。这也就意味着主存可用分为这么多块,可用位当主存块号,位当块内地址。

存放原理:
首先将有效位全部置为。假如要将主存块号放入Cache中,由于采用的是全相联映射意味着可用放到Cache中任意位置。挑选Cache中位置放入。为了区分号Cache块存放的是哪个主存块,将前面标记位设置个,即主存号对应的位置。并且将有效位设置为,表示这个标记地址有效。

访问原理:
假设现在CPU要访问这个位置信息(对应的是上图右边紫色位置),首先取这个地址的前位,对比Cache中所有块的标记,接着若标记匹配且有效位,则Cache命中,根据地址后六位访问块内地址为的单元。若未命中或有效位,则正常访问主存。
优点:Cache存储空间利用充分,命中率高。
缺点:查找"标记"最慢,有可能需要对比所有行的标记。
直接映射
假设某个计算机主存地址空间大小为,按字节编址,其数据Cache有个Cache行,行长
Cache块号主存块号Cache总块数

如上如,将主存号块信息放入Cache中要先计算映射Cache块号,即,所以要放入Cache号块中,而对主存号块的信息也要放入Cache,,而Cache号块已经有数据,那么之前的数据会被覆盖掉。

这一就有一个显而易见的缺点:其他地方有空闲Cache的块,但是号主存不能使用。这种方法灵活性差,空间利用率也不充分。
对于上面标记位,可用进行一个优化,不用将位的主块号全部放入,由于之前进行取余操作,从二进制角度看,主存块号这个运算结果其本质就是保留主存块号末位三位,这三位就直接指明了Cache中的存储位置。所以这里的标记为就不用写为位的,只需要存储前位就可用。

因此如果采用直接映射,若Cache总块数则主存块号末尾位直接反映它在Cache中的位置。所以将主存块号的其余位作为标记位即可。即不用对主存块号取余,只需要知道主存块号后三位就能知道对应的组号。同样这种方法可用直接优化主存块号位数:

CPU访问方法:
CPU访问主存地址:首先根据主存块号的后位确定()Cache行,接着若主存块号的前位与Cache标记匹配,且有效位,则Cache命中,访问块内地址为的单元。若未命中或有效位,则正常访问主存。
优点:对于任意一个地址,只需对比一个"标记",速度最快。
缺点:Cache 存储空间利用不充分,命中率低。
组相联映射
假设某个计算机主存地址空间大小为,按字节编址,其数据Cache有个Cache行,行长
组号主存块号分组数

上图采用路组相联映射,即Cache中块为一组,分四组。
主存号放入Cache中位置需要先计算组号,所以会放入第一组,第一组两个位置都是空的所以随机放一个。同样由于分组数为所以主存块号对分组数取余,相当于主存块号只保留后两位,即可通过这两位就能知道Cache中组号位置。所以标记为只需要位即可。即不用对主存块号取余,只需要知道主存块号后两位就能知道对应的组号。

同样可用块号和块内地址细分:

CPU访问方法:
CPU访问主存地址:首先根据主存块号的后位()确定所属分组号这里是,即第一组。接着若主存块号的前位与分组内的某个标记匹配且有效位,则Cache命中,访问块内地址为的单元。但若未命中或有效位,则正常访问主存。
优点:另外两种方式的折中,综合效果较好。术语:路组相联映射,即每个Cache块为一组。
7.3 Cache替换算法
Cache替换算法可用解决Cache很小,主存很大。如果Cache满了之后出现一系列问题。

结合上一节学的三种映射方式,分析Cache替换规则:
由于直接映射会直接替换不用进行选择,所以替换算法只会用到全相联映射和组相联映射这两种方式中。
随机替换算法
随机替换算法(RAND, Random):若Cache已满 ,则随机选择一块替换。
假设总共有个Cache块,初始整个Cache为空。采用全相联映射,依次访问主存块。访问以及替换方式如下:
由于每访问一次主存都需要将该主存块调入Cache中。当访问前四个主存数据时,刚好可以全部存入Cache中。

接着访问号主存块,由于号已经在Cache缓存中,所以可以命中直接读取即可。后面的号主存块也是一样,同样缓存可以命中。

访问号主存块,由于当前Cache块已满,而访问的数据要立即调入Cache中,所以此时就需要用到随机替换算法,来决定要替换Cache中的哪一块。假设当前替换号Cache块。

之后的号主存块的访问都可以命中Cache缓存

当访问号主存块时,同样使用随机替换算法,替换Cache块中的任意一个位置,这里替换号Cache块。

接着访问号主存块,继续使用随机替换算法,替换Cache块中的任意一个位置,这里替换号Cache块。

之后访问号主存块,该主存块在Cache缓存命中,所以直接访问

可以看出随机替换算法实现简单,但完全没考虑局部性原理,命中率低,实际效果很不稳定。
先进先出替换算法
先进先出算法(FIFO, First In First Out):若Cache已满, 则替换最先被调入Cache的块。
假设总共有个Cache块,初始整个Cache为空。采用全相联映射,依次访问主存块。访问以及替换方式如下:
由于每访问一次主存都需要将该主存块调入Cache中。当访问前四个主存数据时,刚好可以全部存入Cache中。

接着访问号主存块,由于号已经在Cache缓存中,所以可以命中直接读取即可。后面的号主存块也是一样,同样缓存可以命中。

访问号主存块,此时并没有在Cache缓存中,所以要放入Cache中,根据先进先出替换算法规则,此时Cache中最先被放入的是号Cache存储块,所以替换该存储块。

接着访问号主存块,根据先进先出替换算法规则,此时Cache中最先被放入的是号Cache存储块,所以替换该存储块。

访问号主存块,并没有在Cache缓存中,所以要放入Cache中,根据先进先出替换算法规则,此时Cache中最先被放入的是号Cache存储块,所以替换该存储块。

之后的号主存块都没有在缓存中,所以会分别会替换掉号Cache存储块。

先进先出算法:实现简单, 最开始按放入Cache,之后轮流替换号Cache存储块。该依然没考虑局部性原理,最先被调入Cache的块也有可能是被频繁访问的。
并且这种算法还会出现抖动现象:频繁的换入换出现象(刚被替换的块很快又被调入)
近期最少使用算法
近期最少使用算法(LRU, Least Recently Used ):为每一个Cache块设置一个"计数器",用于记录每个Cache块已经有多久没被访问了。当Cache满后替换"计数器"最大的。
采用这种算法需要增加一个计数器,记录一个Cache块多久没有被访问。计数规则如下:
- 命中时,所命中的行的计数器清零,比其低的计数器加,其余不变。
- 未命中且还有空闲行时新装入的行的计数器置,其余非空闲行全加。
- 未命中且无空闲行的,计数值最大的行的信息块被淘汰,新装行的块的计数器置,其余全加。
这里有一个小细节,第一条规则比其低的计数器才会加,这是由于只需要关注谁没有被访问的次数更大就可以完成替换,不需要关心Cache块究竟多久没有被访问。假如四个Cache块,可以保证每个Cache块对应的计数器不大于。不用考虑两个计数器相等情况。
假设总共有个Cache块,初始整个Cache为空。采用全相联映射,依次访问主存块。访问以及替换方式如下:
首先访问号主存块,访问之后装入Cache主存块中,由于此时Cache块都是,处于空闲状态,所以直接装入号Cache块。

之后访问号主存块,缓存未命中此时需要将非空闲行的计数器,即号Cache块对应的计数器。

接着访问号主存块,缓存未命中此时需要将非空闲行的计数器,即号Cache块对应的计数器。

访问号主存块,缓存未命中此时需要将非空闲行的计数器,即号Cache块对应的计数器。

之后再访问号主存块,缓存命中,所命中的行的计数器清零,比其低的计数器加,其余不变。即号Cache块计数器。

接着访问号主存块,缓存命中,所命中的行的计数器清零,比其低的计数器加,其余不变。即号Cache块计数器。

访问号主存块,缓存未命中并且也无空闲行,所以将计数器值最大的Cache块进行替换,即号Cache块会被替换。刚进行替换的Cache块的计数器置,其余全加

紧接着访问号主存块,缓存命中,所命中的行的计数器清零,比其计数器低的计数器加,其余不变。即号的Cache块计数器。号Cache块计数器不变,这是由于只需要关注谁没有被访问的次数更大就可以完成替换,不需要关心Cache块究竟多久没有被访问。此时号Cache块的计数器值已经是最大的,再让其意义不大。

继续访问号主存块,缓存命中,所命中的行的计数器清零,比其计数器低的计数器加,其余不变。即号Cache块计数器。

访问号主存块,缓存未命中并且也无空闲行,所以将计数器值最大的Cache块进行替换,即号Cache块会被替换。刚进行替换的Cache块的计数器置,其余全加

接着访问号主存块,缓存未命中并且也无空闲行,所以将计数器值最大的Cache块进行替换,即号Cache块会被替换。刚进行替换的Cache块的计数器置,其余全加

最后访问号主存块,缓存未命中并且也无空闲行,所以将计数器值最大的Cache块进行替换,即号Cache块会被替换。刚进行替换的Cache块的计数器置,其余全加

可以看出Cache块的总数,则计数器只需位。且Cache装满后所有计数器的值一定不会重复。上面例子有个Cache块,所以只需要位就可以记录计数器信息。
LRU算法:基于"局部性原理",近期被访问过的主存块,在不久的将来也很有可能被再次访问,因此淘汰最久没被访问过的块是合理的。LRU算法的实际运行效果优秀,Cache命中率高。但若若被频繁访问的主存块数量Cache行的数量,则有可能发生"抖动现象"。例如这种访问方式,最频繁访问的主存块数是Cache行的数量。
最不经常使用算法
最不经常使用算法(LFU, Least Frequently Used ):为每一个Cache块设置一个"计数器",用于记录每个Cache块被访问过几次。当Cache满后替换"计数器"最小的。
计数器规则是:
新调入的块计数器,之后每被访问一次计数器。需要替换时,选择计数器最小的一个Cache块替换。如果计数器最小Cache有多个,就可以按照行号递增或FIFO策略进行选择。
假设总共有个Cache块,初始整个Cache为空。采用全相联映射,依次访问主存块。访问以及替换方式如下:
由于每访问一次主存都需要将该主存块调入Cache中。当访问前四个主存数据时,刚好可以全部存入Cache中。计数器都置为。

接着访问号主存块,这两个主存块都可以被缓存命中,所以Cache块的计数器值。

访问号主存块,此时Cache块已满,所以替换掉Cache块对应计数器最小的。即中选一个,这里按照先进先出原则将号Cache块进行替换。

接下来访问主存块,这两个主存块都可以被缓存命中,所以Cache块的计数器值。

继续访问号主存块,此时Cache块已满,所以替换掉Cache块对应计数器最小的。即中选一个,这里按照行号优先原则将号Cache块进行替换。

访问号主存块,主存块可以被缓存命中,所以Cache块的计数器值。

最后访问号主存块,此时Cache块已满,所以替换掉Cache块对应计数器最小的。即号Cache块进行替换。

由于该算法需要用到计数器,并且计数器位数有可能很大。
LFU算法:曾经被经常访问到的主存块在未来不一定会用到(如:微信视频聊天相关的块,使用时计数器会一直增加,但不使用的时候由于计数器值已经很大,这些数据不会在接下来的一段时间内被缓存替换掉),并没有很好地遵循局部性原理,因此实际运行效果不如LRU。
7.4 Cache写策略
Cache写策略可以解决CPU修改了Cache中的数据副本,并如何确保主存中数据母本的一致性问题。
写命中
缓存命中情况下CPU对某个命中地址进行写操作。这种情况有两种解决方法。
写回法
写回法(write-back):当CPU对Cache写命中时,只修改Cache中的内容,而不立即写入主存,只有当此块被替换时才写回主存。
此方法需要增加一个脏位标志,用于判断该Cache缓存块是否被修改过。

该方法可以使CPU的访存次数减少,从而节省写操作所需的时间。但是存在数据不一致的隐患。
全写法
又称写直通法,当CPU对Cache写命中时,必须把数据同时写入Cache和主存,一般使用写缓冲(write buffer)。
这个写缓冲是使用SRAM实现的先进先出的队列。当CPU写操作缓存命中时,会修改缓存中的数据,同时会把要写入的数据放入写缓冲区。之后CPU就可以进行其他操作。在CPU进行其他操作时,写缓冲区在专门的控制电路控制下逐一将数据写回主存。

使用写缓冲,CPU写的速度很快,若写操作不频繁,则效果很好。若写操作很频繁,可能会因为写缓冲饱和(写缓冲大小有限制)而发生阻塞。
写不命中
当CPU进行写操作对Cache缓存没有命中情况下,采用两种方式:
写分配法:把主存中的块调入Cache, 在Cache中修改。通常搭配写回法使用。
CPU进行写操作,没有缓存命中情况下,会先将主存中的数据调入Cache缓存中,在对该缓存进行写操作。之后搭配写回法完成对主存写操作。
非写分配法:当CPU对Cache写不命中时只写入主存,不调入Cache。搭配全写法使用。
采用这种方法就意味着,CPU只有读操作未命中时才调入Cache。
多级Cache
现代计算机常采用多级Cache方式。

上面两个Cache(L1,L2)离CPU越近的速度越快,容量越小;离CPU越远的速度越慢,容量越大。
各级Cache之间常采用全写法非写分配法。
Cache与主存之间常采用写回法写分配法。
8. 页式存储器
主存和Cache之间是以块为单位进行读写的。
假设一个主存每块单元是,而某个程序有,如果将这个程序全部放入主存连续空间中可能会导致主存利用率不高情况出现,所以通常可以将这个程序分为个页,每个页面的大小和物理块的大小(这里是)相同。

将该程序分为四个页面,并给每个页面进行编号:

将程序分页后就可以将程序离散的放在主存的任意位置。储存利用率会得到提高。

所以,所谓页式存储系统就是一个程序(进程)在逻辑上被分为若干个大小相等的"页面","页面"大小要与主存"块"的大小相同。每个页面可以离散地放入不同的主存块中。
注意:程序分为页面是逻辑层面划分。而主存和Cache分块更多是物理层面划分。
8.1 页表
引入两个重要概念:
逻辑地址(虚地址):程序员视角看到的地址。
物理地址(实地址):实际在主存中的地址。
CPU执行的机器指令中,使用的是"逻辑地址",因此需要通"页表"将逻辑地址转为物理地址。页表的作用是记录了每个逻辑页面存放在哪个主存块中。
每个程序都会被离散存放在主存中的某个位置:

假设这个程序大小有,如果按字节编址这个程序的地址范围:。如果这个程序中有两个变量地址分别是和这两个地址是逻辑地址。现在运用取数指令将变量的存放在寄存器中,对应机器指令:。前面的是操作码,后面的是对应的逻辑地址。
现在分析一下这个对应的逻辑地址应该在哪一个页面:
首先,每个页面有,所以对于的逻辑地址来说,可以用后十位表示页内地址,前两位表示在哪个页面中存储(上图只有四个页面)。

所以对于变量其所对应的页面是,即第号页。而上图的号页面被放入到号主存页中。所以变量的实际存放地址可以用号页面的主存块号变量的页内地址就可以将逻辑地址转换为实际存放的物理地址。所以的物理地址是
如果采用这种页式存储方式,作为程序员只能给出变量的逻辑地址,而操作系统会负责将这个逻辑地址映射为与之对应的物理地址。其核心就是要记录逻辑页号到主存块号的关系。基于这种关系,操作系统会建立一张"页表"。这个页表是一张数据结构。

如刚刚的变量,它的页号就是前两位即号页,而根据页表关系号页对应主存块号号位置。之后再根据
主存块号的页内地址进行拼接就可以得到的物理地址。
页表中相关的数据是存放在主存中的。所以,CPU在进行地址转换的时候需要查询页表,就意味着CPU需要进行一次访存操作。另外上面页表中的每行成为"页表项"。
所以一个地址变换详细过程如下:
当CPU执行指令时,这些指令中肯定包含当前要访问哪个逻辑地址。逻辑地址可以拆分为:逻辑页号页内地址两个部分。

首先CPU会将逻辑地址拆分为页号和页内地址两个部分。
接着CPU中会有一个很重要的寄存器:页表基址寄存器。这个寄存器保存页表被存放在哪个起始地址。假设当前基地址是这就表示当前页表第一页页表项的地址存放在主存位置。假设每个页表项占,那么第二页页表项地址是。
对于这个例子来说我们要找的页表对应号逻辑页。通过页表可以知道号页对应主存块号的位置。
之后CPU会将这个主存块号和页内地址进行拼接,拼接之后的地址就是物理地址。
最后根据这个物理地址访问主存。根据之前所学的知识可以知道当要访问主存某一个物理地址时,无论是读写哪个操作CPU都会优先去Cache中查找能否命中所要访问的数据。如果Cache命中能找到则直接读取或写入数据。如果Cache缓存未命中CPU就到主存中找。

8.2 快表
上面地址变换这个过程可以进行优化,根据局部性原理,如果刚刚访问了号页面,那么接下来的一段时间也有很大概率会访问这个号页面。此时可以将号页表对应页表项放入一个更高速的存储器中,这样就可以加快地址变换的速度。基于这种思想可以引入一个类似于Cache硬件:快表(TLB)。

引入快表之后原来主存中存放的信息就可以称为慢表。引入快表之后CPU访问过程如下:
首先仍会将逻辑地址拆分。之后会现在快表中尝试找这个页号对应的主存块号。由于开始时候快表是空的,所以没有命中,CPU会查询慢表。
在慢表中查到后CPU进行物理地址拼接。基于局部性原理,此时可以把号页对应的页表项放入块表。
如果之后访问快表可以命中,则CPU会直接进行地址拼接得到物理地址。

注意不要把Cache和快表混淆。Cache中存储的是主存中某一块数据。快表中存储的是慢表中某一个页表项。引入快表就是为了让逻辑地址转换为物理地址更快。所以快表是在地址变换过程起到变快作用,而Cache是在地址访问时候起到加速作用。
之所以CPU访问快表更快是因为快表使用SRAM,而慢表使用DRAM。并且快表是一种相联存储器,即可以按内容进行访问。而快表会遇到与Cache相同的问题,可以参照Cache解决办法。

9. 虚拟存储器
根据之前的学习可以知道,计算机中经常会出现套娃这种现象,比如之前的Cache,会有等多级Cache。而虚拟存储系统也是这样的多级结构。
一个应用程序只需要将部分内容调入内存,就能正常运行。其余部分等用到该功能时才会调入主存。这就是虚拟存储器。虚拟存储器本质将辅存数据调入内存,与之前内存中数据调入Cache类似。
9.1 页式虚拟存储器
与之前一样将程序分页,对于这个程序,会先将用得到的数据调入主存就能正常使用。

上图中对页表进行改造:
有效位
当有效位为表示这个页已经被调入主存。而有效位是情况下表示该页面相关数据还在辅存当中。上图页数据已经在主存。而页数据还在辅存中,假如现在用到号页数据,需要将辅存中的数据调入主存。
外存块号
之前将Cache和主存都进行相关联分块操作,每块大小都是一样。同理辅存也进行分块存储,每块大小同主存和Cache保持一致。假如现在用到号页数据,需要根据外存块号,将辅存块中位置的数据调入主存。
访问位
为了实现页面替换算法才增加的有效位。类似于Cache的替换算法。辅存很大,而主存很小,因此主存很容易被填满,而当主存填满后,辅存再往主存放数据需要替换哪些数据的问题。也可以使用这种策略。
所以访问位可以记录当前页面被访问多少次。如果采用LFU策略,当主存满的时,可以根据访问位最少的值进行替换。
脏位
与Cache块的脏位一样。如果对主存某些块进行写操作,此时该块对应的脏位就是,当这个块被替换时候,需要将这一块内容写回辅存。
可以看出主存与辅存之间的页面管理策略与主存与Cache的很多管理都类似。
页式虚拟存储器结构图:

逻辑页号也有虚页号,CPU会根据指令中的虚页号查找页表中对应的表项,再根据页表项进行对应位置的读写操作。
9.2 其他虚拟存储器
段式虚拟存储器
段式虚拟存储器:是按照程序的功能模块拆分

如:上面的程序将其分为三段。段是自己的代码,段是库函数代码,段是变量。操作系统会以段为单位决定要把哪一段调入主存。
这种拆分方式是按照程序的功能模块拆分,所以每一段的大小可能不一样。

由于每一段大小不一样,所以段表要增加段长这一项。另外主存也不会进行分块。每一段都会随机存储到主存任意一个位置。因此我们需要记录每一段在内存中的段首地址。
段页式虚拟存储器
把程序按逻辑结构分段,每段再划分为固定大小的页。同时主存空间也划分为大小相等的页。
程序对主存的调入、调出仍以页为基本传送单位。
每个程序对应一个段表,每段对应一个页表。
虚拟地址:段号段内页号页内地址

本节具体内容会在操作系统中学习,是重点。