Appearance

第 7 章 指令系统

第一讲 概述与指令系统设计

指令系统概述

指令系统处在软/硬件交界面,同时被硬件设计者和系统程序员看到

  • 硬件设计者角度:指令系统为 CPU 提供功能需求,要求易于硬件设计
  • 系统程序员角度:通过指令系统来使用硬件,要求易于编写编译器 指令系统设计的好坏还决定了:计算机的性能和成本 冯·诺依曼结构机器对指令的规定:
  • 用二进制表示,和数据一起存放在主存中
  • 由两部分组成:操作码和操作数(或其地址码)

指令系统设计

概述

  • Instruction Fetch:从存储器读取指令
    • 指令地址、指令长度(定长/边长)
  • Instruction Decode:对指令译码,以确定将要做什么操作
    • 指令格式、操作码编码、操作数类型
  • Operand Fetch:计算操作数地址并取操作数
    • 地址码、寻址方式、操作数格式和存放
  • Execute:进行相应计算,并得到标志位
    • 操作类型、标志或条件码
  • Result Store:将计算结果保存到目的地
    • 结果数据位置(目的操作数)
  • Next Instruction:计算下条指令地址(通常和取指令同时进行)
    • 下条指令地址(顺序/转移) 指令执行的每一步都可能发生异常或中断,因此,指令集系统架构(ISA)还需要考虑异常和中断机制。 操作功能:用操作码表示,指定操作类型 源操作数参照:一个或多个源操作数所在的地址
指令
  • 零地址指令
    1. 无需操作数,如空操作、停机等
    2. 所需操作数为默认的,如堆栈、累加器等
  • 一地址指令
    1. 单目运算:如取反、取负等
    2. 双目运算:另一操作数为默认的,如累加器等
  • 二地址指令(最常用)
  • 三地址指令
  • 多地址指令
指令格式的设计
  • 应尽量短
  • 要有足够的操作码位数
  • 指令编码必须有唯一的解释,否则是不合法的指令
  • 指令字长应是字节的整数倍
  • 合理地选择地址字段的个数
  • 指令尽量规整
Note

一般通过对操作码进行不同的编码来定义不同的含义,操作码相同时,再由功能码定义不同的含义。

  • 操作码的全部组成:操作码个数、种类、复杂度 LD/ST/INC/BRN 四种指令已经足够编制任何可计算程序,但程序会很长
  • 数据类型:对哪几种数据类型完成操作
  • 指令格式:指令长度、地址码个数、各字段长度
  • 通用寄存器:个数、功能、长度
  • 寻址方式:操作数地址的指定方式
  • 下条指令的地址如何确定:顺序,PC+1,条件转移,无条件转移……
  • 异常和中断机制,包括存储保护方式等
数据类型
  • 地址(指针):被看成无符号整数,用来参加运算以确定主(虚)存地址
  • 数值数据
    • 定点数(整数):一般用二进制补码表示
    • 浮点数(实数):大多机器采用 IEEE754 标准
    • 十进制数:用 NBCD 码表示,压缩/非压缩(汇编程序设计时使用)
  • 位、位串、字符和字符串:用来表示文本、声音和图像等
    • 4bits = nibble, 8bits = byte
    • 16bits = half-word, 32bits = word
  • 逻辑(布尔)数据:按位操作(0-假/1-真)
Note

操作数存放在寄存器或内存单元中,也可以以立即数的形式存在

操作数及其寻址方式

Addressing Modes(寻址方式)
  • 寻址方式:指令或操作数地址的指定方式
  • 地址码编码由操作数的寻址方式决定
  • 地址码编码原则
    • 指令地址码尽量短→目标代码短,省空间
    • 操作数存放位置灵活,空间应尽量大→利于编译器优化产生高效代码
    • 地址计算过程尽量简单→指令执行快(可变长地址寻址需要计算)
  • 寻找方式的确定
    1. 没有专门的寻址方式位(由操作码确定寻址方式)
    2. 有专门的寻址方式位
  • 有效地址:操作数所在存储单元的地址(逻辑或物理),可通过指令的寻址方式和地址码计算得到
  • 基本寻址方式:立即、直接、间接 假设:A = 字段值,R = 寄存器编号,EA = 有效地址,(X) = X 中的内容
