8086汇编#11

第十一章 标志寄存器 – 汇编语言提纲

第十一章 标志寄存器

第十一章 标志寄存器

11.0 绪论

标志寄存器的作用:

(1) 存储相关指令的执行结果

(2) 为CPU执行相关指令提供行为依据

(3) 控制CPU的相关工作方式

标志寄存器(flag)中存储的信息叫做程序状态字(PSW)

flag按位起作用,结构如图11.1

其中的1、3、5、12、13、14、15位在8086CPU中不起作用

11.1~11.5 标志寄存器的各个标志位

1.ZF标志(zero flag,零标志位)

记录相关指令执行后,结果是否为0

如果为0,那么zf=1

如果不为0,那么zf=0

(注:在计算机中1表示逻辑真(TRUE),0表示逻辑假(FALSE))

add sub mul div inc or and 等运算指令影响标志寄存器
mov push pop 等传送指令不影响标志寄存器

2.PF标志(parity flag,奇偶标志位)

记录相关指令执行后,其结果中的所有bit位中1的个数是否为偶数

若1的个数为偶数,pf=1

若1的个数为奇数,pf=0

3.SF标志(sign flag,符号标志位)

附注2 补码总结、原码反码补码

注:此时要指名有符号数的长度(byte/word/dword/qword)

1. 用数据的最高位作为符号位,0表示正数,1表示负数

2. 将数在机器中的编码称为机器数(如10000001),将原来一般的书写方式表示的数称为真值(如-0000001).

3. 原码:原本的数字不变,最高位作为符号位

如(当长度为byte时)1100110的原码=01100110,-1100110的原码=11100110

原码中0会出现重码(00000000(+0)和10000000(-0))

4. 反码:正数的反码就是它本身,负数的反码是将原码除了符号位以外每个为按位取反

如(当长度为byte时)1100110的反码=01100110,-1100110的反码=10011001

反码中0会出现重码(00000000(+0)和11111111(-0))

5. 补码:正数的补码就是它本身,负数的补码是将反码加1

如(当长度为byte时)1100110的补码=01100110,-1100110的补码=10011010

补码中每个数都是唯一的

*负数补码也可以用0向一个”假想的最高位的前一位”借1,与自己相反数的补码相减得到

如(当长度为byte时)-1100110的补码=(1)00000000-01100110=10011010

最高位的前一位看作1

6. 正数的补码取反加1后,为其对应的负数的补码,负数的补码取反加1后为其绝对值

7. n位二进制数的各个编码能表示的有符号数的范围如下:

原码 -2^(n-1)-1~2^(n-1)-1

反码 -2^(n-1)-1~2^(n-1)-1

补码 -2^(n-1)~2^(n-1)-1

记录相关指令执行后结果是否为负(此时将结果看作有符号数),

如果为负sf=1

如果为非负数,sf=0

对于同一二进制数,可以当作有符号数计算,也可以当作无符号数计算

在将结果当作无符号数时,sf的值没有意义

检测点11.1

写出下面每条指令执行后,ZF、PF、SF、等标志位的值。

sub al,al     al=0h        ZF=1        PF=1        SF=0  
mov al,1      al=1h        ZF=1        PF=1        SF=0  
push ax       ax=1h        ZF=1        PF=1        SF=0  
pop bx        bx=1h        ZF=1        PF=1        SF=0  
add al,bl     al=2h        ZF=0        PF=0        SF=0  
add al,10     al=12h       ZF=0        PF=1        SF=0  
mul al        ax=144h      ZF=0        PF=1        SF=0

4.CF标志(carry flag,进位标志位)

在进行无符号数运算时,它记录了运算结果的最高有效位向更高位的进位值(或借位值)

如:1111 1111B+1B=1 00000000B

结果中的1就在假想的最高位,即CF标志位中

如果是97H-98H,则向CF借位,cf=1,运算变为197H-98H=FFH

有进位或借位时cf=1,吗,没有则cf=0

