目录
一、指令的基本格式
二、指令字长
1. 定长指令字结构
2.变长指令字结构
三、地址码
1.四地址指令
2.三地址指令
3.二地址指令
4.一地址指令
5. 零地址指令
四、操作码
1. 定长操作码指令格式
2. 扩展操作码指令格式
五、指令的操作数类型和操作类型
1. 操作数类型
2. 指令的操作类型
计算机是通过连续执行一条条机器语言语句,而实现自动工作的。习惯上就把每一条机器语言的语句称为 指令,而把全部机器指令的集合称为机器的 指令系统。
-
指令(机器指令)是指计算机执行某种操作的机器语言命令。
-
一台计算机的所有指令的集合构成该计算机的 指令系统,也称 指令集。
指令系统是计算机的主要属性,位于硬件和软件的交界面上。
一、指令的基本格式
指令由 操作码 和 地址码(操作数地址) 两部分组成。
-
操作码:指出指令执行什么操作和具有何种功能。例如,指出是算术加运算,还是减运算;是程序转移,还是返回操作。
-
地址码:指岀被操作的信息(指令或数据)的地址,包括参加运算的一个或多个操作数的地址、运算结果的保存地址、程序的转移地址、被调用的子程序的入口地址等。
二、指令字长
指令字长 是指一条指令中所包含的二进制代码的位数,它取决于操作码的长度、操作数地址的长度和操作数的个数。不同机器的指令字长是不同的,指令字长通常取 8 的整数倍。
按照字长是否可变,又可以将指令系统分为 定长指令字结构 和 变长指令字结构。
1. 定长指令字结构
在一个指令系统中,若所有指令的长度都是相等的,称为 定长指令字结构(定字长指令)。
早期的计算机都是定长指令字结构,而且指令字长、机器字长、存储字长全部相等;这样每次访问某个存储单元,就可以取出一个完整的指令或者数据。
定字长指令的执行速度快,控制简单。精简指令系统计算机(Reduced Instruction Set Compter,RISC)采用定字长指令。
2.变长指令字结构
随着计算机的发展,存储容量不断增大,要求处理的数据类型也越来越多,指令字长发生了很大变化。一台计算机的指令系统可以采用不同长度的指令,比如单字长指令、多字长指令。
若指令系统中各种指令的长度随指令功能而异,就称为 变长指令字结构(变字长指令)。由于主存是按字节编址的,所以指令字长多为字节的整数倍。
控制变长指令的电路会比较复杂,而且多字长指令需要多次访问主存才能取出一条完整指令,导致了 CPU 速度降低。
原则上讲,短指令比长指令好,因为短指令能节省存储空间,提高取指令的速度,但也有很大的局限性。长指令占用更多的存储空间,取指令的时间也会更长,但其能扩大寻址范围或可带多个操作数。 如果长、短指令在同一机器中混合使用,就会给指令系统带来很大的灵活性。为了提高指令运行速度、节省存储空间,一般会尽可能地把常用的指令设计成单字长或者短字长的格式。
复杂指令系统计算机 (Complex Instruction Set Compter,CISC)采用变字长指令。
三、地址码
地址码 用来指出指令操作涉及到的数据或指令具体保存的位置,可以包括:
-
源操作数的地址(一个或两个)
-
操作结果的地址
-
下一条指令的地址
这里的 “地址” 一般指主存地址,也可以是寄存器的地址,甚至可以是 I/O 设备的地址。
我们以主存地址为例,分析一下地址码的分配。根据地址码字段的数量不同,可以把指令再做分类:
1.四地址指令
地址码字段最多的指令,可以包含所有的信息,共有四个地址字段:
其中 OP 是操作码;地址码 A~1~ 为第一操作数地址,A~2~ 为第二操作数地址,A~3~ 为结果地址,A~4~ 为下一条指令的地址。
这一指令完成的操作可以写作:
对 和 中存放的数据执行 OP 操作,得到的结果填入 ,然后再跳转到 位置执行下一条指令。后续指令地址可以任意填写。
假设采用定字长指令结构,指令字长为 32 位,操作码 OP 固定为 8 位。这样,每个地址码就应该占据 6 位,那么能够寻址的地址范围为 2^6^ = 64。
这里如果都是主存地址,那么完成这样的一条四地址指令,需要访问主存 4 次(取指令 → 取操作数 → 取操作数 → 结果写入 )。
2.三地址指令
程序中大多数指令都是顺序执行的,而程序计数器 PC 存放了当前要执行指令的地址,每次执行完会自动计算下一条指令的地址(“加 1”);所以一般并不需要在指令中直接给出下一条指令的地址,可以省去,这样就得到了三地址指令。
跟四地址指令一样,它也可以完成操作:
后续的指令地址隐含在 PC 中。如果指令字长仍为 32 位、操作码为 8 位,那么每个地址码也可以占据 8 位,能够寻址的地址范围为 2^8^ = 256。当然,完成这样一条指令同样需要 4 次访存。
3.二地址指令
如果将操作的结果直接保存在某个操作数地址对应的存储单元,就又可以在指令中节省一个地址,这样就得到了二地址指令。
它表示执行的操作为:
这里 既代表第一个源操作数的地址,也代表本次运算结果的存放地址。这种情况下,完成这一条指令同样需要 4 次访存(取指令 → 取操作数 → 取操作数 → 结果写入 )。
由于访存开销比较大,计算机运行过程中,可以将中间计算结果暂存在 CPU 的寄存器(如 ACC)中,这样就节省了最后写入主存的过程。这时的二地址指令表示执行的操作为:
这种情况下,完成指令只需要 3 次访存。如果指令字长仍为 32 位、操作码为 8 位,那么每个地址码可以占据 12 位,能够寻址的地址范围为 2^12^ = 4K。
4.一地址指令
自然可以想到,如果把二地址指令的两种情况结合起来,把某个操作数放在寄存器中,同时计算结果也放在寄存器中,那么就又可以节省一个地址了;这就是一地址指令。
它表示执行的操作为:
这里第一个操作数存放在 ACC 中,第二个操作数地址为 ,运算结果仍存放在 ACC 中。这样,完成指令只需要 2 次访存(取指令 → 取操作数 )。
当然,上面所讨论的都是需要两个操作数的情况;一些特殊的操作,可能只需要一个操作数,比如按位取反、自增自减操作。这时表示执行的操作为
因为得到的结果还要再写回到对应地址中,所以需要 3 次访存(取指令 → 取操作数 A~1~ → 结果写入 A~1~)。如果指令字长仍为 32 位、操作码为 8 位,那么地址码可以占据 24 位,能够寻址的地址范围为 2^24^ = 16M。
5. 零地址指令
在指令系统中,还有一种指令是没有地址码的,这就是零地址指令。零地址指令中只有操作码也可以分两种情况:
-
没有操作数的指令,比如空操作(NOP)、停机(HLT);
-
有一个隐含操作数的指令,比如子程序返回(RET)、中断返回(IRET),这类操作利用了栈数据结构,操作数的地址就隐含在堆栈指针(SP)中。
四、操作码
操作码的位数就代表了机器的操作种类,也就是机器指令集中的指令条数。操作码的长度可以是固定的,也可以是变化的。根据操作码长度是否可变,可以分为 定长操作码 和 变长操作码 两种指令格式。
1. 定长操作码指令格式
定长操作码指令,是在指令字的最高位部分分配固定的若干位(定长)表示操作码。一般 n 位操作码字段的指令系统最大能够表示 2^n^ 条指令。
这种指令格式便于计算机硬件设计,指令译码和识别时间短,广泛应用于字长较长的、大中型计算机和超级小型计算机以及 RISC(Reduced Instruction Set Compter,精简指令集计算机)中。当计算机字长为 32 位或更长时,这是常规做法。
2. 扩展操作码指令格式
可变长度操作码指令,是指全部指令的操作码字段的位数不固定,且分散地放在指令字的不同位置。显然,这将增加指令译码和分析的难度,使控制器的设计复杂化。
常见的可变长度操作码是 扩展操作码。在指令字长一定的条件下,操作码的长度随地址数的减少而增加,不同地址数的指令可以具有不同长度的操作码。
在设计扩展操作码指令时,需要注意两点:
-
不允许短操作码是长操作码的前缀;
-
各指令的操作码一定不能重复。
下面就是一种扩展操作码的示例。指令字长为 16 位,前 4 位为基本操作码字段 OP,另有 3 个 4 位的地址字段分别为 、、。
4 位基本操作码若全部用于三地址指令,则有 16 条。如果考虑到需要扩展到较少地址的指令,则将三地址指令减为 15 条,1111 留作扩展操作码使用;二地址指令为 15 条,1111 1111留作扩展操作码使用;一地址指令为 15 条,1111 1111 1111 留作扩展操作码使用;零地址指令为 16 条。
除了这种安排以外,还有其他多种扩展方法,如形成 15 条三地址指令、12 条二地址指令、63 条一地址指令和 16 条零地址指令,共 106 条指令;或者 12 条三地址指令、61 条二地址地址、47 条一地址指令和 16 条零地址指令。
在通常情况下,对使用频率较高的指令分配较短的操作码,对使用频率较低的指令分配较长的操作码,从而尽可能减少指令译码和分析的时间。
五、指令的操作数类型和操作类型
1. 操作数类型
计算机中常见的操作数类型有数字、地址、字符、逻辑数据等。
-
数字:计算机中常见的数字有定点数、浮点数和十进制数,它们分别用不同格式的二进制编码来表达。
-
地址:本质上也是一种数据,很多时候需要对操作数地址进行计算,可以认为是一个无符号整数。
-
字符:文本或者字符串也是一种常见的数据形式。计算机不能直接存储和传送数据,需要按一定规则对字符进行编码;广泛使用的是 ASCII 编码。
-
逻辑数据:除算术运算外,计算机还经常需要进行逻辑运算,此时二进制码中的 0 和 1 就应该被看作逻辑上的 “假” 和 “真”,参与逻辑与或非运算。这样的数据就是 “逻辑数据”。
2. 指令的操作类型
设计指令系统时必须考虑应提供哪些操作类型,指令操作类型按功能可分为以下几种。
(1)数据传送
数据传送指令通常有寄存器之间的数据传送(MOV)、从内存单元读取数据到 CPU 寄存器 (LOAD)、从CPU 寄存器写数据到内存单元(STORE)等。
(2)算术和逻辑运算
这类指令主要有加(ADD)、减(SUB)、比较(CMP)、乘(MUL)、除(DIV)、加1 (INC)、减1 (DEC)、与(AND)、或(OR)、取反(NOT)、异或(XOR)等。
(3)移位操作
移位操作指令主要有算术移位指令、逻辑移位指令、循环移位指令等。移位操作经常被用来替代简单的乘/除法运算。
(4)转移操作
转移操作指令主要有无条件转移(JMP)指令、条件转移(BRANCH)指令、调用(CALL)指令、 返回(RET)指令、陷阱(TRAP)指令等。
① 无条件转移指令
在任何情况下都执行转移操作,可以直接把程序转移到下一条要执行指令的地址。
例如:“ JMP X ”,就是无条件跳转到地址 X 去执行下一条指令。
② 条件转移指令
条件转移指令仅在满足特定条件时才执行转移操作,转移条件一般是一个或几个标志位的值。这些标志位是某些操作的结果,也叫做 “条件码”。例如:
-
零标志位(ZF),当结果为 0 时,ZF = 1;
-
负标志位(SF),结果为负时,SF = 1;
-
溢出标志位(OF),结果溢出时,OF = 1;
-
进位标志位(CF),最高位有进位时,CF = 1;
-
奇偶标志位(PF),结果为偶数时,PF = 1
这样,
“ JZ X ”,就表示判断结果是否为 0:如果为 0 就跳转到 X,如果不为 0 则继续顺序执行;
“ JO Y ”,就表示判断结果是否溢出:如果溢出就跳转到 Y,如果没有溢出则继续顺序执行;
“ JC Z ”,就表示判断结果最高位是否有进位:如果有进位就跳转到 Z,如果没有则继续顺序执行。
③ 调用和返回指令
调用指令可以实现从一个程序到另一个程序的转移操作。
程序中,有些特定的程序段会被反复调用。为了避免重复编写,可以将这些程序段设定为 子程序;需要调用时,只需要执行子程序调用指令就可以了。还有一些子程序是系统提供的,用户也可以直接调用。
调用指令(CALL)一般与 返回指令(RETURN)配合使用。CALL 用来从当前程序位置转移至子程序的入口,RETURN 则用于子程序执行完后重新返回到原程序的调用点。
调用指令和转移指令的区别:执行调用指令时必须保存下一条指令的地址(返回地址),当子程序执行结束时,根据返回地址返回到主程序继续执行;而转移指令则不返回执行。
④ 陷阱(Trap)指令
陷阱其实是一种意外事故引发的中断。比如,电压不稳定、I/O 设备发生故障、用户使用未定义的指令、除数为 0 等等各种意外事件,都会导致计算机不能继续正常工作。此时计算机就发出陷阱信号,暂定当前程序的执行,转入故障处理程序进行相应的处理。
计算机的陷阱指令一般不提供给用户使用,而是作为隐指令,在出现故障时由 CPU 自动产生并执行。
(5)输入输出操作
对于 I/O 单独编址的计算机,通常设有 I/O 指令。这类指令用于 CPU 与外部设备交换数据或传送控制命令及状态信息。
(6)其它操作
计算机中还有一些通用的控制操作,比如等待(WAIT)、停机(HLT)、空操作(NOP)、开关中断、置条件码等,都有相应的指令来完成。