指令系统
指令格式
- CPU控制器的主要功能之一:解析指令,协调各部件工作
- 一台计算机所有指令的集合称为该计算机的指令系统,也称指令集
- 例如:x86、arm、mips
- 一条指令通常包括两个部分
- 操作码:要做什么
- 地址码:要对谁操作
- 依照地址码数目分类
- 零地址指令
- 不需要操作数的情况:如nop(空指令)、hlt(停机)等
- $ OP $
- 与栈配合使用,数据已预先压在栈顶:如syscall(系统调用)
- 不需要操作数的情况:如nop(空指令)、hlt(停机)等
- 单地址指令
- 只需要一个操作数:加1、减1、取反等
- $ OP(x) \rightarrow x $
- x:数据的地址,(x):地址中的内容(间接访问)
- 三次访存:读OP、读x、写x
- 需要两个操作数,另一个操作数在栈上/寄存器中
- 假设隐含在ACC中
- $ (ACC)OP(x) \rightarrow ACC $
- 数据压回栈/写回寄存器
- 两次访存:读OP、读x,ACC是寄存器不算访存
- 只需要一个操作数:加1、减1、取反等
- 二地址指令
- 需要两个操作数,常用于逻辑运算、算术运算等
- $ (A1)OP(A2) \rightarrow A1 $
- 数据写回A1地址指向的区域
- 四次访存:读OP、读A1、读A2、写A1
- 三地址指令
- 需要三个操作数,常用于逻辑运算、算术运算
- $ (A1)OP(A2) \rightarrow A3 $
- 数据写回新地址A3
- 四次访存:读OP、读A1、读A2、写A3
- 四地址指令
- 与三地址指令不同点在于,新增加了一个“下一条指令的地址“操作数
- $ (A1)OP(A2) \rightarrow A3, A4 $
- …… 以此类推
- 零地址指令
- 按长度分类
- 指令字长
- 整个指令的长度可以发生变化
- 定长指令字结构
- 变长指令字结构
- 和操作码长度、操作数长度、操作数个数都有关
- 整个指令的长度可以发生变化
- 操作码长
- 操作码本身的长度可以发生变化
- 定长操作码
- 操作码n位,最多$ 2^n $种
- 译码器设计简单,灵活性低
- 可变长操作码
- 译码器设计复杂,灵活性高
- 定长操作码
- 操作码本身的长度可以发生变化
- 机器字长
- 进行一次整数运算时所能处理的二进制位数
- 即ALU位数
- 存储字长
- 主存一个存储单元的二进制位数
- 即MDR位数
- 指令字长
- 按操作类型分类
- 数据传送类
- 内存到寄存器
- 寄存器到内存
- 运算类
- 算术逻辑操作
- 移位操作
- 程序控制类:转移/跳转操作
- 实现程序执行流程的变化
- 使PC寄存器值发生改变
- 输入输出类
- 数据传送类
扩展操作码
- 是一种固定指令字长、可变操作码长的指令结构
- 以指令固定长为16位,零、一、二、三地址指令均15个为例
- 给指令位分段
- $ 15=2^4-1 $,零地址指令至少需要4个二进制位
- $ 16-15=1 $,这一个4位编码可用于表示“扩展”——指令码长于4位
- 构造指令编码
- 前缀0000~1110为三地址操作码
- 前缀1111留作扩展位,表示此时操作码大于4位
- 前缀1111 0000~1111 1110为二地址操作码
- 前缀1111 1111留作扩展位,表示此时操作码大于8位
- 前缀1111 1111 0000~1111 1111 1110为一地址操作码
- 前缀1111 1111 1111保留
- 1111 1111 1111 0000~1111 1111 1111 1110为零地址操作码
- 1111 1111 1111 1111未用
- 给指令位分段
- 习题例子
- 设计时的要求(类比计算机网络 哈夫曼编码)
- 不允许短码是长码的前缀
- 不允许操作码重复
- 通常情况下:指令使用频率越高,码长越短
指令寻址
- 目的:确定下一条待执行指令的指令地址
- PC寄存器(程序计数寄存器)始终保存下一条指令的地址
- 顺序寻址:取指令操作完成后,PC寄存器值自动 + 当前指令字长
- 如果是变长指令字结构:操作码一定会在第一个存储单元(或者第一个字节/第一个能载入寄存器长度的二进制位)中
- CPU判断操作码需要几个操作数(即计算指令字长),以确定如何修改PC
- 跳跃寻址:由转移指令给出
数据寻址
- 目的:确定本条指令的地址码(操作数)指明的真实地址
- 怎么确定指令的地址码采用什么方式寻址
- 统一约定
- CPU预设
- 在地址码前加入描述寻址方式的位,例如地址0010,地址吗0001 0010(立即寻址0010)
- 形式地址(Address)
- 有效地址(Effective Address)
- 隐含寻址
- 立即寻址
- 直接寻址
- 间接寻址
- 寄存器寻址
- 寄存器间接寻址
- 相对寻址
- 基址寻址
- 变址寻址
- 堆栈寻址
存储系统
DRAM
- DRAM的刷新
- 多久刷新
- 2ms为一个周期
- 刷新多少
- 如何刷新
- 分散刷新
- 集中刷新
- 异步刷新:最常用
- 刷新特点
- 内存芯片自动操作 对CPU透明
- 类似读RAM 但不需选片
- 多久刷新
主存与CPU的连接
- 主存容量扩充
- 位扩展
- 增加同时存储的数据量
- 字扩展
- 增加能够存储的数据量
- 线选法
- 译码器片选法:内存地址连续
- 译码器的输出默认高电平有效,若配合低电平有效的片选信号需要使用两端带圈的线段连接(表示取非)
- 增加能够存储的数据量
- 字位扩展
- 位扩展
磁盘存储器
- 磁盘性能指标
- 磁盘容量
- 未格式化容量:物理上的 用于存储用途的 磁化单元总数
- 格式化容量:实际存储信息的总量,会去除掉坏块、备用块等等
- 格式化容量 < 未格式化容量
- 记录密度
- 道密度:半径
- 位密度:单位圆弧
- 面密度:道密度x位密度
- 越内侧的磁道位密度越大
- 平均存取时间:加和
- 寻道时间:机械臂移动
- 旋转延迟时间:盘片旋转
- 没有明确给出则按半圈计算
- 传输时间:磁头在盘片上,盘片继续旋转
- 数据传输率
- 磁道容量*转速
- 磁盘容量
- 磁盘地址
- 驱动器号
- 柱面/磁道号
- 盘面号
- 扇区号
- 工作过程
- 寻址
- 读盘
- 写盘
- 是独立的操作 有控制字
- 取控制字
- 执行控制字
- 读写串行 不同时进行
- 与主机连接需要串行-并行开关
- 磁盘阵列
- RAID 廉价冗余磁盘阵列
- RAID 0~6
- RAID 0:无冗余无校验磁盘阵列
- 相邻扇区依次存放至不同磁盘,提高速度(条带化)
- RAID 1:镜像磁盘阵列
- 同一个数据拷贝并放两个磁盘,浪费100%空间
- RAID 2:海明码磁盘阵列
- 数据和数据的海明码放两个磁盘,浪费75%空间
- 只能纠一位错
- RAID 5:无独立校验的奇偶校验磁盘阵列
- 空间浪费:1/N,N是磁盘数
- 用到了异或特性 不是奇偶校验码 最多一次只能坏一块盘
- RAID 0:无冗余无校验磁盘阵列
固态硬盘
- 基于闪存技术Flash Memory,也即E2PROM
- 主控:闪存翻译层
- 主机提供逻辑块号 闪存翻译层转换为物理块号
- 一个SSD硬盘包含多个闪存芯片
- 一个闪存芯片包含多个数据块
- 一般512K一块
- 因此属于“块设备”
- 一个块内包含多个数据页
- 一般0.5K~4K一页
- 读写特性
- 一次读一个块
- 无用数据会被丢弃
- 一次写一个页
- 一次擦除(删除)一个块
- 如果只需擦除块中的几页,需要先将其他页复制到其它块
- 直观现象:读快写慢
- 通过电路选页选块,速度极快
- 一次读一个块
- 相比机械硬盘来说
- 电路代替盘片旋转和磁头移动,速度大幅提升
- 体积小,安静无噪音,抗震
- 价格高
- 擦除次数过多会磨损 导致损坏
- 引入磨损均衡技术
- 将擦除尽量平均分布在各个块上
- 动态磨损均衡:写入时找擦除次数更少的块
- 静态磨损均衡:由主控自动监测处理,让老块多读、新块多写
- 引入磨损均衡技术
- 正常使用情境下,寿命很长,可以接受
Cache
- 内存速度无法匹配CPU速度,导致性能问题,如何解决?
- [[TODO]]
- 局部性原理
- 空间局部性:数据
- 数组
- 时间局部性:指令
- 循环
- 空间局部性:数据
- 如何让Cache代替部分RAM?或者说如何将RAM拷贝入Cache?:Cache-主存映射方式
- 全相联映射
- 自由存储
- 存储时保存完整的标记位,读取时依次检查各Cache块的标记位
- Cache利用率最高
- 读取时时间消耗最大
- 直接映射:完全不相联
- 存放位置与RAM中地址紧密相关
- 也记录标记,但标记位数最短
- 读取时间最短
- Cache利用率最低
- 全相联映射
虚拟存储器
- 由主存和辅存共同组成,统一编址
- 应用局部性原理,只有当辅存中的数据需要用到时才会调入内存
- 辅存和主存对编程人员来说边界更加模糊了
- 例如:打开文件时无需了解文件的哪些数据在主存哪些数据在辅存、地址各是多少
- 同样存在数据的替换问题和数据的一致性问题
- 处理一致性问题是只使用回写法:辅存速度太慢,全写法不现实
- 页式虚拟存储器
- 扩展的页表:逻辑页号,物理页号,辅存页号,有效位(是否已经调入主存),脏位(数据是否被修改且没回写),访问位(配合LRU算法等)
- 页 也可以称作 块
- 段式虚拟存储器
- 段 按照功能划分,不同段的大小可能不同
- 段表:需要段号、段的起始地址、段的长度、有效位、脏位等
- 段页式虚拟存储器
- 既有段表也有页表,先分段再在段内分页
- 一个程序一个段表,一个段一个页表
- 调入和替换等仍以页为单位
CPU访问内存的大体流程
- 程序提供数据的逻辑地址
- 逻辑页号
- 页内偏移(页内地址)
- CPU依据逻辑页号查找页表
- 先查找TLB,TLB命中则直接获得物理页号
- TLB未命中则访问DRAM中的页表查找,找到后将页表项(键值对)复制到TLB
- 拼接物理页号和页内偏移得到物理地址
- 访问物理地址指向的DRAM块
- 假设1:先找Cache再找DRAM方式
- 假设2:拥有L1和L2两级缓存
- 从Cache中找寻DRAM数据
- 在L1缓存中查找,若找到则继续
- L1缓存未命中,则在L2缓存中查找,若找到则继续
- 从DRAM中读取数据
- L1、L2 Cache均未命中,则读取DRAM中的数据,并将数据替换至L1缓存中
- 假设3:使用LRU算法作为Cache替换算法
- [[TODO]]