您的位置:首页 > 其它

王爽 《汇编语言》 读书笔记 十一 标志寄存器

2017-09-10 20:03 465 查看
第十一章 标志寄存器

标志寄存器

1)用来存储相关指令的某些执行结果

2)用来为cpu执行的相关指令提供行为依据

3)用来控制cpu的相关工作方式

标志寄存器flag存储程序状态字(PSW)

8086点flag寄存器各位有不同的含义

CF,PF,AF,ZF,SF,TF,IF,DF,OF

11.1 ZF标志

flag的第六位是ZF,0标志位。记录相关指令执行后,其结果是否为0.如果为0则ZF = 1

例如

mov ax, 1

sub ax, 1

执行以后结果为0 zf = 1

mov ax, 2

sub ax, 1

执行后结果不为0,zf = 0

有些指令会影响zf的比如add, sub, mil, div, inc, or, and等运算指令

mov, push, pop对ZF没有影响不会修改其值,保留原值

11.2 PF标志

奇偶标志位,表示进行相关运算以后,其结果所含的bit为重1的个数是否为偶数,

如果1的个数为偶数则PF=1,如果为奇数,则PF=0

mov al, 1

add al, 10

执行结果为00001011B 含有奇数个1 PF = 0

mov al, 1

or al, 2

执行结果为00000011B 含有偶数个1 则PF = 1

11.3 SF标志

表明相关指令执行后,结果是否为负。如果为负sf=1,如果非负,sf=0

有些指令会影响flag的多个标记为

例如sub al, al

ZF, PF, SF都要收到影响 分别是 1, 1, 0

11.4 CF标志

进行无符号运算的时候,最高位是否进位,或者从更高位借位。

mov al, 98h

add al, all 执行后 al=30h, cf=1,cf记录了从最高有效位向更高位的进位值。

add al, al 执行后 al = 60h, cf = 0

当两个数执行减法的时候,有可能向更高位借位。比如,两个8位数据:97h - 98h CF也记录了这个借位值。

mov al, 97h

sub al, 98h ; 执行后al = ffh, CF = 1 ,CF记录了向更高位借位值

sub al, al ;执行后al=0, cf=0

11.5 OF标志

记录了有符号运算的结果是否发生了溢出。如果发生了溢出则OF=1 如果没有OF = 0

CF是对无符号数有意义的标志位,而OF是对有符号数有意义的标志位(判断两个操作数的符号,和结果的符号。如果两个操作数符号不同则OF必位0.如果结果的符号和两个操作数的符号不同则结果必为1)

SF记录结果的符号

11.6 adc指令

带进位的加法指令,利用了CF位上记录的进位值(可以扩展成32位,64位加法使用)

指令格式 adc 操作对象1, 操作对象2

功能: 操作对象1 = 操作对象1 + 操作对象2 + CF

比如 adc ax, bx (ax) = (ax) + (bx) + CF



mov ax, 2

mov bx, 1

sub bx, ax ; bx = 0ffh, cf = 1

add ax, 1 ; ax = 2 + 1 + 1(CF) = 4

mov ax, 1

add ax, ax ; ax = 2, cf = 0

add ax, 3 ; ax = 5 ,cf = 0

mov al, 98H

add al, al ; al = 30h, cf = 1, of = 1

add al, 3 ; al = 30h+3+1 = 34h

以下指令具有和add ax, bx相同的效果

add al, bl

add ah, bh

例如计算 1ef000h + 201000h 结果放在ax(高16bit)和bx(低16bit)中

mov ax, 001eh
mov bx, 0f000h
add bx, 1000h
adc ax, 0020h


adc也可能产生进位CF

计算 1E F000 1000 H + 20 10000 1EF0H 结果放在ax(最高16), bx(次高16), cx(低16位)

mov ax, 001eh
mov bx, 0f000h
mov cx, 1000h
add cx, 1ef0h
adc bx, 1000h
adc ax, 0020h


编写一个程序进行两个128位数据的相加运算

名称:add128

功能:两个128位数据进行相加

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

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

add128:	push ax
push cx
push si
push di

sub ax, ax	; set CF to Zero

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

11.7 sbb指令

带借位的减法指令,他利用了CF位上记录的借位值。

指令格式:sbb操作对象1, 操作对象2

功能:操作对象 1 = 操作对象 1 - 操作对象2 - CF

比如sbb ax, bx ; (ax) = (ax) - (bx) - CF

例如计算003E 1000H - 0020 2000H

mov bx, 1000H

mov ax, 003eH

sub bx, 2000H

sub ax, 0020H

11.8 cmp指令

cmp是比较指令,相当于减法指令,只是并不保存结果。cmp指令执行以后,将对标志寄存器产生影响。

cmp指令格式:cmp 操作对象1, 操作对象2

功能:计算操作对象1-操作对象2并不保存结果,仅仅根据计算结果对标志寄存器进行设置。

例如 cmp ax, ax ; Zf = 1, pf = 1, sf = 0, cf = 0, of = 0

下面指令:

mov ax, 8

mov bx, 3

cmp ax, bx ; zf = 0, 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 < 0, 所以 cf = 1

