CISC vs. RISC

早期的趋势:为了能够做复杂的操作,增加越来越多的指令 — CISC

  • 导致学习和理解上的困难
  • 导致硬件复杂(可能会变慢)

改变设计思路:Reduced Instruction Set Computing (RISC)

  • 使用更简单,更小的指令集,会更加容易获得快速的硬件 (pipeline)
  • 如果需要做复杂操作的话,让软件来做,组合几条简单的指令来完成工作 (易于设计)

指令与指令系统

指令和指令系统的概念

计算机系统由硬件和软件两大部分组成。

  • 硬件指由中央处理器、存储器以及外围设备等组成的实际装置。
  • 软件是为了使用计算机而编写的各种系统的和用户的程序,程序由一个序列的计算机指令组成
  • 指令是计算机运行的最小的功能单元,是指挥计算机硬件运行的命令,是由多个二进制位组成的位串,是计算机硬件可以直接识别和执行的一个信息体。
  • 一台计算机提供的全部指令构成该计算机的指令系统。指令用于程序设计人员告知计算机执行一个最基本运算、处理功能,多条指令可以组成一个程序,完成一项预期的任务

  • 可以从 6 个层次分析和看待计算机系统的基本组成。
    • 高级语言层:Application, Algorithm, Programming Language
    • 汇编语言层:Assembly Language
    • 机器码层: Machine Code
    • 指令系统层:Instruction Set Architechture
    • 微体系结构层:Micro Architechture, Gates/Registers
    • 硬件设备层:Devices, Physics
  • 指令系统层处在硬件系统和软件系统之间,是硬、软件之间的接口部分,对两部分都有重要影响。
  • 硬件系统用于实现每条指令的功能,解决指令之间的衔接关系;
  • 软件由按一定规则组织起来的许多条指令组成,完成一定的数据运算或者事务处理功能。
  • 指令系统优劣是一个计算机系统是否成功的关键因素。

指令系统设计要求

  • 完备性: 指令功能齐全、编程方便
  • 规整性: 指令格式简单、统一
  • 高效性: 占内存少,运行高效
  • 兼容性 n 同一系列软件兼容

指令是用户使用计算机和计算机本身运行的最小的功能单元:①指令是由多个二进制位组成的数串, ② 用于设计程序, ③计算机硬件可直接识别和执行。通 常情况下一台计算机需要提供哪些指令呢?

计算机用于计算和处理数据,为此,要在计算机硬件系统中设置 5 种类型的部件:

  • 运算器部件、
  • 控制器部件、
  • 存储器部件、
  • 输入设备、
  • 输出设备,

各自承担数据运算、系统指挥控制、保存当前程序和数据、执行输入和执行输出的功能。因此,需要在计算机中设置为使用和控制这几个部件运行的相应指令。

  • 运算器相关指令:
    • ADD, SUB, AND, OR, MVRR, SHR, RCL
  • 控制器相关指令:
    • JUMP, JRC, CALL, RET
  • 存储器相关指令:
    • STORE, LOAD, PUSH, POP,
  • 输入输出相关指令:
    • IN, OUT

指令功能和分类

  • 算术与逻辑运算指令

    • 加、减、乘、除、变符号等算术运算
    • 与、或、非、异或等逻辑运算
  • 移位操作指令

    • 算术移位(一般只右移)、逻辑移位、循环移位
  • 数据传送指令

    • 通用寄存器之间传送
    • 通用寄存器与主存储器存储单元之间传送
    • 主存储器不同存储单元之间传送
  • 输入输出指令

    • 通用寄存器与输入输出设备(接口)之间传送
  • 转移指令

    • 变动程序中指令执行次序的指令,分为无条件转移指令和条件转移指令
  • 子程序调用与返回指令

    • 调用指令与返回指令二者要配合使用,子程序的最后一条指令一定是返回指令,执行结束后返回主程序断点
  • 堆栈操作指令

    • 堆栈(stack)是由若干个连续存储单元组成的先进后出的存储区,有压入 push(即进栈)和弹出 pop(即退栈)操作
  • 其他指令

    • 置条件码指令、开中断指令、关中断指令
    • 停机指令 halt、空操作指令 nop、特权指令

指令格式

  • 指令中的内容,包括指令操作码(指出指令完成的运算处理功能和数据类型)和操作数或指令的地址(指明用到的数据或地址)两部分。例如:

    • 算逻运算中的运算功能,数据来源或结果去向
    • 数据传送指令中的数据原来位置和新的存储位置
    • 输入输出指令中用到的设备和数据来、去的位置
    • 转移指令的转移类别、转移条件和转移地址等
  • 每一条指令必须指明

    • 它需要完成的功能,
    • 通常用几位指令操作码表示;
    • 还需要指明用到的数据、地址或设备,通常在地址字段给出,可能是:
      1. 寄存器编号,
      2. 设备端口地址,
      3. 存储器的单元地址
      4. 数值等几种信息。

