文章目录
- 标志寄存器
- 1. ZF标志
- 2. PF标志
- 3. SF标志
- 4. CF标志
- 5. OF标志
- 6. adc指令
- 7. sbb指令
- 8. cmp指令
- 9. 检测比较结果的条件转移指令
- 10. DF标志和串传送指令
- 11. pushf和popf
标志寄存器
flag 和其他寄存器不一样,其他寄存器是用来存放数据的,都是整个寄存器具有一个含义。
而flag寄存器是按位起作用的,也就是说,它的每一位都有专门的含义,记录特定的信息。
8086CPU的flag寄存器的结构:
flag的1、3、5、12、13、14、15位在8086CPU中没有使用,不具有任何含义。
而0、2、4、6、7、8、9、10、11位都具有特殊的含义。
1. ZF标志
flag的第6位是ZF,零标志位。它记录相关指令执行后结果是否为0:
- 结果为0 ,ZF = 1
- 结果不为0,ZF = 0
例如:
mov ax,1
sub ax,1
指令执行后,结果为0,则ZF = 1。
mov ax,2
sub ax,1
指令执行后,结果为1,则ZF = 0。
2. PF标志
flag的第2位是PF,奇偶标志位。它记录指令执行后,结果的所有二进制位中1的个数:
- 为偶数,PF = 1;
- 为奇数,PF = 0。
示例:
mov al,1
add al,10
执行后,结果为00001011B,其中有3(奇数)个1,则PF=0;
mov al,1
or al,10
执行后,结果为00000011B,其中有2(偶数)个1,则PF=1;
3. SF标志
flag的第7位是SF,符号标志位。它记录指令执行后结果是否为负数:
- 结果为负,SF = 1;
- 结果为正,SF = 0。
计算机中通常用补码来表示有符号数据。计算机中的一个数据可以看作是有符号数,也可以看成是无符号数。
SF 标志,就是CPU对有符号数运算结果的一种记录 ,它记录数据的正负。 在我们将数据当作有符号数来运算的时候,可以通过它来得知结果的正负。如果我们将数据当作无符号数来运算,SF的值则没有意义,虽然相关的指令影响了它的值。
示例:
mov al,10000001B
add al,1
执行后,结果为10000010B,SF=1,
表示:如果指令进行的是有符号数运算,那么结果为负;
mov al,10000001B
add al,01111111B
执行后,结果为0,SF=0
表示:如果指令进行的是有符号数运算,那么结果为非负。
4. CF标志
flag的第0位是CF,进位标志位。
一般情况下,在进行无符号数运算的时候,它记录了运算结果的最高有效位向更高位的进位值,或从更高位的借位值。
例如
mov al,98H
add al,al
执行后: (al)=30H,CF=1,CF记录了最高有效位向更高位的进位值
另外一种情况,而当两个数据做减法的时候,有可能向更高位借位。
比如,两个 8 位数据:97H-98H,将产生借位,借位后,相当于计算197H-98H。而flag的CF位也可以用来记录这个借位值。
5. OF标志
flag的第11位是OF,溢出标志位。
在进行有符号数运算的时候,如结果超过了机器所能表示的范围称为溢出。
注意CF和OF的区别:
- CF是对无符号数运算有意义的标志位
- 而OF是对有符号数运算有意义的标志位
例如:
mov al, 98d
add al, 99d
对于无符号数运算,98+99没有进位,CF=0;对于有符号数运算,98+99发生溢出,OF=1。
6. adc指令
adc是带进位加法指令 ,它利用了CF位上记录的进位值。
格式: adc 操作对象1,操作对象2
功能:操作对象1 = 操作对象1 + 操作对象2 + CF
比如:adc ax,bx 实现的功能是: (ax) = (ax) + (bx) + CF
adc指令示例:
mov ax,2
mov bx,1
sub bx,ax
adc ax,l
执行后,(ax)=4。
adc执行时,相当于计算: (ax)+1+CF=2+1+1=4。
mov ax,1
add ax,ax
adc ax,3
执行后,(ax)=5。
adc执行时,相当于计算: (ax)+3+CF=2+3+0=5。
在执行 adc 指令的时候加上的 CF 的值的含义,由 adc指令前面的指令决定的,也就是说,关键在于所加上的CF值是被什么指令设置的。
显然,如果CF 的值是被sub指令设置的,那么它的含义就是借位值;如果是被add指令设置的,那么它的含义就是进位值。
7. sbb指令
sbb是带错位减法指令,它利用了CF位上记录的借位值。
格式:sbb 操作对象1,操作对象2
功能:操作对象1 = 操作对象1 – 操作对象 2 – CF
比如:sbb ax,bx
实现功能: (ax) = (ax) – (bx) – CF
8. 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 指令执行后,相关标志位的值就可以看出比较的结果。
同 add、sub 指令一样,CPU 在执行cmp指令的时候,也包含两种含义:进行无符号数运算和进行有符号数运算。
所以利用cmp指令可以对无符号数进行比较,也可以对有符号数进行比较。
9. 检测比较结果的条件转移指令
因为 cmp 指令可以同时进行两种比较,无符号数比较和有符号数比较,所以根据 cmp 指令的比较结果进行转移的指令也分为两种,即:
根据无符号数的比较结果进行转移的条件转移指令,它们检测ZF、CF的值;
和根据有符号数的比较结果进行转移的条件转移指令,它们检测 SF、OF和 ZF的值。
e:表示equal;
ne:表示not equal;
b:表示below;
nb:表示not below;
a:表示above;
na:表示not above。
编程实现:如果(ah)=(bh)则(ah)=(ah)+(ah),否则 (ah)=(ah)+(bh)。
cmp ah,bh
je s
add ah,bh
jmp short ok
s: add ah,ah
ok: ret
虽然 je 的逻辑含义是“相等则转移”,但它进行的操作是,ZF=1时则转移。
“相等则转移”这种逻辑含义,是通过和 cmp 指令配合使用来体现的,因为是cmp 指令为“ZF=1”赋予了“两数相等”的含义。
10. DF标志和串传送指令
flag的第10位是DF,方向标志位。在串处理指令中,控制每次操作后si,di的增减:
- DF = 0:每次操作后si,di递增;
- DF = 1:每次操作后si,di递减。
1)格式1: movsb
功能:以字节为单位传送
步骤1 :((es)×16 + (di)) = ((ds) ×16 + (si))
步骤2:
如果DF = 0则: (si) = (si) + 1
(di) = (di) + 1
如果DF = 1则: (si) = (si) - 1
(di) = (di) - 1
2)格式2:movsw
功能:以字为单位传送
将 ds:si指向的内存字单元中word送入es:di中,然后根据标志寄存器DF位的值,将si和di递增2或递减2。
movsb和movsw进行的是串传送操作中的一个步骤,一般来说,movsb 和 movsw 都和rep配合使用,格式为 rep movsb
rep的作用是根据cx的值,重复执行后面的串传送指令。
由于每执行一次movsb指令 si 和 di 都会递增或递减指向后一个单元或前个单元,则rep movsb就可以循环实现(cx)个字符的传送。
由于flag的DF位决定着串传送指令执行后,si和di改变的方向,所以CPU应该提供相应的指令来对DF位进行设置,从而使程序员能够决定传送的方向。
8086CPU提供下而两条指令对DF位进行设置:
- cld指令:将标志寄存器的DF位置0
- std指令:将标志寄存器的DF位置1
1)编程实现:用串传送指令,将data段中的第一个字符串复制到它后面的空间中。
data segment
db ‘Welcome to masm!’
db 16 dup (0)
data ends
代码:
mov ax,data
mov ds,ax
mov si,0 ;ds:si指向data:0
mov es,ax
mov di,16 ;es:di指向data:0010;
mov cx,16 ;(cx)=16,rep循环16次;
cld ;设置df=0,正向传送
rep movsb
2)编程实现:用串传送指令,将F000H段中的最后16个字符复制到data段中。
data segment
db 16 dup (0)
data ends
代码:
mov ax,0f000h
mov ds,ax
mov si,0ffffh ;ds:si 指向f000:ffff
mov ax,data
mov es,ax
mov di,15 ;es:di 指向data:000F
mov cx,16 ;(cx)=16,rep 循环 16次
std ;设置df=1,逆向传送
rep movsb
11. pushf和popf
pushf :将标志寄存器的值压栈;
popf :从栈中弹出数据,送入标志寄存器中。
pushf 和 popf,为直接访问标志寄存器提供了一种方法。