5.OF标志(overflow flag,溢出标志位)

在进行有符号数运算时,若结果超过了机器所能表示的范围叫做溢出

如99+98=197>127,超过了8位有符号数的范围,便是溢出

溢出时of=1,没有溢出of=0

注意:要分清判断对象是有符号数还是无符号数

检测点11.2

写出下面每条指令执行后,ZF、PF、SF、CF、OF等标志位的值。

              al                 CF    OF    SF    ZF    PF
sub al,al     0h/0000 0000b      0     0     0     1     1
mov al,10h    10h/0010 0000b     0     0     0     1     1
add al,90h    a0h/1010 0000b     0     0     1     0     1
mov al,80h    80h/1000 0000b     0     0     1     0     1
add al,80h    0h/0000 0000b      1     1     0     1     1
mov al,0fch   0fch/1111 1100b    1     1     0     1     1
add al,05h    1h/0000 0001b      1     0     0     0     0
mov al,7dh    7dh/1111 1101b     1     0     0     0     0
add al,0bh    88h/1000 1000b     0     1     1     0     1

11.6 adc指令

adc为带进位加法指令,利用了cf位上记录的进位值

格式 adc oper1,oper2

功能 oper1=oper1+oper2+CF

使用:进行大数相加,可以将加法分为两步:(1)低位相加;(2)高位相加再加上低位相加的进位值

例1:32位加法:计算1EF000H+201000H,结果在ax(高16位),bx(低16位)

mov ax,001EH
mov bx,0F000H
add bx,1000H

adc ax,0020H

adc指令执行后可能产生进位设置cf

例2:编写子程序,进行128位加法

名称:add128

功能:两个128位数据相加

参数:ds:si指向存储第一个数的空间(此时需要8个字单元),由低地址到高地址依次存放128位数据由低到高的各个字,运算结果存储在第一个数的存储空间中。

ds:di指向存储第二个数的内存空间

Program 11-1 ADD128程序

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
inc si
inc si
inc di
inc di 
loop s
pop di
pop si
pop cx
pop ax
ret

inc和loop指令不影响cf位,上面的4个inc指令不能用add代替,因为add影响cf位,会破坏运行结果

11.7 sbb指令

sbb是带借位减法指令,利用了cf记录的借位值

格式 sbb oper1,oper2

功能 oper1=oper1-oper2-cf

应用思路与adc类似

11.8~11.9 cmp指令和条件转移指令

1. cmp为比较指令,功能相当于减法指令,不保存结果但对标志寄存器产生影响

格式 cmp oper1,oper2

功能 计算oper1-oper2,不保存结果,仅仅设置flag

2.▲▲▲cmp指令比较结果通过标志寄存器位的反馈:执行cmp ax,bx

比较内容

cmp指令结果

flag寄存器相关位的内容

(ax)==(bx)

(ax)-(bx)==0

zf=1

(ax)!=(bx)

(ax)-(bx)!=0

zf=0

(ax)<(bx)

(ax)-(bx)<0 产生借位

cf=1

(ax)>=(bx)

(ax)-(bx)>=0 不借位但结果可能为0

cf=0

(ax)>(bx)

(ax)-(bx)>0 不借位结果也不为0

cf=0且zf=0

(ax)<=(bx)

(ax)-(bx)<=0可能借位也可能结果为0

cf=1或zf=1

3.无符号数的比较:执行cmp ax,bx

标志寄存器

结论

zf=1

(ax)==(bx)

zf=0

(ax)!=(bx)

cf=1

(ax)<(bx)

cf=0

(ax)>=(bx)

cf=0且zf=0

(ax)>(bx)

cf=1或zf=1

(ax)<=(bx)

4.有符号数的比较:执行cmp ah,bh

要注意有没有溢出,没有溢出时实际结果的正负和数学运算上(数学运算时没有溢出)的正负才一致,若溢出了说明不一致

标志寄存器

结论

