文章目录
- 第三章 存储系统
-
- 存储系统的基本概念
- 主存储器的基本组成
- SRAM和DRAM
- 只读存储器ROM
- 主存储器与CPU的连接
- 双端口RAM多模块存储器
- Cache 基本原理,基本概念
- Cache以及主存的映射方式
- Cache替换算法
- Cache写策略
- 页式存储器
- 虚拟存储器
- 第四章 指令系统
-
- 指令格式
- 扩展操作码指令格式
- 指令寻址
- 数据搜索(上)
- 数据搜索(中)
- 数据搜索(下)
- CISC和RISC
第三章 存储系统
存储系统的基本概念
存储器的层次结构 各级存储器的速度和价格 存储器的分类–层次 存储器的分类–存储介质 存储器的分类–存取方式
- CAM根据内容检索存储位置
- RAM SAM DAM按地址访问
存储器的分类–可更改信息 存储器的分类–信息的可保存性 存储器的性能指标 知识点小结
主存储器的基本组成
半导体的基本远见和原理
- 一个存储器由多个存储单元组成,一个存储单元有多个存储元,一个存储元可以存储一个二进制数
- MOS管道相当于开关,给高电平可电路;
- 电容器可以储存电荷,导通MOS管道完成后,可以读取电容器中的电荷,也可以高电平存储电荷
- 多个存储元合理连接后,可同时读取或写入多个二进制数据
- 图中,一条红线控制一行MOS管道和绿线可以读取电容电荷,一次读取整行存储元信息
- 这就是为什么存储器一次只能读或写一个存储器,因为存储器一次控制一个单词,因为它们MOS共同连通
- 区分存储字和字节,一个字节8比特,一个存储字有多少字节取决于实际情况
存储器芯片的基本原理
- MAR将n位二进制地址发送后,译码器可对应2n次方根字选线,每个字选线对应一个存储单元(存储字)
- 读取存储元的数据后,通过数据线(位线)MDR数据总线由数据总线保存CPU读取
存储器芯片的基本原理–进一步完善
- 增加控制电路
- 可稳定控制电路MAR译码器可以打开输出的地址信息;同样MAR输出信号也需要控制电路进行稳定
- 选线用于控制当前存储芯片是否有效,低电平是否有效,因为实际情况下会有多个存储芯片
- 读/控制线用于控制当前是读还是写;如果分别使用两个控制器,低电平表示允许写。如果一个控制器用高低电平读写
存储器芯片的基本原理–整体上看
- 译码驱动包括译码器和驱动器,用于确保译码器输出的电信号稳定可靠
- 内存条可能包含多个存储芯片,用于决定哪个芯片工作
- 每个存储芯片都会暴露金属引脚,
- 测试经常测试,已知存储芯片的一些参数信息,以便判断存储芯片的引脚数量至少是多少
- 常见的存储芯片容量描述,几乘数,第一个数是存储单元数,第二个数是每个存储字的位数
寻址
- 总容量1在图中KB,地址线10根,2的10次方个地址刚好满足1KB的寻址
- 图中显示了一个存储字符4字节
- 现代计算机按字节编址,并能实现字节、字、半字、双字寻址,
- 因此,有必要实现字节、字、半字、双字寻址的转换
- 已知字节地址,请这里的存储字地址除以4,即将字节地址二进制数左移两位;半字,双字相同
SRAM和DRAM
高频考点:两者对比 DRAM芯片
- 上节课介绍的是DRAM芯片
- DRAM和SRAM核心差异,存储元不同
- 触发器的具体原理参考数字电路
- 为什么叫双稳态触发器?A高B低对应1,A低B高对应0,需要两条数据线来读取当前状态
- 红线开关后,BL和BLX哪边出现低电平,则读出的就是哪边的数据
- 写入时,给左边BL低电平,右边BLX高电平,写0,反之亦然
- 栅极电容读取信息是破坏性读取,读取后还需要重写操作,再生,
- 双稳态读取数据后,不是破坏性的,不需要重写,所以双稳态读写速度更快
- 格栅极电容器存储可以节省更多的部件、空间、更高的存储密度和更低的功耗
- 两者断电都会丢失信息,容易丢失和破坏性读取要区分开来
刷新
- 格栅电容器存储电荷会慢慢消失,需要定期刷新,给电容器充电
- 不需要双稳态,只要通电,状态不会改变
DRAM刷新
- 译码器将n位地址转换为选线2的n次方,连接每个存储单元,不易实现
- 将地址译码器改为行和列,存储单元编程矩阵排列,行列地址译码器分别对应n/2位地址分别对应2位n/2次方选通线
- 每条选线对应一行或一列存储单元,选线和选线共同确定存储单元
- 每次刷新一行存储单元,指的就是行地址译码器对应的一行
- SRAM也有行列地址线,但不需要刷新
如何刷新,什么时候刷新
- 分散刷新和集中刷新是不可取的。异步刷新也可以使用CPU访问存储器时无需刷新
- 如果考试没有给出明确的刷新周期,默认为2ms
- 刷新由存储器独立完成,无需CPU控制
DRAM地址线复用技术
- n在将信息传输到行列地址译码器之前,可以使用位置地址n/2跟随地址线,分别传输地址和列地址,分别存储在地址行列缓冲器中
- 然后分别发送到地址译码器,使之DRAM对外引脚较少,因为只有对外引脚n/2个地址线
- DRAM由于存储密度大,存储容量大,地址线多,可以分别发送地址
- SRAM由于集成度低,存储容量小,地址线少,直接用n和地址线传输信息
- 如果在考试中计算DRAM引脚的数量需要考虑地址引脚减半的情况
- DRAM已过时,目前已使用SDRAM(DDR3 DDR4)
知识点小结
只读存储器ROM
各种ROM
- 结合英语全称记忆,各种英语全称记忆ROM各种名称ROM选择题的名称和功能可以调查
- 闪存芯片虽然可以擦除重写,但还是叫他ROM
计算机中的重要性ROM
- 启动时主存中没有数据,CPU主板需要BIOS芯片(ROM芯片)读取自举装入程序,读取辅存中操作系统的相关数据给主存,引导启动
- 逻辑上,BIOS芯片也被视为主存的一部分,两者统一编址,
知识点小结
主存储器与CPU的连接
单块存储芯片和CPU的连接
- 扩展主存字数,扩展字数
- 尽量不要浪费数据总线的宽度
- 现在的计算机通常都是MAR和MDR集成在CPU内部,存储芯片中的寄存器只是普通的寄存器
- 目前的计算机内存通常由多个存储芯片组成
存储芯片输入输出信号
- 注意看命名缩写,带横线的是低电平有效
增加主存的存储字长–位扩展
- 假设8K*1位,则对应2的13次方个1位的存储单元,需要13个地址线
- 8个1位存储芯片,每个芯片连接数据总线的1位,对外看起来就像一个8K*8位的存储器一样
- CPU发出的地址信息A0-A12都会同时发给8个芯片
增加主存的存储字数–字扩展
- 假设一块存储芯片是8K*8位,CPU也是数据总线8位,因此不需要位扩展
- 但是CPU地址总线比存储芯片的地址线数量多,可以结合片选线进行存储芯片的字扩展
- 为了不让存储芯片之间相互干扰,一次只能控制一根片选线对应一个存储器
- 如果一根专门的地址线对应一个存储器,n条多余的地址线只能对应n个选片信号,浪费资源
- 可以对A13加非门,这样1根地址线可以控制2个存储芯片,这个扩展电路设计可以理解为增加了一个1-2译码器
- 进一步优化,对CPU多余地址线连接译码器,n条线可以对应2的n次方个选片信号
主存容量扩展–字扩展
- 注意,图中的A0-A12应该是分别连接到存储芯片的,这里是为了不让图片太乱,连接了起来
- 有小圆的一端表示低电平有效
- 两根多余的地址线A13 A14可以对应4个存储芯片,且地址A0-A13可以充分利用,合法地址都是连续的
- 也可以将A13-A15连接成3-8译码器,对应8个存储芯片
考试出题可能会这样考
- A13和A15连接译码器,A14随便
- 图中的第一个存储芯片给的四行地址意思是(容易迷惑人,不是只代表四行),A13-A15片选线部分为000时,地址部分A0-A12可以取全0到全1,A13-A15部分为010时,地址部分A0-A12可以取全0到全1;其他几个芯片同理
- A14的随意浪费了很多合法地址,实际应用是不会这样的
字扩展-线选法和译码器片选法 主存容量扩展–字位同时扩展
- 将二者集合起来
- 每两个芯片对应同一个片选线,实现位扩展,4位扩展成8位
- 2-4译码器可以对应4个这样的分组
- 因此最终实现的效果就是416K8位即64*8位
- 并且合法地址连续,没有浪费
知识点小结 补充–译码器
- 译码器可以分高电平有效和低电平有效
- 实际的译码器,还有一个(或多个)使能端,可以使译码器能够工作
- 使能端也分高电平有效低电平有效
- 只有使能信号有效时,译码器才能工作
使能端作用
- CPU可以通过使能端控制片选信号的生效时间
- CPU需要访问主存的时候,还会使用主存储器请求信号MERQ,这里有横线说明是低电平有效
- CPU先送出地址信号,刚开始输出电信号不稳定,需要等一段时间电流稳定了,在发出主存请求信号
- 使能端让译码器可以工作,地址选通线才能输出信号
- 确保一个芯片被选中时,传过来的地址信号一定是有效的
双端口RAM和多模块存储器
- 存取周期
- DRAM的存取周期包含存取时间和恢复时间,且恢复时间比较长,恢复期间整个存储体都不能再存取
解决方案
- 如果是多核CPU访问一个内存,可以用双端口RAM方式解决
- 也可以使用多模块存储器的方式解决,适用于多个内存
双端口RAM
- 优化多核CPU访问一个内存的速度
- 需要有完全独立的两组数据线,地址线,控制线,主板的总线设计更复杂
多体并行存储器
- CPU读取内存需要等待恢复时间,为了解决问题,这我们使用了四个存储体,理解为四个一样的内存
- 两种编址方案,高位交叉编制和低位交叉编制,分别用内存地址的高两位和低两位来区分不同的存储体
- 假设每个存储体有8个存储单元
- 如果采用高位交叉编制,则高位确定了体号后,存储体内的地址是连续的,相当于图中的纵向编址
- 如果采用低位交叉编址,则低位固定了体号后,一段连续的内存地址其实是在四个存储体中轮流出现的,相当于图中的横向编址
- 如果访问一端连续的内存空间,采用高位交叉编址方式,其实基本上还是在访问同一个存储体,还是要等待恢复时间结束才能继续访问
- 如果访问一端连续的内存空间,采用低位交叉编制方式,CPU其实一直在切换着访问各个存储体,无需等待某一个存储体的恢复时间
- 如果合理的调整存储体的数量,可以做到CPU轮流读取内存时,刚好不会受到恢复时间的影响
- 宏观上读取一个字的时间接近r,指n趋向于无穷大时,
- 为什么探讨连续访问的情况,实际情况中,很多数据就是存放在连续的空间中
应该准备几个存储体
- m=T/r时,刚好可以做到读完一轮内存后,重新读取第一内存的时候,第一个内存恢复时间完毕,实现无缝衔接
- 存储体过多也会导致劳动力过剩,最好方案就是刚好m=T/r,效率最高,成本也有控制
- 对于存取周期和存取时间,图中有两种描述,计算都是一样的
- 给定地址x如何判断他是哪个存储体?看末尾的体号,或者对m取余
多模块存储器
- 上面的例子是多体并行存储器,每个存储体可以独立工作
- 还有一种方案是单体多字存储器,相当于将几个存储体合并,共用一套控制电路,地址寄存器,数据寄存器
- 每次读取一整行的数据,即4个字,相应的,数据总线宽度也改为m个字
- 单体的灵活性不如多体的灵活性高,而且有时候会读取一些不需要的信息
- 总体上看读取速度都差不多,单体的,读取一行周期为T,T/4=r,还是相当于读一个字需要存取时间为r
知识点小结 双通道内存
- 其实就是对插入的两个内存条采用低位交叉编址,组成的二体并行存储器,大幅提升内存的访问速度
- 两个相同的内存条插到颜色相同的卡槽里,才能实现低位交叉,插颜色不同的实现的是高位交叉
- 如,选16G的不如选两个8G的组成双通道
- 为什么推荐两个内存要相同主频相同容量,如果两个内存主频内存不一样,主频高的就会降频,浪费资源
- 相同容量的原因,容量小的与容量大的其中一部分组成低位交叉(低地址取余),容量大的内存多出来的一部分,还是相当于单通道,可能出现程序运行速度不稳定的情况,数据加载到低地址时运行块,加载到高地址值运行慢
Cache 基本原理,基本概念
本章的重中之重,大题小题的高频考点
存储系统存在的问题 Cache的工作原理
- 内存保存了一部分程序和数据,其实同一时间被CPU读取的也只是一部分
- 如果能把这一部分正在使用或者即将使用的数据复制到读写速度更高速的Cache中,CPU直接读取的速度会更快
- 实际上Cache就是被集成在CPU内部,使用SRAM实现,因此成本高,集成度比较低,存储空间也不大,几兆十几兆
- 如何知道在某一段时间内,CPU访问哪一些数据,利用程序的局部性原理
局部性原理
- 程序的指令和数据都存放在内存中
- C语言的二维数组的数据,其实是按行展开在内存中顺序存放的
- 空间局部性,时间局部性(比如循环结构)
- 说明目前访问的地址周围的信息很有可能再次被访问
- 由此可知,遍历一个二维数组,按行优先遍历的效率比按列遍历的效率高,因为按行遍历会有更多的临近数据被保存到Cache中,按列遍历单个元素的存放地址跨度更大
性能分析
- 访问Cache所需时间,访问主存所需时间,命中率,缺失率,平均访问时间
- 做题要认真审题,有两种访问方法,第一种先找Cache,找不到再找主存;第二种,两个同时找,即使没命中,最多也是耗时访问一次主存的时间
练习题 如何界定CPU目前访问地址周围的大小
- 将主存分块,比如1KB一块,
- 可以查出当前访问的内存地址从属于哪个分块,把整个分块存到Cache中
- Cache与主存以块为单位进行数据交换
- Cache中也会以块为单位将空间分成一块一块
- 假设主存按字节编址,则从逻辑上,我们可以把主存地址的一部位用来表示块的编号,剩余部分位可以用来表示块内地址
- 注意块的各种叫法,我们还是习惯统一叫法,不论在Cache还是主存都叫做块
待解决问题 知识点小结
Cache和主存的映射方式
三种映射方式
- 全相联映射,直接映射,组相联映射
- 给每个Cache块增加个标记,记录保存的是来自哪个主存的块
- 再加一个有效位,1表示Cache内存块有效,0表示无效,因为没有使用的Cache内存块的标记都是初始值为0,无法确定究竟是为空,还是来自主存0号块
- 因此,对于Cache来说,只有当有效为1,标记与主存的块号匹配,才算访问Cache的块命中
- 这些操作直接用硬件电路实现
全相联映射–随意放
- 根据块的大小(行长)可以求出Cache的块数,主存的块数
- 对主存地址位数分成用于确定块号和块内存地址的两个部分
- 主存与Cache交换数据以块为单位
全相联映射具体实现
- Cache有效位初始为0,标记初始为全0
- 将主存某一个块随机存放在Cache中,有效为变为1,标记记录主存的块号
- 已知主存地址访存?先看Cache是否有命中,有则直接访问Cache,没有则访问主存
- 先根据这个主存地址得到块号(这里是前22位),和Cache的所有标记对比,发现有匹配且有效位是1,说明Cache命中
- 说明要访问的数据就在这个Cache块内,直接访问这个根据块内地址找到具体数据
- 如果标记没有匹配,或者有效位是0,则没有命中,直接访问主存即可
直接映射–只能放固定位置
- 每个主存块只能放在固定位置,新的主存块很容易把旧的覆盖掉,即使有空余Cache块
- 灵活性较差,空间利用不好
- 总结规律发现,主存块号对8取余,其实就是主存块号的后三位决定了放在哪个Cache块上
- 比如某个主存块放在Cache的0号块上,就代表主存块号内后三位一定是000,因此Cache的标记无需包含主存块号的后三位
直接映射具体实现
- 已知主存地址,通过主存块号中的3位行号,确定了他对应Cache中哪一行
- 然后对比主存地址中的19位标记与对应的Cache行中的标记是否一致,如果一致,且有效位是1,则Cache命中,直接访问Cache行中6位块内地址即可
- 若不命中,则直接访问主存地址
组相联映射–可放到特定分组
- 假定二路组相联映射,即2块为一组,这里分了四组
- 和上面类似,8行分了四组,其实就是主存块号后两位决定了放在哪个Cache分组,放在分组里时哪有空位放哪里
- 因此标记只需要20位即可,
组相联映射具体实现
- 已知主存地址,根据2位组号找到对应Cache分组,用主存地址中的标记与这个Cache的对应分组的所有行比对
- 如果这个Cache组中有某一行的标记与主存地址中的标记相同,且有效位为1,则命中,直接访问Cache行中的6位块内地址即可
- 若不命中,直接访问主存地址
知识点小结
Cache替换算法
哪种映射需要替换算法
- 直接映射方式每个主存块是固定对应Cache行的,直接覆盖即可,所以不需要替换算法
- 全相联映射当Cache行满了以后,新的保存需要替换算法选择具体替换哪一行
- 组相联映射一个分组内有多个行,当主存对应的Cache分组里满了以后,需要替换算法决定具体替换Cache分组内的哪一行
Cache替换算法
- 这里以全相联映射为例,介绍四种替换算法,
- 四种替换算法需要明确名称及英文缩写
随机替换算法 先进先出算法(FIFO)
- 如图所示,呈现阶梯状替换即可
- 理解抖动现象
近期最少使用算法(LRU)
- 如果是做题,我们可以使用手算方法实现,如图所示
- 访问1234,不命中,加入Cache
- 访问12,命中
- 访问5,不命中,准备替换,5的前面是214,因此我们可以判断是近期最少使用的,替换3
- 访问12,命中
- 访问3,不命中,3的前面是215,因此4是近期最少使用,替换4
硬件实现
- 硬件实现的过程步骤比较多,需要看原视频理解,考试时能手算解题即可
- 第二个图,命中1时,1的计数为2,则2清零,比2大的3不用+1,为什么?因为比2小的是1,1+1=2,还是小于3,所以3没必要+1,我们的目的是找出计数器最大的,没必要无谓的+1
- 这么做的好处是,对于4行Cache,计数器不会超过3,可以尽量减低计数器的位数,节省成本
- Cache块的总数为2的n次方时,只需要n位计数器就够用
- 优点:实际运行效果优秀,命中率高
- 缺点:若频繁访问的主存块数量大于Cache行数,还是有可能发生抖动
最不经常使用算法(LFU)
- 计数器用来记录每行Cache行被访问了几次,Cache满了以后,替换计数器最小的Cache行
- 问题,如果有多个行最小时,选哪个?
- 可以按行号递增的优先级,比如优先选择行号小的替换
- 可以按FIFO策略选择,先进先出,优先替换先进来的,图中就是看哪一行的最近的红色数字更靠左侧一些
- 缺点:可能导致计数器数值很大,有可能记录整个全局的访问次数;曾经被经常访问的主存块,在未来不一定经常用,还占着坑位
- 实际运行效果不如LRU
知识点小结
- LRU替换算法最合理,适合实际使用,命中率高,也是常考点,做题会手算求即可
Cache写策略
写命中–写回法
- 要写的数据已经在Cache中命中了
- 给Cache增加脏位信息,表示是否被修改过,如果被修改过,Cache被替换时需要把信息写回主存
- 根据标记位判断写回到主存的什么位置
- 存在数据不一致的隐患,因为CPU写如Cache与Cache写回主存有时间差
写命中–全写法
- CPU写入操作同时作用在Cache和主存上
- 导致CPU访存次数增加,速度变慢,但更能保证数据一致性
- 加入写缓冲,提高访存速度,写缓冲采用SRAM,提高写入速度
- 写缓冲可以是一个队列,在专门的控制电路下逐一写回主存中
- 如果写操作很频繁,容易是写缓冲饱和,CPU会发生阻塞,等待
写不命中–写分配法
- CPU需要写的地址没有被Cache命中
- 先把主存对应的地址调入Cache行,再对Cache执行写操作
- 后续可以搭配写命中–写回法,当Cache行被替换时,才会同步回主存
写不命中–非写分配法
- CPU直接往主存里写入
- 通常搭配全写法使用,即写命中时CPU就同时两边写,写不命中时就只写主存
多级Cache
- CPU与一级缓存之间有写缓冲
- 缓存之间用全写法+非写分配法,因为Cache的写入速度较快,并且可以保证数据一致性
- 缓存与主存之间用写回法+写分配法,因为这样可以减少因为访问主存而耽误的时间
- 可以进入任务管理器-性能,查看缓存情况
知识点小结
页式存储器
虚拟存储在计组和操作系统中都有讲解,也是容易出综合考点的地方
页式存储器
- 辅存中的应用程序比较大,不会全部加载到主存中,而且加载的这一部分也不一定在主存的连续地址上
- 辅存的程序是被分成一个个的页,每个页的大小和主存的物理块大小相同
- 每个页面可以离散的放入主存中,
- 辅存对应用程序的分页是逻辑层面的划分,主存块的划分是物理层面的划分,但二者的大小相同
虚地址和实地址
- 程序员视角看到的地址是逻辑地址(虚地址),实际上在主存中的真实地址是物理地址(实地址)
- 给程序分页是操作系统完成的
- 程序员看到的逻辑地址可以划分两部分,逻辑页号,页内地址
- 主存中的实地址也可以划分两部分内,主存块号,块内地址
- 程序员使用逻辑地址后,操作系统将其映射为物理地址,这个过程其实就是将逻辑地址的逻辑页号,换成了主存块号
- 页与块是大小相同的,因此页内地址与块内地址可以完全一致
页表–逻辑页号到主存块号
- 为了实现逻辑页号到主存块号的映射,主存里保存了页表数据
- 页表是操作系统中非常重要的数据结构
- 页表中的一行成为一个页表项,一个页表项包含了一对映射关系,大小固定
- CPU执行机器指令时,需要用逻辑地址查询页表转为物理地址,才能找到真实地址
地址变换过程
- CPU还有页表基址寄存器,指明了页表在主存中的地址
- 找到了页表基址,就可以根据页号找到具体某一个页表项的主存地址,因为页表项大小相同,页号按顺序递增,(类似于数组和的随机访问)
- CPU根据逻辑地址,页表基地址查出对应的物理地址,然后访存,
- 访存不论读写都先看是否能被Cache命中,如果能被命中,则访问Cache,不命中再直接访问主存
- 根据局部性原理,被访问过的页表项可能会再次被访问,如果频繁访问注册也会影响速度
- 可以将近期访问的页表项存入更高速的存储器,提高地址变换的速度
地址变换过程(增加TLB)
- 引入快表,可以更快速的查询页表项,相对的内存保存的页表也称为慢表
- CPU在得到逻辑地址和页表基地址后,首先查询快表,如果命中则直接映射出物理地址,没有命中则到主存中查慢表,映射出物理地址,然后将页表项保存到快表中
- 快表的查询速度很快,采用了SRAM,电路设计上是相联存储器,可以按内容寻访;因此快表的成本高,设计复杂,容量比较小,只能保存页表的部分信息
- 因此快表也容易存满,如果存满也需要进行替换,可以结合前面的Cache块的替换理解
- 快表和Cache的区别:
- Cache存储的是某一主存块数据的某一部分,大小可能会比较大,作用是明确了物理地址后,可以对物理地址的访问更快
- 快表存储的是慢表的某一些页表项,一般都比较小,作用是加快了逻辑地址到物理地址的映射
知识点小结
虚拟存储器
虚拟存储器的知识重点在操作系统课里学习,这里只做简要了解
虚拟存储系统
- 辅存中的应用程序很大,主存比较小,没有必要把应用程序所有文件全部加载到主存
- 只需要把应用程序的一部分调入主存即可使用,这样系统也可以支持很多应用程序同时使用
- Loading比较慢就是辅存读取速度比较慢
页式虚拟存储器
- 可以将辅存的程序数据也分页,把当前用的某些页放到主存相应的位置
- 上一节的页表只是完成了逻辑页号到主存块号的映射
- 对页表进行改造,外存块号表示这一页对应外存位置;有效位是1表示这一页已经被调入主存,0表示没有;访问位用于实现页面替换算法,当主存没有空位置,需要替换页面时,使用页面替换算法对主存中的页面进行替换,具体采用什么算法看具体情况;脏位与Cache的脏位类似,当主存中某一块发生更改,也要将脏位标记为1,当这主存的这一块被淘汰时,要把更新的数据写回外存中
- 与主存对Cache的页面管理在原理上都是相通的
页式虚拟存储器
- CPU接收的是逻辑地址,里面包含逻辑页号,逻辑页号也叫虚页号,CPU根据虚页号查到页表项,判断当前页在主存还是外存,如果不在主存,就把外存的页调入主存,以及后续可能的页面替换
- 如何把外存数据调入主存,有操作系统完成;
存储器的层次化结构 段式虚拟存储器
- 程序可以拆分为页,每个页长度相同;也可把程序按功能模块拆分成段,操作系统以段为单位决定把那些段调入主存,每个段长度不一样
- 如果采用段式虚拟存储器时,主存不会再分块
- 类似于页,段式存储器也有段表基地址,段表,段表里有段号,段首地址,段长,CPU收到的虚拟地址可以拆分为段号+段内地址
- 具体细节在操作系统里学习
段页式虚拟存储器
- 具体细节看操作系统课程
第四章 指令系统
机器指令中包含操作码和地址码,操作码指明做什么,地址码指明对谁操作,有的指令不需要地址码
指令格式
指令的定义 指令格式 零地址指令 一地址指令 二三地址指令 四地址指令 按地址码数目分类 按指令长度分类 按操作码长度分类 按操作类型分类
- 转移操作,改变程序的执行流,本质上就是改变PC的值
知识点小结
扩展操作码指令格式
扩展操作码
- 操作码不能取全1,因为操作码取全1的情况,留着作为下一级操作码的前缀,扩展用
- CPU一次读取全部指令,然后判断开头的全1情况,判断这是几地址指令
- 图中给出的是一种扩展操作码的方法,基于操作码分别为4,8,12,16位时的情况,
- 分别对应了零地址指令有16条,一地址指令15条,二地址指令15条,三地址指令15条
设计扩展操作码注意要点 扩展操作码的另一种方式
- 究竟采用哪种方式,主要还是看实际需要
- 类似于IP地址类型的划分,指令长度是固定的,地址位数高的指令占比大,给操作码留下的余地就少,所能设计的操作码的总数就会减小
- 举例,62条一地址指令
- 从右向左,4位作为一地址,62条可以用000000-111101,因此紧挨着地址位,再往左边分出6位作为指令的范围
- 剩下的,也就是前面的为全1,作为前缀,这样CPU才能根据前缀的位数判断这是几地址指令
- 图中的c行给的迷惑人了,他是按照划分四个部分,给出取值范围,如果按照前缀,操作码,地址的方式拆分,取值范围还是上面这一条的范围000000-111101;他给的A1A2的第一行是他这种划分的取值的合法范围(就是把全1排除了),下一行给的是他这种划分情况下的操作码的取值范围
- CPU读取16位指令,首先看前四位是不是全1,如果不是说明是三地址指令;如果是全1,在看下两位,如果不是全1,说明是二地址指令,如果是全1,说明不是二地址指令;在看下五位,如果不是全1,说明是一地址指令,如果不是,说不是一地址指令;前面都不是,那就是一定是零地址指令
考试可能出相关计算的题
- 记住做题规律,
- 具体的原理,在笔记里不太好描述,动笔算就能知道,大概意思是
- 比如,三地址指令如果采用4位,那么有16种状态,但不能全用,至少留下1111作为前缀,要不然就和下一级的指令混淆了
- 所以采用剩下的数量乘以2的n次方,至少是1,如果是0,后面就没法编码了
- 如果剩余的多,三地址指令的编码位在整个指令的高位部分,因此用剩余的状态数做乘法
- 本例中,地址长度是4,因此也就是m乘以2的4次方
指令操作码小结
指令寻址
回顾计算机工作过程
- 正常情况下,程序计数器PC会在CPU执行一条指令时自动+1,指向下一条指令地址,CPU执行完当前指令后根据PC的指引,执行下一条指令
指令寻址
- 实际上指令寻址不是简单的PC+1,但确定的是PC始终指向下一条要执行的指令的地址
- 指令在主存中顺序存放
- 指令字长,主存按什么进行编制,会影响PC每次加多少
- 图中的操作码用汇编语言表示的,方便阅读,这两个图是定长指令字结构的情况
变长指令字结构
- 不同的指令字长度不同,所以PC应该根据不同的指令字长加不同的数值
- CPU一开始不知道指令字长,PC也无法指向下一条指令位置
- 首先CPU先读取一个字,根据操作码判断这条指令的总字节数,再修改PC的值
- 当CPU执行完指令后,再根据PC的指向执行下一条指令
顺序寻址
- 以上两种情况,不论PC加几,都是对指令进行顺序执行的,只不过每次PC加的数值不同,我们可以他们统一归为都是+1
- 后面的PC+1是双引号的+1,指一个指令字长,注意理解
跳跃寻址
- 转移类的指令会改变CPU的执行流,CPU会根据转移的位置修改PC
- 这里用定长指令字结构举例
- 比如当CPU执行完上一条指令后,PC还是会+1,但是CPU当前执行的指令是无条件转移指令
- 这条指令指明了下一条指令跳跃到哪里,CPU就是重新把PC的值修改为新的值,JMP这条指令改变了程序的执行流
- 然后CPU执行完当前指令后,再根据PC的指向执行下一条指令
知识点小结
数据寻址(上)
数据寻址
- 数据寻址的目的是为了,解读本条指令中的地址码指明的真实地址
- 因为不同的指令方式,可能会对这条地址码解读成不同的真实地址
知识总览
- 为了区分地址码的解读方式,在地址码的前面加上几个比特位用来标识寻址方式,指令=操作码+寻址特征+形式地址
- 如果是多个地址的指令,则每个地址前面都有一个寻址特征
- 这里以一地址指令为例
直接寻址
- 取指令访存1次,执行指令时读操作数地址访存1次,结果写入ACC(不算访存)
- 缺点:地址位长度优先,所能表示的寻址范围有限,如果操作数的地址发生改变,除非修改指令中的地址位,灵活性差
间接寻址
- 有点类似C语言的指针,一次间接寻址对应一级指针,两次间接寻址对应二级指针
- 一次间接寻址:取指令1次访存,执行指令访存2次,一共3次
- 两次间接寻址:取指令1次访存,执行指令访存3次,一共4次
- 扩大了寻址范围,比如,指令的地址位由16位,主存中存放真实地址的数据的位数是32位
- 便于编制程序的含义,类似于函数调用,当内层函数调用完成返回到外层函数的执行位置(这一点简要了解)
- 缺点,增加了访存次数,指令的执行效率降低
寄存器寻址
- 指令中的地址码指向了某一寄存器的编号,CPU有很多寄存器,每个寄存器有自己的编号
- 执行指令时无需访存,直接访问寄存器
- CPU中的寄存器不多,编号可以比较短,指令字可以更短,执行速度更快,支持向量/矩阵运算(这一点了解)
- 缺点:寄存器成本高,个数有限,导致寻址能力有限
寄存器间接寻址(开始套娃)
- 指令中给出的地址位保存的是寄存器的编号,对应的寄存器上保存的是主存地址,主存地址指向的才是真实操作数
- 比一般寻址速度更快
隐含寻址
- 图中所示,A给出的只是其中的一个操作数的地址,另一个操作隐含在ACC中
立即寻址
- 形式地址本身就是操作数的值本身,通常用补码,汇编语言中这种寻址方式用#表示
- 执行速度最快
- 形式地址的位数限制了他所能表示的立即数的范围
知识点小结
数据寻址(中)
剩下三种寻址方式都可以归为偏移寻址 偏移寻址
- 由于偏移起点不一样,这三种偏移寻址的应用面也不一样
基址寻址
- 需要注意的是,经常使用英文缩写表示这是一个什么寄存器,有些寄存器有特定的作用,我们应该对这些英文缩写熟悉,有助于记忆
- 这里的BR就是专门的基址寄存器,有些计算机也是用通用寄存器保存偏移量
- 如果是使用通用寄存器存放基址,还需要在指令中指明是将哪个通用寄存器作为基址寄存器使用(这里是R0)
- 根据通用寄存器的个数,确定用几个比特位表示通用寄存器
基址寻址的作用
- 如果指令在主存中的保存位置是0开始存放,那么可以用指令中保存的地址码进行直接寻址
- 实际中有很多程度,第一条指令不一定是从地址0开始的,
- 这时候需要基址寄存器保存整个指令的起始地址,用形式地址+基址地址,结果才是最终要访问的真实地址
- 当这段程序在主存中的位置发生浮动,操作系统只需要改变基址寄存器中的程序起始地址即可
基址寻址需要注意
- 基址寄存器BR面向操作系统,只能有操作系统或操作系统的管理程序确定,程序员决定不了
- 程序员可以用汇编语言读写通用寄存器的内容,如果这个通用寄存器被指定为基址寄存器,那么程序员也不能再修改,而是由操作系统管理
- 采用基址寻址也可以扩大寻址范围,因为基址寄存器的位数大于形式地址的位数
变址寻址
- 使用变址寄存器IX(专用)
- 有的计算机也使用通用寄存器作为变址寄存器
- 变址寄存器面向用户,程序员可以改变变址寄存器的内容,
- 从另一个角度理解,形式地址可以作为基地址,变址寄存器存放偏移量,这一点刚好和基址寻址相反,
- 个人理解,都是找偏移量,就是看基于什么作为参考点,基址寻址是基于指令的起点作为基准点,变址寻址是基于程序内部的某个位置作为相对基准点
变址寻址的作用
- 如果执行循环操作,循环次数很多,就会导致指令数量非常多,这显然不合适
- 为了解决问题,引入跳转指令,和变址寻址
- 相当于IX记录了循环执行的次数(i++),通过条件跳转判断是否跳转
- 由于数组里的元素地址是递增的,将第一个元素的地址结合IX记录的次数,可以得到下一轮循环对应的操作数的位置
- 这样相当于形式地址是首地址,不断地循环,导致IX不断的变化,IX就成为了偏移量,便于知道到数组中的任意数据地址
- 所以才说变址寻址面向用户,因为执行指令过程中,程序可能会根据需要不断地改变IX中存放的偏移量
变址寻址 基址&变址 复合寻址(套娃)
- 如果这段循环的程序在内存不是从地址0开始
- 那么根据相对地址,既要加上基址寄存器保存的程序起始地址,又要加上循环时访问数组元素对应的偏移量
- 在基址寻址的基础上加上变址寻址,实际应用往往是复合使用的
相对寻址
- 把形式地址作看做PC所指向位置的偏移量
- CPU从PC取出一条指令后,PC将会+“1”,指向下一条指令,这里的相对地址可正可负,补码表示
- 王道书上的表述有错误,正确的为,A是相对于下一条指令地址的偏移量
相对寻址的作用
- 一段程序,程序员可能会挪动某一段代码的位置,这时候直接寻址就会出现错误
- 引入相对寻址,这段代码的挪动会对应指令中的相对地址A的变化,重新修正PC所指的位置
- 个人理解,需要区分的地方是,变址寻址中IX保存的偏移量不断变化,方便找到不断变化的数组元素;相对寻址中A保存的是这一段代码移动导致的偏移,方便对PC的指向进行修正
- 那么问题来了,代码移动之后,数组元素的位置也变化了,如果每次挪动都要修改指令中的数组元素地址参数,这样很麻烦
- 解决办法,采用分段处理,分成程序段和数据段,程序段保存程序代码,数据段保存数据,所以不管代码怎么移动,数据段的位置是不会变化的,段内的相对位置也不会变,无需因为代码的挪动在修正数组元素的位置
- 个人疑问?后面这种情况属于基址寻址+变址寻址+相对寻址的方式么?
相对寻址小结
- 基址寻址所说的便于程序浮动是整段程序在内存里的浮动,相对寻址的便于程序浮动是一段代码在程序内的浮动
知识点小结 补充,硬件如何实现数的比较
- 汇编语言中,条件跳转指令有很多种,注意区分
数据寻址(下)
堆栈寻址
- 操作数存放在堆栈中,隐含的使用堆栈指针(SP寄存器)作为操作数地址
- 堆栈寻址的操作数地址隐含的存放在SP寄存器中
- 存放操作数的堆栈可以使用专门的一组寄存器,每个寄存器存放一个元素,也可以是主存中的一块特定区域
- SP首先指向栈顶,每弹出一个元素,SP+1;加法得到结果,需要压栈,先将SP-1,在将结果压入SP所指向的位置
- 这里的POP和PUSH就是使用了堆栈寻址,且这个地址隐含在了SP中
- 实际出题,可能会规定栈顶方向的地址更大,需要灵活调整
- 图中给出的堆栈是用一组专用寄存器,这个堆栈称为硬堆栈
软堆栈
- 从主存中划分出一片区域作为堆栈
- 意味着栈的弹出和压入都需要访存
- 硬堆栈速度快,成本高,软堆栈速度略慢,成本低,实际中更多使用的软堆栈
知识点小结
- 需要注意的是,出栈时,操作数的真实地址EA就在SP中,入栈时,首先SP+1,然后在将操作数保存到SP指向的地址中
- SP的加减是由硬件完成的,所以也可以说堆栈寻址时,有效地址就是SP指向的
- 执行指令期间,硬堆栈不需要访存,软堆栈需要访存1次
- 这些寻址方式是第四章的高频考点,需要好好消化,结合课后习题熟悉出题方式
CISC和RISC
CISC和RISC
- CISC是复杂指令集的计算机系统,RISC是精简指令集的计算机系统
- CISC可以理解为C语言提供了基本语法,还提供了许多功能的库函数,因此对应的电路比较复杂
- RISC可以理解为C语言只提供基本语法,复杂功能靠自己定义函数,因此电路比较简单
- 然而实际上很多复杂指令使用频率不高,而复杂指令导致电路设计比较复杂,其实用简单指令也可以实现
- RISC指令更加简单,因此各条指令执行时间接近,适合实现并行技术和流水线技术
CISC和RISC对比
- RISC的指令集简单,灵活度大,我们可以优化编译程序,生成代码更高效,就像C语言提供的基本语句,我们自己写出经过优化,执行效率更好的函数
- CISC好比使用了C语言提供的库函数,优化代码很难
- 控制方式,组合逻辑控制比微程序控制效率更高,细节见第五章
- RISC的指令简单,执行时间都差不多,更容易实现指令流水线,实现指令流水线后CPU执行效率会更高
引用之前的例子
- 图中的指令一定CISC指令系统的,因为执行指令期间可以轻松访问主存进行取数操作,指令访存基本没有限制
- 如果是RISC指令系统只能是Load/Store实现访存功能
- 因此RISC指令系统需要更多的寄存器,先把操作数读入到寄存器,在用通过指令从寄存器取数