如果ax >= bx, 则 ax - bx >=0, 所以 cf = 0

如果ax > bx, 则 ax- bx >0, cf = 0且 zf = 0

如果ax<= bx, 则 ax - bx <=0, cf = 1 或 zf = 1

执行cmp的时候:也可以表示进行无符号运算和 进行有符号运算

如果利用cmp进行有符号数的比较

cmp ah, bh

如果 ah == bh, 则 ah - bh = 0, 所以 zf = 1

如果 ah != bh, 则 ah - bh != 0, 所以 zf = 0

如果ah < bh, ah - bh <0 sf = 1

如果 ah = 22h, bh = 0a0h(-96)

ah - bh = 34 - (-96) = 82H (-126) < 0 但是实际上 ah > bh

如果运算结果发生了溢出则所得到的结果sf就不能说明问题

总结cmp ah, bh sf of是如何来说明比较结果的。

当of = 0 sf = 1 则 ah < bh

当of=0, sf = 0 则 ah >= bh

当of=1 sf = 1,因为溢出导致实际结果位负,那么逻辑上的真正结果必然为正。因此 ah > bh

当of =1, sf = 0,因为溢出导致了实际结果为正,那么逻辑上真正的结果必然为负,因此 ah < bh

11.9 检测比较结果的条件转移指令

所有条件转移指令的转移位移应该都是 -128 ,127

常见的无符号数的比较结果进行转移的条件转移指令(zf cf)

je 等于则转移
zf = 1

jne 不等于则转移
zf = 0

jb 低于则转移
cf = 1 (below)

jnb 不低于则转移
cf = 0

ja 高于则转移
cf = 0 且 zf=0 (above)

jna 不高于则转移
cf = 1 或 zf = 1

编程实现如下功能

如果 ah == bh 则 ah = ah + ah

否则 ah = ah + bh

cmp ah, bh
je s
add ah, bh
jmp short OK
s:	add ah, ah
OK:	;...


在代码设计的时候可以将 cmp 和 jxx 联合一起使用相当于高级语言的if语句

例子统计data段中数值为8段字节的个数,用ax保存统计结果

assume cs:code

data segment
db 8, 11, 8, 1, 8, 5, 63, 38
data ends

stack segment
db 32 dup (0)
stack ends

code segment
start:		mov ax, data
mov ds, ax

mov ax, stack
mov ss, ax
mov sp, 20h

mov ax, 0
mov si, 0
mov cx, 8

s:		cmp byte ptr ds:[si], 8
je cnt
jmp short next
cnt:	inc ax

next: 	inc si
loop s

mov ax, 4c00h
int 21h

code ends
end start


运行结果



2)编程,计算data段中数值大于8段字节的个数,用ax保存统计的结果

assume cs:code

data segment
db 8, 11, 8, 1, 8, 5, 63, 38
data ends

stack segment
db 32 dup (0)
stack ends

code segment
start:		mov ax, data
mov ds, ax

mov ax, stack
mov ss, ax
mov sp, 20h

mov ax, 0
mov si, 0
mov cx, 8

s:		cmp byte ptr ds:[si], 8
jna next
inc ax
next: 	inc si
loop s

mov ax, 4c00h
int 21h

code ends
end start


3)编程,统计data段中数值小于8段字节的个数,用ax保存统计结果

assume cs:code

data segment
db 8, 11, 8, 1, 8, 5, 63, 38
data ends

stack segment
db 32 dup (0)
stack ends

code segment
start:		mov ax, data
mov ds, ax

mov ax, stack
mov ss, ax
mov sp, 20h

mov ax, 0
mov si, 0
mov cx, 8

s:		cmp byte ptr ds:[si], 8
jnb next
inc ax
next: 	inc si
loop s

mov ax, 4c00h
int 21h

code ends
end start


11.10 DF标志和串传送指令

DF方向标志位,在串处理中,控制每次操作后si,di的递减。

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

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

movsb串传送指令

功能:执行movsb指令相当于以下几个步骤

1)((es)*16 + (di)) = ((ds)*16+(si)) 把ds:si的值传送到es:di

2) 如果df=0, 则 (si)=(si)+1 , (di) = (di) + 1

反之 (si) = (si) - 1, (di) = (di) -1

也可以传送一个字

格式:movsw

将ds:si指向的内存字单元传入es:di中,然后根据标志寄存器将si和di 递增或递减2

movsb 和 movsw 要配合rep (还有一个传送双字的movsd)

rep movsb

相当于 s: movsb

loop s

也就是根据cx的值来执行循环 rep movsb 传送cx个字节

同理也可以传送 rep movsw 和 (rep movsd)

相当于 s:movsw

loop s

cld指令,可以将df设置位0 (递增)

std指令,可以将df设置位1 (递减)

movsX 系的指令需要用到的寄存器

DS,ES,SI,DI,CX(配合REP) 和标志寄存器的DF

1)将data段的字符传送到他后面的空间中

assume cs:code

data segment
db 'Welcome to masm!'
db 16 dup (0)
data ends

stack segment
db 32 dup (0)
stack ends

