8.1 取指、译码与执行
第 7 章把指令作为构造程序的工具。第 8 章将深入这一层之下:存储器中的位模式怎样变成寄存器、标志和存储器的受控变化?答案是指令周期(instruction cycle),也就是一组按依赖顺序执行的步骤:取得指令字节、解释含义、获取操作数、产生结果,再提交结果。
第 4 章介绍过 8086 的总线接口单元、执行单元与预取队列,这些单元可以重叠工作。因此,下面的阶段模型是追踪一条指令依赖关系的教学模型,并不表示真实芯片必须在五个僵硬方框之间让所有其他单元空闲。
一条指令依次改变不同种类的状态
一个有用的概念模型包含五个阶段:
1. 取指(fetch):从 CS:IP 指定的地址读取指令字节,并让 IP 越过这些字节。
2. 译码(decode):解释操作码字段、操作数宽度、寻址形式与指令长度。
3. 读取操作数:取得寄存器值、立即数或存储器操作数。
4. 执行(execute):让数据通过传送逻辑或算术逻辑单元(ALU)。
5. 写回(writeback):把结果锁存到选定的体系结构目的位置,并更新该指令规定的标志。
假设 ADD AX,BX 编码为 01 D8,AX=0001H、BX=0002H。取出两个字节后,IP 可以先从 0100H 变为 0102H,而 AX 还没有变化。译码识别 ADD、字宽度、AX 目的与 BX 源;操作数读取让 0001H 与 0002H 在内部可用;执行产生 0003H;直到写回使能 AX 锁存 0003H,AX 才改变。
这种分离解释了常见诊断线索:ALU 输出端已经出现正确值时,程序员可见的目的位置仍可能保持旧值。产生数值与提交状态是两件不同的事。
变长指令让边界成为译码的一部分
8086 指令并非都占相同字节数。操作码之后可能有 ModR/M 字节、位移、立即数,或这些部分的组合。存储器不会标记哪些字节是操作码。译码器必须从已知指令边界开始,再使用当前指令字段确定下一边界。
对于下面的字节流:
地址: 0100 0101 0102 0103 0104 0105 0106
字节: B8 34 12 40 75 FD F4顺序译码得到:
- 0100H–0102H:
B8 34 12→MOV AX,1234H
- 0103H:
40→INC AX
- 0104H–0105H:
75 FD→JNZ 0103H
- 0106H:
F4→HLT
相对分支位移 FDH 按有符号解释为 −3。它要加到两字节 JNZ 之后的 IP 上,因此目标=0106H−3=0103H。有效分支目标必须落在指令边界上;若落到 0101H,就会进入 MOV 立即数中间,使译码器把数据误当成操作码。
发生控制转移时,顺序下一 IP 会被目标地址替换。对 8086 来说,已经从放弃路径预取的字节也要作废,因为它们不再对应新 IP。第 8.4 节会把这部分无效工作与性能联系起来。
现在我们已经知道每个阶段必须产生什么信息。第 8.2 节将研究承载操作数、把数据送入 ALU 并向寄存器提交结果的硬件路线。