方式算法优点缺点操作数存储位置
立即数操作数 = A指令执行速度快操作数幅值有限指令寄存器
直接EA = A有效地址计算简单地址范围有限存储器
间接EA = (A)有效地址范围大多次存储器访问存储器
寄存器(直接)操作数 = (R)指令执行快,指令短地址范围有限寄存器
寄存器间接EA = (R)地址范围大额外存储器访问存储器
偏移EA = A + (R)灵活复杂存储器
EA = 栈顶指令短应用有限存储器
偏移寻址

指令组成:OP R A 指令中给出的地址码 A 成为形式地址。EA=A+(R),R 可以明显给出,也可以隐含给出。R 可以为 PC、基址寄存器 B、变址寄存器 I

  • 相对寻址:EA=A+(PC),相对于当前指令所处位移量为 A 的单元
    • 实现公共子程序、动态链接库(类似规定某条指令的数据永远来自其的下面几行,然后此指令在代码中多处出现)
  • 基址寻址:EA=A+(B),相对基址 B 所处位移量为 A 的单元
    • 多段程序转移(静态转移,将多段程序合在一起)
  • 变址寻址:EA=A+(I),相对于首地址 A 所处位移量为 I 的单元
    • 实现数组(每次会自动加/减数组元素的长度 x,即 I=(I)+x)

操作类型和操作码编码

操作类型
  • 算术逻辑运算指令
    • 加减乘除、比较、与或非、取反、取负、异或等
    • 算术运算包含整数和浮点数操作
  • 移位指令
    • 算术移位、逻辑移位、循环移位、半字交换
  • 数据传送指令
    • 寄存器间、内存-寄存器、内存内换
  • 顺序控制指令
    • 条件转移、无条件转移
    • 调用、返回
  • 系统控制指令
    • 停机、开中断、关中断、系统模式切换等
  • 输入/输出指令
Instruction Format(指令格式)
  • Fixed Length Opcodes(定长操作码法)
  • Expanding Opcodes(扩展操作码编法) 指令长度:
  • 代码长度更重要时:采用变长指令字、变长操作码
  • 性能更重要时:采用定长指令字、定长操作码 变长更紧凑,定长方便快速访问和译码。操作码长度和指令字长度没有绝对的关系。
定长操作码编码
  • 基本思想:指令的操作码部分采用固定长度的编码。
  • 特点:译码方便,但有信息冗余
扩展(变长)操作码编码
  • 基本思想: 将操作码的编码长度分成几种固定长的格式。被大多指令集采用。
  • 种类:等长扩展法:4-8-12;3-6-9;……/不等长扩展法

标志信息的生成与使用

条件测试方式

条件转移指令通常根据 Condition Code 转移,通过执行算数指令或显示地由比较和测试指令来设置 CC 常用的标志(条件码)有四种:

  • SF:negative
  • OF:overflow
  • CF:进位/借位
  • ZF:zero 标志可存于 FLAGs(称为标志寄存器/条件码寄存器/状态寄存器/程序状态字寄存器),也可由指定的通用寄存器来存放状态位
条件转移指令
  • 根据单个标志的值转移
  • 按无符号整数比较转移
  • 按带符号整数比较转移
转移指令并不是必须的

知道了 SF、OF、CF、ZF 即可判断并转移,其他判断则可以在程序设计阶段实现

指令设计风格

按照数据存储位置分类

累加器型 (Accumulator)

特点:其中一个操作数和目的操作数总在累加器中

  • 相当于 ALU 的其中一端始终是累加器 ACC,结果也存储在 ACC 中。 电路更加简单,但效率更低。
栈型 (Stack)

特点:总是将栈顶的两个操作数进行运算,指令无需指定操作数地址

通用寄存器型 (General Purpose Register)

特点:操作数可以是寄存器或存储器数据(即 A、B 和 C 可以是寄存器或存储单元)

装入/存储型 (Load/Store)

