n3wFake3

计算机组成原理(02318) 第三章 指令系统

课程内容

  1. 指令格式设计
  2. 指令系统设计
  3. 指令系统实例
  4. 程序的机器级表示

考核知识点及考核要求

  1. 指令格式设计
  • 一地址指令格式, 二地址指令格式, 三地址指令格式
  • 一条指令需包含的基本信息,指令的基本格式及其设计原则, 指令中地址字段的个数
  1. 指令系统设计
  • 指令操作码, 指令的操作数, 寻址方式(立即, 直接, 间接, 寄存器, 寄存器间接, 变址, 相对, 基址), 传送指令, 逻辑运算指令, 算术运算指令, 移位指令, 条件转移指令(分支), 跳转指令, 调用指令, 返回指令, 程序计数器(指令指针), 累加器型指令系统, 栈型指令系统, 通用寄存器型指令系统, Load/Store型指令系统, RISC, CISC
  • 定长指令字指令格式, 变长指令字格式, 定长操作码指令格式, 扩展操作码指令格式, 指令执行顺序的控制, 有效地址的概念, CISC和RISC的区别及各自特点
  1. 指令系统实例
  • MIPS指令集体系结构中指令格式, 指令类型, 通用寄存器组织, 汇编表示等
  1. 程序的机器级表示
  • 汇编语言程序和机器语言程序之间的对应关系, 高级语言源程序和机器语言程序之间的对应关系

重点难点

  • 重点
    • 指令操作码, 指令的操作数, 寻址方式, 有效地址的概念, 指令格式的概念, CISC和RISC的区别以及各自特点, 汇编语言程序和机器语言之间对应关系, 高级语言源程序和机器语言程序之间对应关系
  • 难点
    • CISR和RISC的区别及各自特点, MIPS指令集体系结构的特点, 汇编语言程序和及其语言程序之间的对应关系, 高级语言源程序和机器语言程序对应关系

序言

  • 一台计算机能执行的机器指令的集合称为该机的 指令集或指令系统
    • 指令是构成程序的基本元素
  • 系统软件直接建立在硬件支持的指令基础上, 系统程序员感知到的是 指令集体系结构(ISA)
    • ISA设计的好坏直接决定计算机的性能和成本, 所以ISA的设计至关重要

3.1 指令格式设计

3.1.1 指令地址码的个数

  • 冯诺依曼结构计算机采用 存储程序 的工作方式, 根据该思想, 计算机程序一旦启动执行则必须能够自动地逐条从主存取出指令执行. 因此一条指令中需包含多条信息以便于控制单元(CPU)能够自动地读取指令
    • 操作码 : 指定操作类型, 移位,加减乘除,传送等
    • 源操作数或其地址 : 指出一个或多个源操作数(所在地址亦可, 可以是存储单元的地址, 寄存器编码或I/O端口, 也可在指令中直接给出一个立即数)
    • 结果的地址 : 结果所存放的地址, 可以是存储单元的地址/寄存器编码或I/O端口
    • 下条指令的地址 : 下调指令存放的存储单元的地址
    • 上述步骤中, 1-3步即可完成一条指令的自动执行, 第4步则可以周而复始地自动执行一条条指令.
  • 下条指令的地址可以不在指令中明显给出, 而是隐含程序计数器(PC) 中.
    • 指令按顺序执行时, 自动将PC的值加上指令的长度即可得到下一条指令的地址;
    • 当遇到转移指令而不按顺序执行时, 则需由指令给出转移到的目标地址
  • 一条指令由一个操作码和几个(源操作数地址/结果地址/下条指令地址)地址构成; 根据指令显式给出的地址个数, 可分为 :
    • 三地址指令 : 三个地址分别作为 双目运算中两个源操作数的地址和一个结果的地址
    • 二地址指令 : 两个地址分别存放双目运算中两个操作数, 并将其一地址作为结果的地址
    • 单地址指令 : 如果时单目运算(取反/取负等)指令, 则其地址既是操作数的地址也是结果的地址; 若是双目运算, 则另一个操作数和结果可默认存放在累加器
    • 零地址指令 : 可能本身无操作数, 也无需地址码, 一般是空操作指令, 停机指令

3.1.2 指令格式设计原则

  1. 指令应尽量短. 指令长度短, 使得程序占用存储空间小, 降低空间开销.
  2. 有足够的操作码位数. 向后兼容使指令操作类型不断增加, 因此必须预留足够的操作码位数
  3. 操作码的编码必须有唯一的解释. 操作码最终送到 指令译码器 进行译码, 所以指令操作码要么是一个唯一的合法编码要么是不合法的序列.
    • 译码器发现是不合法序列时会出现 非法指令 异常
  4. 指令长度应是字节的整倍数. 指令存放在内存中, 内存往往按字节编址, 因此指令长度为字节整数倍便于指令读取和指令地址计算
  5. 合理选择地址字段的个数. 地址字段个数涉及指令的长度和指令的规整性问题, 是 空间开销时间开销 权衡的结果
  6. 指令应尽量规整. 指令的规整性体现在很多方面(如下); 规整的指令系统可大大简化硬件的实现.
    1. 指令长度是否固定
    2. 操作码位数是否固定
    3. 地址码格式是否一致
    4. 指令字中各字段的划分位置是否一致

