指令系统全:基本概念、寻址方式、CISC/RISC与x86机器级代码表示。
4.1 指令系统的基本概念
4.1.1 指令执行过程的描述
以取数指令为例,描述指令执行过程:
取指令:$(PC) \to MAR \to M \to MDR \to IR$
- 将PC的内容送往MAR,MAR内容送地址线。
- 主存根据地址读出指令送到数据线。
- MDR从数据线接收指令,传送到IR。
分析指令:$OP(IR) \to CU$
- 将IR中指令的操作码部分送控制器进行译码。
执行指令:$AD(IR) \to MAR \to M \to MDR \to ACC$
- 将IR中的地址码送MAR。
- 主存根据地址取出操作数,经MDR传送到ACC。
更新PC:$(PC) + 1 \to PC$,计算下一条指令地址。
注意:
- 括号表示寄存器中的内容,箭头左边需加括号,右边不加。
- 多个箭头时,除第一个寄存器外,其余可省略括号。
- 若要求每条语句只描述一次传输,需严格使用括号。
4.1.2 指令集体系结构 (ISA)
指令系统是ISA的核心部分,ISA定义了软件与硬件的接口,包括:
- 指令格式、寻址方式、操作类型。
- 操作数类型、存放方式(大端/小端)。
- 可访问的寄存器、存储空间编址。
- 指令执行控制方式(PC、条件码等)。
4.1.3 指令的基本格式
指令由操作码和地址码组成:
| 字段 | 作用 |
|---|---|
| 操作码 | 指出指令执行的操作 |
| 地址码 | 给出操作数或操作数地址 |
指令字长
- 与机器字长无固定关系,可为单字长、半字长、双字长。
- 定长指令字:所有指令长度相等。
- 变长指令字:指令长度随功能变化。
按地址码数量分类
| 类型 | 格式 | 说明 |
|---|---|---|
| 零地址 | OP |
无操作数(如空操作)或隐含操作数(如堆栈) |
| 一地址 | OP A1 |
单操作数:OP(A1) → A1双操作数隐含ACC: (ACC) OP (A1) → ACC |
| 二地址 | OP A1, A2 |
(A1) OP (A2) → A1 |
| 三地址 | OP A1, A2, A3 |
(A1) OP (A2) → A3 |
| 四地址 | OP A1, A2, A3, A4 |
(A1) OP (A2) → A3,A4为下一条指令地址 |
4.1.4 可变长度操作码(扩展操作码)
- 通过减少地址码位数来增加操作码位数。
- 规定:短码不能是长码的前缀,操作码不可重复。
示例
指令字长16位,地址码4位:
- 三地址指令:15条(1111留作扩展)
- 二地址指令:15条(1111 1111留作扩展)
- 一地址指令:15条(1111 1111 1111留作扩展)
- 零地址指令:16条
典型例题
设指令字长16位,地址码6位。二地址指令15条,一地址指令34条,求零地址指令最多多少条?
解法:
- 二地址:操作码4位,0000~1110共15条。
- 一地址:操作码10位,最高4位为1111,剩余6位,最多64条。用其中34条(如11110 00000 ~ 11111 00001)。
- 零地址:操作码16位,最高5位为11111,次5位为00010~11111(30种),低6位任意,共 $30 \times 2^6$ 条。
4.2 指令的寻址方式
4.2.1 形式地址与有效地址
- **形式地址 (A)**:指令中给出的地址码。
- **有效地址 (EA)**:操作数在存储器中的真实地址。
4.2.2 常见寻址方式
| 寻址方式 | 有效地址 EA | 访存次数 | 特点 |
|---|---|---|---|
| 隐含寻址 | 隐含(如ACC) | 0 | 缩短指令字长 |
| 立即寻址 | A 即操作数 | 0 | 速度快,但立即数范围受限 |
| 直接寻址 | EA = A | 1 | 简单,但寻址范围小 |
| 间接寻址 | EA = (A) | 2(一级) | 扩大寻址范围 |
| 寄存器寻址 | EA = Ri | 0 | 速度快,寄存器有限 |
| 寄存器间接寻址 | EA = (Ri) | 1 | 扩大范围,速度快 |
| 相对寻址 | EA = (PC) + A | 1 | 用于转移指令,程序浮动 |
| 基址寻址 | EA = (BR) + A | 1 | 面向OS,动态重定位 |
| 变址寻址 | EA = (IX) + A | 1 | 面向用户,数组访问 |
| 堆栈寻址 | 隐含 SP | 0/1 | 栈操作 |
基址与变址对比:
- 基址:BR不变,A可变(偏移量),面向系统。
- 变址:IX可变,A不变(基地址),面向用户。
4.3 CISC 与 RISC 的基本概念
| 特性 | CISC | RISC |
|---|---|---|
| 指令数量 | 多(>200) | 少 |
| 指令长度 | 不固定 | 固定 |
| 指令格式 | 多 | 少 |
| 寻址方式 | 多 | 少 |
| 访存指令 | 不受限 | 仅 LOAD/STORE |
| 通用寄存器 | 较少 | 多 |
| 控制器 | 微程序 | 硬布线 |
| 流水线 | 难实现 | 必须支持 |
| 指令执行时间 | 相差大 | 大多单周期 |
4.4 程序的机器级代码表示(x86)
4.4.1 常用汇编指令
寄存器
- 32位通用寄存器:EAX, EBX, ECX, EDX, ESI, EDI, EBP, ESP
- 低16位:AX, BX, CX, DX
- 8位:AH/AL, BH/BL, CH/CL, DH/DL
- ESP(栈指针),EBP(基址指针)
指令格式(Intel风格)
- 目标操作数在前,源操作数在后。
- 内存寻址用
[],如[eax + ebx*2 + 8]。 - 数据长度:
byte ptr、word ptr、dword ptr。
数据传送指令
1 | mov eax, ebx ; ebx → eax |
算术与逻辑指令
1 | add eax, ebx ; eax + ebx → eax |
控制流指令
1 | label: ; 标签 |
4.4.2 选择语句的机器级表示
C语言 if-else 结构:
1 | if (op1 == op2) { |
对应汇编:
1 | mov eax, op1 |
4.4.3 循环语句的机器级表示
编译器将 for/while 转换为 do-while 形式。
示例:自然数求和
1 | int sum = 0; |
转换为 do-while 形式后,对应汇编:
1 | mov eax, 0 ; sum = 0 |
4.4.4 过程调用的机器级表示
调用过程(P调用Q)
- P将参数放到Q能访问的位置。
- P保存返回地址,
call Q转移控制。 - Q保存P的现场(被调用者保存寄存器)。
- Q分配局部变量空间。
- 执行Q。
- Q恢复现场,将返回值放入
eax。 ret返回P。
调用者保存与被调用者保存
| 类型 | 寄存器 | 职责 |
|---|---|---|
| 调用者保存 | EAX, ECX, EDX | 调用者负责保存和恢复 |
| 被调用者保存 | EBX, ESI, EDI | 被调用者负责保存和恢复 |
栈帧
- EBP:当前过程栈帧基址(固定)
- ESP:栈顶指针(动态变化)
- 栈向低地址增长
示例:过程调用与栈帧
1 | int add(int x, int y) { return x + y; } |
汇编实现(caller部分):
1 | caller: |
栈帧结构示意
1 | 高地址 |
备考tips
- 指令执行过程:重点关注微操作序列与数据通路结合题。
- 扩展操作码:掌握计算最大指令数的方法。
- 寻址方式:区分基址与变址,理解有效地址计算。
- CISC vs RISC:对比记忆,关注RISC特点(LOAD/STORE架构)。
- 汇编与C对应:能根据C代码写出关键汇编片段,或反之理解程序逻辑。
- 过程调用:理解栈帧变化、参数传递、返回值存放(eax)。