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

时间:2021-09-13 01:25:33

第十一章 标志寄存器


标志寄存器

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

运行结果


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