3.2 指令系统设计

指令系统设计是计算机系统结构设计的关键之一

  • 设计指令系统时, 指令的操作类型应尽量完备, 能够编制任何可计算程序
    • 但如果指令系统太复杂也会给硬件实现增加困难, 因此复杂的功能可通过 伪指令 实现.
  • 系统机设计时, 高档机的指令系统应兼容旧的低档机的指令系统(给软件资源重复利用带来方便)
  • 运算指令应能对多种类型的数据进行处理, 包括三种整数(字节, 字, 双字)和两种浮点数(单精度和双精度)类型
  • 操作码字段要预留一定的编码空间, 以便需要时进行扩充.

3.2.1 操作数类型

  • 操作数时指令处理的对象, 从高级语言程序所用的数据类型来看, 指令涉及的基本操作数类型包括
    1. 指针或地址. 指针或存储单元地址通常用 无符号整数 表示
    2. 数值数据. 数值数据主要是 带符号整数和浮点数. 有些指令系统液体哦那个十进制运算指令, 一般用NBCD码(8421码) 表示十进制数
      • 带符号整数用二进制补码表示
      • 浮点数大多用IEEE754标准表示
    3. 位/位串/字符/字符串.
      • 位和位串一般用于表示一些标志/控制和状态等信息
      • 字符和字符串数据用于表示文本/流式文件基本信息等
    4. 逻辑(布尔)数据. 表示逻辑值
      
    IA-32处理器提供的基本类型有:
        1. 字节,字(16位),双字(32位),四字(64位)
        2. 对于整数, 有16/32/64位三种补码表示的整数和18位压缩BCD码表示的十进制整数
        3. 对于序数(地址,指针等), 有字节,字或双字长的无符号整数
        4. 对于浮点数, 有用IEEE754表示的32位单精度,64位双精度和80位扩展精度三种
      
    

3.2.2 寻址方式

  • 指令要规定执行的操作还要给出操作数或其地址.
    • 操作数可能时一个常数/简单变量/数组/结构中的某个元素/栈(stack)的元素/外设IO接口的状态字/控制字等
  • 指令的角度来看, 操作数存放位置可以时CPU中的通用寄存器/存储单元和IO端口
  • 指令中给出的操作数所在存储单元的地址称为 有效地址(指令中,操作数所在的存储单元的地址)
  • 指令给出操作数或操作数地址的方式称为 寻址方式
    • 地址字段长度影响指令长度, 所以指令地址要尽量短但操作数存放位置又必须灵活存放空间也应尽量大.
  • 指令系统应能提供灵活的寻址方式并使用尽量短的地址码访问尽可能大的寻址空间; 为加快指令执行速度, 有效地址计算过程应尽量简单
  • 常用的寻址方式
    1. 立即寻址 : 指令中直接给出操作数本身, 该操作数称为 立即数

    2. 直接寻址 : 指令中给出的地址码是操作数的有效地址, 该地址称为 直接地址/绝对地址

    3. 间接寻址 : 指令中给出的地址码存放操作数有效地址的存储单元地址; 在以下图例中, @字符是间接寻址标志 间接寻址

    4. 寄存器直接寻址 : 指令中给出的是操作数所在寄存器编号, 操作数在寄存器中;

      • 寄存器数量远小于主存存储单元数, 所以寄存器编号比存储地址短,因为寄存器寻址方式的指令段
      • 采用该种寻址方式的操作数不用访存,因此执行速度快
    5. 寄存器间接寻址 : 指令中给出的地址码是一个寄存器编号, 该寄存器存放的是操作数的有效地址.

      • 寄存器间接寻址指令较短, 所以只需给出寄存器编号不必给出有效地址
      • 指令长度和寄存器寻址指令长度差不多, 但需要访存所以寄存器间接寻址指令执行时间比寄存器寻址指令的时间长
    6. 变址寻址 : 用于对线性表之类的数组元素进行方便访问.

      • 用变址寻址方式时, 指令中地址码字段A给出一个基准地址(比如数组的起始地址, 而数组元素相对于基准地址的偏移量在指令中明显或隐含地由变址寄存器I给出, 所以变址寄存器的内容实际上相当于数组元素的下标, 每个数据元素的有效地址为基准地址加变址寄存器内存, 即操作数的有效地址 EA=(I)+A, 其中(I)表示变址寄存器I的内容)
      • 若任何一个通用寄存器都可作为变址寄存器则指令需明确地给出一个通用寄存器的编号且标明作为变址寄存器使用;
      • 若处理器中有一个专门的变址寄存器则无需明确指出
      • 指令中的地址码字段称为 形式地址, 指的是 基准地址A, 而变址寄存器种存放的时偏移量
        • 例如8086指令 MOV AL,[SI+1000H]中SI为变址器,1000为形式地址,SI的内容加上1000H形成操作数的有效地址
      • 如图所示, 指令中的地址码A给定数组在存储单元中的首地址, 变址器I每次自动加/减数组元素的长度; 数组元素的变址寻址
          对应高级语言语句:
          for (i=0;i<N;i++){
              // A[i]=...
          }
          数组元素将沿低地址向高地址方向访问,此时是自动加;反过来则是自动减
      
      • 按字节编址的情况下, 若每个数组元素为一个字节, 则下次变址器I中的内容为 (I)±1; 若每个数组元素为4字节, 则下次变址器I的内容为 (I)±4
      • 某些计算机允许变址与间址结合使用.
        • 假定指令中给的变址寄存器为I, 形式地址为A, 则先变址后间址时操作数的有效地址为 EA=((I)+A), 称为 前变址;
        • 先间址后变址时, 则 EA=(I)+(A), 称为 后变址
    7. 相对寻址 : 若指令操作数的有效地址或转移目标地址在该指令所在位置的前/后某固定位置, 则可用相对寻址获得操作数有效地址或转移目标地址.

      • 采用该方式时指令的地址码字段A给出一个偏移量, 基准地址隐含由PC给出, 即操作数有效地址或转移目标地址 EA=(PC)+A
        • 偏移量A是形式地址, 操作数的有效地址或目标转移地址可以在该指令之前或之后, 因为偏移量A是一个带符号整数
      • 相对寻址可实现公共子程序的浮动或实现相对转移
    8. 基址寻址 : 指令中的地址码字段A给一个偏移量, 基准地址可以明显或隐含地由寄存器B给出; 操作数有效地址 EA=(B)+A;

      • 与变址方式一样若任意一个通用寄存器都可用作基址寄存器则指令必须明确给出通用寄存器编号且标明用于基址寄存器
      • 基址寻址的过程 :
        1. 基址寄存器R指定任意一个通用寄存器
        2. 寄存器R的内容是基准地址, 加上形式地址A形成操作数有效地址
        3. 基址寻址为 逻辑地址到物理地址变换 提供了支持, 用于实现程序的动态重定位
      • 基址寻址过程
      • 变址寻址, 基址寻址相对寻址三种寻址方式非常类似, 都是将某个寄存器内容与形式地址相加生成操作数的 有效地址, 通常把三者统称为 偏移寻址