特点:运算操作只能是寄存器数据,只有 load/store 指令能访问存储器 访问寄存器的速度比访问主存快,可以加快计算速度。

指令风格比较
  • 指令字长
  • 所需指令数量
  • 指令执行周期
栈型累加器型寄存器型
(寄存器存储器通用型)
寄存器型
(装入存储型)
指令字长
所需指令数量较少较少
指令执行周期
说明

  • 累加器型所需指令数量较少,但因为所有运算都要使用累加器,表达式比较复杂时,会出现多次移入/移出累加器的指令,从而使累加器型所需指令数量迅速增加

寄存器型占据主导地位,优势:

  • 寄存器速度快,使用大量通用寄存器可减少访存操作
  • 表达式编译时与顺序无关(相对于 Stack 型)

按照指令设计的复杂度分类

复杂指令集计算机(CISC:Complex Instruction Set Computer) 精简指令集计算机(RISC:Reduced Instruction Set Computer)

CISC 的特点
  • 指令系统复杂:变长操作码、变长指令字、指令多、寻址方式多、指令格式多
  • 指令周期长:绝大多数指令需要多个时钟周期才能完成
  • 各种指令都能访问存储器:除了专门的存储器读写指令外,运算指令也能访问存储器
  • 采用微程序控制
  • 有专用寄存器
  • 难以进行编译优化来生成高效目标代码
CISC 的缺陷
  • 研制周期变长、难以保证设计正确性、难以调试和维护、降低系统性能
  • 指令出现的频率悬殊很大,常用的简单指令在程序指令中占大多数
RISC 的特点
  • 简化的指令系统:指令少、寻址方式少、指令格式少、指令长度一致
  • 以 RR 的方式工作:除 Load/Store 指令可访问存储器外,其余指令都只访问寄存器
  • 指令周期短:以流水线方式工作,除了 Load/Store 指令外,其他指令都需要一个或者不到一个时钟周期即可完成
  • 采用大量通用寄存器,以减少访存次数
  • 采用组合逻辑电路控制,不用或少用微程序控制
  • 采用优化的编译系统,力求有效地支持高级语言程序

异常和中断处理机制

  • 程序执行过程中,CPU 会遇到一些特殊情况,使正在执行的程序被“中断”
    • CPU 终止原来正在执行的程序,转到处理异常情况或特殊事件的程序去执行,结束后再回到原来终止的程序处(断点)继续执行
  • 程序执行被“中断”的事件有两类
    • 内部“异常”:在 CPU 内部发生的意外事件或特殊事件
      • 硬故障中断:如电源掉电、硬件线路故障等
      • 程序性中断:Exception 事件,如溢出、缺页、越界、越权、越级、非法指令、除数为 0、堆/栈溢出、访问超时、断点设置、单步、系统调用等。
    • 外部“中断”:在 CPU 外部发生的特殊事件,通过“中断请求”信号向 CPU 请求处理。如时钟、控制台、打印机缺纸、外设准备好、采样计时到、DMA 传输结束等。
  • 发生异常(Exception)和中断(Interrupt)事件后,系统将进入 OS 内核态对相应事件进行处理,即改变处理器状态(用户态→内核态)

第二讲 指令系统实例:RISC-V 架构

RISC-V 指令系统概述

  • 设计目标
    • 广泛的适应性:从最袖珍的嵌入式微控制器,到最快的高性能计算机
    • 支持各种异构处理架构,成为定制加速器的基础
    • 稳定的基础指令架构,并能灵活扩展,且扩展时不影响基础部分
  • 开源理念和实际原则
    • 指令集完全公开,且无需为指令集付费
    • 采用模块化设计,既保持基础指令集的稳定,也保证扩展指令集的灵活配置
    • 特点:具有模块化结构、稳定性和扩展性好,在简洁性、实现成本、功耗、性能和程序代码量等方面具有显著优势
  • 模块化结构
    • 核心(RV32I) + 标准扩展集(RV32M、RV32F、RV32D、RV32A) = RV32G
    • 32 位架构 RV32G = RV32IMAFD,其压缩指令集为 RV32C(指令长度为 16 位)
    • 64 位架构 RV64G = RV64IMAFD,其压缩指令集为 RV64C(指令长度为 16 位)
    • 向量计算 RV32V 和 RV64V;嵌入式 RV32E(RV32I 的自己,16 个通用寄存器)

