所有指令都有1个共同特点,就是如果有2个操作数的话,两个操作数不能同时在内存
数据传送类指令
数据传送指令都不影响标志位
通用数据传送指令
传送指令MOV
定义:
- 把一个字节或字的操作数从源地址传送至目的地址
- MOV不影响标志位
举例:
例1:立即数传送
- mov al,4 ;al←4,字节传送,是一条将立即数4(十进制)移动到寄存器AL(即8位的累加器)的指令
- mov cx,0ffh ;cx←00ffh,字传送,传送前要根据高位补齐一条将立即数0xFF(十六进制)移动到寄存器CX(即16位的计数器)的指令
- mov si,200h ;si←0200h,字传送
- mov byte ptr [si],0ah ;byte ptr
说明是字节操作,将立即数0x0A(十六进制)移动到以SI寄存器作为基址的内存位置。这里的
byte ptr
指定了操作数的大小为一个字节,[si]
表示SI寄存器中的地址处。因此,这条指令将0x0A写入到SI寄存器指向的内存地址中。 - mov word ptr [si+2],0bh ;word ptr 说明是字操作
注: 注意立即数是字节量还是字量,明确指令是字节操作还是字操作
例2:寄存器传送
mov ax,bx ;ax←bx,字传送 mov ah,al ;ah←al,字节传送 mov ds,ax ;ds←ax,字传送 mov [bx],al ;[bx]←al,字节传送
例3:存储器传送
mov al,[bx] mov dx,[bp] ;dx←ss:[bp] mov es,[si] ;es←ds:[si]
不存在存储器向存储器的传送指令
小结
非法传送
两个操作数的类型不一致 例如源操作数是字节,而目的操作数是字;或相反
常见错误:对于存储器单元与立即数同时作为操作数的情况,必须显式指明;byte ptr指示字节类型,word ptr指示字类型
就是想MOV word ptr[ax] 000AH
两个操作数不能都是存储器 传送指令很灵活,但主存之间的直接传送却不允许
段寄存器的操作有一些限制 段寄存器属专用寄存器,对他们的操作能力有限
- 不允许立即数传送给段寄存器 MOV DS,100H ;非法指令:立即数不能传送段寄存器
- 不允许直接改变CS值 MOV CS,[SI] ;不允许使用的指令
- 不允许段寄存器之间的直接数据传送 MOV DS,ES ;非法指令:不允许段寄存器间传送
交换指令XCHG
XCHG不影响标志位
寄存器与寄存器之间对换数据
mov ax,1234h ;ax=1234h mov bx,5678h ;bx=5678h xchg ax,bx ;ax=5678h,bx=1234h xchg ah,al ;ax=7856h
寄存器与存储器之间对换数据
xchg ax,[2000h] ;字交换 等同于 xchg [2000h],ax xchg al,[2000h] ;字节交换 等同于 xchg [2000h],al
不能在存储器与存储器之间对换数据
换码指令XLAT
定义
- 将BX指定的缓冲区中、AL指定的位移处的一个字节数据取出赋给AL
- XLAT不影响标志位
堆栈操作指令
SS指向的基准量,SP指向的是“偏移量”,计算SP指向的物理地址需要加上SS* 10H
堆栈的操作
PUSH ;进栈指令先使堆栈指针SP减2,然后把一个字操作数存入堆栈顶部
【例】 PUSH BX 指令执行前: SS=4000H,SP=2000H,BX=3248H
POP ;出栈指令把栈顶的一个字传送至指定的目的操作数,然后堆栈指针SP加2
注
- 堆栈操作的单位是字,进栈和出栈只对字量
- 字量数据从栈顶压入和弹出时,都是低地址字节送低字节,高地址字节送高字节
- 堆栈操作遵循先进后出原则,但可用存储器寻址方式随机存取堆栈中的数据
- 堆栈常用来
- 临时存放数据
- 传递参数
- 保存和恢复寄存器
标志传送指令
定义
- 标志寄存器传送指令用来传送标志寄存器FLAGS的内容
- 标志位操作指令直接对CF、DF、IF标志进行复位或置位
标志寄存器传送
标志低字节进出AH指令
1 | LAHF ;AH←FLAGS的低字节 |
LAHF指令将标志寄存器的低字节送寄存器AH SF/ZF/AF/PF/CF状态标志位分别送入AH的第7/6/4/2/0位,而AH的第5/3/1位任意
1 | SAHF ;FLAGS的低字节←AH |
SAHF将AH寄存器内容送FLAGS的低字节 用AH的第7/6/4/2/0位相应设置SF/ZF/AF/ PF/CF标志
标志寄存器进出堆栈指令
1 | PUSHF ;SP←SP-2 |
PUSHF指令将标志寄存器的内容压入堆栈,同时栈顶指针SP减2
1 | POPF |
POPF指令将栈顶字单元内容送标志寄存器,同时栈顶指针SP加2
举例
1 | pushf ;保存全部标志到堆栈 |
标志位操作
进位标志操作指令
用于任意设置进位标志
CLC(Clear Carry Flag) ;复位进位标志:CF←0
STC(Set Carry Flag) ;置位进位标志:CF←1
CMC(Complement Carry Flag) ;求反进位标志:CF←~CF
方向标志操作指令
串操作指令中,需要使用
CLD ;复位方向标志:DF←0
STD ;置位方向标志:DF←1
中断标志操作指令
在编写中断服务程序时,需要控制可屏蔽中断的允许和禁止 CLI ;复位中断标志:DF←0 STI ;置位中断标志:DF←1
地址传送指令
定义:
- 地址传送指令将存储器单元的逻辑地址送至指定的寄存器
- 有效地址传送指令 LEA
- 指针传送指令 LDS和LES
- 注意不是获取存储器单元的内容
有效地址传送指令LEA(load EA)
定义:
将存储器操作数的有效地址传送至指定的16位寄存器中
举例:
1 | mov bx,0400h |
注
- 获得主存单元的有效地址;不是物理地址,也不是该单元的内容
- 可以实现计算功能
LDS
格式
1 | LDS r16,mem |
LDS指令将主存中mem指定的字送至r16,并将mem的下一个字,地址就是在MEM基础上加2送DS寄存器
1 | 比如 |
LES
格式
1 | LES r16,mem |
LES指令将主存中mem指定的字送至r16,并将mem的下一字送ES寄存器
算术运算类指令
状态标志
常用状态标志: 进位标志CF、溢出标志OF 零位标志ZF、符号标志SF 奇偶标志PF
进位标志CF(Carry Flag)
定义:
当运算结果的最高有效位有进位(加法)或借位(减法)时,进位标志置1,即CF = 1;否则CF = 0。
注:最高有效位不一定非要是16位寄存器AX等的最高位
举例:
1 | 3AH + 7CH=B6H ;没有进位:CF = 0 |
溢出标志OF(Overflow Flag)
若算术运算的结果有溢出,则OF=1; 否则 OF=0
溢出和进位的区别
首先什么是溢出
处理器内部以补码表示有符号数 8位表示的整数范围是:-128~+127 16位表示的整数范围是:-32768~+32767 如果运算结果超出这个范围,就产生了溢出 有溢出,说明有符号数的运算结果不正确
举例:
3AH+7CH=B6H,就是58+124=182, 已经超出-128~+127范围,产生溢出,故OF=1; 另一方面,补码B6H表达真值是-74, 显然运算结果也不正确
本质区别
进位标志表示无符号数运算结果是否超出范围,超出范围后加上进位或借位运算结果仍然正确; 溢出标志表示有符号数运算结果是否超出范围,超出范围后运算结果不正确。
溢出和进位的对比
举例:
例1:3AH + 7CH=B6H 无符号数运算: 58+124=182 范围内,无进位 有符号数运算: 58+124=182 范围外,有溢出
用二进制运算表示
例2:AAH + 7CH=(1)26H 无符号数运算: 170+124=294 范围外,有进位 有符号数运算: -86+124=38 范围内,无溢出
二进制表示
如何运用溢出和进位
如果将参加运算的操作数认为是无符号数,就应该关心进位;
认为是有符号数,则要注意是否溢出
溢出的判断
当两个相同符号数相加(包括不同符号数相减),而运算结果的符号与原数据符号相反时,产生溢出
零标志ZF(Zero Flag)
若运算结果为0,则ZF = 1; 否则ZF = 0
符号标志SF(Sign Flag)
运算结果最高位为1,则SF = 1;否则SF = 0
奇偶标志PF(Parity Flag)
当运算结果最低字节中“1”的个数为零或偶数时,PF = 1;否则PF = 0
辅助进位标志AF(Auxiliary Carry Flag)
运算时第3位(低半字节)有进位或借位时,AF = 1;否则AF = 0。
加法
加法指令ADD
定义:
ADD指令将源与目的操作数相加,结果送到目的操作数
举例:
1 | mov al,0fbh ;al=0fbh |
带进位加法指令ADC
定义:
ADC指令将源与目的操作数相加,再加上进位CF标志,结果送到目的操作数
ADC指令主要与ADD配合,实现多精度加法运算
1 | mov ax,4652h ;ax=4652h |
增量指令INC(increment)
- INC指令对操作数加1(增量)
- INC指令不影响进位CF标志,按定义设置其他状态标志
减法
减法指令SUB(subtract)
定义:
SUB指令将目的操作数减去源操作数,结果送到目的操作数
1 | mov al,0fbh ;al=0fbh |
带借位减法指令SBB
1 | mov ax,4652h ;ax=4652h |
减量指令DEC(decrement)
定义
- DEC指令对操作数减1(减量)
- DEC指令不影响进位CF标志,按定义设置其他状态标志
求补指令NEG(negative)
定义:
NEG指令对操作数执行求补运算:用零减去操作数,然后结果返回操作数
求补运算也可以表达成:将操作数按位取反后加1
NEG指令对标志的影响与用零作减法的SUB指令一样
NEG对CF和OF的影响
根本原因:虽然人在计算的时候是求反加1,但CPU运算是用0-操作数
1 | mov ax,0ff64h |
比较指令CMP(compare)
- CMP指令将目的操作数减去源操作数,按照定义相应设置状态标志
- CMP指令执行的功能与SUB指令相同,但结果不回送目的操作数
1 | cmp al,100 ;al-100 |
经典例题
题1:
【例】: 设X、Y、Z均为双精度数。其存放地址为:X,X+2,Y,Y+2,Z,Z+2。存放时,高位字在高位地址,低位字存放在低地址中。 试编程完成 W←X+Y+24-Z ,结果存放在W和W+2单元。
总结
1. 用DX、AX表示双精度数
2. 低位用AX,高位用DX
3. 先用非进位运算低位,再用进位运算高位
1 | MOV AX,X ;用DX,AX来表示双精度数 |
乘法指令(MUL/IMUL)
乘法指令的源操作数显式给出,隐含使用另一个操作数AX和DX
- 字节量相乘:AL与r8/m8相乘,得到16位的结果,存入AX
- 字量相乘:AX与r16/m16相乘,得到32位的结果,其高字存入DX,低字存入AX
乘法指令如下影响OF和CF标志:
MUL指令——若乘积的高一半(AH或DX)为0,则OF=CF=0;否则OF=CF=1
解释:
OF = 1表示溢出,因为原来是8(或者16位),高一半不为0说明现在的乘积超过8位(或者16位)。原来是8位现在就是16位,原来是16位现在就是32位
CF = 1表示进位,因为原来是8位(或者16位),高一半不为0说明原来的8位(或者16位)的有效位的最高位发生进位
IMUL指令——若乘积的高一半是低一半的符号扩展,则OF=CF=0;否则均为1
举例:
1 | mov al,0b4h ;al=b4h=180 |
除法指令(DIV/IDIV)
除法指令的除数显式给出,隐含使用另一个操作数AX和DX作为被除数
字节量除法:AX除以r8/m8,8位商存入AL,8位余数存入AH
字量除法:DX.AX除以r16/m16,16位商存入AX,16位余数存入DX
被除数位数至少是除数1倍
被除数远大于除数时,所得的商就有可能超出它所能表达的范围。如果存放商的寄存器AL/AX不能表达
便产生溢出,8086CPU中就产生编号为0的内部中断——除法错中断
- 对DIV指令,除数为0,或者在字除时商超过8位,或者在字除时商超过16位
- 对IDIV指令,除数为0,或者在字节除时商不在-128~127范围内,或者在字除时商不在-32768~32767范围内
举例
1 | mov ax,0400h ;ax=400h=1024 |
对进位标志CF的影响
- 会修改CF
- ADD/ADC
- SUB/SBB
- 不会修改CF
- INC
- DEC
- 不确定
- MUC/IMUL
- DIV/IDIV
符号扩展指令(CBW/CWD)
定义:
符号扩展是指用一个操作数的符号位(即最高位)形成另一个操作数,后一个操作数的各位是全0(正数)或全1(负数)。符号扩展不改变数据大小
种类:
1 | CBW ;AL的符号扩展至AH |
举例:
1 | mov al,80h ;al=80h |
典型例题:指令的综合运用
【例】:综合运算举例。计算: (V-(X*Y+Z-540))/X 其中X、Y、Z、V均为16位带符号数,已分别装入X、Y、Z、V单元中,要求计算结果把商存入AX,余数存入DX。
十进制算术运算指令
十进制数的运算步骤: 1.对BCD码进行二进制运算 2.用十进制调整指令进行调整
压缩的BCD码调整指令(无操作数,默认对放在AL的数据操作)
常用来处理数字,所以D:decimal,A:adjust,A表示加法add,S表示减法sub
BCD码的运算逻辑还是十进制,只不过是用二进制表示
DAA(加法)
解释:为什么第②点是加60H:因为只要当前位表示的数大于等于10都要加6,但是当AL中高四位超过时,直接加6会误解,所以就要加60H,6分配给高4位,0分配给低4位。如果高低一起超过就加66H
DAS(减法)
就是将上面加法中减换成加
小结:就是看每个半字是否有进位或者借位,对于低半字就是看AF和低半字是否大于等于10,对于高半字就是看CF和高半字是否大于等于10
非压缩的BCD码调整指令
常用来处理字符,所以A:表示ASCII码,A表示调整adjust,其他就是加(ADD)减(sub)乘(mul)除(div)
压缩的BCD码就是通常的8421码,非压缩的BCD码是用8个二进制位表示一个十进制位
AAA(加法)
注:AAA调整的时候一定还要根据AF判断是否调整的原因如下:
AAS(减法)
就是将上图加1改成减1,加6改成减6
小结:无论是压缩还是非压缩的BCD码的加减调整就是看低位有没有向高位进位和借位
AAM(乘法)
将二进制乘法的结果调整成十进制非压缩的形式,所以跟在乘法操作后面
举例:
AAD(除法)
先将十进制表示的被除数调整成二进制形式,再做除法,所以放在除法前面
举例:
位操作类指令
位操作指令都是将CF和OF设置为0,因为位操作不会产生进位,不会溢出
逻辑与指令AND
AND指令设置CF = OF = 0,根据结果设置SF、ZF和PF状态,而对AF未定义
逻辑或指令OR
OR指令设置CF = OF = 0,根据结果设置SF、ZF和PF状态,而对AF未定义
逻辑异或指令XOR
与0异或不变,与1异或得相反数
XOR指令设置CF = OF = 0,根据结果设置SF、ZF和PF状态,而对AF未定义
逻辑非指令NOT
NOT指令是一个单操作数指令 NOT指令不影响标志位
测试指令TEST
- 对两个操作数执行逻辑与运算,结果不回送到目的操作数
- TEST指令设置CF = OF = 0,根据结果设置SF、ZF和PF状态,而对AF未定义
移位指令(shift)
逻辑左移(SHL)
SHL reg/mem,1/CL ;逻辑左移,最高位进入CF,最低位补0
算术左移(SAL)
SAL reg/mem,1/CL ;算术左移,最高位进入CF,最低位补0
注:逻辑左移和算术左移没什么区别
逻辑右移(SHR)
SHR reg/mem,1/CL ;逻辑右移,最低位进入CF,最高位补0
举例
算术右移(SAR)
SAR reg/mem,1/CL ;算术右移,最低位进入CF,补符号位
举例
算术左移和算术右移主要用来进行有符号数的倍增、减半;
逻辑左移和逻辑右移主要用来进行无符号数的倍增、减半。
注:移位指令的第一个操作数是指定的被移位的操作数,可以是寄存器或存储单元 后一个操作数表示移位位数,该操作数为1,表示移动一位;当移位位数大于1时,用且只能用CL寄存器值表示,该操作数表达为CL
循环移位指令(rotate)
ROL reg/mem,1/CL ;不带进位循环左移
ROR reg/mem,1/CL ;不带进位循环右移
RCL reg/mem,1/CL ;带进位循环左移
RCR reg/mem,1/CL ;带进位循环右移
带进位和不带进位的区别:
比如不带进位的左移,是将最高位移动到CF里;
而带进位的左移,是将CF和要移动的8位合起来看做一个整体一起移动
带进位一般用来处理多精度数的移动
举例:
题1:高精度移位
题2:BCD码合并
控制转移类指令
非条件转移
段内寻址
相对寻址
1 | JMP LABEL |
效果就是将当前IP指针加上LABEL表示的位移量
间接寻址
1 | JMP R16/M16 |
注:R16表示16进制寄存器,M16表示16进制内存
效果就是将IP修改为R16/M16中内容
段间寻址
直接寻址
1 | JMP FAR PTR LABEL |
效果是将IP修改为LABEL的偏移地址,CS修改为LABEL的段地址
间接寻址
1 | JMP FAR PTR MEM |
效果就是将IP修改为MEM的低2位字节[MEM],将CS修改为LABEL的高2位字节[MEM+2](所以MEM是四个字节)
注:段间间接寻址只能用内存,如果是寄存器的话是寄存器中保存的是对应内存中的地址,举例如下
1
2
3
4 MOV WORD PTR [BX], 0
MOV WORD PTR [BX + 2], 1500H
JMP FAR PTR [BX]
; 转移到1500H:0
条件转移指令
条件转移指令的判断条件:PF, CF, OF, SF, ZF
举例:
题1:
1 | test al,80h ;测试最高位 |
题2:
1 | ;计算|X-Y|(绝对值) |
条件转移指令大全
- A(above)/B(below)适用于无符号数
- G(greater)/L(lower)适用于有符号数
- 比如JNBE:not below and not equal,非小于等于就是大于。然后是前操作数减后操作数,如果前比后大,那么就不用借位,CF = 0,ZF = 0