指令集体系结构 ¶
约 2536 个字 30 行代码 预计阅读时间 9 分钟
Abstract
计算机系统 Ⅰ 第十一~十二周课程内容
参考:
- 逻辑与计算机设计基础(第五版) 第九章、指令集体系结构
ISA 概念 ¶
指令 ¶
指令(instruction)= 操作符(opcode)+ 操作数(operand)
指令格式包含长度、操作数个数、寄存器个数、寻址内存大小、寻址模式等
指令集 ¶
CPU 可以“理解”的一系列指令,以二进制机器码(machine code)的形式表现
指令集体系结构 ¶
规定了所有硬件实现的指令、规定了指令符号名称、二进制编码格式,提供了每条指令精确定义的”手册“即指令集体系结构(ISA,Instruction Set Architecture)
计算机根据 ISA 实现,ISA 可以有多种实现、ISA 使软件可以操纵硬件、ISA 定义了机器语言,ISA 规定了微处理器(microprocessor)的设计(ISA 定义了 CPU 或者一类 CPU,它包含 CPU 的内存视图、寄存器个数等信息,而不只是一系列指令的集合)
注:体系结构覆盖整个计算机,包括 ISA、组成和硬件,而不仅仅是 ISA。ISA 也不是 CPU 的体系结构(同一 ISA 有不同种 CPU)
ISA 设计 ¶
设计原则 ¶
指令格式设计原则 ¶
- 指令长度要短
- 为新的 opcode 留出足够空间
- 有区分性的编码
- 设计好操作数的个数
- 设计好指令的对齐模式
- 保持规范化
ISA 设计原则 ¶
- Simplicity favors regularity
- Make the common case fast
- Smaller is faster
- Good design demands good compromises
操作数 ¶
操作数个数 ¶
一般没有 4 个或以上操作数的指令,这样每个操作数不一定都会用上,而且会增加 CPU 的复杂度,并且使指令变长
大部分指令集均有 0/1/2/3 个操作数。下面以计算 Y = (A - B) / (C + (D * E)) 为例子
三操作数指令 ¶
可以有两个源操作数和一个目的操作数
三操作数的指令优点是可以很灵活地指定结果存放在哪里,计算表达式的程序很短,缺点是二进制编码指令时需要用较多位数来指定三个地址二操作数指令 ¶
压缩目的操作数到源操作数,也就是用一个源操作数同时代表目的
但是这样会更改 ABCDE 原来的值,所以需要通过 MOV 类指令来暂存用做计算: 所以它会比三操作数指令的指令条数更多一操作数指令 ¶
可以通过继续隐藏一个操作数的方法来构造出一操作数的指令,比如规定运算中的一个操作数和目的都为 Acc(累加器)
LDA D ; Acc <- D
MUL E ; Acc <- Acc * E
ADD C ; Acc <- Acc + C
STO R1 ; R1 <- Acc
LDA A ; Acc <- A
SUB B ; Acc <- Acc - B
DIV R1 ; Acc <- Acc / R1
零操作数指令 ¶
因为是零操作数,所以指令运算中的三个地址都是隐式的,可以使用栈来操作,即每次运算取出栈顶两个元素然后运算后将结果压回栈中
PUSH B ; B
PUSH A ; B, A
SUB ; A-B
PUSH E ; A-B, E
PUSH D ; A-B, E, D
MUL ; A-B, D*E
PUSH C ; A-B, D*E, C
ADD ; A-B, C+D*E
DIV ; (A-B)/(C+D*E)
可见操作数越多,指令越复杂但程序包含的指令条数少;操作数越多,指令越简单,指令执行越快,但程序包含的指令条数也会越多
寻址模式 ¶
在指令执行的过程中,如何获取操作数取决于指令的寻址模式。寻址模式指定了一个在实际访问操作数之前,解释或调整指令地址字段的规则,用这个规则可以生成操作数的有效地址(effective address
寻址模式可以指定到常数、寄存器和内存地址。高效的寻址模式设计可以减少指令的长度。下面是一些常见的寻址模式
立即数寻址 ¶
立即数寻址(immediate addressing)即操作数就在指令当中,也就是指令中有一个操作数字段就代表了这个常数本身而不是地址。
直接寻址 ¶
直接寻址(direct addressing)即操作数作为内存地址,直接读取该地址处的值进行操作,也就是指令中有 ADRS,但实际用的是 M[ADRS]
这就有了一个问题,如果是 32 位的地址,指令也是 32 位的,不能放下完整的地址,所以一般使用段地址和偏移地址配合,隐含一个段地址,然后 ADRS 仅使用偏移地址。但是直接寻址需要在汇编的时候就知道准确的地址位置
直接寻址的地址也可以代表一个寄存器
间接寻址 ¶
间接寻址(indire addressing)即操作数中包含内存地址,这个内存地址处的值还是一个地址,这个地址所指向的位置是实际要用的数。也就是指令中有 ADRS,但实际用的是 M[M[ADRS]]
ADRS 必须在汇编的时候固定,但是 ADRS 所指向的位置可以是变化的,这样可以使访问数组这样的操作变得更方便
ADRS 也可以是一个寄存器
变址寻址与基址寻址 ¶
二者很相似,都是将寄存器值与地址加起来的和作为实际要访问的地址
- 变址寻址(indexed addressing
) ,寄存器保存的是偏移地址,指令中地址保存的是基地址 - 基址寻址(based addressing
) ,寄存器保存的是基地址,指令中地址是偏移地址
总结:
寻址模式 | 表示法 | 含义 |
---|---|---|
立即数寻址 | #K | K |
直接寻址 | K | M[K] |
间接寻址 | (K) | M[M[K]] |
寄存器寻址 | (Rn) | M[Rn] |
寄存器变址寻址 | (Rm+Rn) | M[Rm+Rn] |
寄存器基址寻址 | (Rm+X) | M[Rm+X] |
寄存器基址变址寻址 | (Rm+Rn+X) | M[Rm+Rn+X] |
操作类型及编码 ¶
操作类型 ¶
一般的指令集都包含下面这些种操作类型:
- 算数运算、逻辑运算
- 移位运算
- 数据传送(MOV/LOAD/STORE 之类)
- 字符串运算
- 控制流变化(BRANCH/JMP/CALL/RET 等)
- 系统指令(HALT/INT 等)
- 输入输出
- ...
指令编码 ¶
指令编码的长度有几种
- 变长(Variable
) :每条指令的长度都不一定 - 定长(Fixed
) :所有指令都是同一长度 - 混合(Hybrid
) :有多种指令的长度
一般如果代码的大小最重要的话选择变长指令,如果是执行表现最重要的话选择定长指令。而一些为了兼容,可能会选择混合长度指令
RISC 与 CISC ¶
CISC¶
CISC(Complex Instruction Set Computer)即复杂指令集计算机
- 编程和执行之间的语义间隔(semantic gap)小
- 程序机器码体积小
- 编译过程简单
CISC 类型的指令集体系结构有 x86、Intel 432、IBM 360、DEC VAX 等
RISC¶
RISC(Reduced Instruction Set Computer)即精简指令集计算机
- 由 IBM 发明
- RISC 的指令很少,而且每个指令简单,长度固定
- CISC 每增加一个指令都会使解码变慢,从而使整个 ISA 都会变慢,但 RISC 不会
- 运算的操作数都是寄存器(reg-reg)
- 编译会更复杂
RISC 类型的指令集体系结构有 RISC I、RISC II、MIPS、ARM、RISC V 等
CISC 与 RISC 区别:
CISC | RISC |
---|---|
变长指令 | 定长指令 |
大量指令和寻址模式 | 指令和寻址模式都很少 |
编码长、复杂 | 编码简单 |
包含从内存到内存的操作 | 只能存 / 取 |
使用微指令 | 没有微指令,一切都直接从指令中解码出来 |
语义间隔小 | 需要更智能的编译器 |
CISC 和 RISC 在发展中也不应完全割裂
寻址结构 ¶
寻址结构有几种:
- 累加器结构,Accumulator(1960 前,如 68HC11)
- 栈结构,Stack(1960s ~ 1970s)
- 存储器到存储器结构,Memory-Memory(1970s ~ 1980s)
- 寄存器到存储器结构,Register-Memory(1970s 至今,如 x86)
- 寄存器到寄存器结构,Register-Register(1960s 至今,如 MIPS
) ,又称装载 / 存储结构(Load/Store)
栈结构 ¶
- ALU 运算没有操作数,push/pop 有一个操作数
- 优点
- 指令短
- 硬件要求低
- 编译器好写
- 缺点
- 效率低
- 栈空间有限
- 并行或流水线能力弱
- 编译器难优化
- 例子:60 年代的 B5500/6500 HP3000/70,现在的 Java 虚拟机
累加器结构 ¶
- 使用单个操作数(一个显式一个隐含)
- 指令有 ALU 运算、加载到累加器、从累加器输出到存储器
- 优点
- 硬件要求极低
- 易于设计、理解
- 缺点
- 累加器成为瓶颈
- 并行 / 流水线能力弱
- 需要的 load store 很多,内存读写频繁
- 例子:早期 IBM 7090 等,现在的 DSP 结构
存储器到存储器结构 ¶
- 所有的 ALU 运算都从存储器读写
- 优点
- 无需使用寄存器
- 需要的指令数量少
- 容易写编译器
- 缺点
- 指令长度变化大
- 每条指令执行的时间浮动也大
- 巨大的存储器读写导致效率低
- 例子:VAX
寄存器到存储器结构 ¶
- ALU 操作中有一个存储器
- 一般指令有两个操作数
- 优点
- 指令数量少
- 指令易于编解码
- 缺点
- 运算结果会覆盖原值
- 指令长度变化大
- 指令运行时间变化大
- 可能会限制寄存器个数
- 例子:IBM 360/370、VAX
装载 / 存储结构 ¶
- ALU 指令中不需要存储器
- 一般指令有三个操作数
- 优点
- 简单、定长的指令编码
- 指令运行的时间变化小
- 易于进行流水线
- 缺点
- 指令个数多
- 并不是所有操作都有三个操作数
- 需要更好的编译器
- 例子:CDC6600、CRAY-1、大部分 RISC
寄存器的优缺点
- 优点
- 比存储器读写更快
- 更明确
- 需要更少比特就能定位使用哪个寄存器
- 节省内存读写
- 缺点
- 在进行过程调用的时候需要保护寄存器(存储 / 恢复)
- 不能取一个寄存器的地址
- 寄存器可存储的长度固定
- 编译器需要更好的管理寄存器
- 寄存器个数有限
RISC-V ISA¶
创建日期: 2022年5月29日 12:21:50