3.2.3 操作类型

  • 操作系统的完备性要求在设计指令系统时必须考虑指令系统应提供哪些操作类型.
  • 指令操作类型可分为:
  1. 算术和逻辑运算指令
    • 加(ADD), 减(SUB), 比较(CMP), 乘(MUL), 除(DIV), 与(AND), 或(OR), 取反(NOT), 取负(NEG), 异或(XOR), 加1(INC), 减1(DEC)等
    • 为方便多字长数据运算, 多数机器还设置了带进位的加(ADC)和带借位的减(SBB)等指令
    • 算术运算指令中有的还设置了十进制的运算指令
  2. 移位指令
    • 算术移位/逻辑移位/循环移位/半字交换等; 有的机器默认一条指令只移一位, 要移多位则要多条移位指令; 有的机器可在指令中规定移动的位数, 移动多位只需一条指令就可实现
    • 各类移位操作的含义 :
      • 算术左移 : 操作数的各位依次向左移, 低位补零.
        • 有的机器将原操作数的最高位移入 进位标志(CF)位, 则可判断符号标志和进位标志是否相等可得知是否发生溢出
      • 算术右移 : 各位依次向右移, 高位补符号; 有的机器将最低位移入 进位标志位
      • 逻辑左移 : 操作与 算术左移 相同, 大多数机器一般不再专门设置该指令
      • 逻辑右移 : 各位依次向右移, 高位补零. 有些机器将原操作数最低位移入 进位标志位
      • 小循环左移 : 最高位移入 进位标志位, 同时也移入最低位
      • 小循环右移 : 最低位移入 进位标志位, 同时也移入最高位
      • 大循环左移 : 最高位移入 进位标志位, 而 进位标志位移入最低位
      • 大循环右移 : 最低位移入 进位标志位, 而 进位标志位移入最高位
      • 半字交换 : 寄存器的前半部分和后半部分内容进行交换
  3. 传送指令
    • 寄存器之间的传送(MOV)
    • 从内存单元读取数据到CPU寄存器(LOAD)
    • 从CPU寄存器写数据到内存单元(STORE)
    • 等等
  4. 串指令
    • 是对 字符串 进行操作的指令, 比如 串传送/串比较/检索和传送转换
  5. 顺序控制指令
    • 控制程序执行的顺序. 功能是通过将转移目标地址送到PC中实现. 转移目标地址可用直接寻址方式给出(又称 绝对转移), 或由相对寻址方式给出(又称 相对转移), 部分机器还可以用寄存器寻址方式寄存器间接寻址方式给出转移目标地址
      • 有条件转移(BRANCH),又称 分支指令 : 仅仅在特定条件满足下才执行转移操作
        • 转移条件一般是某个标志位的值又或是两个以上的标志位组合而成, 例如,CF=1,CF=0,CF=1或ZF=1(CF为进位/借位标志, ZF为零标志)
      • 无条件转移(JMP) : 在任何情况下都执行转移操作
      • 跳步(SKIP) : 转移的一种特例, 使PC再增加一个定制(一般使指令字所占用的存储单元数); 需要注意的是取指令时PC已增量过, 所以跳步指令实际上是 跳过下条指令
      • 调用(CALL),也称 转子指令 : 和转移指令的区别在于执行调用指令时必须保存下条指令的地址(称为 返回地址)
        • 调用指令一般用于 过程调用或函数调用, 当被调用结束时根据 返回地址 返回到调用过程继续执行; 而转移指令则不反悔执行所以不需要保存返回地址
      • 返回(RET) : 在被调用过程执行完毕时将事先保存的 返回地址 送到CP, 让处理器能回到原来调用过程继续执行
      • 等等指令
  6. CPU控制指令
    • 此类指令有 停机/开中断/关中断/系统模式切换以及进入特殊处理程序 等指令.
    • 此类指令大多数被划为 特权指令(管态指令), 只能在内核代码执行时使用以防止用户使用不当对系统造成危害
  7. 输入输出指令
    • 用于CPU与外部设备交换数据或传送控制命令及状态信息
    • 大多数都设置了该类命令, 但寻址方式较少, 常见的只有 寄存器寻址/直接寻址和寄存器间接寻址 等.
    • 当外设中的IO地址空间和主存地址空间统一编址时可不设置该类指令, 而用 访存指令 完成IO操作