zf=1

(ah)==(bh)

zf=0

(ah)!=(bh)

of=0且sf=1

(ah)<(bh)

这时没有溢出,说明(ah)<(bh)在数学计算上确实是负数

of=1且sf=1

(ah)>(bh)

溢出导致了实际结果为负,说明在数学计算上(不考虑溢出)结果为正

of=1且sf=0

(ah)<(bh)

溢出导致了实际结果为正,说明在数学计算上(不考虑溢出)结果为负

of=0且sf=0

(ah)>=(bh)

5.条件转移指令的用法

套路:

cmp oper1,oper2

jxxx 标号

6.根据无符号数的比较结果进行转移

指令

含义

检测的标志位

je/jz

等于则转移

zf=1

jne/jnz

不等于则转移

zf=0

jnae/jc/jb

低于则转移(小于)

cf=1

jae/jnc/jnb

不低于则转移(大于等于)

cf=0

ja/jnbe

高于则转移(大于)

cf=0且zf=0

jna/jbe

不高于则转移(小于等于)

cf=1或zf=1

7.根据有符号数的比较结果转移

指令

含义

检测的标志位

jl/jnge

小于则转移

sf=1且of=0

jnl/jge

不小于则转移(大于等于)

sf=0且of=0

jle/jng

小于等于则转移

sf=0或of=0

jnle/jg

不小于等于则转移(大于)

sf=1且of=1

8.根据单个标志位转移

指令

含义

检测的标志位

js

结果为负

sf=0

jns

结果为非负

sf=1

jo

结果溢出

of=1

jno

结果不溢出

of=0

jp

奇偶位为1

pf=1

jnp

奇偶位为0

pf=0

*以上指令中每个字母的含义:

j=jump,e=euqal,n=not,b=below(低于),a=above(高于),l=less(小于),g=greater(大于),s=sign,c=carry,

p=parity,o=overflow,z=zero

检测点11.3

(1)补全下面的程序,统计F000:0处32个字节中,大小在[32,128]的数据个数。

mov ax,0f000h
mov ds,ax
mov bx,0;ds:bx指向第一个字节
mov dx,0;初始化累加器
mov cx,32
s: mov al,[bx]
cmp al,32;和32进行比较
jb s0     ;如果低于al转到s0,继续循环
cmp al,128;和128进行比较
ja s0     ;如果高于al转到s0,继续循环
inc dx
s0:inc bx
loop s

[32,128]是闭区间,包括两端点的值

(32,128)是开区间,不包括两端点的值

检测点11.3

(2)补全下面的程序,统计F000:0处32个字节中,大小在(32,128)的数据个数。

mov ax,0f000h
mov ds,ax
mov bx,0;ds:bx指向第一个字节
mov dx,0;初始化累加器
mov cx,32
s: mov al,[bx]
cmp al,32;和32进行比较

jna s0 ;如果不高于al转到s0,继续循环

cmp al,128;和128进行比较

jnb s0 ;如果不低于al转到s0,继续循环

inc dx
s0:inc bx
loop s

11.10 DF标志(direction flag,方向标志位)和串传送指令

1.DF标志在处理指令中控制每次操作后si、di的增减

df=0,每次操作后si、di递增

df=1,每次操作后si、di递减

2. 串传送指令

格式:movsb

功能:将ds:si指向的内存单元中的字节送入es:di中,再根据df的值将si和di递增或递减,即

mov es:[di],byte ptr ds:[si];8086不支持该指令,此处用作功能描述,是伪代码

if(df==0):

inc si
inc di

if(df==1):

dec si
dec di

格式:movsw

功能:与movsb类似,不过传送的是字,即

mov es:[di],word ptr ds:[si];8086不支持该指令,此处用作功能描述,是伪代码

if(df==0):

add si,2
add di,2

if(df==1):

sub si,2
sub di,2

一般movsb和movsw与rep配合使用,格式:rep movsb或rep movsw

