• 一. 计算机习题概述1.计算机硬件的基本组成1.1 冯诺依曼结构1.2 现代计算机结构2.各个硬件功能概况2.1 主存储器2.2 运算器2.3 控制器2.4 计算机层次结构3. 计算机的性能指标3.1 存储器的性能指标3.2 CPU的性能指标3.3 系统整体性能指标3.4 总结二. 数据的表示与运算1. 进位计数制1.1 进制转化为十进制1.2 二进制转化为八进制和十六进制1.3 十进制转化任意进制1.4 真值和机器数2. BCD码2.1 8421码2.2 其他码3. 无符号整数的表示和运算4. 带符号整数在计算机中应用4.1 原码表示法4.2 原码计算方式4.3 移码4.4 原码、补码、反码和无符号整数特性4.5 定点小数表示和运算4.6 奇偶校验码5. 字符与字符串6. 算术逻辑单元6.1 最基本的逻辑运算6.2 复合逻辑运算逻辑运算实现偶校验位逻辑运算实现一位全加器6.3 并行加法器优化7. 补码加减运算器7.1 补码加法器原理7.2 标志位的生成7.3 加减运算和溢出判断8. 移位运算8.1 算数移位8.2 反码算数移位8.3 补码算数移位8.4 逻辑移位8.5 循环移位9. 原码与补码的运算9.1 乘法运算原码乘法运算补码乘法运算9.2 除法运算原码的除法补码的除法9.3 C语言强制类型转换10. 数据的存储与排列10.1 大小端存储10.2 边界对齐11. 浮点数表示与运算11.1 浮点数表示11.2 浮点数尾数规格化11.3 浮点数标准IEEE 75411.4 浮点数运算11.5 浮点数强制类型转换三. 存储系统1. 主存储器基本组成1.1 存储芯片基本原理1.2 寻址方式实现2. SRAM和DRAM2.1 SRAM和DRAM区别2.2 DRAM的刷新2.3 DRAM地址线复用技术3. ROM3. 主存优化3.1 双端口RAM3.2 多体并行存储器3.3 单体多字存储器4. 主存储器与CPU连接4.1 位扩展4.2 字扩展4.3 几种常见译码器5. 磁盘存储器5.1 磁盘设备的组成5.2 磁盘的性能指标5.3 磁盘工作原理5.4 磁盘阵列6. 固态硬盘SSD7. Cache缓存7.1 Cache基本原理与概念Cache工作原理性能分析有待解决的问题7.2 Cache主存映射方式全相联映射直接映射组相联映射7.3 Cache替换算法随机替换算法先进先出替换算法近期最少使用算法最不经常使用算法7.4 Cache写策略写命中写不命中多级Cache8. 页式存储器8.1 页表8.2 快表9. 虚拟存储器9.1 页式虚拟存储器9.2 其他虚拟存储器

    一. 计算机习题概述

    计算机概述:计算机系统=硬件+软件

    硬件:计算机的物理性能,决定计算机性能天花板在哪

    软件:计算机的虚拟性能,决定硬件性能可以发挥到什么程度。可分为系统软件和应用软件:

    计算机功能好坏取决于"软","硬"件功能的总和。计算机组成原理重点讨论硬件内容。

    计算硬件发展:

    硬件的发展

    计算机目前的发展趋势:一方面向更微型、多用途方向发展;另一方面向更巨型,超高速方向发展。

    1.计算机硬件的基本组成

    1.1 冯诺依曼结构

    提出设想:

    提出"存储程序的概念":将指令以二进制的形式先输入计算机的主存储器,然后按其在存储中的首地址执行程序的第一条指令,以后就按该程序的规定顺序执行其他指令,直到程序执行结束。

    5ZzPzD.png

    冯诺依曼机

    处理步骤:

    1. 输入设备:将信息转化成机器能识别的形式
    2. 存储器:存放数据和程序
    3. 运算器:算术运算和逻辑运算
    4. 控制器:指挥程序运行
    5. 输出设备:将结果输出

    在计算机系统中,软件和硬件在逻辑上是等效的。对于同一个功能,既可以用软件实现也可以用硬件实现,但用软件实现成本低,效率也低;而用硬件实现成本高,效率也高。如:对于乘法运算,可以设计一个专门的硬件电路实现乘法运算也可以用软件的方式,执行多次加法运算来实现。

    冯诺依曼计算机的特点:

    1. 计算机由五大部件组成
    2. 指令和数据以同等地位存于存储器,可按地址寻访
    3. 指令和数据用二进制表示
    4. 指令由操作码(如:加减乘除)和地址码组成
    5. 存储程序:会提前将指令和程序存放到存储器中
    6. 以运算器为中心:输入/输出设备与存储器之间的数据传送通过运算器完成。由于运算器还要完成数据中转操作,所以执行效率会降低。

    1.2 现代计算机结构

    现代计算机结构本质上是冯诺依曼结构的优化。

    优化后的冯诺依曼结构:

    优化后的冯诺依曼结构

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

    现代计算机结构:

    5eSbDJ.png

    I/O设备会直接和主存储器进行数据交换。

    控制器控制运算器进行数据操作(如:加减乘除),另外也会控制主存储对CPU的读写,及输入输出设备的停止和启动。

    主存储器会和CPU之间进行数据交换:一种是参与运算的数据(如:x,y之类的变量)。另一种是放在控制器中的指令,指令会由控制器解析其含义。

    主存储器和CPU统称为主机。

    现代计算机硬件结构:

    现代计算机硬件结构

    上面比较混淆的是主存和辅存:这两个都是存储器,主存就是主存储器(如:运行内存),包含在主机内;而辅存指辅助存储器(如:机械硬盘),属于I/O设备。

    现代冯诺依曼结构

    总结5epWse.png

     

    2.各个硬件功能概况

    2.1 主存储器

    主存储器由三个部分构成:

    1. 存储体:相当于"货架"部分,存储二进制数据,并根据MAR发送的数据地址,取出数据。
    2. MAR(存储地址寄存器):CPU将想要的数据地址存放到MAR中,即数据地址。
    3. 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:MAR=4位总共有24个存储单元。(4位的排列组合:4!=4*3*2*1=24)

    例2:MDR=16位每个存储单元可存放16bit,1个字(word) =16bit

    计算机基本单位:

    2.2 运算器

    用于实现算术运算(如:加减乘除)、逻辑运算(如:与或非)

    有四部分构成:

    运算器

    ACC、MQ、X在进行加减乘除操作区别:

     
    ACC被加数、和被减数、差乘积高位被除数、余数
    MQ  乘数、乘积低位
    X加数减数被乘数除数

    2.3 控制器

    指挥各个部件,使程序可以正常运行

    主要有三部分构成:

    控制器

    代码相当于指令,每完成一条指令过程:

    1. 取指令(PC)

      根据PC中所记录的指令地址,从内存中取出该指令。

    2. 分析指令(IR)

      将取出的指令由IR进行分析这条指令可以干什么。

    3. 执行指令(CU)。

      分析完成后CU会控制其他部件完成指令具体执行。

    程序在计算机中的运行过程:

    运行顺序:PCMARMDRIRCUIRMARMDRACC

    例:给定以下高级语言分析其在计算机内执行过程。

    代码在主存结构如下:

    计算机工作过程1

    地址04y=a*b+c这段程序对应的机器指令;地址58是四个变量a,b,c,y的的存储情况。这里存储字长为16bit

    运行步骤:

    总结:

    硬件运行过程总结

    OP:操作码

    AD:地址码

    CPU区分指令和数据的依据:根据指令周期的不同阶段

    运行汇总

    5nF48s.png

    汇总二

    2.4 计算机层次结构

    最底层:由传统机器(机器语言的机器)和微程序机器(微指令系统)组成。

    这一层传统机器执行二进制机器指令,而机器指令可以分解为多个微指令,微程序机器就是执行这些微指令的。

    计算机最底层

    再上一层是:虚拟机器(汇编语言机器)

    汇编语言编写的代码需要翻译成机器码,所以是虚拟机器。

    计算机层次

    再上一层是:虚拟机器(高级机器语言)

    需要用编译程序翻译成汇编语言。

    计算机层次2

    而我们编写的程序往往需要用到操作系统的调用,向上提供广义指令。

    所以总的计算机层次:

    计算机层次3

    计算机层次结构特点:下层是上层的基础,上层是下层的扩展

    计算机硬件层:微程序机器MO(微指令系统)------>传统机器M1(用机器语言的机器)

    计算机软件层:虚拟机器M2(操作系统机器)------>虚拟机器M3(汇编语言机器)------>虚拟机器M4(高级语言机器)

    硬件层位于最底层,具有下层是上层的基础,上层是下层的扩展的特点。

    编译程序
    汇编程序
    解释型
    高级语言
    汇编语言
    机器语言
    JavaScript和python

    编译型程序:将高级语言编写的源程序全部语句一次全部翻译成机器语言程序,而后再执行机器语言程序(只需翻译一次)

    解释型程序:将源程序的一条语句翻译成对应于机器语言的语句,并立即执行。紧接着再翻译下一句(每次执行都要翻译)

    注意:编译、汇编、解释程序可以统称为翻译程序。

    3. 计算机的性能指标

    3.1 存储器的性能指标

    主寄存器的容量=存储单元的个数×存储字长bit

    计算机存储器性能指标

    例:MAR为32位,MDR为8位,总容量=2328=4GB

    3.2 CPU的性能指标

    3.3 系统整体性能指标

    注:

    1. 主频高的CPU不一定比主频低的CPU快。如两个CPU,A的主频为2GHz,平均CPI=10B的主频1GHz,平均CPI=1。所以B虽然主频低,但是CPI处理快,总体比A快。
    2. 若两个CPU的平均CPI相同,频率高的CPU也不一定快。还要看指令系统,如A不支持乘法指令,只能用多次加法实现乘法;而B支持乘法指令。
    3. 基准程序(跑分软件)执行得越快也不能说明机器性能越好:基准程序中的语句存在频度差异,运行结果也不能完全说明问题

    3.4 总结

    5MVr8S.png

    计算机性能指标

    二. 数据的表示与运算

    1. 进位计数制

    十进制

    如:975.36

    其可以表示为:9×102+7×101+5×100+3×101+3×102

    由十进制可以推广到多进制。

    1.1 r进制转化为十进制

    基数:每个数码位所用到的不同符号的个数,十进制基数是09r进制的基数为0r

    下面是一些常见进制的基数:

    二进制:0,1

    八进制:0,1,2,3,4,5,6,7

    十进制:0,1,2,3,4,5,6,7,8,9

    十六进制:0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F

    r进制转化为十进制例题:

    1. 二进制(B):101.11×22+0×21+1×20+1×21=5.5
    2. 八进制(O):5.45×80+4×81=5.5
    3. 十进制(D):5.55×100+5×101=5.5
    4. 十六进制(0X/H):5.85×160+8×161=5.5

    计算机用二进制好处是:

    1. 可使用两个稳定状态的物理器件表示。
    2. 01正好对应逻辑值假、真。方便实现逻辑运算。
    3. 可很方便地使用逻辑门电路实现算术运算。

    1.2 二进制转化为八进制和十六进制

    (AE86.1)16(1010 1110 1000 0110.0001)2

    具体是:A1010E1110810006011010001

    1.3 十进制转化任意进制

    1.4 真值和机器数

    十进制+15转换为二进制需要再前面加一位符号位,正号用0,负号用1。所以+15011111511000

    真值:实际的带正负号的数值(人类习惯的样子)。如上面的+1515

    机器数︰把正负号数字化的数(存到机器里的样子)。如上面的0111111000

    2. BCD码

    BCD码指:用二进制编码的十进制数。主要有:8421、余3码、2421码。

    由于机器数(二进制)转换为真值(十进制)过程较为麻烦,而BCD码就是为了解决这个问题。

    BCD码原理:可以用4bit对应一个十进制位。因为4bit对应有24=16种状态,完全可以表示09这十种情况。同时也会与六种状态是冗余的。

    2.1 8421码

    8421码是指四位二进制位,来表示一个十进制。这四个二进制位的权重分别是8421。如表示584210101,因为从左至右第二位4和最后一位1相加等于5

    098421码表:

    589oge.png

    根据上面表9858421100110000101。可以用三个8421码表示985这个数字

    8421码的加法运算:

    5(0101)+8(1000)=13(00010011)8421

    计算机做法是首先将两个码二进制相加5(0101)+8(1000)=13(1101),显然1101已经超出842109的范围,即不在映射表中。实际上当结果处于10(1010)15(1111)内是没有定义的,是一个非法8421码区间。解决做法是让结果码13(1101)+6(0110),由于加6后这四个数肯定会向高位进1,此时低位部分就是我们需要个位数3。所以13(1101)+6(0110)=19(10011),低位00113。而高位1我们只需要在前面补上30,即0001,最终1(0001)3(0011)正好可以表示13这个数,所以上面5+88421表示是00010011

    再看一种情况:对于9(1001)+9(1001)=18(10010)结果已经大于8421码定义的四位。处理方法同样是后四位加6,即0010+0110=11000。低位的(1000)84218,即个位。前面高位1前面补足三个0。最终00011000。所以9(1001)+9(1001)=18(00011000)8421

    总结:只要相加结果处于10(1010)18(10010)这个区间都需要加6修正。如果在合法范围内无需修正。

    58AcuD.png

    2.2 其他码

    3. 无符号整数的表示和运算

    无符号整数即自然数,有0,1,2

    无符号整数的表示:假设现在机器字长是8位,那么其通用寄存器只能存8位。

    如:25511111111,刚好八位,可以存放在机器字长是8位的寄存器中。

    256100000000,二进制是九位,而机器字长8位,其在计算机中只能保存低八位,即00000000

    无符号整数存储

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

    无符号整数

    无符号整数特点:

    1. 全部二进制位都是数值位,没有符号位,第i位的位权是2i1
    2. n比特的无符号整数表示范围是02n1,超出则溢出,意味着该计算机无法一次处理这么多位
    3. 可以表示的最小的数是:所有位全是0,最大的的数是:所有位全是1

    无符号整数的加法:从最低位开始,按位相加,并往更高位进位。如:99(01100011)2+9(00001001),其实二进制位相加即可。

    无符号整数的加法

    无符号整数的减法:

    如:99(01100011)29(00001001)

    首先减数0000100111110110,之后11110110的最后一位+1,即11110111

    最后计算01100011+11110111=90(101011010),由于计算结果是九位,寄存器只能存储八位,所以舍弃高位的1,结果是01011010

    无符号整数的减法

    4. 带符号整数在计算机中应用

    带符号整数,如:2,1,0,1,2

    带符号整数可以用原码、反码、补码三种不同编码方式来表示。

    带符号整数的表示:假设现在机器字长是8位,那么其通用寄存器只能存8位。最多只能同时进行8位运算

    4.1 原码表示法

    开头第一位是符号位:正号用0,负号用1,剩下后七位是数值位。

    如:真值+19+10011,在8bit寄存器中存储方式是0,0010011

    真值1910011,在8bit寄存器中存储方式是1,0010011

    有符号整数原码表示

    原码特性:

    1. 若机器字长是n+1位,带符号整数的原码表示范围(2n1)x2n1
    2. 符号位0/1对应/,剩余的数值位表示真值的绝对值
    3. 真值0有两种形式+00[+0]=0,0000000[0]=1,0000000

    原码缺点:符号位不能参与运算,需要设计复杂的硬件电路才能处理。

    4.2 原码计算方式

    原码加法计算方式是:先将原码反码补码。在进行正常二进制计算即可。

    正数转换为补码不变

    负数(原码),反码+1补码

    原码转换为补码

    原码转换为补码快速技巧:原码从右往左找到第一个1,这个1左边的数值位按位取反就可以变为补码。同样补码转换为原码方式一样。

    如:[19]=1,0010011转换为补码[19]=1,1101101

    计算机硬件如何做补码的加法:从最低位开始,按位相加(符号位参与运算), 并往更高位进位。

    补码加法运算

    注意:负数补码的数值为不能解读成位权。我们需要将其转换为原码。

    如上面[38]=1,10110101,0100110,而1,010011038

    而对应原码的减法计算,仍需要将其转换为补码再计算。不同的是计算机只能处理加法运算,所以将减法变为加法即可。如[A][B]=[A]+[B]

    所以只需要解决已知一个补码求其负值的补码。方法是[B],+1[B]

    补码变负数补码

    如:[19][11101100]+1[11101101]=[19]

    同样有快速转换的技巧:原码从右往左找到第一个1,这个1左边的全部位按位取反就可以变为负值补码。

    可以看出有符号整数减法和无符号整数减法方法一样,这样就意味着可以用同一套电路就可以实现处理所有加减法。

    所以有符号整数的减法:

    原码计算总结:

    原码计算总结

    注意:计算机内部所有带符号整数的加减法都要先转换为补码形式。

    4.3 移码

    移码:在补码[A]基础上,符号位取反就可以得到移码[B]

    移码

    注意:移码只能表示整数,不能表示小数。且真值0只有一种表示形式10000000,若机器字长为n+1位,移码整数的范围:2nx2n1

    4.4 原码、补码、反码和无符号整数特性

    n+1bit合法表示范围最大的数最小的数真值0的表示
    带符号的整数:原码(2n1)x2n10,111111=2n11,111111=(2n1)[+0]=0,000000
    [0]=1,000000
    带符号整数:反码(2n1)x2n10,111111=2n11,000000=(2n1)[+0]=0,000000
    [0]=1,111111
    带符号整数:补码2nx2n10,111111=2n11,000000=2n[0]=0,000000
    真指0只有一种补码
    带符号整数:移码2nx2n11111111=2n10000000=2n[0]=1000000
    真值0只有一种移码
    无符号整数0x2n+111111111=2n+110000000=00000000

    原码和反码的合法表示范围完全相同,都有两种方法表示真值0

    补码和移码的合法表示范围比原码多一个负数,只有一种方法表示真值0

    常见考点:两个数AB进行某种运算后,是否发生溢出。可以手算做题可以带入十进制验证,是否超出合法范围

    如:计算机是8位。A=B=64,如果其用原码表示A+b=128会溢出。而用补码表示则不会溢出。

    几种码的表示:

    几种码的表示

    4.5 定点小数表示和运算

    之前的定点整数,即带符号的整数,小数点隐含在数值部分末尾。

    定点整数的小数

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

    定点小数

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

    如:[x]=1.1100000

    定点小数原码

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

    定点小数和定点整数对比:

    定点小数和定点整数对比

    4.6 奇偶校验码

    数据在计算机内部进行计算存取过程中可能会发生错误,所以要用到校验。

    奇校验码:整个校验码(有效信息位和校验位)中1的个数为奇数。

    偶校验码:整个校验码(有效信息位和校验位)中1的个数为偶数。

    一般高位是校验位,剩下n位是信息位

    奇偶校验

    如:1001101奇校验码:11001101,因为是奇校验而信息位的14个,所以在首位添加1,整体1个数位5是奇数。

    1001101偶校验码:01001101,信息位1个数是4,所以不用补1,首位添加个0即可。

    如果是奇校验码,计算会校验1个数,如果个数是偶数,则证明发生错误,会要求重新发送。如果是奇数,这没有问题。

    奇偶校验码可能检测不出来错误。特别是在发生多位跳变时候。

    偶校验的硬件实现:各信息进行异或 (模2加)运算,得到的结果即为偶校验位。

    如:100110101001101,对校验码各个位两两进行异或,若结果为0则说明正确。

    奇偶校验运算

    5. 字符与字符串

    字母,数字和字符等都是以ascll码的数字形式存储再电脑中

    补充:字符数字转整型数字:'1'—'0'=1

    整型数字转字符数字:1+'0'='1'

    ASCLL码:

    58VQS0.png

    字形码:

    58l16s.png

    总结:

    588Fl4.png

    6. 算术逻辑单元

    主要是算术逻辑单元ALU的构成。

    ALU可以实现算术运算:加、减、乘、除等;逻辑运算:与、或、非、异或等;辅助功能:移位、求补等。

    ALU图像

    上图是ALU大致图像,AiBi是输入信号,如要实现两个数加法,这两个数一个从Ai输入,一个从Bi输入。

    Fi是输出信号,运算结果从这里输出。

    Ki是控制信号,控制信号是由控制单元CU发出的,控制信号主要用于解析指令是加法减法等。

    下面是ALU实例图

    ALU实例图

    右边五个控制单元就是上图的Ki,是用于接收运算符号的。如:M=1S3S0=1001时,做逻辑运算AB

    由于上图ALU4位,所以可以支持16种运算状态。

    最下方输入信号,可以反映机器字长。通常与上面输出信号位数保持一致。如上图都是4位。

    所以ALU至少需要有控制信号、输入信号和输出信号。

    6.1 最基本的逻辑运算

    常见的有:与、或、非。与或非三种逻辑运算对应的门电路如下:

    与或非的门电路

    假设,A端输入5V电信号代表1B端输入1V电信号代表0,两个信号做与运算结果为1V0。只有两端输入都是高电平信号5V时候结果才会是1

    如果非门A端输入5V高电平,则会输出1V低电平。

    如果一个运算涉及到多个逻辑运算,那么执行顺序要看优先级。运算可以看作乘法, 而运算可以看作加法。

    与或运算

    如:AB+CD,要先算与运算AB,CD;再算或运算+。同样的这样的运算也符合分配律和结合律。

    上面意义在于,设计门电路本质上逻辑表达式是对电路的数学化描述,简化逻辑表达式,就是在简化优化电路,就是在省钱。

    如:实现AC+AD。其门电路可以设计如下方式:

    门电路实现

    这里我们用两个门,ACAD进行与运算后,两个电信号再通过上面的门做最后一次运算,最后输出。

    同时由于运算遵循分配律,所以AC+ADA(C+D)A(C+D)设计的门电路如下:

    门电路实现优化

    可以看到这里只用了一次运算计算C+D;一次运算计算A(C+D)。所以这样设计相当于优化了门电路。

    6.2 复合逻辑运算

    常见的复合逻辑运算有:与非(先进行运算,再进行运算)、或非(先进行运算,再进行运算)、异或

    其表达式表示如下:

    复合逻辑表达式

    其门电路符号如下:

    复合逻辑门电路图

    上面运算遵循反演律(德摩根律):

    A+B=A·BA·B=A+B

    重点介绍异或运算:即AB不同时,输出1。详细可以理解为A=0B=1或者A=1B=0时输出1

    表示式表示为A·B+A·B。其电路图如下:

    异或电路图

    假设A=0,B=1A的上路输入0,下路经过运算后是1B的上路经过运算后是0,下路输入0。所以上面的与门&输入两个数是0,0运算后是0,下面的与门&输入两个数是1,1结果是1,最后两个运算结果1,0再做运算结果是1

    组后补充一个复合逻辑:同或。其就是异或运算取反。

    同或逻辑

    逻辑运算实现偶校验位

    1001101的偶校验位

    方法一:整体异或1001101=0

    方法二:部分异或再整体异或((10)(11))((10)1)=0

    与之对应电路如下:

    门电路求偶校验位2

    方法三:

    门电路求偶校验位3

    从上面三种方法可以看出逻辑表达式是对电路的数学化描述。

    逻辑运算实现一位全加器

    可以使用异或运算实现全加器。

    一位全加器

    上面Ai,Bi表示两个数相加的第i位,Ci1来自低位的进位,当前正在运算位称为本位。

    计算步骤:

    1. 当输入AiBi时,可以用异或运算,输入中有奇数个1时为1(异或),偶数异或为0Si=AiBiCi1
    2. 有两种情况会产生进位,如果AiBi=1表示AiBi都是1,则要向高位进1。另一种情况是两个本位中有一个1,且来自低位的进位是1,即(AiBi)Ci1=1

    综上其进位逻辑表示式为AiBi+(AiBi)Ci1=1。对应门电路如下:

    一位全加器门电路图

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

    一位全加器图

    上面门电路图可以理解为一个函数具体实现。而下面简化图可以理解为函数对外暴露的接口。

    可以将多个一位全加器串联起来形成串行加法器:只有一个全加器,数据逐位串行送入加法器中进行运算。进位触发器用来寄存进位信号,以便参与下一次运算。

    串行加法器

    串行加法器本质是一位一位运算进位。所以如果操作数长n位加法就要分n次进行,每次只能产生一位和,并且串行逐位地送回寄存器。效率较低。

    与之对应的是并行全加器。把n个全加器串接起来,就可进行两个n位数的相加。

    并行加法器

    这样特点是只有低位的运算结束后,才能进行高位的运算。电信号传递需要大量时间。其效率取决于每一位进位产生速度。

    6.3 并行加法器优化

    上面介绍的串行进位的并行加法器,特点是其速度依赖于来自低位的进位。接下来要探究的是如何让每个进位产生的更快。

    进位Ci=AiBi+(AiBi)Ci1,其中Ci1又可以进一步展开为Ci1=AiBi+(AiBi)Ci2

    还可以进一步对Ci1进行展开,当展开到一定次数时会得到最后C0。而C0是一开拥有的信息。所以第i位向更高位的进位Ci可根据被加数、加数的第1i位信息,再结合C0即可确定。即可以利用刚开始被加数和加数每一位信息,和C0信息直接求Ci。这就是其优化思路。

    为了方便,记AiBi=GiAiBi=Pi,即Ci=Gi+PiCi1

    所以第一位进位:C1=G1+P1C0

    第二位进位:C2=G2+P2C1=G2+P2G1+P2P1C0

    以此类推。可以算出Ci位的进位信息。

    进位信息

    从上面可以看出GiPi值是经常用到的,只要是角标大于2的进行Ci都要用到Gi,Pi。所以可以根据加数和被加数对应的两个比特位算出GiPi,这两个信息可以通过线路送往更高位的运算中。所以我们在计算C4这一位进位信息时,其各个值都是确定的,只需要根据表达式设计出对应的线路,就可以在C4这里直接算出C4进位值。也就是说采用这种优化方式,每一位的进位信息几乎都是同时产生的。不需要像之前那样等待后一位进位信息往后传。

    这种方式的加法器称为并行进位的并行加法器:各级进位信号同时形成,又称为先行进位、同时进位。

    这种方案也有不足:可以看出到C4表达式已经很复杂了,再往后会更复杂,其对应的电路也会设计的更加复杂。所以要适可而止,通常到C4这个值就可以了,也就是可以同时支持4+4的运算。在这个加法器内部,每个进位都是同时并行产生的。

    并行加法器优化

    7. 补码加减运算器

    即从硬件的层面看,补码的加减运算是如何实现的。

    7.1 补码加法器原理

    加法器原理:

    加法器原理

    假设上面的n4吗,即这个加法器实现的是4bit的加法运算。计算A=1000,B=0111,cin=0,则结果是F=1111,cout=0

    计算机实现步骤:

    再看一个例子:计算A=1000,B=0111,cin=1,则计算结果F=0000,cout=1

    加法器实现步骤:

    如果将两个如上图所示的加法器进行串联,即在cout一边再连接一个加法器。如果要实现两个8bit加法器相加,在把两个加法器串联即可。

    对上面加法器进行改造,使其能进行补码的加减运算。补码手算方式参考原码计算方式

    改造后的加法器结构如下:

    补码加法运算原理

    例1:4bit补码,当x=8,y=7x=1000y=0111

    加法器实现步骤:

    实现减法步骤:

    同时这个加法器也可以实现无符号数的运算,因为无符号运算与补码运算一样。但是二者判断溢出方式不同,这涉及到标志位的产生。

    7.2 标志位的生成

    对上面的加法器的输出部分进行扩展:

    加法器的扩展

    nbit的数相加,除了得到相加的结果之外,加法器还可以输出四个标志位信息OFSFZFCF

    总之,无符号数的运算是否发生溢出,要看CF。有符号加减运算是否溢出要看OF

    7.3 加减运算和溢出判断

    8位的补码所能表示的范围是128127,所以如果补码的加减运算结果值如果不在这个范围内,就会出现值溢出的现象。

    如:A=1580,0001111C=12480,1111100,则(A+C)=1,0001011,其真值=117。显然结果不正确,而其值15+124=139,显然超出8位补码所能表示的范围,所以出现值溢出现象,导致结果错误。

    既然溢出的状况不可避免,计算机硬件必须要判断溢出问题。当进行补码加减运算时,都会转换为加法运算。所以我们只需要探讨加法运算即可。

    首先,只有正数+正数才会出现上溢出,导致正+=负;只有负数+负数才会出现下溢出,导致负+=正。

    判处判断

    例如下图:

    溢出检验

    计算2+3的值,(010)+(011)=101,按照上图表示2+3=3,由于2+3实际值为5出现,显然这里出现了上溢,导致结果为负数,其实从枢轴上也可以看出2向右走3,会回到了负轴的3位置。同样如果4+(1)值会出现下溢,导致结果为011=3

    基于这个规律计算机判断溢出方法如下:

    无论哪种方法其关键在于:+=,此时一定发生溢出。

    8. 移位运算

    8.1 算数移位

    指小数点前后移动。含义:通过改变各个数码位和小数点的相对位置,从而改变各数码位的位权。可用移位运算实现乘法、除法。

    对于十进制数,小数点往后移1位相当于×101;小数点前移1位相当于÷101

    同样,小数方法一样。

    8.2 反码算数移位

    反码的算数移位:正数的反码与原码相同,因此对正数反码的移位运算也和原码相同。

    右移:高位补0,低位舍弃。 左移:低位补0,高位舍弃。

    反码的算数移位:负数的反码数值位与原码相反,因此负数反码的移位运算规则如下: 右移:高位补1,低位舍弃。 左移:低位补1,高位舍弃。

    反码移位

    8.3 补码算数移位

    补码正数算数移位:正数的补码与原码相同,因此对正数补码的移位运算也和原码相同。

    补码负数算数移位:负数补码=反码末位+1。导致反码最右边几个连续的1都因进位而变为0,直到进位碰到第一个0为止。

    规律:负数补码中,最右边的1及其右边同原码。最右边的1的左边同反码。

    负数补码的算数移位规则如下:

    1. 右移(同反码):高位补1,低位舍弃。
    2. 左移(同原码):低位补0,高位舍弃。

    负数补码右移:

    负数补码右移

    总结:

    算数移位总结

    由于位数有限,因此有时候无法用算数移位精确地等效乘除法。

    例如:20×7

    相当于20×(20+21+22),计算机对20原码,不左移、左移1位、左移2位。

    8.4 逻辑移位

    可以把逻辑移位看作是对"无符号数"的算数移位。

    逻辑右移:高位补0,低位舍弃。

    逻辑左移:低位补0,高位舍弃。

    逻辑移位

    8.5 循环移位

    循环左移:当原码左移时高位溢出的1会移动到末位,进行循环补位。循环右移原理相同。

    带进位位的循环左移:会有一位专门记录低位往高位进位信息。当循环左移一位时,进位信息会移动到原码最末尾。

    循环移位

    循环移位主要用于把数据的低字节和高字节进行调换。

    9. 原码与补码的运算

    9.1 乘法运算

    先看十进制乘法:0.985×0.211

    其中0.211=2×101+1×102+1×1030.985=985×103

    所以0.985×0.211=(985×1×106)+(985×1×105)+(985×2×104)

    十进制手算

    扩展到二进制0.1101×0.1011

    乘数0.1011=1×21+0×22+1×23+1×24

    被乘数0.1101=1101×24

    0.1101×0.1011=(1101×1×28)+(1101×1×27)+(1101×0×26)+(1101×1×25)

    二进制手算

    可以看出二进制原码实现方法比十进制更为简单,因为每一位不是0就是1。并且2n这样运算对于计算机也很简单相当于向右移动n位即可。

    原码乘法运算

    如果用计算机实现原码乘法,要考虑的问题很多,实现步骤大致如下:

    1. ACC内清空,MQ内存放乘数,X存放被乘数

    2. MQ最低位与被乘数参与运算:

      如果最低位是1ACC内的值+被乘数

      如果最为位是0ACC内的值+0

    3. ACC与MQ中的值同时右移,ACC内低位称为MQ高位,此时MQ低位再次重复1,2

    4. 一直右移到MQ中剩符号位,此时运算结束

    总结下来就是:先加法再移位,重复n

    首先设机器字长n+1=5位,其中一位是符号位,[x]=1.1101[y]=0.1011,采用原码一位乘法求x·y

    符号处理相对简单:符号位xsys,数值位取绝对值进行乘法计算[|x|]=0.1101[|y|]=0.1011

    机器实现上面[|x|]·[|y|]相乘步骤:

    所以运算结果是0.10001111,手算过程如下:

    手算过程

    由于上面是绝对值乘法,所以最后还要对原本的符号位进行异或,添加到符号位。[x]=1.1101[y]=0.1011,符号位是10=1,所以最后结果是1.10001111

    这种方法叫原码一位乘法。因为每次参与运算只有一位。接下来用手算方式解题:

    设机器字长为5位(含1位符号位,n=4) ,x=0.1101,y=+0.1011,采用原码一位乘法求x·y

    原码一位乘法手算模拟

    由于补码乘法要用到双符号位,所以建议原码乘法也像上面题一样采用双符号位。

    整数运算与上面小数运算类似,注意整数最后小数点位置是在末位前面的位置。

    原码乘法整数计算

    补码乘法运算

    补码计算方法和原码十分相似。

    原码补码计算对比:

    原码补码
    进行n轮加法,移位。进行n轮加法,移位,最后再多来一次加法。
    每次加法可能+0,+[|x|]每次可能+0,+[x],+[x]
    每次移位是逻辑右移每次移位是算数右移

    补码每次加的数值要根据MQ中最低位、辅助位来确定:

    补码运算器与原码有差距:

    补码运算器

    因为MQ多一位辅助位,由于运算器内部部件位数相同,所以ACC和X都要扩展一位。

    辅助位初始为0。每次右移会使MQ的最低位顶替原本的辅助位。

    用计算机实现步骤大致如下:

    1. ACC内清空,MQ内存放乘数末位留一位当辅助位,X存放被乘数采用双符号位。

    2. 补码每次加的数值要根据MQ中最低位、辅助位来确定:

      辅助位MQ中最低位=1时,(ACC)+[x]

      辅助位MQ中最低位=0时,(ACC)+0

      辅助位MQ中最低位=1时,(ACC)+[x]

    3. ACC与MQ中的值同时进行补码算术右移

      符号位不动,数值位右移,正数右移补0,负数右移补1

    4. 重复上面三步,直到乘数符号位,最后还要再进行2中的一次加法,才能结束。最后将ACC中的值与MQ中除去符号位的前n位拼接即可。所以说补码乘法符号位也会参与运算。

    例:设机器字长为5位(含1位符号位,n=4),x=0.1101,y=+0.1011,采用Booth算法求x·y

    [x]=11.0011[x]=00.1101[y]=0.1011

    补码乘法手算模拟

    最后结果是:[x·y]=11.01110001,即x·y=0.10001111

    注:上面的Y5是辅助位,Y4是MQ的最低位,Ys是MQ符号位。

    9.2 除法运算

    首先从十进制出发,0.211÷0.985运算如下:

    手算十进制除法

    上面竖式可以转换为:0.211=0.9850.214+0.000210,即x÷y=ab()x=ay+b

    其本质是每上一位商要尽可能接近余数,但不超过余数。

    对于二进制除法:0.1011÷0.1101,首先取绝对值狐狸小数点:(0.1011×24)÷(0.1101×24)

    手算二进制除法

    规律:忽略小数点,每确定一位商,进行一次减法,得到4位余数,在余数末尾补0,再确定下一位商。确定5位商即可停止(机器字长为5位)

    原码的除法

    设机器字长位5位(含1位符号位,n=4),x=0.1011y=0.1101,采用原码恢复余数的求法求xy

    首先符号位=xsys,之后对数值位取绝对值进行除法计算

    运算器实现大致步骤:

    1. 首先通用寄存器放入除数,ACC放入被除数,MQ清空用于存放商

    2. 默认MQ低位上商1,此时ACC,结果为余数放入ACC中。如果:

      ACC高位是1,则说明余数是负数表明默认商1是不正确的。寄存器弥补做法是MQ中低位1改为0,之后ACC+,运算结果值放入ACC中

      ACC高位是0,说明余数正数,商1正确进入。

    3. 之后ACC和MQ整体逻辑左移,左移之后ACC中的值就是余数。之后重复上述两步骤即可

    这种恢复余数方法称为:恢复余数法

    计算机实现:

    手算做题方法如下:

    原码除法手算

    注意:总共要左移n次,上商n+1次,最后一次上商余数不左移。

    优化恢复余数法策略:

    优化恢复余数法

    可以看到,将余数为负数的值设为a,除数设为b,则恢复操作为a+b,之后a+b的值左移:(a+b)×2=2a+b。最后再默认商1(a+b)×2b=2a+b。所以当发现余数是负数(高位为1),此时不用恢复余数,直接让余数左移1位再加上||即可。

    基于这种思路的方法称为加减交替法,又称不恢复余数法。优化后的步骤如下:

    不恢复余数法

    注意:余数的正负性与商相同。加减法要进行n+1/n+2次,最终可能由于余数为负数还要再多一次加。逻辑左移进行n次(最后一次加减完不移位)。

    定点小数运算中被除数一定要比除数小。因为如果大于除数,结果就是一个大于1的数,定点小数无法表示大于1的数。所以运算中第一步一定得到商是0,如果商1,则证明被除数比除数大,此时硬件电路会检测到这个问题,并且直接停止运算。

    补码的除法

    补码的除法与原码类似,同样是使用加减交替法。但不同在于:补码符号位要参与运算(不用绝对值),并且被除数、余数、除数采用双符号位。

    具体做法如下:

    1. 首先根据被除数和除数符号进行运算

      同号,则被除数减去除数

      异号,则被除数加上除数

    2. 根据第一步得到的余数之后再根据余数和除数符号进行运算

      同号,商1,余数左移一位减去除数

      异号,商0,余数左移一位加上除数

    3. 重复第二步n次,即可

    最后一位直接横置为1,这样不仅效率高而且误差不超过2n

    例:设机器字长为5位(含有一位符号位),x=+0.1000y=0.1011,采用补码加减交替法求xy

    补码的除法

    结果:[xy]=1.0101,余数0.0111×24

    原码与补码除法对比:

    原码与补码除法对比

    9.3 C语言强制类型转换

    C语言中定点正数都是用补码形式存储的。用关键字unsigned修饰的是无符号整数。

    10. 数据的存储与排列

    多字节数据在内存中一定是占连续的几个字节。

    10.1 大小端存储

    如:4字节int类型:(01234567),其最高有效字节01;最低有效字节67

    其在计算机中二字节存储:00000001001000110100010101100111

    在计算机中存储方式有两种:大端存储和小端存储

    10.2 边界对齐

    现代计算机通常是按字节编址,即每个字节对应一个地址。

    通常也支持按字,按半字,按字节寻址。假设存储字长为32位,则1个字32bit,半字=16bit。 每次访存只能读/1个字。

    内存中字的存储方式

    由于计算机每次只能读/1个字,所以有的计算机会采取边界对齐方式,有的会用边界不对齐方式。

    补充:

    计算机系统位数单位
    16bit1字(word)=2半字=2字节(byte)=16位(bit)
    32bit1字(word)=2半字=4字节(byte)=32位(bit)
    64bit1字(word)=2半字=8字节(byte)=64位(bit)

    无论操作系统的 位宽 是多少,1byte=8bite,半字为字的一半,双字(double word)为字(word)的2倍永远不变。

    一个ASCII字母占用 1 byte,一个汉字占用 2 byte

    11. 浮点数表示与运算

    定点数可表示的数字范围有限,不能无限制地增加数据的长度,所以要用上浮点数。

    计算机中的浮点数原理和科学计数法相似。如:+302657264526+3.026×1011。由于后面的底数10是不变的,所以也可以写作+11+3.026。其中左边+11称为阶码,阶码最前面一位是阶符,阶符为正小数点往后移动,阶符为负小数点往前移;后面的+3.026称为尾数,尾数最前面一位是数符,后面是数值部分,一般来说数值部分越短表示的精度就越低。

    科学计数法理解浮点数

    11.1 浮点数表示

    以上是十进制科学计数法描述,接下来看二进制浮点数的科学计数法:

    设阶码为E,尾数为M,则r进制的浮点数真值=rE×M

    同样阶码E反映浮点数的表示范围及小数点的实际位置;尾数M的数值部分的位数n反映浮点数的精度。

    例如:阶码、尾数均用补码表示。a=0,01;1.1001b=0,10;0.01001

    a的阶码0,01对应真值+1;尾数1.1001对应真值0.0111;则a的真值=21×(0.0111)=0.111

    最后真值部分相当于真题左移一位。a对应内存中存储结构如下:

    浮点数表示1

    b的阶码0,10对应真值的+2,尾数0.01001对应真值+0.01001;则b的真值=22×(+0.01001)=+1.001

    b对应内存中存储结构如下:

    浮点数表示2

    上面可以看到b的尾数太长导致存储空间溢出,末位1舍弃,精度降低。可以采用浮点数规格化方式提高精度。

    11.2 浮点数尾数规格化

    规格化方式:尾数最高值必须为有效值,即1

    上面b=0,10;0.01001,小数点前的尾数是符号位不变,后面0完全没有必要保留,所以将小数点后整体右移一位,即0.01001×21,得到0.1001,最后结果真值乘21即可。b的真值=21×(+0.10010)=+1.0010。其在内存中表示:

    浮点数表示3

    上面将尾数算数左移1位,阶码减1。直到尾数最高位是有效值,这种方式称为左规。

    当浮点数运算的结果尾数出现溢出(双符号位为0110)时,将尾数算数右移一位,阶码加1,这种方法称为右规。

    例:a=010;00.1100b=010;00.1000,求a+b

    a=22×00.1100b=22×00.1000,则a+b=22×00.1100+22×00.1000=22×01.0100

    由于双符号位异号,说明出现溢出。可以通过右规方式将浮点数规格化。将尾数右移一位,阶码加1。即23×00.1010。这个尾数就是一个规格化尾数。其在内存中存储如下:

    浮点数表示4

    注:采用("双符号位"),当溢出发生时,可以挽救。更高的符号位是正确的符号位。

    左规右规总结:

    1. 左规:当浮点数运算的结果为非规格化时要进行规格化处理,将尾数算数左移一位,阶码减1
    2. 右规:当浮点数运算的结果尾数出现溢出(双符号位为0110)时,将尾数算数右移一位,阶码加1

    规格化浮点数特点:

    例子:若某浮点数的阶码、尾数用补码表示,共4+8位:0.110;1.1110100。则如何规范化。

    数值部分1.1110100左移三位,变为1.0100000,由于是左移所以阶码3,则移动后阶码为0.011。所以规范化后是0.011;1.0100000

    如果机器数超出浮点数正数范围称为正上溢。如果超出负数范围称为负上溢。而规格化后所表示的小数也有下限,如果表示的正数比浮点数还要小,则会出现正下溢情况。相反如果表示负数比浮点数所能表示的负数还要小,则会出现负下溢情况。如果有一个数值出现正下溢或负下溢计算机默认该数值为0。如果出现正上溢或者负上溢,则计算机会中断程序。

    11.3 浮点数标准IEEE 754

    如果不能统一一个规格来表示浮点数阶码,尾数各占多少位,各自采用原码补码还是移码来表示,则计算机之间进行数据传输就会出现解析之间的问题。所以,IEEE754标准可以统一计算机规范。

    先回顾一下移码,移码定义:移码=真值+偏置值。此处8位移码的偏置值=128=10000000,即2n1n指计算机位数。

    如果真值127=1111111,则移码=1111111+10000000=00000001

    移码与真值

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

    改变偏置值后移码如下:

    移码偏置值改变

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

    IEEE754标准

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

    IEEE754标准数值类型

    真值范围是126127,因为128=11111111127=00000000有其他用途。

    阶码全10的用途:

    上面单精度浮点数最小能表示(1.0)2×2126,如果还想表示比这更小的数此时就要用到阶码全0和阶码全1两种状态。

    IEEE754标准2

    对于单精度来说上面阶码部分8位,如果看作无符号数所能表示范围就是0255,其中002551。所以取出这两种状态,阶码表示范围就是1254

    但如果阶码全0,而尾数不全为0时,这表示非规格化小数,此时默认小数点前面一位就是0而不是1,这种情况下所能表示浮点数对应真值是0.M×2126后面阶码真值也会固定为126

    如果阶码全0,尾数也全0,这表示±0

    如果阶码全1,尾数全0,表示无穷大±

    如果阶码全1,尾部不全为0,表示非数值数"NaN"(Not a Number)。如:进行00等非法运算的结果就是NaN

    11.4 浮点数运算

    浮点数加减运算步骤:

    1. 对阶。策略是阶数更小的向阶数更大的对齐。
    2. 尾数加减
    3. 规格化
    4. 舍入
    5. 判断溢出

    先从十进制开始理解上述步骤。给定十进制数科学计数法:9.85211×1012+9.96007×1010

    接着看二进制浮点数加减法。

    例:已知十进制数X=5256Y=+591024,则按机器补码浮点运算规则计算XY,结果用二进制表示,浮点数规格如下:阶符取2位,阶码取3位,数符取2位,尾数取9位。

    解题步骤:

    上面例子没有舍入,下面是需要舍入方法:

    "0"舍"1"入法:类似于十进制数运算中的四舍五入法,即在尾数右移时,被移去的最高数值位为0,则舍去;被移去的最高数值位为1,则在尾数的末位加1。这样做可能会使尾数又溢出,此时需再做一次右规。

    恒置"1"法:尾数右移时,不论丢掉的最高数值位是"1"还是"0"都使右移后的尾数末位恒置"1"。这种方法同样有使尾数变大和变小的两种可能。

    例如:加减运算结果为11100,10.110001011。由于数值符号10异号,所以规格化11101,11.0110001011。可以看到数值进行右规操作后整体右移,导致低位1溢出。按照01入策略,要在数值末位+111101,11.011000101+1=11101,11.011000110。同样横置1法类似。

    当进行规格化和舍入操作时会导致阶码值改变,如果发生下溢,直接当作0处理即可。如果发生上溢则会发生中断,这是必须要处理的错误。而有的计算机可能会把浮点数的尾数部分单独拆出去计算(24bit32bit),算完了经过舍入后(32bit24bit)再拼回浮点数。

    11.5 浮点数强制类型转换

    系统位数对应的变量类型如下:

    系统位数对变量

    如果按照charintlong,如果按照这样的顺序转换则不会出现精度丢失问题。其中,double所能表示的位数是1个数值位+11位阶码+52尾数还有一个隐含的1=53位。

    如果是32位操作系统那么longdouble,这里long型有32,而double53位。所以在32位操作系统中,longdouble转换是不会丢失精度的。但如果是64位操作系统long64位,而doble只有53位。此时就会有精度的损失。

    同样的float尾数是1+23=24位,double1+52=53位。显然floatdouble不会丢失精度。

    再看intfloat,在32位操作系统中,int位数是1个符号位+31个数值位;而float1个符号位+8个阶码+23数值位+1个隐藏数值位,所以是24数值位。那么intfloat可能会有精度的损失,但考虑到float8位的阶码所能表示的数肯定比int更大,所以范围不会出现溢出。而floatint,由于float可能表示小数,小数在转变为int类型时,小数点后的所有数值都会舍去,此时会有精度损失。而float所能表示的范围比int更大,所以会有溢出可能性。

    int和float强制类型转换

    三. 存储系统

    存储器层次结构

    存储器层次结构

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

    存储器层次结构图如下:

    存储器层次结构图

    由于CPU运算速度很快,所以不能直接访问辅存。辅存中数据必须先调入主存中,才能进行访问。虽然数据被放入主存中,CPU访问速度可以大大提高,但速度还是不够快,所以就要用到高速缓冲存储器(Cache)。一些经常用到的数据会从主存中复制一份到cache缓存中,这样效率会大大提高。如:微信在视频通话时候,处理视频通话模块会在通话期间经常用到,所以这一处理模块会写入cache缓存中。

    再详细一点,主存和辅存之间的数据交换是由硬件+操作系统实现的,操作系统根据页面置换算法可以决定把哪些数据从主存置换到外存,这一层面需要系统程序员关系。主存和Cache之间的数据交换通常由硬件自动完成,这一部分由硬件工程师完成。

    主存辅存:实现虚拟存储系统,解决了主存容量不够的问题

    Cache主存:解决了主存与CPU速度不匹配的问题

    存储器分类如下:

    存储器分类

    同时,存储器也可以按照存储介质分类:

    也可以按存取方式分类:

    后两种存储器由于读写某个存储单元所需时间与存储单元的物理位置有关,所以也可以一起称为串行访问存储器。

    还有一种特殊存储器:相联存储器:一种可以按内容访问的存储器(CAM),按照内容检索到存储位置进行读写。快表就是一种相联存储器。即可以直接表明要查找的内容,根据内容找到数据存储位置。

    也可以按照信息的可更改性进行分类:

    还可以按照信息可保存性分类:

    存储器性能指标:

    1. 存储容量:存储字长×字长。如:1M×8位。MDR位数反映存储字长。
    2. 单位成本:每位价格=总成本/总容量
    3. 存储速度:数据传输率=数据的宽带/存储周期。数据的宽度即存储字长。

    存储周期

    存取时间:存储时间是指从启动一次存储器操作到完成该操作所经历的时间,分为读出时间和写入时间。

    存取周期:存取周期又称为读写周期或访问周期。它是指存储器进行一次完整的读写操作所需的全部时间,即连续两次独立地访问存储器操作(读或写操作)之间所学地最小时间间隔。即存取周期Tm=存取时间Ta+回复时间

    主存带宽(Bm):主存带宽又称数据传输率,表示每秒从主存进出信息地最大数量,单位为字/秒、字节/秒(B/s)或位/秒(b/s)

    1. 主存储器基本组成

    一个存储体可以分为:存储体、MAR、MDR三大部分。其中MAR是地址寄存器,MDR是数据寄存器。这三个原件会在时序控制逻辑指挥下进行配合工作。

    存储器三大部件

    1.1 存储芯片基本原理

    存储体就是存放实际地二进制数据。一个存储体由多个存储单元构成,而每个存储单元又由多个存储元构成。一个存储元可以存放一位地二进制01

    存储元

    上面的MOS管可以理解为一种电控开关,输入电压达到某个阈值时,MOS管就可以接通。具体原理是:如在MOS管一端输入一个5V高电压,这个5V高电压会达到MOS管阈值,接着MOS管就是导电。而如果电压没有达到阈值,那这个MOS管元件就是一个绝缘体。这种在电压达到阈值后是导体,如果电压不够或没有电压情况下又是绝缘体的材料被称为半导体材料。

    另一个元件是电容:一个电容由两个金属板和中间的绝缘体构成,下边的三条依次变短的线表示下边这个金属板是接地的,即接地端电压是0V。如果现在给上面的金属板加一个5V电压,由于与下面接地的金属板产生电压差,因此电容中的电荷就会开始移动,这个移动过程就是给电容充电的过程。即当我们输入一个5V电压后,这个电容中就会保存一定的电荷,而如果上面输入的是低电压的0V1V,由于上下两个金属板的电压差很小,所以此时的电容并不会充电。可以根据电容是否保存电荷的两种状态信息来对用二进制的01

    假设下面电容中已经有一些电荷,即电容表示二进制1,此时读取这个二进制1办法是:给MOS管一端加一个高电压信号5V,也可以理解为对MOS管输入二进制1,MOS管就会接通变为导体,接通后,电容中存储的电荷就可以顺着导线外流,当上图最右端的出口检测到电流时,就可以认为这个存储元输出一个二进制1。而另一种情况如果电容中没有保存电荷,当MOS管接通后,输出端并不能检测到电荷流出,因此在这种情况下电容中保存的是二进制的0,也即存储元输出一个二进制0

    输入一个二进制位原理类似:在输出端加一个5V高电压,同时给MOS管也加一个5V高电压接通,接通后输出口的高电压顺着接线流入电容,此时上边金属板电压是5V,下边是0V,产生电压差,电荷会移动到电容中。也即电容存储了二进制1。最后再将MOS管断开即可完成存储。

    如果将多个存储元进行科学合理的连接,那么就可以一次性读出或写入多个二进制数据。存储单元构成如下:

    存储单元

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

    多个存储单元就构成了存储体,也称存储矩阵。存储体结构如下:

    存储体原理结构

    一次可以读出的一行二进制位就是存储字,上面例子中一行有8个存储元,所以存储字长是8bit。所以在这个例子中一个存储字=8bit

    实际情况中要使用译码器,来解决如何根据地址决定要读或写的存储字位置。如下:

    存储芯片原理

    译码器使用原理:假定给出n位地址信息,这n位地址就会对应2n个存储单元,所以译码器会根据地址寄存器MAR中给出的这几位地址,将其转变成某一条选通线的高电压信号。

    假如CPU给MAR的地址是000,对应十进制是0。所以移码器会把第0根字选线给它一个高电平的输出,之后再根据上面存储单元读取数据原理,就可以读取第一行的二进制信息。

    总之每一个地址会对应一条字选线,如果有23个地址,就会对应8条字选线。译码器根据地址选取字选线,给定该字选线一个高电平信号,这个线或接通对应一行的MOS管,之后再根据绿色的数据线读取到每一位的二进制信息。之后CPU会通过数据总线取走这一整个字的数据。所以数据总线的宽度=存储字长。

    对于上面例子,其总容量=存储单元个数×存储字长=23×8bit=23×1Byte=8B。这里的23表示MAR给定的只有三个地址。

    继续完善这个存储芯片构成,还需要增加一个控制电路,用于控制译码器、MAR和MDR。

    控制电路

    如CPU通过地址总线把地址送入MAR中,但是由于使用的是电信号来传输二进制数据,而电信号难免有不稳定的时候。因此当MAR中电信号稳定之前这个地址信息是不能送到译码器中的。所以这就是控制电路作用,只有MAR稳定后才会打开译码器开关让译码器翻译这个地址。同样当数据输出时,输出电信号稳定后控制电路才会认为此时输出是正确无误的,所以控制电路也需要控制MDR在什么时候给数据总线送出数据。

    另一方面存储芯片还需要对外提供:

    1. 片选线(用CSCE表示)。这种头上画线表示该信号低电平有效。

    2. 读控制线和写控制线。

      如果将两根线分开设计:WE允许写、OE允许读

      如果两个线设计为一根:WE低电平表示写,高电平表示读。

    至此存储芯片完整构造原理已经介绍完:

    存储芯片完整构造

    存储芯片逻辑图:

    存储芯片逻辑图

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

    详细说一下片选线,给定一个内存条:

    主存图

    上面主存每一个黑色矩形就是一个存储芯片,所以一个内存条包含多个存储芯片。如果要读取的数据只存放在某一块存储芯片中,在提供一个读写地址之后,只能让存储数据那一块芯片工作,而其他芯片不参与工作。此时就需要片选线,发送一个CS低电平信号给要读取的芯片。而其他芯片都给一个高电平信号。这样就能保证此时读取的就是指定芯片的数据。

    存储芯片逻辑图中每根线都会对应硬件的一个金属引脚。有的题目会让判断金属引脚最少数目。这种题其实就是判断地址线和数据线的总根数,再加上一定需要的一根片选线和至少一根的读写控制线的数目就是金属引脚的最少数目。另外还会有供电引脚、接地引脚。

    地址线总数就是MAR数,数据线总数就是MDR

    如果告诉一个地址芯片有n位地址,则有2n个存储单元,意味着地址线有n条。

    常见描述:8K×8位,即存储单元个数有8K=213个,每个存储单元字长是8bit,即213×8bit

    1.2 寻址方式实现

    寻址

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

    地址空间

    地址空间2

    如果想按字寻址,由于一个字占四个字节,所以会把一行合并看作一个字。当我们指定要读的是第几个字时,只需要把字地址进行算术左移两位,这样就可以把字地址转为与之对应的起始字节地址。如此时要读取1号字,也就是要读第二行的字,我们将001100,此时这个100对应的十进制是4,这样我们就得到这个字的起始字节的地址。

    其他寻址方式原理类似。

    2. SRAM和DRAM

    SRAM即静态RAM;DRAM即动态RAM。

    DRAM主要用于主存,SRAM用于Cache。重点在于SRAM和DRAM的对比。

    上一节中介绍的存储器基本原理是DRAM芯片。两个芯片核心区别在于:存储元不一样。

    DRAM芯片:使用栅极电容存储信息。SRAM芯片使用双稳态触发器存储信息。

    2.1 SRAM和DRAM区别

    DRAM存储元(栅极电容):

    存储元

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

    双稳态触发器

    DRAM存储元在上一节介绍过,这里重点介绍SRAM存储元双稳态触发器原理。上图一个双稳态触发器中包含六个MOS管(M1M6)表示。这中存储元可以呈现出两种稳定的状态:

    双稳态

    同时双稳态触发器还需要两根数据线,根据两条线哪条线输出低电平信号,就可以判断触发器中存放的是0还是1

    如果要写入一个0,只需要左边线BL为低电压,右边线BLX高电压,就可以变为AB高,存入0

    两中存储元区别:

    栅极电容双稳态触发器
    电容放电信息被破坏,是破坏性读出,读出后应有重写操作,读写速度更慢读出数据,触发器状态保持稳定,是非破坏性读出,读写速度更快
    每个存储元制造成本更低,集成度高,功耗低每个存储元制造成本更高,集成度低,功耗大

    更详细对比:

    DRAM和SRAM对比

    上面提到了刷新的概念:

    2.2 DRAM的刷新

    DRM刷新周期一般为2ms,且以行为单位,每次刷新一行存储单元。

    之前介绍的译码器,如果有20位地址,那么选通线的数量为220=1M。所以给译码器一端接1M根线(一百万根)不太可能实现。

    存储器简单模型

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

    寄存器二维排列

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

    二维寻址

    上面地址是8位,采用二维存储需要28=256根选通线,其中行地址译码器负责24个根,列地址译码器负责24根。

    DRAM刷新方式有硬件支持,读出一行的信息后重新写入,占用1个读/写周期

    假设DRAM内部结构排列成128×128的形式,读/写周期是0.5微秒(us),2ms共有2ms/0.5us=4000个周期。则刷新方式如下:

    在实际操作中,可以利用CPU不需要访问存储器这段时间进行刷新。即可在译码阶段进行刷新。这个刷新由存储器独立完成,不需要CPU控制。

    2.3 DRAM地址线复用技术

    DRAM在行译码器和列译码器输送地址时候不是和SRAM那么同时发送,而是分两次发送。本来DRAM中需要n个地址线同时送行和列地址,但是采用地址线复用技术后,可以将行地址和列地址通过前后两次进行传输,也就是只需要n2条地址线就可以。先将行地址送达行地址缓冲器,再将列地址送入列地址缓冲器,两个缓冲器再送给两个译码器。

    DRAM地址线复用技术

    这种行列地址分两次送,可以使地址线减半、芯片引脚减半。原本需要n个地址线,现在只需要n2个地址线即可。

    所以在题中如果问DRAM引脚数量要考到地址复用技术导致引脚数量减半这一因素。

    现在DRAM芯片已经过时,现在主存通常是采用SDRAM芯片。如:主存DDR3和DDR4。

    3. ROM

    ROM芯片:非易失性,断电后数据不会丢失

    几种ROM芯片:

    之前的学习可以知道主存中存放重要指令。CPU根据这些指令完成对应操作。由于主存是RAM芯片,这种芯片会在断电后数据丢失。当再次开机时会将辅存中指令数据调用到主存中。操作系统装在辅存中,由于开机时主存中没有指令所以CPU必须向主板上面的ROM芯片读取开机所需要执行的指令。这个主板上ROM芯片就是BIOS芯片,其内部存储了"自举装入程序",负责引导装入操作系统(开机)。

    在逻辑上主存由:RAM+ROM(BIOS)组成。且二者统一编址。

    BIOS

    统一编址指的是:如果ROM芯片的容量是1kb,那么CPU会将01023的地址分配给主存中的ROM芯片,RAM地址从1024开始往后编号。

    总结:

    很多ROM芯片虽然名字是“Read-Only",但很多ROM也可以进行"写"操作。

    闪存的写速度一般比读速度更慢,因为写入前要先擦除。

    RAM芯片是易失性的,ROM芯片是非易失性的。很多ROM也具有"随机存取"的特性。

    3. 主存优化

    上面介绍过存取周期:存取周期T=存取时间r+恢复时间

    存储周期

    存取周期是指可以连续读写的最短时间间隔。DRAM芯片的恢复时间比较长,有可能是存取时间的好几倍(如:存取时间为r,存取周期为T,则可能T=4r)。而SRAM的恢复时间较短。由于存取周期长,从而引发多核CPU访问内存难得问题。

    3.1 双端口RAM

    作用:优化多核CPU访问一根内存条的速度。

    双端口RAM

    这里CPU两个内核可以通过内存RAM的两个端口进行访问。如果要支持双端口RAM必须要有两组完全独立的数据线、地址线、控制线。CPU、RAM中也要有更复杂的控制电路(主板)。

    两个端口对同一主存操作有以下4种情况:

    1. 两个端口同时对不同的地址单元存取数据。
    2. 两个端口同时对同一地址单元读出数据。
    3. 两个端口同时对同一地址单元写入数据。这种情况是不被支持的,会出现写入错误情况。
    4. 两个端口同时对同一地址单元,一个写入数据,另一个读出数据。这种情况不被支持,因为会出现读出错误。

    后两种不支持的操作解决方法是置"忙"信号为0,由判断逻辑决定暂时关闭一个端口(即被延时),未被关闭的端口正常访问,被关闭的端口延长一个很短的时间段后再访问。

    致忙

    对比操作系统的"读者写者"问题。

    3.2 多体并行存储器

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

    多体并行存储器

    上面的M0M3可以理解为四根规格一样的内存条。这种方案有两种编址方式:高位交叉编址和低位交叉编制。

    所以可以得出一个结论当访问连续存储的地址时,低位交叉编制更快,且连续读取n个存储字耗时为T+(n1)r。实际上数据在内存中存储就是连续的,所以低位交叉编址方式应用更广泛,而高位交叉编址方式相当于单纯的扩容,速度上提升不大。

    低位交叉编址方式采用流水线的方式并行存取(宏观上并行,微观上串行):

    在宏观上,一个存储周期内,m个存储体交叉存储器可以提供的数量为单个模块的m倍。而为了保证这种流水线式存取不间断,当存取周期为T,存取时间为/总线传输周期为r,应保证模块数mTr。最好的方案式存储体个数m=Tr

    3.3 单体多字存储器

    相当于将多体多体并行存储器中的存储体进行合并。整个存储器只用一套读写电路、地址寄存器和数据寄存器。

    单体多字存储器

    上面每一个方格代表一个字。每次可以读取一行数据,即m个字。所以数据总线宽度也为m个字。显然这种存储器要比多体并行存储器灵活性要差。每次能同时取m个字,不能单独取其中某个字。所以要读取的指令和数据在内存必须连续存放。即如果指令和数据不在同样一行存储,就意味着要读取两行数据,这两行数据中有部分无用信息。所以灵活性差。

    但从速度方面来说单体多字存储器和多体并行存储器速度一样。每读入一个字平均时间都是r。都可以很大程度上提升主存读写速度。

    4. 主存储器与CPU连接

    先回忆一下单块存储芯片:

    单块存储芯片

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

    现代计算机主存结构

    如果想扩展主存的字数,需要字扩展;如果存储芯片字长比数据总线宽度要小,要用到位扩展。

    4.1 位扩展

    为了描述方便可以给存储芯片输入信号和输出信号进行命名:

    存储芯片输入输出信号

    地址从低位到高位是A0A7,数据总线从低到高是D0D7。片选先开关是CSCE。读写控制线开关是WEWR有的地方会把两根读写线分开表示。

    下面是一个8k×1位的存储芯片:

    8k存储芯片

    8k=213,即需要13根地址总线,连接上就完成了地址线的连接。

    连接地址总线

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

    WE总线连接

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

    数据总线连接

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

    片选线连接

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

    位扩展

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

    为扩展增加芯片

    这样存储器存储字长就扩展为8bit。这种扩展方式称为位扩展。

    4.2 字扩展

    假设现在有一块8k×8位的存储器

    字扩展

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

    字扩展的线选法和译码片选法对比:

    线选法和译码片选法对比

    实际情况应用最多的是译码片选法。

    同时可以将二者结合产生新的方法:字位同时扩展法。

    字位同时扩展法

    图中有八块芯片:由于数据总线有8根,所以可以每两块芯片为一组实现了位扩展,因为每个芯片是4位。

    每个芯片有16k对应214即有14根地址总线可以用上,可以将CPU的A0A13全部连接。这样会多出A14,A15两根地址总线,所以可以接入一个24译码器,此时能产生四种不同状态,可以再连接三个存储芯片。此时字扩展为64k×8位的寄存器。整个存储空间从全0到全1不间断存储。

    4.3 几种常见译码器

    5. 磁盘存储器

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

    磁表面存储器

    这种磁表面存储器一次读写只能是1bit。并且读写这两种状态不能同时进行。

    磁表面存储器的优点:

    1. 存储容量大,位价格低
    2. 记录介质可以重复使用
    3. 记录信息可以长期保存而不丢失,甚至可以脱机存档
    4. 非破坏性读出,读出时不需要再生。

    磁表面存储器的缺点:

    1. 存取速度慢
    2. 机械结构复杂
    3. 对工作环境要求较高(磁性材质易受强磁场的干扰)。

    外存储器既可以作为输入设备,也可以作为输出设备。(既可以存数据,也可以读数据)

    5.1 磁盘设备的组成

    磁盘存储器组成

    磁盘分为两部分:正面是左图的机器部分。背面是右图的电路部分。具体细分如下:

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

    磁盘横切面图

    5.2 磁盘的性能指标

    磁盘性能指标通常看以下几点:

    1. 磁盘的容量:一个磁盘所能存储的字节总数称为磁盘容量。磁盘容量有非格式化容量和格式化容量之分。

      非格式化容量是指磁记录表面可以利用的磁化单元总数。即磁盘在物理上来看总共可以存储的二进制比特位上限。

      格式化容量是指按照某种特定的记录格式所能存储信息的总量。即磁盘有的扇区可能会损坏,为了避免有的扇区损坏导致整个磁盘无法使用,因此很多厂商生产的磁盘需要格式化留下某些备用的扇区作为顶替使用。所以实际用量会减少。

      所以对于一块磁盘来说格式化的容量要比非格式化的容量要小。

    2. 记录密度:记录密度是指盘片单位面积上记录的二进制的信息量,通常以道密度、位密度和面密度表示。

      道密度是沿磁盘半径方向单位长度上的磁道数。如:60/cm指的是磁盘上一厘米半径有60个磁道。

      位密度是磁道单位长度上能记录的二进制代码位数。如:如果某圈磁道的位密度是600bit/cm,指的是外圈每一厘米的磁道可以存储600bit的信息。

      注意:磁盘所有磁道记录的信息量一定是相等的,并不是圆越大信息越多,故每个磁道的位密度都不同。即越内测的磁道位密度越大。因此内测磁道会影响到磁盘的总体容量。

      位密度

      位密度与道密度

      面密度是位密度和道密度的乘积。

    3. 平均存取时间

      =()+()+()

      磁盘读取过程如下:

      磁盘读取过程

      首先磁盘要先进行寻道(找到所读位置的磁道),通常来说寻道花销时间较长。接着会旋转盘片直到磁头靠近所读扇区的起始位置。最后盘片接着旋转,使得磁头划过所读扇形弧道长度。

      通常来说寻道时间题目会给个平均时间,旋转延迟时间如果题目没给,一般取盘片转半圈的时间。最后扇区时间需要根据题中所给的磁盘转速算出。有的题目还需要加上磁盘控制器延迟时间(CPU传输读取指令的时间)。

    4. 数据传输率:磁盘存储器在单位时间内向主机传送数据的字节数,称为数据传输率。

      假设磁盘转数为r(转/秒),每次旋转都会读取一整条磁道,而每条磁道容量为N个字节,则数据传输率为Dr=rN

    5.3 磁盘工作原理

    上面介绍过磁盘读取过程原理。主机为了指明要读取的扇区位置,需要给磁盘中的各个扇区编号,即地址。

    磁盘地址一般如下图所示:

    磁盘地址

    例如:若系统中有4个驱动器,每个驱动器带一个磁盘, 每个磁盘256个磁道、16个盘面,每个盘面划分为16个扇区,则每个扇区地址18位二进制代码

    磁盘地址计算

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

    磁盘串并行

    5.4 磁盘阵列

    RAID(Redundant Array of Inexpensive Disks 廉价冗余磁盘阵列)是将多个独立的物理磁盘组成一个独立的逻辑盘,数据在多个物理盘上分割交叉存储、并行访问,具有更好的存储性能、可靠性和安全性。也就是可以用某些手段将多个磁盘组成磁盘阵列,再结合相应的算法和机制可以提高磁盘的读写速度,同时也能提升存储性能、可靠性和安全性。

    RAID的分级如下所示。在RAID1RAID5的几种方案中,无论何时有磁盘损坏,都可以随时拔出受损的磁盘再插入好的磁盘,而数据不会损坏。

    上面六种方案越往后可靠性越高,成本也越低。

    6. 固态硬盘SSD

    固态硬盘存储技术是基于闪存技术(Flash Memory),属于电可擦除ROM,即EEPROM。

    固态硬盘SSD

    SSD组成有两部分:

    SSD读写性能:是以页为单位进行读写的。以块为单位进行擦除,擦干净的块,其中的每页都能写一次,被读无限次。且支持随机访问,系统给定一个逻辑地址,闪存翻译层可以通过电路迅速定位到对应的物理地址。

    如果要写的页有数据,则不能写入,需要将有数据的块内其他页全部复制到一个新的(擦除过的)块中,再在新的块中写入想要写入的数据,最后将原来的块内所有页擦除。此时地址会放生改变,但闪存翻译层会修正写入块的地址。这就导致了SSD读的速度比写的速度快很多。

    固态硬盘相较于机械硬盘特点:

    由于上面的SSD一个块擦除次数过多可能会坏掉,所以现代SSD都会使用磨损均衡技术。

    磨损均衡技术思想:将"擦除"平均分布在各个块上,以提升使用寿命。原理还是闪存翻译层有逻辑映射的功能,所以其真实物理地址会变。这种磨损技术分为两种:

    1. 动态磨损均衡:写入数据时,优先选择累计擦除次数少的新闪存块。
    2. 静态磨损均衡:SSD监测并自动进行数据分配、迁移,让老旧的闪存块承担以读为主的储存任务,让较新的闪存块承担更多的写任务。如:假设电脑中存储一部电影,对于电影来说读的次数更多基本上不会进行修改。所以SSD会监测到,并将电影放入擦除次数多的块中。

    SSD总结:

    SSD总结

    例题:某固态硬盘采用磨损均衡技术,大小为240B=1TB, 闪存块的擦写寿命只有210=1K次。平均每天会对该固态硬盘写237B=128GB数据。在最理想的情况下,这个固态硬盘可以用多久?

    SSD采用磨损均衡技术,最理想情况下,SSD中每个块被擦除的次数都是完全均衡的。1TB128GB=8,所以平均每8天,每个闪存块需要擦除一次。而每个闪存块可以被擦除1K次,因此,经过8K天,约23年后,该固态硬盘会坏。

    7. Cache缓存

    之前运用双端口RAM、多模块存储器提高存储器的工作速度,但优化后主存与CPU速度差距依然很大,所以可以增加一个Cache层缓和CPU与主存之间的速度矛盾。

    7.1 Cache基本原理与概念

    Cache工作原理

    Cache工作原理

    假设启动一个微信并使用视频聊天功能,首先会将视频聊天的代码放入Cache中,CPU可以直接从缓存中读取。而Cache读写速度非常快可以更好配合CPU工作。

    注意:实际上Cache被集成在CPU中。Cache使用SRAM实现,速度快,成本高,但集成度低所以Cache芯片不能做的大,现在一般CPU的Cache缓存只有12MB

    Cache的局部性:

    看一段代码:

    Cache局部工作原理

    上图是代码翻译成指令后,与数据一起存放在主存中。这个程序会一行一行访问数组中的元素:

    根据空间局部性当我们访问完a[0][0]后,在接下来的一段时间内与它相邻的其他元素也有可能被访问到。

    根据时间局部性,由于循环内部执行了sum加法后,在这一段时间内这个加法指令还会被使用到。另外由于循环结构代码内的sum,i,j这些变量在短时间内也会被循环访问。

    基于这些局部性原理,可以把CPU目前访问的地址"周围"的部分数据放到Cache中。再看下面一段程序:

    上面一段程序将会按照列来访问数组,显然这种按列优先的方式访问二维数组,其空间局部性会更差。所以这段代码在执行时间上要慢于第一段代码。

    性能分析

    假设CPU访问一次Cache所需时间为tC,而访问主存时间为tm,命中率为H,即CPU能在Cache中找到想要的数据的概率。与之对应的缺失率M=1H。CPU读取可以分为两个策略:

    例题:假设Cache的速度是主存的5倍,且Cache的命中率为95,则采用Cache后,存储器性能能提高多少?(设Cache和主存同时被访问,若Cache命中则主存中断访问)。

    设Cache的存取周期为t,则主存的存取周期为5t。且由于主存和Cache同时访问,所以命中时访问时间为t,未命中时访问时间为5t。则平均访问时间为0.95×t+0.05×5t=1.2t。故性能为原来的5t1.2t4.17倍。

    若先访问Cache再访问主存,命中时访问时间为t,未命中时访问时间为t+5t,则平均访问时间为Ta=0.95×t+0.05×6t=1.25t故性能为原来的5t1.25t=4倍。

    有待解决的问题

    基于局部性原理,不难想到,可以把CPU目前访问的地址"周围"的部分数据放到Cache中。关于这个"周围"可以用以下方法确定:

    将主存的存储空间"分块",如:每1KB为一块。主存与Cache之间以"块"为单位进行数据交换。

    Cacge与主存块交换

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

    Cache中的块

    如上图,4MB内存中每块大小是1KB,即主存被分割成222210=212=4096块内存。另外主存共有22位,那么块号可以用12位表示,块内地址可以用10位表示。

    注意:操作系统中,通常将主存中的"一个块"称为"一个页/页面/页框"。而Cache中的"块"也称为"行"

    同时每次被访问的主存块,一定会被立即复制进Cache中。从而还有以下几个问题要解决:

    7.2 Cache主存映射方式

    映射方式可以解决Cache与主存的数据块对应关系这一问题。

    映射方式有三种:全相联映射、直接映射、组相联映射。

    三种映射方式

    对于如何区分Cahce中存放的是哪个主存块内容,可以通过一个标记+一个有效位方式解决。

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

    两个标记

    如上图,Cache中7号存储块有效位是1,表示标记为可用用,即7号块存储的是主存中0号块的信息。下面会介绍每种映射方式细节。

    全相联映射

    假设某个计算机主存地址空间大小为256MB,按字节编址,其数据Cache有8个Cache行,行长64B

    由于Cache行长是64B,所以为了保持全相联,主存行长也要是64B。主存256MB对应228即主存地址共28位。而256MB大小,每行行长是64=26,所以22826=222。这也就意味着主存可用分为222这么多块,可用22位当主存块号,6位当块内地址。

    全相联映射例子

    存放原理:

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

    全相联映射例子1

    访问原理:

    假设现在CPU要访问11101001110这个位置信息(对应的是上图右边紫色位置),首先取这个地址的前22位,对比Cache中所有块的标记,接着若标记匹配且有效位=1,则Cache命中,根据地址后六位访问块内地址为001110的单元。若未命中或有效位=0,则正常访问主存。

    优点:Cache存储空间利用充分,命中率高。

    缺点:查找"标记"最慢,有可能需要对比所有行的标记。

    直接映射

    假设某个计算机主存地址空间大小为256MB,按字节编址,其数据Cache有8个Cache行,行长64B

    Cache块号=主存块号%Cache总块数

    直接映射例子

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

    直接映射例子1

    这一就有一个显而易见的缺点:其他地方有空闲Cache的块,但是8号主存不能使用。这种方法灵活性差,空间利用率也不充分。

    对于上面标记位,可用进行一个优化,不用将22位的主块号全部放入,由于之前进行取余操作,从二进制角度看,主存块号%23这个运算结果其本质就是保留主存块号末位三位,这三位就直接指明了Cache中的存储位置。所以这里的标记为就不用写为22位的001000,只需要存储前19位就可用。

    直接映射例子2

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

    直接映射主存块号

    CPU访问方法:

    CPU访问主存地址001000001110:首先根据主存块号的后3位确定(000)Cache行,接着若主存块号的前19位与Cache标记匹配,且有效位=1,则Cache命中,访问块内地址为001110的单元。若未命中或有效位=0,则正常访问主存。

    优点:对于任意一个地址,只需对比一个"标记",速度最快。

    缺点:Cache 存储空间利用不充分,命中率低。

    组相联映射

    假设某个计算机主存地址空间大小为256MB,按字节编址,其数据Cache有8个Cache行,行长64B

    组号=主存块号%分组数

    组相联映射

    上图采用2路组相联映射,即Cache中2块为一组,分四组。

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

    组相联映射1

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

    组相联映射2

    CPU访问方法:

    CPU访问主存地址11101001110:首先根据主存块号的后2位(01)确定所属分组号这里是1,即第一组。接着若主存块号的前20位与分组内的某个标记匹配且有效位=1,则Cache命中,访问块内地址为001110的单元。但若未命中或有效位=0,则正常访问主存。

    优点:另外两种方式的折中,综合效果较好。术语:n路组相联映射,即每n个Cache块为一组。

    7.3 Cache替换算法

    Cache替换算法可用解决Cache很小,主存很大。如果Cache满了之后出现一系列问题。

    三种映射方式

    结合上一节学的三种映射方式,分析Cache替换规则:

    由于直接映射会直接替换不用进行选择,所以替换算法只会用到全相联映射和组相联映射这两种方式中。

    随机替换算法

    随机替换算法(RAND, Random):若Cache已满 ,则随机选择一块替换。

    假设总共有4个Cache块,初始整个Cache为空。采用全相联映射,依次访问主存块{1,2,3,4,1,2,5,1,2,3,4,5}。访问以及替换方式如下:

    1. 由于每访问一次主存都需要将该主存块调入Cache中。当访问前四个主存数据时,刚好可以全部存入Cache中。

      随机算法

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

      随机算法1

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

      随机算法2

    4. 之后的1,2号主存块的访问都可以命中Cache缓存

      随机算法3

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

      随机算法4

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

      随机算法5

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

      随机算法6

    可以看出随机替换算法实现简单,但完全没考虑局部性原理,命中率低,实际效果很不稳定。

    先进先出替换算法

    先进先出算法(FIFO, First In First Out):若Cache已满, 则替换最先被调入Cache的块。

    假设总共有4个Cache块,初始整个Cache为空。采用全相联映射,依次访问主存块{1,2,3,4,1,2,5,1,2,3,4,5}。访问以及替换方式如下:

    1. 由于每访问一次主存都需要将该主存块调入Cache中。当访问前四个主存数据时,刚好可以全部存入Cache中。

      随机算法

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

      随机算法1

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

      先进先出算法

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

      先进先出算法1

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

      先进先出算法2

    6. 之后的3,4,5号主存块都没有在缓存中,所以会分别会替换掉3,0,1号Cache存储块。

      先进先出算法3

    先进先出算法:实现简单, 最开始按0,1,2,3放入Cache,之后轮流替换0,1,2,3号Cache存储块。该依然没考虑局部性原理,最先被调入Cache的块也有可能是被频繁访问的。

    并且这种算法还会出现抖动现象:频繁的换入换出现象(刚被替换的块很快又被调入)

    近期最少使用算法

    近期最少使用算法(LRU, Least Recently Used ):为每一个Cache块设置一个"计数器",用于记录每个Cache块已经有多久没被访问了。当Cache满后替换"计数器"最大的。

    采用这种算法需要增加一个计数器,记录一个Cache块多久没有被访问。计数规则如下:

    这里有一个小细节,第一条规则比其低的计数器才会加1,这是由于只需要关注谁没有被访问的次数更大就可以完成替换,不需要关心Cache块究竟多久没有被访问。假如四个Cache块,可以保证每个Cache块对应的计数器不大于4。不用考虑两个计数器相等情况。

    假设总共有4个Cache块,初始整个Cache为空。采用全相联映射,依次访问主存块{1,2,3,4,1,2,5,1,2,3,4,5}。访问以及替换方式如下:

    1. 首先访问1号主存块,访问之后装入Cache主存块中,由于此时Cache块都是0,处于空闲状态,所以直接装入0号Cache块。

      近期最少使用算法

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

      近期最少使用算法1

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

      近期最少使用算法2

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

      近期最少使用算法3

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

      近期最少使用算法4

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

      近期最少使用算法5

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

      近期最少使用算法6

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

      近期最少使用算法7

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

      近期最少使用算法8

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

      近期最少使用算法9

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

      近期最少使用算法10

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

      近期最少使用算法11

    可以看出Cache块的总数=2n,则计数器只需n位。且Cache装满后所有计数器的值一定不会重复。上面例子有22个Cache块,所以只需要2位就可以记录计数器信息。

    LRU算法:基于"局部性原理",近期被访问过的主存块,在不久的将来也很有可能被再次访问,因此淘汰最久没被访问过的块是合理的。LRU算法的实际运行效果优秀,Cache命中率高。但若若被频繁访问的主存块数量>Cache行的数量,则有可能发生"抖动现象"。例如{1,2,3,4,5,1,2,3,4,5,1,2..}这种访问方式,最频繁访问的主存块数是5>Cache行的数量4

    最不经常使用算法

    最不经常使用算法(LFU, Least Frequently Used ):为每一个Cache块设置一个"计数器",用于记录每个Cache块被访问过几次。当Cache满后替换"计数器"最小的。

    计数器规则是:

    新调入的块计数器=0,之后每被访问一次计数器+1。需要替换时,选择计数器最小的一个Cache块替换。如果计数器最小Cache有多个,就可以按照行号递增或FIFO策略进行选择。

    假设总共有4个Cache块,初始整个Cache为空。采用全相联映射,依次访问主存块{1,2,3,4,1,2,5,1,2,3,4,5}。访问以及替换方式如下:

    1. 由于每访问一次主存都需要将该主存块调入Cache中。当访问前四个主存数据时,刚好可以全部存入Cache中。计数器都置为0

      最不经常使用算法

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

      最不经常使用算法1

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

      最不经常使用算法2

    4. 接下来访问1,2主存块,这两个主存块都可以被缓存命中,所以Cache块0,1的计数器值+1

      最不经常使用算法3

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

      最不经常使用算法4

    6. 访问4号主存块,主存块可以被缓存命中,所以Cache块3的计数器值+1

      最不经常使用算法5

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

      最不经常使用算法6

    由于该算法需要用到计数器,并且计数器位数有可能很大。

    LFU算法:曾经被经常访问到的主存块在未来不一定会用到(如:微信视频聊天相关的块,使用时计数器会一直增加,但不使用的时候由于计数器值已经很大,这些数据不会在接下来的一段时间内被缓存替换掉),并没有很好地遵循局部性原理,因此实际运行效果不如LRU。

    7.4 Cache写策略

    Cache写策略可以解决CPU修改了Cache中的数据副本,并如何确保主存中数据母本的一致性问题。

    写命中

    缓存命中情况下CPU对某个命中地址进行写操作。这种情况有两种解决方法。

    写不命中

    当CPU进行写操作对Cache缓存没有命中情况下,采用两种方式:

    多级Cache

    现代计算机常采用多级Cache方式。

    多级Cache

    上面两个Cache(L1,L2)离CPU越近的速度越快,容量越小;离CPU越远的速度越慢,容量越大。

    各级Cache之间常采用全写法+非写分配法。

    Cache与主存之间常采用写回法+写分配法。

    8. 页式存储器

    主存和Cache之间是以块为单位进行读写的。

    假设一个主存每块单元是1KB,而某个程序有4KB,如果将这个程序全部放入主存连续空间中可能会导致主存利用率不高情况出现,所以通常可以将这个程序分为4个页,每个页面的大小和物理块的大小(这里是1KB)相同。

    页式存储

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

    程序分为四个页面

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

    主存离散存放

    所以,所谓页式存储系统就是一个程序(进程)在逻辑上被分为若干个大小相等的"页面","页面"大小要与主存"块"的大小相同。每个页面可以离散地放入不同的主存块中。

    注意:程序分为页面是逻辑层面划分。而主存和Cache分块更多是物理层面划分。

    8.1 页表

    引入两个重要概念:

    逻辑地址(虚地址):程序员视角看到的地址。

    物理地址(实地址):实际在主存中的地址。

    CPU执行的机器指令中,使用的是"逻辑地址",因此需要通"页表"将逻辑地址转为物理地址。页表的作用是记录了每个逻辑页面存放在哪个主存块中。

    每个程序都会被离散存放在主存中的某个位置:

    程序页

    假设这个程序大小有4KB=212B,如果按字节编址这个程序的地址范围:000000000000111111111111。如果这个程序中有两个变量地址分别是x:001000000011y:110000001010这两个地址是逻辑地址。现在运用取数指令将变量x的存放在ACC寄存器中,对应机器指令:000001001000000011。前面的000001是操作码,后面的是x对应的逻辑地址。

    现在分析一下这个x对应的逻辑地址应该在哪一个页面:

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

    页表

    如刚刚的变量x:001000000011,它的页号就是前两位000号页,而根据页表关系0号页对应主存块号2号位置。之后再根据 主存块号+x的页内地址进行拼接就可以得到x的物理地址。

    页表中相关的数据是存放在主存中的。所以,CPU在进行地址转换的时候需要查询页表,就意味着CPU需要进行一次访存操作。另外上面页表中的每行成为"页表项"。

    所以一个地址x:001000000011变换详细过程如下:

    当CPU执行指令时,这些指令中肯定包含当前要访问哪个逻辑地址。逻辑地址可以拆分为:+两个部分。

    地址变过程

    1. 首先CPU会将逻辑地址拆分为页号和页内地址两个部分。

    2. 接着CPU中会有一个很重要的寄存器:页表基址寄存器。这个寄存器保存页表被存放在哪个起始地址。假设当前基地址是1058这就表示当前页表第一页页表项的地址存放在主存1058位置。假设每个页表项占4B,那么第二页页表项地址是1062

      对于这个例子来说我们要找的x页表对应0号逻辑页。通过页表可以知道0号页对应主存块号2的位置。

    3. 之后CPU会将这个主存块号和页内地址进行拼接,拼接之后的地址就是物理地址。

    4. 最后根据这个物理地址访问主存。根据之前所学的知识可以知道当要访问主存某一个物理地址时,无论是读写哪个操作CPU都会优先去Cache中查找能否命中所要访问的数据。如果Cache命中能找到则直接读取或写入数据。如果Cache缓存未命中CPU就到主存中找。

      地址变过程1

    8.2 快表

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

    快表

    引入快表之后原来主存中存放的信息就可以称为慢表。引入快表之后CPU访问过程如下:

    注意不要把Cache和快表混淆。Cache中存储的是主存中某一块数据。快表中存储的是慢表中某一个页表项。引入快表就是为了让逻辑地址转换为物理地址更快。所以快表是在地址变换过程起到变快作用,而Cache是在地址访问时候起到加速作用。

    之所以CPU访问快表更快是因为快表使用SRAM,而慢表使用DRAM。并且快表是一种相联存储器,即可以按内容进行访问。而快表会遇到与Cache相同的问题,可以参照Cache解决办法。

    快表总结

    9. 虚拟存储器

    根据之前的学习可以知道,计算机中经常会出现套娃这种现象,比如之前的Cache,会有L1,L2等多级Cache。而虚拟存储系统也是这样的多级结构。

    一个应用程序只需要将部分内容调入内存,就能正常运行。其余部分等用到该功能时才会调入主存。这就是虚拟存储器。虚拟存储器本质将辅存数据调入内存,与之前内存中数据调入Cache类似。

    9.1 页式虚拟存储器

    与之前一样将程序分页,对于这个程序,会先将用得到的数据调入主存就能正常使用。

    页式虚拟存储器

    上图中对页表进行改造:

    可以看出主存与辅存之间的页面管理策略与主存与Cache的很多管理都类似。

    页式虚拟存储器结构图:

    页式虚拟存储器结构图

    逻辑页号也有虚页号,CPU会根据指令中的虚页号查找页表中对应的表项,再根据页表项进行对应位置的读写操作。

    9.2 其他虚拟存储器

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