3.2.4 操作码编码

  • 指令的操作码可以是固定长度也可以是可变长度.
  • 选择定长操作码还是变长操作码时间和空间之间的开销权衡问题
    • 希望降低空间开销, 代码的长度更重要, 应采用紧凑的变长操作码变长指令字
    • 希望降低时间开销以取得更好性能时, 应采用定长操作码定长指令字
  1. 定长操作码编码
    • 指令操作码采用固定长度编码, 该种方式译码方便, 指令执行速度快, 但有信息冗余.
      • IBM 360/370采用8位定长操作码, 最多可有256条指令, 但指令系统中只提供了183条指令, 有73种为冗余编码
  2. 扩展操作码编码
    • 该种方式将操作码的编码长度分成几种固定长度的格式. 可以采用登场扩展法, 例如4-8-12,3-6-9这种等步长方式扩展, 也可采用不等长扩展法.
    • 扩展编码方式的操作码长度不固定, 是可变的, 且该种编码方式被大多数非规整型指令集采用
      • 例如Intel公司x86系列处理器采用的就是该种编码方式
    • 扩展操作码编码的例子
        设某指令系统的指令字为16位, 每个地址码为6位. 若二地址指令15条, 单地址指令34条, 则剩下的零地址指令最多有多少条?
        解:    扩展编码的基本思想就是操作码按短到长进行扩展编码. 二地址指令操作码最短, 零地址指令的操作码最长, 所以按照二地址单地址零地址的顺序进行扩展编码
        二地址指令的地址码部分占12位, 故操作码只有4位, 最多有16种编码, 用去15种编码(0000-1110)分别表示15条指令, 还剩下一种编码(1111)未使用
        单地址指令的地址码部分占6位, 故操作码有10位, 最高4位为1111, 还剩6位, 最多有2的6次方(64)种编码, 用其中32+2=34种编码(11110 00000 ~ 11110 11111 和 11111 00000 ~ 11111 00001)分别表示34条一地址指令
        剩下的零地址指令共有16位操作码, 其中高5位只能是11111, 所以编码范围为 : 11111(00010 ~ 11111)(000000 ~ 111111),即高5位为11111, 次5位为00010~11111,低6位为 000000~ 111111, 因此零地址指令最多有30×2的6次方种编码可用    
    

3.2.5 标志信息的生成与使用

  • 条件转移指令(也称分支指令), 是根据程序当前生成的标志信息进行转移
  • 标志信息也成为 条件码(Condition Codes,CC)或 状态位(status bits)
    • 常用的标志有 : (不同数据类型的运算指令,这些标志信息含义有一定差别)
    1. 零标志ZF
    2. 溢出标志OF
    3. 符号标志SF
    4. 进位/借位标志CF
  • 对于逻辑运算指令, 通常只有零标志ZF才有意义. 可以通过判断ZF是否等于1来确定与或非等操作的结果是否为0.
  • 移位指令, 左移时可能发生溢出; 有的机器的算术左移指令会生成OF标志. 也有的机器在算术左移时将操作数的最高位移入进位标志, 通过判断符号标志和进位标志是否相等来判断是否溢出
  • 生成的标志位可由专门的 条件码寄存器 或称(状态寄存器/标志寄存器/程序状态字寄存器)来存放, 也可指定通用寄存器来存放.(不同机器说法和做法类似,但不一定完全相同)
    • 程序状态字寄存器用于存放条件码CC和自陷允许标志(Trap Enable Flag)等状态信息
    • 不同计算机对程序状态描述以及程序状态存放位置可能不一样, 但在概念上应有一个程序状态字(Program Status Word,PSW)
  • 用通用寄存器存放标志位的例子
    cmp r1,r2,r3;  # 比较r2和r3, 标志位存储在r1
    bgt r1,label;  # 根据r1的标志位判断是否大于,以转移到label处

    有的指令系统可用一条计算并转移指令完成以上两条指令的功能
    例如下面的指令首先对r1和r2两个寄存器内容做减法以比较大小, 然后根据比较结果确定是否转移
    bgt r1,r2 label;  # 若r1>r2则转移到label处, 否则继续执行下条指令
  • 标志信息的生成和使用方式有多种, 实现条件转移的方式也可以不同; 处理器中的运算电路必须能够产生这些标志信息. IA-32中常用条件转移指令

  • IA-32中(如上图), 不管高级语言程序中定义的变量是带符号整数还是无符号整数类型, 对应的加减法指令都是一样的.

    • 每条加减指令或比较指令执行后会根据运算结果产生相应的进位/借位标志CF, 符号标志SF, 溢出标志OF和零标志ZF, 并保存到标志寄存器(EFLAGS)中
  • 对于比较大小后进行分支转移的情况, 通过减法获得标志信息, 再根据标志信息判断两个数大小, 从而决定该转移到何处执行指令

  • 对于无符号整数, 判断大小时使用的是CF和ZF标志. ZF=1说明两数相等, CF=1说明有借位,是小于的关系, 通过对ZF和CF的组合, 得到上图中9,10,11,12的4条指令中的结论

  • 对于带符号整数, 判断大小时使用的是SF,OF和ZF标志. ZF=1说明两数相等, SF=OF说明结果是以下两种情况之一, 这两种情况反映的是大于的关系. 若SF≠OF, 则反映的是小于关系; 带符号整数比较时对应上图13,14,15,16的4条指令

    • 两数之差为正数(SF=0)且结果无溢出(OF=0)
    • 两数之差为负数(SF=1)且结果溢出(OF=0)