变长指令字/定长指令字

  • 指令字长是指组成一条指令的二进制数的位数,例如 8 bits、16 bits、32 bits、64 bits 等,
  • 指令格式与指令字长密切相关,指令字越长可以给出的信息越多。
  • 一个指令字通常由指令操作码和操作数地址两部分组成,如何把一个指令字划分成多个字段并分配各字段所表示的内容大有学问。

Fig. RISC-V instruction format ⭐

Fig. MIPS instruction format
  • 指令字:完整的一条指令的二进制表示

  • 指令字长:指令字中二进制代码的位数

    • 机器字长:计算机能直接处理的二进制数据的位数
    • 指令字长(字节倍数)=0.5、1、2…个机器字长
    • 定长指令字结构 vs. 变长指令字结构
  • 指令格式:指令字中操作码和操作数地址的二进制位的分配方案

    • 操作码 operate:指明本条指令的操作功能,每条指令有一个确定的操作码
      • 定长的操作码的组织方案:在指令字最高位部分分配固定若干位用于表示操作码,有利于简化计算机硬件设计,提高指令译码和识别速度,例如:IBM360 机、THINPAD 教学机
      • 变长的操作码的组织方案:在指令字最高位部分用一固定长度的字段来表示基本操作码,而对于部分操作数地址位数可以少的指令,则把另外多位辅助操作码扩充到该操作数地址字段,即操作码位数可变
        • 这种方法在不增加指令字长的情况下,可表示更多的指令, 但增加了译码和分析难度,要求更多的硬件支持
        • 例如:PDP-11 计算机、TEC-2000 的 8 位机
      • 操作码字段与操作数地址字段有所交叉的方案:不同指令的操作码长度可以不同,表示操作码所用到的一些二进制位不再集中在指令字的最高位部分,而是与用于表示操作数地址的一些字段有所交叉,操 作码还被区分为主操作码和辅助操作码这样不同的两部分,这是一种比较特殊、不很常用的方案。例如:NOVA (DJS-130) 计算机就采用这种方案
    • 操作数 operand 地址:说明操作数存放的地址,有时是操作数本身(立即数)

指令操作码的位数限制指令系统中的指令条数!

操作码位数为 k,则指令不会超过 2^k 个,除非进行操作码扩展。

指令操作数个数

  • 无操作数指令(零地址指令)
  • 单操作数指令(一地址指令)
  • 双操作数指令(二地址指令)
  • 三操作数指令(三地址指令)
  • 多操作数指令(多地址指令)

指令操作数来源和去向

  • CPU 内部的通用寄存器 register
  • 输入输出设备(接口)的一个寄存器 I/O register
  • 主存储器的一个存储单元 memory
  • 立即数(只做来源)

操作码扩展

假设某机器的指令长度为16位,包括4位基本操作码和三个4位地址码段。

  • 4 位基本操作码可表示 16 个状态,如用 4 位操作码,则能表示 16 条三地址指令,
  • 若用 8 位操作码,则可表示 256 条二地址指令,
  • 而用 12 位操作码,则可表示 4096 条一地址指令,
  • 若16位全用作操作码,则可表示 65536 条零地址指令

[! example] 操作码扩展方案示例 若需要在 16 位字长的指令中能够同时支持三地址、二地址、一地址指令各 15 条,零地址指令 16 条,则可以选用如下方案的变长操作码实现:

  • 15 条三地址指令的操作码为:0000 ~ 1110
  • 15 条二地址指令的操作码的高 4 位选用 1111,低 4 位用 0000 ~ 1110, 即得到: 11110000 ~ 11111110
  • 15 条一地址指令的操作码的高 8 位选用 11111111, 低 4 位用 0000 ~ 1110, 即: 111111110000 ~111111111110
  • 16 条零地址指令的操作码的高 12 位每位均用 1,低 4 位随意, 即: 1111111111110000~1111111111111111

该操作码扩展方案中,每次扩展 4 位并仅保留了一个编码用于接下来的扩展过程,当每次扩展的位数和保留的位数变化时,后面可扩展的指令条数就可以变化。例如在16位字中的指令字中,可以选用如下方案支持三地址指令、二地址指令、一地址指令和零地址指令14、30、31、16条:

  • 14 条三地址为:0000 ~ 1101 (保留 1110、1111 两个码)
  • 30 条二地址为:11100000 ~11111101 (保留 2 个码)
  • 31 条一地址为:111111100000 ~111111111110 (保留 1 个码)
  • 16条零地址为:1111111111110000~1111111111111111

寻址方式

