指令被编码为由一个或多个字节序列组成的二进制格式。
一个处理器支持的指令和指令的字节级编码称为它的 指令集体系结构(Instruction-Set Architecture, ISA)。
定义一个指令集体系结构,包括:
- 定义各种状态元素
- 指令集和它们的编码
- 一组编程规范
- 异常事件处理
程序员可见状态
汇编语言可以读取或修改的处理器状态。
CPU 硬件实现并不一定存在这些组件,可以理解为这是 CPU 底层硬件开放给汇编语言的接口。
Y86 指令
指令格式
每条指令需要 1 ~ 6 个字节不等。
-
第 1 个字节:表明指令的类型
高 4 位:指令代码(code)部分 + 低 4 位:功能代码(function)部分
当一组指令共用一个指令代码时,功能代码部分才有用。
-
第 2 个字节:指令用到的寄存器地址 rA 和 rB
8 个程序寄存器分别对应 0 ~ 7 的寄存器标识符(register ID)。所以,可用 4 位来表示这些寄存器。
不需要访问任何寄存器时,就用 0xF 来表示。
-
第 3 ~ 5 共 4 个字节:常数字(constant word)
Y86 指令集基本上是 IA32 的子集。它只包括四字节整数运算,寻址方式比较少,操作也比较少。
好处是方便我们学习理解 CPU 的实现机制。
指令详解
MOV 数据传送指令
共 4 个,包括 irmovl
rrmovl
mrmovl
和 rmmmovl
。
首字母表示来源类型,第二个字母表示了目的类型。
字母 | 类型 |
---|---|
i | 立即数 |
r | 寄存器 |
m | 存储器 |
存储器引用方式为基址+偏移量形式(Imm(E)),上图中的常数字 D 就是偏移量。
OP 整数操作
共 4 个,包括 addl
subl
andl
和 xorl
。
如上图所示,只对寄存器数据进行操作。
这些指令会设置条件码 ZF、SF 和 OF(零、符号和溢出)。
JXX 跳转指令
共 7 个,包括 jmp
jle
jl
je
jne
jge
和 jg
。
根据条件码来选择分支。
CMOV 条件传送指令
共 6 个,包括 cmovle
cmovl
cmove
cmovne
cmoge
和 cmovg
。
他们与 rrmovl 一样,都是在两个寄存器之间传送数据,但是只有条件码匹配时,才会执行。
CALL 和 RET
call
指令将返回地址入栈,然后跳转到目的地址。ret
指令从这样的过程调用中返回。
PUSH 和 POP
pushl
和 popl
分别实现了入栈和出栈。
HALT
停止指令的运行,并将状态码设置为 HLT。
另外,
简单起见,跳转指令和 call
指令使用绝对地址,而不像 IA32 那样使用相对 PC 的相对寻址方式。
同 IA32 一样,所有整数采取小端法编码。所以,反汇编后,这些字节会以相反的顺序出现。
指令集的一个重要性质就是字节编码必须有唯一的解释。
Y86 每条指令的第一个字节有唯一的代码和功能组合,可以决定所有其他附加字节的长度和含义。
Y86 异常
状态码 Stat 描述了程序执行的总体状态。
对于 Y86,遇到非 AOK 的状态码时,只是简单地让处理器停止执行指令。在更完整的设计中,处理器通常会调用一个 异常处理程序(exception handler)。
一些 Y86 指令的详情
两个特别的指令组合需要注意:
pushl %esp
popl %esp
在下一篇中将会得到答案。