例子

  • 假设被减数的机器数为X, 减数的机器数为Y, 按照补码加减运算器(图2.11?)计算两数差的公式为 \( X-Y=X+ \overline Y(取反)+1 \), 通过以下两个例子说明无符号和带符号整数的大小判断规则
  1. 假定X=1001,Y=1100,Sub=1,则Y'=0011, 加法器中运算为 1001-0011=1001+0011+1=(0)1101, 得知ZF零标志位为0,Count=0. 若是无符号比较则是9与12的比较,是小于的关系, 此时 \(CF=Count \bigoplus Sub=1 \), 满足上图的11序号对应指令的条件
    • 若是带符号整数比较, 则是-7和-4的比较, 也是小于的关系, 此时符号位为1, SF=1, 根据两加数符号相异一定不会溢出的原则, 得到OF=0, 因为SF≠OF, 满足上图序号15对应指令的条件
  2. 假定X=1100, Y=1001,Sub=1,则Y'=0110, 加法器中的运算为 1100-1001=1100+0110+1=(1)0011, 因此ZF=0,Count=1. 若是无符号数比较则是12和9相比, 是大于的关系, 此时\( CF=Count \bigoplus Sub=0 \), 满足上图序号9对应指令的条件
    • 若是带符号整数则是-4和-7的比较也是大于关系, 此时SF=0且OF=0,即SF=OF,满足上图序号13对应指令的条件

3.2.6 指令系统设计风格

按操作数位置指定风格区分, 可分成4种不同风格类型指令系统

  1. 累加器(Accumulator)型指令系统
    • 该类型指令系统中, 总把其中一个操作数隐含在累加器中, 指令执行结果也是送到累加器中
    • 该类型指令系统中, 指令字短, 但每次运算要通过累加器, 因此进行复杂表达式运算时, 程序会多出移入/移出累加器指令, 从而让程序变长, 影响程序执行效率
    • 这种设计风格的指令系统只在早期机器中使用过, 现在一般不采用
  2. 栈(stack)型指令系统
    • Java虚拟机采用的是栈型指令系统.
    • 栈是一种采用 **后进先出(LIFO)或先进后出(FILO)**存取方式的特定的存储区.
    • 栈型指令系统中规定指令的操作数总是来自栈顶
    • 往栈里存数叫(入)进栈或压栈, 从栈里取数据叫出栈或弹出
    • 栈型指令系统的指令都是零地址或一地址指令, 所以指令字很短. 但由于指令操作数只能来自栈顶, 所以在对表达式编译时生成的指令顺序以及操作数在栈中的排列都有严格的顺序规定, 所以不灵活且带来指令条数的增加
    • 栈型指令系统很少被通用计算机使用
  3. 通用寄存器(General Purpose Register)型指令系统
    • 特点 : 使用通用寄存器而不是累加器存放运算过程中所用的临时数据, 其指令的操作数可以是立即数(I), 或者来自通用寄存器(R), 或者来自存储单元(S)
    • 指令类型可以时RR/RS/SI/SS型等
      • RR表示两个操作数都来自通用寄存器
      • RS表示两个操作数分别来自通用寄存器和存数单元
      • SI表示两个操作数分别来自存储单元和立即数
  4. Load/Store型指令系统
    • 该指令系统也使用通用寄存器存放运算过程中的临时数据, 因此也是一种通用寄存器型指令系统
      • 特点 : 只有取数(Store)和存数(Store)指令才可以访问存储器, 运算类指令不能访存, 即运算指令只能是RR型或RI型
    • 该指令系统的指令比较规整, 体现在每条指令的指令字长度和指令执行时间能够比较一致
    • 目前通用寄存器型指令系统占主导地位, 主要原因
      1. 通用寄存器和处理器集成在一起, 作为ALU的操作数来源两者可以靠得很近, 因而缩短传输延迟
      2. 寄存器位于存储器层次化结构的顶端, 速度快且易使用
    • 寄存器个数不能太多也不能太少;
      • 太多会导致成本高且演唱存取时间使得时钟周期变长
      • 太少会导致编译器只能把许多变量分配到内存单元,每次都要去内存访问操作数而影响程序性能
    • 通用寄存器的设计和有效使用时程序性能好坏的关键之一

