CA3 指令集体系结构

机器指令

包含:存储地址、寄存器地址、立即数

  • 操作码 opcode
    • 操作内容 add,mult
    • 操作数 int,fp
  • 操作数 operand
    • 位置(寄存器或储存器)
    • 操作数个数不定(1个或2个)

指令运行

  • PC 存放的当前执行的指令在内存中的地址(32bit or 64bit)
  • PC 输出到指令存储器 IM(只读)
  • IM 传到 IR
  • IR 译码器 到 通用寄存器 GPRs
  • GPRs 包含 rs1->rd1 rs2->rd2 ws wd
  • 输出到 A B 两个寄存器,通过 MUX 选择输出到 ALU
  • ALU 运算输出结果,可以写到 DM 中,也可以写入 寄存器 wd 中

定义

  • 是软件和硬件之间的边界
  • 是程序员或编译器所见到的计算机
  • 在某种意义上,是由一组所使用的汇编语言及它们所完成的工作来定义的

指令集体系结构里包含的基本内容

寄存器、存储器寻址和寻址方式、指令操作数、有效操作、控制流指令、指令编码……

设计目标

较短的指令宽度

  • 最小化指令宽度,从而最小化程序长度

较好的指令密度(完成一件事情需要的指令数要少)

  • 最小化指令数目,从而最小化程序长度

快速的指令操作

  • 如:add (100) (200) (300) 执行的时间比 add r1 r2 r3 要长

简单的电路实现

优化的编译器

指令集体系结构类型

  • 堆栈型(Stack)(早期)
    • 所有操作数都来自堆栈
  • 累加器型(Accumulator)
    • 一个操作数在累加器中,另一个操作数必须显式地引用
  • 寄存器型(Register)(现在主要使用)
    • 所有操作数必须显式地引用
    • 操作数可以存储在寄存器或存储器中

寄存器型指令集体系结构

  • 操作数必须有明显的操作数格式
    • 寄存器在 CPU 内部
  • 指令集体系结构提供
    • LOAD 存储器 -> 寄存器
    • STORE 寄存器 -> 存储器
  • 这种体系结构也被称为通用寄存器 General-Purpose Register 指令集体系结构
  • 分为三种类型
    • 寄存器-存储器 ISA
    • 寄存器-寄存器 ISA(装入-存储 ISA)——现代 CPU 常用结构
    • 存储器-存储器 ISA——废弃

寄存器-寄存器 ISA

  • 特殊指令访问存储器:LOAD、STORE
  • 基本运算步骤
    • 从存储器装入第一个操作数到寄存器中
    • 从存储器装入第二个操作数到寄存器中
    • 在 ALU 中完成运算操作
    • 如果需要,将操作结构存储到存储器中
  • 两个操作数和结果的位置都需要显式地引用

寄存器数目

  • 现代指令集体系结构倾向于拥有更多的寄存器
  • 拥有更多的寄存器使得编译器拥有更多的机会来提高效率
  • 通常,编译器预留一些寄存器用于特殊目的
    • 保留函数调用的参数
    • 帮助表达式求值
  • 剩余的寄存器用于保存程序变量

存储器寻址

  • ISA 必须定义存储器的寻址方式

    • 如何解释
    • 如何在指令中说明
  • 绝大多数的存储器寻址采用字节地址

    • 能够寻址的最小存储器片段是一个字节

    • 意味着每个字节拥有一个使用二进制串表示的地址

  • 通常,ISA 可以访问

    • 字节 8bit
    • 半字 16bit
    • 字 32bit
    • 双字 64bit

存储对齐

  • 当大多数计算机访问大于一个字节的对象时,往往必须对齐

  • 定义:如果访问对象地址是对象长度 S 的倍数时,称问访问对象是对齐的

    (objectss address) mod S=0(objects’s\ address)\ mod\ S=0

  • 例如

    • 在000000 访问一个 byte 是对齐的
    • 在000001 访问一个 半字 是未对齐的

字节顺序

  • 在半字、字和双字内的字节存在着两种约定
    • 小端法 0x0000 的字节放的最低有效位
    • 大端法 0x0000 的字节放的最高有效位
  • 某些体系结构可以通过设置来决定采用哪种字节顺序
  • 在绝大多数情况下不必关系字节顺序问题,但
    • 当以双字和字节方式访问相同存储位置时,可能出现问题
    • 当在计算机之间交换数据时,可能出现问题

寻址方式

寄存器寻址(直接写寄存器号得到寄存器的内容)

立即数寻址(立即数前加个#)

位移寻址(寄存器内容加上外部偏移量寻址)

寄存器间接寻址(将寄存器的内容作为地址来寻址)

索引寻址(两寄存器内容之和作为内存地址)

直接寻址(mem[100],直接写死地址)

存储器间接寻址(寄存器的内容作为mem地址进行寻址,再将这个mem读出的值作为地址来寻址,mem[mem[regs[R3]]])

自动增/减量寻址(寄存器简介寻址后该寄存器的值自增/减)

比例寻址(mem[100+regs[R2]+regs[R3]*d])

基准程序中各种寻址方式的频度

选择寻址方式:平衡

  • 寻址方式的选择

    • 一些 ISA 选择所有的寻址方式,如 WAX
    • 另一些 ISA 只使用少数几种寻址方式,如 MIPS
  • 平衡因素

    • 寻址方式越多,IC(指令数) 越低
    • 寻址方式越多,硬件越复杂
    • 寻址方式越多,CPI(指令周期数) 越高
  • 目标:平衡

    • 简化硬件
    • 拥有足够的寻址方式,以至于书写代码不会太痛苦

选择位移范围

  • 权衡考虑
    • 位移最大值越大,指令使用范围越广
    • 位移最大值越小,指令编码越短

操作数类型和大小

  • 字符 1byte
  • 半字 2byte
  • 字 4byte
  • 单精度浮点和长整数 4byte
  • 双精度浮点 8byte

各种类型操作

  • 算术和逻辑(通用)

    • 整数加减乘除、与或运算
  • 数据传输(通用)

    • 装入、存储
  • 控制(通用)

    • 分支、跳转、过程调用和返回、陷阱
  • 系统(可变)

    • 操作系统调用、管理虚拟内存指令
  • 浮点数(可选)

    • 加减乘、比较
  • 字符串(可选)

    • 字符串比较、字符串搜索
  • 图形(可选)

    • 像素点和顶点操作,压缩与解压操作

指令编码

  • 关键考虑因素

    • 拥有更多的寄存器和寻址方式,会造成较长的指令代码
    • 期望降低平均指令代码长度和平均程序长度
    • 期望指令能够容易且快速译码
  • 指令编码方法

    • 可变格式(满足前二)
    • 固定格式(满足第三)
    • 混合格式(尝试达到平衡)
  • 可变的,如 intel 的 VAX;固定的,如 RISC-V,ARM,MIPS,PowerPC,SPARC;混合的

编译优化

  • 高层优化
    • 针对源代码进行,可能是源到源的转换
    • 如:为了 cache 有效性来映射数据,除去条件等
  • 局部优化
    • 在较短的直线段源代码中优化代码
  • 全局优化
    • 跨过分支指令进行优化,循环优化(循环展开)
  • 寄存器分配
    • 寄存器赋初值

CISC vs RISC

  • 谬误:“简约指令集”并不意味着指令数目少
  • RISC 的关键
    • 寄存器中完成操作
    • 使用 LOAD 和 STORE 指令完成寄存器和存储器之间的通信
    • 代码是由一系列简单操作实现的
  • 注解:当代码量是关键因素时,RISC 并不是一个好的选择