寻址方式(又称编址方式)指的是确定本条指令的操作数地址及下一条要执行的指令地址的方法

  • 不同的计算机系统,使用数目和功能不同的寻址方式,其实现的复杂程度和运行性能各不相同。有的计算机寻址方式较少,而有些计算机采用多种寻址方式。
  • 通常需要在指令中为每一个操作数专设一个地址字段,用来表示数据的来源或去向的地址。
    • 在指令中给出的操作数(或指令)的地址被称为形式地址
    • 使用形式地址信息并按一定规则计算出来或读操作得到的一个数值才是数据(或指令)的实际地址
  • 在指令的操作数地址字段,可能要指出:
    1. 运算器中的累加器的编号或专用寄存器名称(编号) Register
    2. 输入/输出指令中用到的 I/O 设备的入出端口地址 I/O address
    3. 内存储器的一个存储单元(或一 I/O 设备)的地址 Mem addr

有多种基本寻址方式和某些复合寻址方式,简介如下:

立即数寻址

所需的一个操作数在指令的地址字段部分直接给出。

  • operand 即为操作数的值
  • 适用情况:
    • 操作数固定时,取指同时取得操作数,指令执行阶 段不必到存储器中取操作数,提高了指令执行速度;
    • 当该立即数的值较小 (占用位数少)时,可在指令字第一个字中直接给出,否则需要用指令的第二个字提供。
  • 例:Num = 1234H,指令的一个操作数就是 1234H

直接寻址

在指令的地址码字段,直接给出所需的操作数(或指令) 在存储器中的地址。

  • Addr 为操作数在存储器中的地址, 或转移指令等用到的指令地址。
  • 例:Addr = 5718H ,可能是下一条指令的地址或一个操作数的地址,若 [5718H] = 3,则用 5718H 作地址,从内存储器单元中读出的操作数是 3。

寄存器 (间接)寻址

计算机的 CPU 中设置有一定数量的通用寄存器,用于存放操作数、操作数地址或中间结果。

  • 假如指令地址码字段给出某一通用寄存器的编号 (地址),且所需的操作数就在这一寄存器中,这就是寄存器寻址方式;
  • 若该寄存器中存放的是操作数在内存储器中所在单元的地址,这就是寄存器间接寻址方式。

可通过指令的操作码或另设一个字段,来区分这两种不同的寻址方式。例:

  • RegNo. = 5,即使用 5# 累加器,此时若 5# 累加器中的内容为 7,可记为 (R5)=7
    • 对寄存器寻址,操作数就是寄存器中的数值 7
    • 对寄存器间接寻址,从内存 7# 单元读出来的数才是操作数

变址寻址

操作数的地址由指定的变址寄存器(由 Reg 指定)的内容和指令中的变址偏移量(Disp)相加得到。

  • 上图中,
  • Reg == Index Register
  • Disp == Address

变址寄存器内容变化,变址偏移量不变,便于读写数组中的元素,是计算机中常用的一种寻址方式。

相对寻址

指令的地址由程序计数器 PC 的内容(即当前执行指令的地址)和指令的相对寻址偏移量相加得到。

  1. 主要用于转移指令,对浮动程序很有用。
  2. 偏移量可正可负,通常用补码表示。

间接寻址

指令的地址码字段给出的内容既不是操作数,也不是操作数的地址,而是操作数(或指令)地址的地址,这被称为间接寻址方式,多一次读内存的操作。

指令中的 Addr 可以用其他寻址方式给出,例如变址寻址,这就成为变址寻址与间接寻址的复合寻址方式

基址寻址

在计算机中设置一个专用的基址寄存器,操作数(或指令)的地址通过基址寄存器的内容和指令中的地址码相加得到。

主要用于为程序或数据分配存储区,对多道程序或浮动程序很有用,解决了程序在存储器中的定位和扩大寻址空间等问题

堆栈寻址

堆栈是内存储器中一块按“后进先出”原则进行读写的存储 区,并通过一个专用的寄存器 (称为堆栈指针 SP) 给出堆栈的栈顶地址,执行读写堆栈操作通常总在栈顶进行,故不必在指令中给出堆栈地址,而且在读写操作的前后伴随有自动修改 SP 内容的动作,确保使 SP 总是指向堆栈的栈顶。

例如,按字寻址时:

  • 入栈操作: SP-1->SPAR,即 SP 的内容减 1 存回 SP, 并送入内存地址寄存器,接下来才可以把数据写到堆栈中,这是因为需要把数据写到新开辟出来的栈顶单元中。
  • 出栈操作: SP->AR,完成一次读堆栈操作后,还要执行一次 SP+1->SP 的操作,用于修改 SP 内容,这是因为数据读出后原来它的下一个相邻单元变成为栈顶。