按指令格式的复杂度区分

  1. CISC风格指令系统
    • VLSI技术迅速发展, 硬件成本下降, 软件成本上升, 在设计指令系统时增加了越来越强大的复杂命令使机器指令功能接近高级语言语句的功能, 给软件支持提供较好的支持.
      • VAX 11/780指令系统包含了16种寻址方式, 9种数据格式, 303条指令, 每条指令包含1-2字节的操作码和下续N个操作数说明符,
      • 而一个操作数说明符长度可达1-10字节,
      • 该类计算机被称为 复杂指令集计算机(Complex Instruction Set Computer, CISC)
    • CISC指令系统设计的主要特点
      • 指令系统复杂 : 指令多, 寻址方式多, 指令格式多
      • 指令周期长 : 觉多数指令需要多个时钟周期才能完成
      • 指令周期差距大 : 各种指令都能访问存储器, 使得简单指令和复杂指令所用的时钟周期数相差很大, 不利于指令流水线的实现
      • 采用微程序控制 : 由于有些指令非常复杂, 以至于无法用硬连线控制器来实现, 而微程序控制器用软件设计思想实现硬件, 可以实现对复杂指令的控制
      • 难以进行编译优化 : 编译器可选指令序列增多, 使目标代码组合增加, 从而增加目标代码优化难度
    • 复杂指令系统让计算机结构也越复杂, 不仅增加研制周期和成本, 且难以保证正确性, 甚至降低系统性能
    • CISC指令系统常用的只占20%的一些简单指令, 它们占程序代码的80%以上, 需要大量硬件支持的复杂指令在程序中出现频率很低, 造就了硬件资源的浪费
    • 微程序控制的计算机中, 占程序指令总数20%的最复杂的指令占用了微程序控制存储器容量的80%
  2. RISC风格指令系统
    • 1975年IBM开始研究指令系统合理性问题, John Cocke 领导的一个研究小组提出了 精简指令集计算机(Reduced Instruction Set Computer, RISC) 的概念
    • RISC的重点不是简单地放在简化指令系统上, 而是通过简化指令让计算机结构更简单合理, 提高机器性能
    • RISC的特点
      • 指令数目少 : 只包含使用频率高的简单指令
      • 指令格式规程 : 寻址方式少, 指令格式少, 指令长度一致
      • 采用Load/Store型指令设计风格
      • 采用流水线方式执行指令 : 规整的指令格式有利于采用流水线方式执行, 除Load/Store指令外, 其他指令都只需一个或小于一个时钟周期即可完成, 指令周期短
      • 采用大量用通用寄存器 : 编译器可将变量分配到寄存器中, 减少访存次数
      • 采用硬连线控制器 : 指令少而规整使得控制器的实现变得简单, 可以不用或少用微程序控制
      • 采用优化的编译系统 : 指令数少有利于编译器的优化
    • 采用RISC技术, 指令系统简单, CPU控制逻辑简化, 芯片上可设置更多通用寄存器, 指令也可采用速度较快的硬连线控制器来控制, 更适合采用指令流水线技术, 可使指令执行速度提高
    • 指令数量少, 让编译工作量加大, 但由于指令系统的指令都是精选的, 编译时间少, 反过来对编译程序的优化又是有利的
      • 第一代RISC机器 : 美国加州伯克利大学的RISC I, 斯坦福大学的MIPS, IBM公司的IBM 801
      • 20世纪80年代, RISC技术蓬勃发展且每年翻番速度发展, 先后出现了 PowerPC, MIPS, Sun SPARC, Compaq Alpha等高性能RISC芯片以及计算机
    • 虽然RISC技术在性能上有优势, 但最终RISC机并没有在市场上占优势, 反而Intel一致保持处理器时长的较大份额, 主要原因有二 :
      • 软件的向后兼容性, 许多用户早期花了很多前投资购买了在Intel系列机开发的软件, 如果换成RISC则要重新投资
      • 随着处理器速度和芯片密度不断提高, RISC系统也日趋复杂, 而CISC由于采用了RISC技术(Intel Pentium4中将简单指令直接转换乘类RISC指令, 复杂指令用微码实现),
        • 使其性能更加提高; 虽然该混合方案不如纯RISC方案速度快, 却能保证软件兼容的前提下达到具有较强竞争力的整体性能
    • 随着后PC时代的到来, 个人移动设备的使用和嵌入式系统的应用广泛起来, 像ARM处理器等这些采用RISC技术的产品又迎来了新的机遇, 在嵌入式系统中占有绝对优势, 因而被更广泛使用

3.3 指令系统实例

  • 指令系统设计使计算机系统设计的核心工作, 不同机器的指令集体系结构差异大

