# 指令格式
# 操作码、地址码的概念
指令 (又称机器指令):是指示计算机执行某种操作的命令,是计算机运行的最小功能单位。
一台计算机的所有指令的集合构成该机的指令系统,也称为指令集
注:一台计算机只能执行自己指令系统中的指令,不能执行其他系统的指令
一条指令就是机器语言的一个语句,它是一组有意义的二进制代码。
# 指令格式
一条指令通常要包括操作码字段和地址码字段两部分
操作码 (OP):用户要干什么?(停机中断、求反求补、加减乘除、...)
地址码 (A):对谁进行操作?(不需要操作对象、需要一个操作对象、需要两个操作对象、...)
一条指令可能包含 0 个、1 个、2 个、3 个、4 个地址码...
根据地址码数量的不同,可以将指令分为零地址指令,一地址指令,二地址指令...
# 根据地址码数目不同分类
若指令总长度固定不变,则地址码数量越多,寻址能力越差
# 零地址指令
零地址指令:OP
- 不需要操作数,如空操作、停机、关中断等指令
- 堆栈计算机 (数据结构:后缀表达式),两个操作数隐含存放在栈顶和次栈顶,计算结果压回栈顶
# 一地址指令
一地址指令:OP+A1
- 只需要单操作数,如加 1,减 1,取反,求补等。
- 指令含义:,完成一条指令需要 3 次访存:取址 -> 读 A1-> 写 A1
- 需要两个操作数,但其中一个操作数隐含在某个寄存器 (如隐含在 ACC)
- 指令含义:,完成一条指令需要 2 次访存:取址 -> 读 A1
- 注: (类比:C 语言指针) 指某个主存地址,(指针所指位置的内容) 表示 所指向的地址中的内容
# 二、三地址指令
二地址指令:OP+A1 (目的操作数)+A2 (源操作数)
- 常用于两个操作数的算数运算、逻辑运算相关指令
- 指令含义:,完成一条指令需要 4 次访存:取址 -> 读 A1-> 读 A2-> 写 A1
三地址指令:OP+A1+A2+A3 (结果)
- 常用于两个操作数的算数运算、逻辑运算相关指令
- 指令含义:,完成一条指令需要 4 次访存:取址 -> 读 A1-> 读 A2-> 写 A3
# 四地址指令
四地址指令:OP+A1+A2+A3 (结果)+A4 (下址)
- 指令含义: 下一条将要执行指令的地址
- 完成一条指令需要访存 4 次,取址 -> 读 A1-> 读 A2-> 写 A3
- 正常情况下:取指令后 PC+1,指向下一条指令
- 四地址指令:执行指令后,将 PC 的值修改为 A4 所指地址
# 根据指令长度分类
指令字长:一条指令的总长度 (可能会变)
机器字长:CPU 进行一次整数运算所能处理的二进制数据的位数 (通常和 ALU 直接相关)
存储字长:一个存储单元中二进制代码位数 (通常和 MDR 位数相同)
半字长指令、单字长指令、双字长指令 —— 指令长度是机器字长的多少倍
指令字长会影响取指令所需时间。如:机器字长 = 存储字长 = 16bit,则取一条双字长指令需要两次访存
定长指令字结构:指令系统中所有指令的长度都相等
变长指令字结构:指令系统中所有指令的长度不等
# 根据操作码的长度不同分类
定长操作码:指令系统中所有指令的操作码长度都相同 (控制器的译码电路设计简单,但灵活性较低)
可变长操作码:指令系统中各指令的操作码长度可变 (控制器的译码电路设计复杂,但灵活性较高)
定长指令字结构 + 可变长操作码 -> 扩展操作码指令格式
# 根据操作类型分类
- 数据传送
- LOAD—— 作用:把存储器 (源) 中的数据放到寄存器 (目的) 中
- STORE—— 作用:把寄存器中的数放到存储器中
- 算数逻辑操作
- 算数:加、减、乘、除、增 1、减 1、求补、浮点运算、十进制运算
- 逻辑:与、或、非、异或、位操作、位测试、位清除、位求反
- 移位操作
- 算数移位、逻辑移位、循环移位 (带进位和不带进位
- 转移操作
- 无条件转移 JMP
- 条件转移 JZ:结果为 0;JO:结果溢出;JC:结果有进位
- 调用和返回 CALL 和 RETURN
- 陷阱 (Trap) 与陷阱指令
- 输入输出操作
- CPU 寄存器与 IO 端口之间的数据传送 (端口即 IO 接口中的寄存器)
总的来说:
数据传送类:进行主存与 CPU 之间的数据传送
运算类
程序控制类:改变程序执行的顺序
输入输出类 (I/O):进行 CPU 与 I/O 设备之间的数据传送
# 扩展操作码指令格式
# 扩展操作码举例
指令字长为 16 位,每个地址码占 4 位:前 4 位的基本操作码字段 OP,另有 3 个 4 位长的地址字段 和。
4 位基本操作码若全部用于三地址指令,则有 16 条。但至少需将 1111 留作扩展操作码之间,则三地址指令为 15 条;
1111 1111 留作扩展操作码之用,二地址指令为 15 条
1111 1111 1111 留作扩展操作码之间,一地址指令为 15 条;
零地址指令为 16 条
- 在设计扩展操作码指令格式时,必须注意以下两点:
- 不允许短码是长码的前缀,即短操作码不能与长操作码的前面部分的代码相同
- 各指令的操作码一定不能重复
通常情况下,对使用频率较高的指令,分配较短的操作码;对使用频率较低的指令,分配较长的操作码,从而尽可能减少指令译码和分析的时间。
Example:
设指令字长固定位 16 位,试设计一套指令系统满足:
a) 有 15 条三地址指令 | 0000~1110 | A1 | A2 | A3 | |
---|---|---|---|---|---|
b) 有 12 条二地址指令 | 1111 XXXX XXXX XXXX | 1111 | 0000-1011 | A1 | A2 |
c) 有 62 条一地址指令 | 1111 11XX XXXX XXXX | 1111 | 1100-1110|1111 | 0000-1111|0000-1101 | A1 |
d) 有 32 条零地址指令 | 1111 1111 111X XXXX | 1111 | 1111 | 1110~1111 | 0000-1111 |
设地址长度为 n,上一层留出 m 种状态,下一层可扩展出 中状态
# 指令操作码
操作码指出指令中该指令应该执行什么性质的操作和具有何种功能。
操作码是识别指令、了解指令功能与区分操作数地址内容的组成和使用方法等的关键信息。
操作码分类:
- 定长操作码:在指令字的最高位部分分配固定的若干位 (定长) 表示操作码
- 一般 n 位操作码的指令系统最大能够表示 条指令
- 优:定长操作码对于简化计算机硬件设计,提高指令译码和识别速度很有利
- 缺:指令数量增加时会占用更多固定位,留给表示操作数地址的位数受限
- 扩展操作码 (不定长操作码):全部指令的操作码字段的位数不固定,且分散地放在指令字的不同位置上。
- 最常见的变长操作码方法是扩展操作码,使操作码的长度随地址码的减少而增加,不同地址数的指令可以具有不同长度的操作码,从而在满足需要的前提下,有效地缩短指令字长
- 优:在指令字长有限的前提下仍保持比较丰富的指令种类
- 缺:增加了指令译码和分析的难度,使控制器的设计复杂化
# 指令寻址
程序计数器 PC:指明下一条指令的存放地址
每次取指令之后,PC 一定会自动加 1,指向下一条应该执行的指令 (即在执行本条指令之前,PC 已经 + 1 指向下一条指令)
下一条指令地址:(PC)+1->PC
下一条欲执行的指令的地址 (始终由程序计数器 PC 给出)
系统采用定长指令字结构时,指令字长 = 存储字长 = 16bit=2B,主存按字编址 ——(PC)+1->PC
系统采用定长指令字结构时,指令字长 = 存储字长 = 16bit=2B,主存按字节编址 ——(PC)+2->PC
系统采用变长指令字结构时,指令字长 = 存储字长 = 16bit=2B,主存按字节编址 —— 读入一个字,根据操作码判断这条指令的总字节数 n,修改 PC 的值,(PC)+n->PC
根据指令的类型,CPU 可能还要进行多次访存,每次读入一个字
顺序寻址:(PC)+"1"(这里的 1 理解为 1 个指令字长,实际加的值会因指令长度,编址方式而不同)->PC
跳跃寻址:由跳转指令给出
# 数据寻址
数据寻址:确定本条指令的地址码指明的真实地址
- 相对寻址、基址寻址、变址寻址、堆栈寻址、隐含寻址、立即寻址、直接寻址、间接寻址、寄存器寻址、寄存器间接寻址
在地址码前面加上寻址方式位,指令 = 操作码 (OP)+ 寻址特征 + 形式地址 (A)
求出操作数的真实地址,称为有效地址 (EA)
假设指令字长 = 机器字长 = 存储字长,操作数为 3
# 直接寻址
直接寻址:指令字中形式地址 A 就是操作数的真实地址 A,即 EA=A
一条指令的执行:
- 取指令:访存 1 次
- 执行指令:访存 1 次
- 暂不考虑存结果,共访存 2 次
优点:简单,指令执行阶段仅访问一次主存,不需要专门计算操作数的地址
缺点:A 的位数决定了该指令操作数的寻址范围。操作数的地址不易修改
# 间接寻址
间接寻址:指令的地址字段给出的形式不是操作数的真正地址,而是操作数有效地址所在的存储单元的地址,也就是操作数地址的地址,即 (EA)=A。(可分为一次间接寻址与多次间接寻址)
一条指令的执行:
- 取指令:访存 1 次
- 执行指令:访存 2 次
- 暂不考虑存结果,共访存 3 次
优点:可扩大寻址范围 (有效地址 EA 的位数大于形式地址 A 的位数),便于编制程序 (用于间接寻址可以方便地完成子程序返回)
缺点:指令在执行阶段要多次访存 (一次间址需要两次访存,多次访存需根据存储字的最高位确定几次访存)
# 寄存器寻址
寄存器寻址:在指令中直接给出操作数所在的寄存器编号,即 EA=Ri,其操作数在由 Ri 所指的寄存器内。
一条指令的执行:
- 取指令:访存 1 次
- 执行指令:访存 0 次
- 暂不考虑存结果,共访存 1 次
优点:指令在执行阶段不访问主存,只访问寄存器,指令字短且执行速度快,支持向量 / 矩阵运算
缺点:寄存器价格昂贵,计算机中寄存器个数有限
# 寄存器间接寻址
寄存器间接寻址:寄存器 Ri 中给出的不是一个操作数,而是操作数所在主存单元的地址,即 EA=(Ri)
一条指令的执行:
- 取指令:访存 1 次
- 执行指令:访存 1 次
- 暂不考虑存结果,共访存 2 次
特点:比一般间接寻址更快,但指令的执行阶段需要访问主存 (因为操作数在主存中)
# 隐含寻址
隐含寻址:不是明显地给出操作数的地址,而是在指令中隐含着操作数的地址
例如 ADD 指令,会指明一个操作数的地址,但另一个操作数的地址隐含在操作中,即另一个操作数在 ACC 内
优点:有利于缩短指令字长
缺点:需要增加存储操作数或隐含地址的硬件
# 立即寻址
立即寻址:形式地址 A 就是操作数本身,又称为立即数,一般采用补码形式。# 表示立即寻址特征
- 取指令:访存 1 次
- 执行指令:访存 0 次
- 暂不考虑存结果,共访存 1 次
优点:指令执行阶段不访问主存,指令执行时间最短
缺点:A 的位数限制了立即寻址的范围。如 A 的位数为 n,且立即数采用补码时,可表示数据范围为~
# 偏移寻址
以某个地址为起点,形式地址视为 "偏移量"
三种偏移寻址区别在于偏移的起点不一样。
# 相对寻址
EA=(PC)+A,以程序计数器 PC 所指地址作为起点
相对寻址:把程序计数器 PC 的内容加上指令格式中的形式地址 A 而形成操作数的有效地址,即 EA=(PC)+A,其中 A 是相对于 PC 所指地址的位移量,可正可负,补码表示
优点:操作数的地址不是固定的,它随着 PC 值的变化而变化,并且与指令地址之间总是相差一个固定值,因此便于程序浮动 (一段代码在程序内部的浮动)
注意:取出当前指令后,PC 会指向下一条指令,相对寻址是相对于下一条指令的偏移
相对寻址广泛应用于转移指令
拓展:ACC 加法指令的地址码,可采用 "分段" 方式解决,即程序段、数据段分开
# 基址寻址
EA=(BR)+A,以程序的起始存放地址作为起点
基址寻址:将 CPU 中基址寄存器 (BR) 的内容加上指令格式中形式地址 A,而形成操作数的有效地址,即 EA=(BR)+A
- 采用专用寄存器 BR 作为基址寄存器 (操作系统中,重定位寄存器就是基址寄存器)
- 采用通用寄存器作为基址寄存器 (在指令中指明,要将哪个通用寄存器作为基址寄存器使用)
- 指令 = OP + 寻址特征 + Ri+A,Ri 占几个 bit 由通用寄存器总数决定
优点:便于程序 "浮动",方便实现多道程序并发运行
采用基址寻址无需修改指令中的地址码
拓展:程序运行前,CPU 将 BR 值修改为该程序的起始地址 (存在操作系统 PCB 中)
注意:
基址寄存器是面向操作系统的,其内容由操作系统或管理程序确定。在程序执行过程中,基址寄存器的内部不变 (作为基地址),形式地址可变 (作为偏移量)
当采用通用寄存器作为基址寄存器时,可由用户决定哪个寄存器作为基址寄存器,但其内容仍由操作系统决定
优点:可扩大寻址范围 (基址寄存器位数大于形式地址 A 的位数);用户不必考虑自己的程序存于主存的哪一空间区域,故有利于多道程序设计,以及可用于编制浮动程序 (整个程序在内存里边的浮动)
# 变址寻址
EA=(IX)+A,程序员自己决定从哪里作为起点
变址寻址:有效地址 EA 等于指令字中形式地址 A 与变址寄存器 IX 的内容相加之和,即 EA=(IX)+A,其中 IX 可为变址寄存器 (专用),也可用通用寄存器作为变址寄存器
注意:变址寄存器是面向用户的,在程序执行的过程中,变址寄存器的内容可由用户改变 (IX 作为偏移量),形式地址 A 不变 (作为基地址)
优点:在数据处理过程中,可设定为数组的首地址,不断改变变址寄存器 IX 的内容,便可很容易形成数组中任一数据的地址,特别适合编制循环程序。
硬件比较数的大小:
- 本质上是两个数相减,通过进位 / 错位标志,零标志,符号标志,溢出标志来比较两个数的大小
# 堆栈寻址
堆栈寻址:操作数存放在堆栈中,隐含使用堆栈指针 (SP) 作为操作数地址
堆栈是存储器 (或专用寄存器) 中一块特定的按 "后进先出 (LIFO)" 原则管理的存储区,该存储区中被读 / 写单元的地址是一个特定的寄存器给出的,该寄存器称为堆栈指针 (SP)。
硬堆栈:用专门的寄存器来保存堆栈信息,执行指令时无需访存
软堆栈:在主存中划分出一片区域作为堆栈,执行指令时需要访存
堆栈可用于函数调用时保存当前函数的相关信息