adc指令
- adc是带进位加法指令,它利用了CF位上记录的进位值
- 指令格式:adc 操作对象 1,操作对象 2
- 功能:操作对象1=操作对象1+操作对象2+CF
- 比如指令 adc,ax,bx 实现的功能是:(ax)=(ax)+(bx)+CF
CPU为什么要提供这样的一条指令?
- 如果CF的值是被sub指令设置的,那么它的含义就是借位值
- 如果是被add指令设置的,那么它的含义就是进位值
- 我们来看一下两个数据:0198H和0183H如何相加的:
可以看出,加法可以分为两步来进行:
- 低位相加
- 高位相加再加上低位相加产生的进位值
adc指令和add指令相配合就可以对更大的数据进行加法运算
编程,计算1EF000H+201000H,结果放在ax(高16位)和bx(低16位)中
因为两个数据的位数都大于16,用add指令无法进行计算,我们将计算机分两步进行,先将低16位相加,然后将高16位和进位值相加
mov ax,001EH
mov bx,0F000H
add bx,1000H
adc ax,0020H
sbb指令
- sbb是带借位减法指令,它利用了CF位上记录的借位值
- 指令格式:sbb 操作对象1,操作对象2
- 功能:操作对象 1=操作对象 1-操作对象2-CF
- 比如指令 sbb ax,bx 实现的功能是:(ax)=(ax)-(bx)-CF
cmp指令
- cmp是比较指令,cmp的功能相当于减法指令,只有不保存结果,cmp指令执行后,将对标志寄存器产生影响,其他相关指令通过识别这些被影响的标志寄存器来得知比较结果
- cmp指令格式:cmp 操作对象1,操作对象2
- 功能:计算操作对象 1-操作对象 2 但并不保存结果,仅仅根据计算结果对标志寄存器进行设置
- 比如,指令 cmp ax,ax,做(ax)-(ax)的运算,结果为0,但并不在ax中保存,仅影响flag的相关指令,指令执行后:zf=1,pf=1,sf=0,cf=0,of=0
这时候,我们能不能得到一个结论:cmp指令执行后,sf=1,就说明操作对象 1<操作对象 2
当然不能
- 我们知道,实际结果的正负,之所以不能说明逻辑上真正结果的正负,关键的原因在于发生了溢出,如果没有溢出发生的话,那么实际结果的正负和逻辑上真结果的正负就一致了
我们以cmp ah,bh为例,总结一下CPU执行cmp指令后,sf和of的值是如何来说明比较结果的.
- 1.如果sf=1,而of=0
of=0,说明没有溢出,逻辑上真正结果的正负=实际结果的正负
所以(ah)<(bh) - 2.如果sf=1,而of=1
of=1,说明有溢出,因为sf=1,实际结果为负,如果因为溢出导致了实际结果为负,那么逻辑上真正的结果必然为正,说明(ah)>(bh)
后面同理可得
检测比较结果的条件转移指令
CPU提供了其他条件转移指令,大多数条件转移指令都检测标志寄存器的相关标志位,根据检测的结果来决定是否修改IP,这些条件转移指令通常都和cmp相配合使用,就好像call和ret指令通常相配合使用
下面常用的根据无符号数的比较结果进行转移的条件转移指令
指令 | 含义 | 检测的相关标志位 |
---|---|---|
je | 等于则转移 | zf=1 |
jne | 不等于则转移 | zf=0 |
jb | 低于则转移 | cf=1 |
jnb | 不低于则转移 | cf=0 |
ja | 高于则转移 | cf=0且zf=0 |
jna | 不高于则转移 | cf=1或zf=1 |
注意观察一下它们所检测的标志位,都是cmp指令进行无符号数比较的时候,记录比较结果的标志位,比如je,检测zf位,当zf=1的时候进行转移,如果在je前面使用了cmp指令,那么je对zf的检测,实际上就是间接的检测cmp的比较结果是否为两数相等。
DF标志和串传送指令
flag的第10位是DF,方向标志位,在串处理指令中,控制每次操作后si,di的增减。
- df=0,每次操作后si,di递增
- df=1,每次操作后si,di递减
我们来看下面的一个串传送指令
格式:movsb
功能:执行movsb指令相当于进行下面几步操作
- ((es)*16+(di))=((ds)*16+(si))
- 如果df=0则:(si)=(si)+1 (di)=(di)+1
- 如果df=1则:(si)=(si)-1 (di)=(di)-1
可以看出,movsb的功能是将ds:si指向的内存单元中的字节送入es:di中,然后根据标志寄存器df位的值,将si和di递增或递减
当然,也可以传送一个字,相关指令为movsw
movsb和movsw进行的是串传送操作中的一个步骤,一般来说,movsb和movsw都和rep配合使用,格式如下:
rep movsb
用汇编语法来描述rep movsb的功能就是:
s: movsb
loop s
可见,rep的作用是根据cx的值,重复执行后面的串传送指令,由于每执行一次movsb指令si和di都会递增或递减指向后一个单元或前一个单元,则rep movsb就可以循环实现(cx)个字符的传送
8086CPU提供了两条指令对df位进行设置
cld指令:将标志寄存器的df位置0
std指令:将寄存器的df位置1
pushf和popf
pushf的功能是将标志寄存器的值压栈,而popf是从栈中弹出数据,送入标志寄存器中。
pushf和popf,为直接访问标志寄存器提供了方法
标志寄存器在Debug中的表示
下面列出Debug对我们已知的标志位的表示:
标志 | 值为1的标记 | 值为0的标志 |
---|---|---|
of | OV | NV |
sf | NG | PL |
zf | ZR | NZ |
pf | PE | PO |
cf | CY | NC |
df | DN | UP |