3.3.1 MIPS指令格式和寻址方式

  • MIPS是典型的RISC结构, 按字节编址, 采用32位定长指令字, 操作码也是固定长度, 没有专门的寻址方式字段, 由指令系统确定操作数的寻址方式
  • MIPS指令采用三地址指令格式, 只有三种类型, 如下图 MIPS指令格式
  1. R-型指令
    • R-型指令的两个操作数和结果都存放在寄存器中, 其操作码OP为 000000, 操作数类型由 funct 字段指定
    • 若是双目运算类指令, 寄存器rs和rt的内容分别作为第一和第二源操作数, 结果送寄存器rd
    • 若是移位运算类指令, 则对rt内容移位, 结果送rd, 所移位数由 shamt 字段给出
    • 指令需要左移或右移若干位, 所以MIPS中移位指令多用桶形移位器实现以提高速度
    • R-型指令的寻址方式只有一种, 就是 寄存器直接寻址
  2. I-型指令
    • I-型指令是立即数型指令
    • 若是双目运算类指令, rs的内容和立即数分别作为第一和第二源操作数, 结果送rt
    • 若是Load/Store指令, 则将rs内容和立即数符号扩展后的内容相加作为内存单元地址, Load指令将内存单元内容送rt, Store指令将rt内容送内存单元
    • 若是条件转移(分支)指令, 则对rs和rt内容进行指定运算, 根据运算结果决定是否转到转移目标地址处执行, 转移目标地址是通过 相对寻址方式 得到, 即将PC内容和立即数符号扩展后的内容相加得到
    • I-型指令的寻址方式有4种
      • 寄存器直接寻址
      • 立即数寻址
      • 相对寻址
      • 基址或变址寻址
  3. J-型指令
    • J-型指令是无条件跳转指令, 给出的是26位直接地址, 将当前PC高4位拼上26位直接地址最后添两个0可得到32位的跳转目标地址
    • 只有一种寻址方式, 变通的直接寻址
    • J-型指令中的跳转目标地址最后两位要添0的原因以及实现方式
      • 因为32位MIPS机器采用32位定长指令字, 采用字节编址, 所以一条指令占4个存储单元, 因而指令地址总是4的倍数, 即地址最后两位总是0, 无需再指令中显式给出, 只要在实现指令功能的数据通路中具有添加"00"的电路即可

3.3.2 MIPS指令中数据的表示

  • MIPS指令的操作数可以是立即数也可以是通用寄存器的内容也可以是存储单元的内容
  • MIPS处理器提供了32个32位通用寄存器, 因此寄存器编号占5位.
    • R-型指令格式的rs/rt/rd和I-型指令中的rs/rt都是指通用寄存器
  • MIPS通用寄存器名称及编号及功能如下图 MIPS通用寄存器
  • 0号寄存器恒为0, 31号寄存器用于存放过程调用的返回地址
  • 寄存器的汇编表示以 $ 符号开始, 也可以使用名称 $a0, 也可以用编号 $4
  • MIPS还提供了32个32位单精度浮点寄存器, 用汇编符号 $f0-$f31 表示, 可配对成16个64位浮点寄存器, 用于表示64位双精度浮点数
  • MIPS中提供了两个乘商寄存器 Hi和Lo, 无需再指令中显式给出.
    • 用32位的Hi和Lo可实现一个64位寄存器, 在执行乘法运算时Hi和Lo联合用来存放64位乘积, 而执行除法时最终余数存放在Hi中商在Lo中
  • MIPS中用程序计数器PC指出下条指令的地址
  • MIPS的存储器按字节编址
    • 对于存储器数据, 其操作数地址为32位, 通过一个32位寄存器内容加16位偏移量得到, 其中32位寄存器就是I-型指令的rs, 16位偏移量就是I-型指令中的16位立即数,
    • 通常是一个带符号整数, 因此存储器操作数可访问的地址空间大小为 \( 2^{32} \)字节
  • MIPS采用大端方式(Big Endian)存放数据, 数据要求按字节界对其, 只能通过Load/Store指令访问存储器数据
  • 对于立即操作数, 指令中给出的位数为16位, 指令执行时需要将其进行符号扩展或0扩展, 变成32位操作数后才能参加运算

3.3.3 MIPS汇编语言

MIPS汇编语言示例列表

  • 运算类指令包括 算术运算和逻辑运算指令, 可以是R-型格式指令也可以是I-型指令格式
    • 根据上图中的说明 “sub $s1,$s2,$s3"的含义为”$s1=$s2+$s3",得知R-型格式汇编指令中, 最左边第一个寄存器是目的操作数寄存器, 后面两个寄存器分别是第一第二个源操作数所在寄存器, $s1,$s2,$s3分别是R-型格式指令中的rd/rs/rt
    • I-型格式运算类指令的汇编表示有一个特点, 就是指令操作码助记符总是以i结尾且第二个源操作数所一定是立即数
      • andi $s1, $s2, 100的含义为 $s1=$s2&100,指令操作码助记符为andi, 是与操作码and后跟字母i得到, $s1,$s2和100分别是I-型格式指令中的rs/rt和16位立即数
  • ….中间省略将书角折起来了
  • 从汇编表示转换为机器代码的过程称为 汇编, 从机器代码转换为汇编表示的过程为 反汇编 MIPS机器代码示例列表1 MIPS机器代码示例列表2

