5、 指令格式
约 3563 字大约 12 分钟
2025-06-18
- 零地址指令
不需要操作数,如空操作、停机、关中断等指令 堆栈计算机,两个操作数隐含存放在栈顶和次栈顶,计算结果压回栈顶
- 一地址指令
1.只需要单操作数,如加1、减1、取反、求补等指令含义:OP(A1)→A1,完成一条指令需要3次访存:取指→读A1→写A1 2.需要两个操作数,但其中一个操作数隐含在某个寄存器(如隐含在ACC)指令含义:(ACC)OP(A1)-ACC完成一条指令需要2次访存:取指→读A1
- 二地址指令
常用于需要两个操作数的算术运算、逻辑运算相关指令 指令含义:(A1)OP(A2)→A1 完成一条指令需要访存4次,取指→读A1→读A2→写A1
- 三地址指令
常用于需要两个操作数的算术运算、逻辑运算相关指令 指令含义:(A1)OP(A2)→A3
- 四地址指令
指令含义:(A1)OP(A2)→A3,A4=下一条将要执行指令的地址 完成一条指令需要访存4次,取指→读A1→读A2→写A3
正常情况下:取指令之后PC+1,指向下一条指令 四地址指令:执行指令后,将PC的值修改位A4所指地址
指令字长:一条指令的总长度 (可能会变) 机器字长:CPU进行一次整数运算所能处理的二进制数据的位数(通常和ALU直接相关) 存储字长:个存储单元中的二进制代码位数(通常和MDR位数相同)
按指令长度分类 定长指令字结构:指令系统中所有指令的长度都相等 变长指令字结构:指令系统中各种指令的长度不等
按操作码长度分类 定长操作码:指令系统中所有指令的操作码长度都相同 可变长操作码:指令系统中各指令的操作码长度可变
扩展操作码指令格式 定长指令字结构+可变长操作码
指令寻址
顺序寻址
若是定长的指令则程序执行的时候程序计数器pc只需要加上固定的指令字长就可以了 如果是边长的指令,程序执行的时候会根据其前面的操作码确定这个指令的长度是多少按照相应的指令给pc加上正确的值来取正确的指令
跳跃寻址
根据转移类的指令来确定下一个要运行的指令的地址
数据寻址
确定本指令的地址码指向的真实地址 第一种情况7代表的是数据的地址 第二种情况7代表着相对于程序入口的偏移量 第三个情况3代表着基于程序计数器pc向后偏移的位置 要区分数据寻址的方式需要在操作码和形式地址中间插入一个4bit 的寻址特征
对于而地址指令有两个地址因此需要给两个形式地址各设置一个寻址特征
寻址方式 | 特征码 |
---|---|
隐含寻址 | 0000 |
立即寻址 | 0001 |
直接寻址 | 0010 |
间接寻址 | 0011 |
寄存器寻址 | 0100 |
寄存器间接寻址 | 0101 |
相对寻址 | 0110 |
基址寻址 | 0111 |
变址寻址 | 1000 |
堆栈寻址 | 1001 |
直接寻址
指令字中的地址就是操作数的真实地址 优点:简单,指令执行阶段仅访问一次主存不需专门计算操作数的地址 缺点:A的位数决定了该指令操作数的寻址范围操作数的地址不易修改
间接寻址
指令的地址字段给出的形式地址不是操作数的真止地址,而是操作数有效地址所在的存储单元的地址,也就是操作数地址的地址,即EA=(A)。 优点:可扩大寻址范围(有效地址EA的位数大于形式地址A的位数)。便于编制程序(用间接寻址可以方便地完成子程序返回)。
寄存器寻址
在指令字中直接给出操作数所在的寄存器编号,即EA=R,其操作数在由R;所指的寄存器内。 优点:指令在执行阶段不访问主存,只访问寄存器指令字短且执行速度快,支持向量/矩阵运算 缺点:寄存器价格昂贵,计算机中寄存器个数有限
寄存器间接寻址
寄存器R;中给出的不是一个操作数,而是操作数所在主存单元的地址,即EA=(R;)。 特点:与一般间接寻址相比速度更快但指令的执行阶段需要访问主存(因为操作数在主存中)。
隐含寻址
不是明显地给出操作数的地址,而是在指令中隐含着操作数的地址。 优点:有利于缩短指令字长 缺点:需增加存储操作数或隐含地址的硬件
立即寻址
形式地址A就是操作数本身,又称为立即数,一般采用补码形式。#表示立即寻址特征。
优点:指令执行阶段不访问主存,指令执行时间最短 缺点:A的位数限制了立即数的范围。如A的位数为n,且立即数采用补码时,可表示的数据范围为-2n-1~2n-1-1
偏移寻址
基址寻址、变址寻址、相对寻址都是偏移寻址,区别在于偏移的起点不一样
基址寻址
以程序的起始存放地址作为起点 将CPU中基址寄存器(BR)的内容加上指令格式中的形式地址A而形成操作数的有效地址,即EA=(BR)+A 重定位寄存器就是基址寄存器
有的计算机使用通用寄存器作为基址寄存器,这时就需要在指令中指明要将哪个寄存器作为基址寄存器 优点:便于程序浮动,方便实现多道程序并发运行
注:基址寄存器是面向操作系统的,其内容由操作系统或管理程序确定。在程序执行过程中,基址寄存器的内容不变(作为基地址),形式地址可变(作为偏移量)。 当采用通用寄存器作为基址寄存器时,可由用户决定哪个寄存器作为基址寄存器但其内容仍由操作系统确定
变址寻址
程序员自已决定从哪里作为起点(以变址寄存器IX存储的地址作为起点) 有效地址EA等于指令字中的形式地址A与变址寄存器X的内容相加之和,即EA=(IX)+A,其中Ix可为变址寄存器(专用),也可用通用寄存器作为变址寄存器。 注:变址寄存器是面向用户的,在程序执行过程中,变址寄存器的内容可由用户改变(Ix作为偏移量),形式地址A不变(作为基地址)
相对寻址
以程序计数器PC所指地址作为起点 把程序计数器PC的内容加上指令格式中的形式地址A而形成操作数的有效地址,即EA=(PC)A,其中A是相对于PC所指地址的位移量,可正可负,补码表示。
堆栈寻址
操作数存放在堆栈中,隐含使用堆栈指针(SP)作为操作数地址
X86汇编
常用指令
mov
#mov指令功能:将源操作数s复制到目的操作数d所指的位置
mov 目的操作数d,源操作数s
#将寄存器ebx的值复制到寄存器 eax
mov eax,ebx
#将立即数5复制到寄存器 eax
mov eax,5
#将内存地址af996h所指的32bit值复制到寄存器 eax
mov eax,dword ptr [af996h]
#将立即数5 复制到内存地址 af996h 所指的一字节中
mov byte ptr [af996h],5
#将 ebx 所指主存地址的 32bit 复制到 eax 寄存器中
mov eax, dword ptr [ebx]
#将 ebx+8 所指主存地址的 32bit 复制到eax 寄存器中(偏移8位)
mov eax, dword ptr [ebx+8]
指明读写的长度 dword ptr 双字,32bit word ptr 单字,16bit byte ptr 字节,8bit 若没有指明读取的数据长度默认是32bit
[] 表示取地址
汇编中的地址都是十六进制
x86架构的CPU中的寄存器
通用寄存器可以存任意数据 X是未知表示不知道寄存器中存储的是什么数据
变址寄存器通常用于线性表和字符串的处理 堆栈寄存器用于函数实现
对于通用寄存器如果指令中不带e,如:mov ax,bx 此时代表只使用该寄存器的低16比特 且通用寄存器还可以使用更灵活直接使用低8bit,语法: mov ah,bl ah表示eax寄存器低16bit的前8bit,bl表示ebx寄存器低16bit的后8bit
而变址寄存器和堆栈寄存器只能固定使用32比特
指令对数据的操作有三种情况,一种是数据在寄存器中,这时指定寄存器即可,一种是数据在主存中需要指明其主存的逻辑地址,还有一种是直接数据可直接写在指令中
destination:目的地(d目的操作数)。source:来源地(s源操作数)
算数运算指令
指令 | 作用 |
---|---|
add d,s | 计算d+s,结果存入d |
sub d,s | 计算d-s,结果存入d |
mul d,s | 无符号数d*s,乘积存入d |
imul d,s | 有符号数d*s,乘积存入d |
div s | 无符号数除法edx:eax/s,商存入eax,余数存入edx |
idiv s | 有符号数除法edx:eax/s,商存入eax,余数存入edx |
neg d | 将d取负数,结果存入d |
inc d | 将d++,结果存入d |
dec d | 将d--,结果存入d |
对于将结果存入d的指令,不允许d是常量,只能是寄存器或内存 | |
对于两个数的操作不允许两个操作数都来自主存,是为了不让每条指令访问太多次主存,访问太多次主存会影响运行速度 |
逻辑运算指令
指令 | 操作 |
---|---|
and d,s | d和s逐位相与,结果放入d |
or d,s | d和s逐位相或,结果放入d |
not d | d逐位取反,结果放回d |
xor d,s | d和s逐位异或,结果放入d |
shl d,s | 将d逻辑左移s位,结果放回d(通常s是常量) |
shr d,s | 将d逻辑右移s位,结果放回d(通常s是常量) |
同样的d操作数不可以是常数 |
用于实现分支结构、循环结构的指令:cmp、test、jmp、jxxx 用于实现函数调用的指令、push、pop、call、ret 用于实现数据转移的指令:mov
AT&T格式和Intel格式
程序计数器pc(program counter)有时也被称为ip(instruction pointer)
实现分支循环的指令
指令 | 作用 |
---|---|
jmp d | 无条件跳转指令,指令无条件跳转到地址d |
cmp a,b | 比较a和b两个数 |
je d | jump when equal若a==b则跳转。ZF==1 |
jne d | jump when not equal若a!=b则跳转。ZF==0 |
jg d | jump when greater than若a>b则跳转。ZF==0 && SF==OF |
jge d | jump when greater than若a>=b则跳转。SF==OF |
jl d | jump when less than若a<b则跳转。SF!=OF |
jle d | jump when less than or equal to若a<=b则跳转。SF!=OF || ZF==1 |
jmp的地址可以以常量给出即目标地址,也可以取寄存器中的值,也可以取内存中的值 | |
但直接给定值就很不灵活,如果程序改变跳转的地址就不是想要的地址了 | |
可以使用锚点,锚点名可以任意取 |
mov eax,7
mov ebx,6
jmp NEXT
mov ecx,edx
NEXT:
mov ecx,eax
这样即使程序的地址发生改变依旧可以跳转到需要的位置
cmp指令比较的底层原理是使两个操作数放到ALU中进行相减操作,得到四个标志位:
- OF(OverflowFlag)溢出标志。溢出时为1,否则置0
- SF(SignFlag)符号标志。结果为负时置1,否则置0
- ZF(ZeroFlag)零标志,运算结果为O时ZF位置1,否则置0
- CF(CarryFlag)进位/借位标志,进位/借位时置1,否则置0 标志位存入PSW程序状态字寄存器(Intel称为标志寄存器),8086芯片中标志寄存器有16位 0位存CF标志位,6位存ZF标志位,7位存SF标志位,11位存OF标志位
函数调用
指令 | 作用 |
---|---|
call 函数名 | 调用函数 |
ret | 函数返回 |
#定义函数add
add:
push ebp
mov ebp,esp
mov eax,[ebp+12]
mov edx,[ebp+8]
add eax,edx
leave
ret #函数返回
call add #调用add函数
call指令的作用:
- 将IP旧值压栈保存(保存在函数的栈帧顶部)
- 设置P新值无条件转移至被调用函数的第一条指令 ret指令的作用: 从函数的栈帧顶部找到IP旧值将其出栈并恢复IP寄存器
CISC和RISC
CISC
complex instruction set computer复杂指令集的计算机系统 代表:x86架构,主要用于笔记本、台式机等 80-20规律:典型程序中的80%的语句仅仅使用处理机的20%的指令
RISC
reduced instruction set computer精简指令集的计算机系统 代表:arm架构,主要用于手机、平板等
贡献者
版权所有
版权归属:PinkDopeyBug