RISC-V 指令参考卡和指令格式

指令卡

  • 核心指令集:基础整数指令集 RV32I 和 RV64I
  • 特权指令:陷阱指令对应的返回指令、wfi等待中断指令、sfence.vma 虚拟存储器的同步操作
  • 伪指令(一共有 60 个):
    • 如 MoVe rd, rs 指令实际执行了 ADDI rd, rs, 0 指令
  • 压缩指令集:RV32C 和 RV64C
    • 压缩指令的底层实现是通过电路转化为标准指令,然后用标准指令的电路进行实现
  • 扩展指令集:
    • 乘除运算指令集 RVM、原子操作指令 RVA、浮点运算指令集 RVF 和 RVD、向量操作指令集 RVV
  • 通用寄存器的调用约定:
    • 32 个定点通用寄存器 x0~x31;
    • 32 个浮点寄存器 f0~f31;
    • 通用寄存器 x0 中恒 0 ;x1 中返回地址;x2、x3 和 x4 分别为栈指针、全局指针和线程指针

指令格式

RISC-V 采用定长指令,共有6种指令格式:

  • R-型为寄存器操作数指令
  • I-型为短立即数或装入(Load)指令
  • S-型为存储(Store)指令
  • B-型为条件跳转指令
  • U-型为长立即数操作指令
  • J-型为无条件跳转指令 图注:
  • opcode:操作码字段
  • rd、rs1和rs2:通用寄存器编号
  • imm:立即数,其位数在括号[ ]中表示
  • funct3和funct7:分别表示 3 位功能码和 7 位功能码,和 opcode 字段一起定义指令的操作功能
16 位 RISC-V 压缩指令格式

每条 16 位指令都有功能完全相同的 32 位指令,在执行时由硬件先转换为 32 位指令再执行。目的是:缩短程序代码量,用少量时间换空间。

RISC-V 基础整数指令集

  • 整数运算类指令
    • 移位
    • 算术运算
    • 逻辑运算
    • 比较
  • 控制转移类指令
    • 分支
    • 跳转链接
  • 系统控制类指令
    • 同步
    • 环境
    • 控制状态寄存器
  • 存储访问类指令
    • 取数
    • 存数
符号扩展

  • 若为正数,则零扩展和符号扩展是一样的
  • 若为负数,则 SEXT[1101] = 1111 1101

统一起来,就是将最高位进行扩展

RISC-V 可选的扩展指令集

  • 标准扩展指令集
    • RV32I基础指令集之上,可标准扩展RV32M、RV32F/D、RV32A,以形成32位架构合集RV32IMAFD,也称为RV32G
    • RV32G基础上,对每个指令集进行调整和添加,可形成64位架构RV64G,原先在RV32G中处理的数据将调整为64位。但为了支持32位数据操作,每个64位架构指令集中都会添加少量32位数据处理指令。
  • RISC-V扩展集包括
    • 针对64位架构需要,在47条RV32I指令基础上,增加12条整数指令(+RV64I),包括6条32位移位指令、3条32位加减运算指令、两条64位装入(Load)指令和1条64位存储(Store)指令,故RV64I共59条指令。
    • 针对乘除运算需要,提供了32位架构乘除运算指令集RV32M中的8条指令,并在此基础上增加了4条RV64M专用指令(+RV64M)
    • 针对浮点数运算的需要,提供了32位架构的单精度浮点处理指令集RV32F和双精度浮点处理指令集 RV32D,并在此基础上分别增加了RV64F和RV64D专用指令集(+RV64F)和(+RV64D)。
    • 针对事务处理和操作原子性的需要,提供了32位架构原子操作指令集RV32A以及RV64A专用指令集 (+RV64A)。
    • 向量处理指令集RVV、未来可选扩展指令集RVB、RVE、RVH、……