3.4 程序的机器级表示

  • 任何高级语言编写的源程序最终都必须翻译(汇编,解释/编译)成机器指令表示的机器语言才能在计算机运行

3.4.1 选择结构的机器代码表示

  • 过程式程序设计语言提供顺序/选择和循环三种控制结构
    • 选择结构根据判定条件控制语句是否被执行
      • if-then
      • if-then-else
      • switch-case
      • if-goto
    • 对应高级语言中这些选择语句在机器语言中提供了各种 条件码(标志位) 的设置功能以及各种分支(条件转移)指令和无条件转移指令
    • 编译器通过条件设置指令和各类转移指令实现程序中的选择结构语句
// 假定C语言赋值语句 f=(g+h)-(i+j)中
//    变量i,j,f,g,h由编译器分别分配给MIPS寄存器$t0~$t4.
// 要求给出编译后的MIPS机器代码和汇编表示

// 解: 用三条R-型指令即可, 其中两条是add指令, 一条是sub指令, 且三条指令的op字段都为000000
//     add指令的funct字段为32=1000000B, sub指令的funct字段为34=100010B
//     寄存器$t0~$t7对应8~15, 所以上述程序段对应MIPS机器代码和汇编表示如下
000000 01011 01100 01101 00000 100000 add $t5,$t3,$t4 # g+h
000000 01000 01001 01110 00000 100000 add $t6,$t0,$t1 # i+j
000000 01101 01110 01010 00000 100010 sub $t2,$t5,$t6 # f=(g+h)-(i+j)
// C语言程序段 : if (i==j) f=g+h; else f=g-h;.
// 假定 i,j,f,g,h由编译器分别分配给MIPS寄存器$s1~$s5. 要求给出编译后的MIPS汇编表示

// 解 : 首先要有一条分支指令能根据i,j是否相等进行转移, 此外还要有一条无条件转移指令
bne $s1,$s2,else # if i!=j, jump to else
add $s3, $s4,$s5 # f=g+h
j exit # jump to exit
else: sub $s3,$s4,$s5 # f=g-h
exit:

3.4.2 循环结构的机器代码表示

  • 循环结构是可重复执行的一组语句
    • while
    • until
    • for
    • loop
    • goto loop
  • 需要用到自动变址寻址, 如果指令系统不提供自动变址, 则编译器需要选用对变址器进行增量的指令使每次循环按顺序取不同元素
while (i!=k) {
    x = x+A[i];
    i = i+1;
}
// 假定x,i,k由编译器分别分配给MIPS寄存器$s1,$s2,$s3,数组A每个元素为一个32位字, 首地址存放在$s5中,要求给出编译后的MIPS汇编表示
// 解 : 循环体内有一个数组元素访问, 首先要计算每次循环中数组元素A[i]的地址, 应等于A的首地址加上偏移量(ix4),可用乘法指令实现, 也可用加法指令(两次加倍)或移位指令(左移2)来实现x4
// 一般不用乘法指令实现x4操作,  从内存读取数组元素的功能可用指令lw实现
// 循环开始时先用分支指令beq判断循环结束条件以便循环结束条件满足时跳出循环体
// 循环结束后第一条指令用一个标号Exit标识; 循环最后要有一条无条件转移指令j, 以转移到循环体的开始, 循环体内第一条指令的标号为Loop
// MIPS没有自动变址寻址方式, 所以用一条显式加法指令addi实现数组下标i的增量
// 编译后的MIPS汇编表示如下
Loop:    beq $s3,$s2,Exit
         add $s7,$s2,$s2    # ix2
         add $s7,$s7,$s7    # ix4
         add $s7,$s7,$s5    
         lw $s6,0($s7)      # $6=A[i]
         add $s1,$s1,$s6    # x=x+A[i]
         addi $s2,$s2,1     # i+1
         j Loop
Exit:    ......

本章小结

  • 指令格式,操作数类型,寻址方式,操作类型等介绍
  • 定长指令字和定长操作码可方便指令地址计算/取指和译码
  • 变长指令字和变长操作码导致指令字段编码紧凑且程序占空间少
  • 指令类型主要类型
    • 数据传送
    • 算术逻辑运算
    • 字符串处理
    • IO处理
    • 程序流控制
    • 系统控制
  • 指令设计的操作数类型主要有
    • 无符号整数
    • 带符号整数
    • 浮点数
    • 位串
  • 常用寻址方式有
    • 立即寻址
    • 直接寻址
    • 间接寻址
    • 寄存器直接寻址
    • 寄存器间接寻址
    • 相对寻址
    • 变址寻址
    • 基址寻址
  • 对应高级语言程序中的选择结构和循环结构相应的机器代码中需要有
    • 条件设置
    • 条件转移(分支)指令 : 根据不同标志信息改变程序执行顺序
  • 常用的标志有
    • CF(进位借位)
    • ZF(零标志)
    • OF(溢出标志)
    • SF(符号标志)
  • 按地址码指定方式分指令系统可分成
    • 累加器型
    • 栈型
    • 通用寄存器型
    • Load/Store型
  • 按指令系统复杂度来分
    • CISC, 复杂指令系统计算机
    • RISC, 精简指令系统计算机
comments powered by Disqus