相当于:

s:movsb

loop s

rep根据cx的值重复执行串传送指令

设置df位的方法:

(1) cld指令(clean):将df置为0;(2)std指令(setup):将df置为1

11.11 pushf将标志寄存器的值压栈,popf从栈中弹出数据送入标志寄存器

检测点11.4

下面指令执行后,(ax)= 45h

mov ax,0 
push ax 
popf 
mov ax,0fff0h 
add ax,0010h 
pushf 
pop ax 
and al,11000101B 
and ah,00001000B 
推算过程:
popf后,标志寄存器中,本章节介绍的那些标志位都为0(但是此时标志寄存器并不是所有位置都为0,没学过的位置用*先代替),向下进行,那么pushf将计算后的当时状态的标志寄存器入栈,然后pop给ax,这是ax是寄存器的值(这个值中包含了我们的*号),接下来就是对那些没有学过的标志位的屏蔽操作,这就是最后两条指令的意义所在,将不确定的位置都归0,那么只剩下我们能够确定的位置了,所以,结果就可以推理出来了。
mov ax,0   
push ax   
popf   
mov ax,0fff0h   
add ax,0010h   
pushf 
pop ax               0  0  0  0  of df if tf sf zf 0  af 0  pf 0  cf 
                     0  0  0  0  0  0  *  *  0  1  0  *  0  1  0  1 
                     ax=flag=000000** 010*0101b 
and al,11000101B     al=01000101b=45h 
and ah,00001000B     ah=00000000b=0h

11.12标志寄存器在debug中的显示

标志

值为1的标记

值为0的标记

of

OV,overflow

NV,not overflow

sf

NG,negative

PL,positive

zf

ZR,zero

NZ,not zero

pf

PE,even

PO,odd

cf

CY,carry

NC,not carry

df

DN,down

UP

实验11 编写子程序

实验11(letterc子程序)小写改成大写

编写一个子程序,将包含任意字符,以0结尾的字符串的小写字母转变成大写字母。

Program ex-11-1 自主解法

assume cs:codesg
datasg segment
db "Beginner's All-purpose Symbolic Instruction Code.",0
datasg ends
stack segment
db 64 dup(0)
stack ends
codesg segment
begin:
mov ax,datasg
mov ds,ax
mov si,0 ;ds:si指向第一个字节
mov ax,stack
mov ss,ax
mov sp,64
call letterc
mov ax,4c00h
int 21h
letterc:
push ax
push si
letc_start:
mov al,[si]
;if(al==0)
cmp al,0
je ok
;if(97<=al && al<=122)
;测试第一个条件
cmp al,97
jae s1
;else
jmp next
;测试第二个条件
s1: cmp al,122
jbe s2
;else
jmp next
s2:;满足两个条件,进行转换
sub al,32
mov [si],al
jmp next
next:;下一个
inc si
jmp letc_start

ok: pop si
pop ax
ret
codesg ends
end begin

Program ex-11-2 参考解法

assume cs:codesg
datasg segment
db "Seginner's All-purpose Symbolic Instruction Code.",'0'
datasg ends
codesg segment
begin:
mov ax,datasg
mov ds,ax
mov si,0;ds:si指向第一个字节
call letterc

mov ax,4c00h
int 21h

;名称:letterc

;功能:将以0结尾的字符中的小写字母转变成大写字母

;参数:ds:si指向字符串首地址

letterc:push ax
push si
let:cmp byte ptr [si],0;和0进行比较
je let0;如果等于0则转到let0,结束
cmp byte ptr [si],61h;和61h进行比较
jb let1;如果低于60h则转到let1,继续循环
cmp byte ptr [si],86h;和86h进行比较
ja let1;如果高于86h则转到let1,继续循环
mov al,[si]
sub al,20h;转为大写字母
mov [si],al
let1:
inc si
jmp let
let0:
pop si
pop ax
ret
codesg ends
end begin

发表评论

滚动至顶部