code segment
start:		mov ax, data
mov ds, ax
mov es, ax

mov ax, stack
mov ss, ax
mov sp, 20h

mov si, 0
mov di, 10h
mov cx, 10h
cld
rep movsb

mov ax, 4c00h
int 21h

code ends
end start


执行结果



2)编程,用串传送指令,将F000H段中的最后16个字符复制到data段中。

assume cs:code

data segment
db 16 dup (0)
data ends

stack segment
db 32 dup (0)
stack ends

code segment
start:		mov ax, 0f00h
mov ds, ax

mov ax, data
mov es, ax

mov ax, stack
mov ss, ax
mov sp, 20h

mov si, 0fffh
mov di, 15
mov cx, 16
std
rep movsb

mov ax, 4c00h
int 21h

code ends
end start
运行结果



11.11 pushf和popf

pushf将标志寄存器压栈

popf将标志寄存器从栈中弹出

提供了一种间接访问标志寄存器的方法。

11.12 标志寄存器在DEBUG中的表示

NV UP EI PL NZ NA PO NC

OF DF SF ZF PF CF

值为1 值为0

of OV NV

sf NG PL

zf ZR NZ

pf PE PO

cf CY NC

df DN UP

实验11 编写子程序

将包含人意字符,以0结尾的字符串中的小鞋字符转变成大写字母

名称:letterc

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

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

assume cs:code

datasg segment
db "Beginner's All-purpose Symbolic Instruction Code.", 0
datasg ends

stack segment
db 64 dup (0)
stack ends

code segment
begin:		mov ax, datasg
mov ds, ax

mov ax, stack
mov ss, ax
mov sp, 40h

mov si, 0

call letterc

mov ax, 4c00h
int 21h
;*****************************************************************************
; sub procedure letterc
;*****************************************************************************
letterc:	push si
push ax
pushf

lts:	mov al, ds:[si]
cmp al, 0
je letterc_ok	; meet the end of the string '\0'
cmp al, 'a'
jb next
cmp al, 'z'
ja next
and al, 11011111B	; conver to upper case
mov ds:[si], al		; apply change to data
next:	inc si
jmp short lts

letterc_ok:	popf
pop ax
pop si
ret
code ends

end begin


运行结果



将此实验和上一个单元中的show_str等例子集成

assume cs:code

datasg segment
db "Beginner's All-purpose Symbolic Instruction Code.", 0
datasg ends

stack segment
db 64 dup (0)
stack ends

code segment
begin:		mov ax, datasg
mov ds, ax

mov ax, stack
mov ss, ax
mov sp, 40h

mov si, 0

call cls

mov dh, 2			; line 2
mov dl, 0			; point the column 0
mov cl, 7			; 0 000 0 111B = 7 set the bkcolor(black) color(white)
mov si, 0			; point to the start of the string
call show_str
call letterc

mov dh, 3
call show_str

mov ax, 4c00h
int 21h
;*****************************************************************************
; sub procedure letterc
;*****************************************************************************
letterc:	push si
push ax
pushf

lts:	mov al, ds:[si]
cmp al, 0
je letterc_ok	; meet the end of the string '\0'
cmp al, 'a'
jb next
cmp al, 'z'
ja next
and al, 11011111B	; conver to upper case
mov ds:[si], al		; apply change to data
next:	inc si
jmp short lts

letterc_ok:	popf
pop ax
pop si
ret
;*****************************************************************************
; sub memset16
; di:si point to the start of the memory
; cx is the length of the memory
; ax is the value of the memory
;*****************************************************************************
memset16:		push si
push ax
push cx

jcxz memret16		; if the cx is equal to zero just return
setvalue16:	mov ds:[si], ax
add si, 2
loop setvalue16

memret16:	pop cx
pop ax
pop si
ret

;*****************************************************************************
; sub show_str
;*****************************************************************************
show_str:	push ax
push bx
push cx
push dx
push bp
push si
push di
push es

mov ax, 0b800h	; load the first address to vram
mov es, ax

mov bp, 0		; reset bp to 0
mov ax, 0		; reset al ah
mov al, dh
mov bl, 0a0h
mul bl			; dh x 160 = line offset
add bp, ax		; add the line offset

mov ax, 0		; reset al ah
mov al, dl
mov bl, 2
mul bl			; dl x 2 = column offset
add bp, ax		; add the column offset

mov di, 0
mov ah, cl		; store the color info
change:	mov cl, [si]
mov ch, 0
jcxz ok			; check whether pointer to '\0'
mov al, cl		; store the char
mov es:[bp][di], ax ;
inc si
add di, 2
jmp short change

ok:	pop es
pop di
pop si
pop bp
pop dx
pop cx
pop bx
pop ax
ret

;*****************************************************************************
; sub cls.
; clean the screen
;*****************************************************************************
cls:	push ds				; clean the screen
push ax
push cx
push si

mov cx, 690h
mov ax, 0b800h
mov ds, ax
mov al, ' '
mov ah, 7
mov si, 0
call memset16

pop si
pop cx
pop ax
pop ds
ret
code ends

end begin


运行结果

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  汇编语言