标记寄存器
CPU内部的寄存器中,有一种特殊的寄存器(对于不同的处理机,个数和结构都可能不同)具有以下3种作用。
(1)用来存储相关指令的某些执行结果。
(2)用来为CPU执行相关指令提供行为依据。
(3)用来控制CPU的相关工作方式。
这种特殊的寄存器在8086CPU中,被称为标志寄存器(flag)。如图:
11.1 ZF标志
flag的第6位是ZF,零标志位。它记录相关指令执行后,其结果是否为0。如果结果为0那么zf=1;如果不为0,那么zf=0。
运算指令的执行对标志寄存器会产生影响,而传送指令对标志寄存器不会产生影响。
比如:
mov ax,1 ;不对标志寄存器产生影响
sub ab,1 ;对标志寄存器产生影响,并且zf=1
11.2 PF标志
flag的第2位是PF,奇偶标志位。它记录相关指令执行后,其结果的所有bit位中1的个数是否为偶数。如果1的个数为偶数,pf=1,如果为奇数,那么pf=0。
比如:
mov al,1 ;不影响标志寄存器
add al,10 ;影响标志寄存器,并且1的个数为奇数,pf=0
11.3 SF标志
flag的第7位是SF,符号标志位。它记录相关指令执行后,其结果是否为负。如果结果为负,sf=1;如果非负,sf=0。
检测点 11.1
写出下面指令执行后,ZF、PF、SF等标志位的值。
指令 | ZF | PF | SF |
---|---|---|---|
sub al,al | 1 | 1 | 0 |
mov al,1 | 0 | 0 | 0 |
push ax | —— | —— | —— |
pop bx | —— | —— | —— |
add al,bl | 0 | 0 | 0 |
add al,10 | 0 | 1 | 0 |
mul al | 0 | 1 | 1 |
11.4 CF标志
flag的第0位是CF,进位标志位。一般情况下,在进行无符号数运算的时候,它记录了运算结果的最高有效位向更高位的进位值,或从更高位的借位值。如图(加法器的Ci进位,i=7):
加法减法都会产生借位:
(1)加法比如:
mov al,98H
add al,al ;执行后:(al)=30H,CF=1,CF记录了从更高有效位向更高的进位值
(2)减法比如:
mov al,97H
sub al,98H ;执行后:(al)=FFH,CF=1,CF记录了向更高位进行借位值
11.5 OF标志
flag的第11位是OF,溢出标志位。一般情况下,OF记录了有符号数运算的结果是否发生了溢出。如果发生溢出,OF=1;如果没有,OF=0。
注意CF和OF的区别:CF是对无符号位数运算有意义的标志位,而OF是对有符号数运算有意义的标志位。
比如:
mov al,0f0h ;有符号为-10,无符号为240
add al,78h ;有无符号都为120
;进行无符号运算则发生溢出,进行有符号运算将不溢出
;则cf=1,of=0
检测点 11.2
写出下面每条指令执行后,ZF、PF、SF、CF、OF等标志位的值。
指令 | CF | OF | SF | ZF | PF |
---|---|---|---|---|---|
sub al,al | 0 | 0 | 0 | 1 | 1 |
mov al,10h | —— | —— | —— | —— | —— |
add al,90h | 0 | 0 | 1 | 0 | 1 |
mov al,80h | —— | —— | —— | —— | —— |
add al,80h | 1 | 1 | 0 | 1 | 1 |
mov al,0fch | —— | —— | —— | —— | —— |
add al,05h | 1 | 0 | 0 | 0 | 0 |
mov al,7dh | —— | —— | —— | —— | —— |
add al,0bh | 1 | 1 | 0 | 0 | 0 |
11.6 adc指令
adc是带进位加法指令,它利用了CF位上记录的进位值。
指令格式:adc 操作对象1,操作对象2
功能:操作对象1=操作对象1+操作对象2+CF
例子:
编程,计算1EF000H+201000H,结果放在ax(高16位)和bx(低16位)中。
mov ax,001eh
mov bx,0f000h
add bx,1000h ;标志寄存器cf置1
adc ax,0020h ;(ax)=(ax)+0020h+cf
编写一个子程序,对两个128位数据进行相加。
名称: add128
功能:两个128位数据进行相加。
参数:
*参数1:*ds:si指向存储第一个数的内存空间,因数据为128位,所以需要8个字单元,由低地址单元到高地址单元一次存放128位数据由低到高的各个字。运算结果存储在第一个数的存储空间中。
*参数2:*ds:di指向存储的第二个数的内存空间。
程序如下:
add128:
push ax
push cx
push si
push di
sub ax,ax ;将cf置0
mov cx,8
s:
mov ax,[si]
adc ax,[di]
mov [si],ax
add si,2
add di,2
loop s
pop di
pop si
pop cx
pop ax
ret
11.7 sbb指令
sbb是带借位减法指令,它利用了CF位上记录的借位值。
指令格式:sbb 操作对象1,操作对象2
功能:操作对象1 = 操作对象1-操作对象2-CF
与adc具有相同的思想设计。
11.8 cmp指令
cmp是比较指令,cmp的功能相当于减法指令,只是不保存结果。cmp指令执行后,将对标志寄存器产生影响。
cmp指令格式:cmp 操作对象1,操作对象2
功能:计算操作对象1-操作对象2但并不保存结果,仅仅根据计算结果对标志寄存器进行设置
比如:cmp ax,ax
指令执行后:zf=1,pf=1,sf=0,cf=0,of=0。
执行cmp ax,bx
后:
- 如果(ax)=(bx) 则(ax)-(bx)=0,所以:zf=1
- 如果(ax)!=(bx) 则(ax)-(bx)!=0,所以:zf=0
- 如果(ax)<(bx) 则(ax)-(bx)将产生借位,所以:cf=1
- 如果(ax)>=(bx) 则(ax)-(bx)不必借位,所以:cf=0
- 如果(ax)>(bx) 则(ax)-(bx)即不必借位,结果又不为0,所以:cf=0并且zf=0
- 如果(ax)<=(bx) 则(ax)-(bx)既可能借位,结果可能为0,所以:cf=1或zf=1
显然,除了上面那样还不够!
还需要sf和of一起作用(记住,of=1溢出导致实际结果与逻辑结果相反):
11.9 检测比较结果的条件转移指令
“转移”指的是它能够修改IP,而“条件”指的是它可以根据某种条件,决定是否修改IP。
指令 | 含义 | 检测的相关标志位 |
---|---|---|
je | 等于则转移 | zf=1 |
jne | 不等于则转移 | zf=0 |
jb | 低于则转移 | cf=1 |
jnb | 不低于则转移 | cf=0 |
ja | 高于则转移 | cf=0且zf=0 |
jna | 不高于则转移 | cf=1或zf=1 |
e:表示equal
ne:表示not equal
b:表示below
nb:表示not below
a:表示above
na:表示not above
检测点 11.3
(1)补全下面的程序,统计F000:0处32个字节中,大小在[32,128]的数据的个数。
assume cs:code
code segment
start:
mov ax,0f000h
mov ds,ax
mov bx,0
mov dx,0
mov cx,32
s:
mov al,[bx]
cmp al,32
;低于32
jb s0
cmp al,128
;高于128
ja s0
;如果在范围内,则+1
inc dx
s0:
;如果不在范围内,则+1
inc bx
loop s
code ends
end start
(2)补全下面的程序,统计F000:0处32个字节中,大小在(32,128)的数据个数。
assume cs:code
code segment
start:
mov ax,0f000h
mov ds,ax
mov bx,0
mov dx,0
mov cx,32
s:
mov al,[bx]
cmp al,32
;不高于是<=
jna s0
cmp al,128
;不低于是>=
jnb s0
;如果在范围内,则+1
inc dx
s0:
;如果不在范围内,则+1
inc bx
loop s
code ends
end start
11.10 DF标志和串传送指令
flag的第10位是DF,方向标志位。在串处理指令中,控制每次操作后si、di的增减。
格式:movsb
功能:执行movsb
指令相当于进行下面几步操作。
(1)
((es)∗16+(di))=((ds)∗16+(si))
(
(
e
s
)
∗
16
+
(
d
i
)
)
=
(
(
d
s
)
∗
16
+
(
s
i
)
)
(2)如果df=0则:
(si)=(si)+1,(di)=(di)+1
(
s
i
)
=
(
s
i
)
+
1
,
(
d
i
)
=
(
d
i
)
+
1
(3)如果df=1则:
(si)=(si)−1,(di)=(di)−1
(
s
i
)
=
(
s
i
)
−
1
,
(
d
i
)
=
(
d
i
)
−
1
格式:movsw
功能:将ds:si指向的内存单元中的字送入es:di中,然后根据标志寄存器df位的值,将si和di递增2或递减2。
(1)如果df=0则:add si,2 and add di,2
(2)如果df=1则:sub si,2 and sub si,2
格式:rep movsb
功能:根据cx来决定循环次数,n次就是复制n个字节的内容
s: movsb
loop s
同理:拥有格式rep movsw
功能:根据cx来决定循环次数,n次就是复制n个字的内容
改变方向的2个指令:
(1)cld指令
:将标志寄存器的df置0
(2)std指令
:将标志寄存器的df置1
例子:
编程,用串传送指令,将data段中的第一个字符复制到它后面的空间中。
mov ax,data
mov ds,ax
mov si,0
mov es,ax
mov di,16
mov cx,16
cld
rep movsb
11.11 pushf和popf
pushf的功能是将标志寄存器的值压入栈中,而popf是从栈中弹出数据,送入标志寄存器中。pushf和popf,为直接访问标志寄存器提供了一种方法。
检测点 11.4
下面的程序执行后:
(ax)=?
(
a
x
)
=
?
mov ax,0 ;ax=0
push ax ;ax=0,stack=[top>0>bottom]
popf ;ax=0,stack=[top>bottom]
mov ax,0fff0h ;ax=fff0h
add ax,0010h ;ax=0h
pushf ;ax=0,stack=[top>1000111B>bottom]
pop ax ;ax=47h(0100 0111B),stack=[top>bottom]
and al,11000101B;ax=45h(0100 0101B)
and ah,00001000B;ax=45h
11.12 标志寄存器在Debug中的表示
在Debug中,标志寄存器是按照有意义的各个标志位单独表示的。在Debug中,我们可以看到下面的信息。
–
实验11 编写子程序
应用举例:
assume cs:codesg
datasg segment
db "Beginner's All-purpose Symbolic Instruction Code.",0
datasg ends
codesg segment
begin:
mov ax,datasg
mov ds,ax
mov si,0
call letterc
mov ax,4c00h
int 21h
letterc:
;比较是'a'<=ds:[si]<='z'
;如果是,则变为大写
;否则,啥也不干
;循环到0位置
push ax
change:
mov al,ds:[si]
;ax<'a'则什么也不做
cmp al,97
jb next
;ax>'z'则什么也不做
cmp al,122
ja next
;ax=0,则返回
cmp al,0
je return
and al,11011111B
mov ds:[si],al
next:
inc si
loop change
return:
pop ax
ret
codesg ends
end begin