標志寄存器
flag 和其他寄存器不一樣,其他寄存器是用來存放數據的,都是整個寄存器具有一個含義。
而flag寄存器是按位起作用的,也就是說,它的每一位都有專門的含義,記錄特定的信息。
8086CPU的flag寄存器的結構:

ZF標志
flag的第6位是ZF,零標志位(zero flag)。
它記錄相關指令(add、sub、mul、div、inc、or、and操作)執行后,結果是否為0 。ZF = 1結果不為0,ZF = 0結果為0。
mov、push、pop等傳送指令不修改標志寄存器的信息。
PF標志
flag的第2位是PF,奇偶標志位。
它記錄指令執行后,結果的所有二進制位中1的個數是否為偶數,如果為偶數則PF = 1,為奇數,PF = 0。
SF標志
flag的第7位是SF,符號標志位。
它記錄指令執行后,結果是否為負(就是看它二進制的第一位是不是1),如果為負數則SF = 1,結果為正,SF = 0。
例如:
我們可以將add指令進行的運算當作無符號數的運算,那么add指令相當於計算129+1,結果為130(10000010B),
也可以將add指令進行的運算當作有符號數的運算,那么add指令相當於計算-(125+1)(補碼=-(原碼取反+1)),結果為-126(10000010B)。

CF標志
flag的第0位是CF,進位標志位。
一般情況下,在進行無符號數運算的時候,它記錄了運算結果的最高有效位向更高位的進位值,或從更高位的借位值。
比如,兩個8 位數據:98H+98H,將產生進位。
由於這個進位值在8位數中無法保存,其實CPU在運算的時候,並不丟棄這個進位值,而是記錄在一個特殊的寄存器的某一位上。
8086CPU 就用flag的CF位來記錄這個進位值。
比如,兩個 8 位數據:97H-98H,將產生借位,借位后,相當於計算197H-98H。
而flag的CF位也可以用來記錄這個借位值。
CF在減法時記錄借位,加法時記錄進位
判斷加法是否有進位:兩個八位數據相加是否大於255(2^8)
判斷減法是否有借位:兩個八位數據相加是否小於-255
OF標志
在進行有符號數運算的時候,如結果超過了機器所能表示的范圍稱為溢出。
mov al,98
add al,99
add指令運算的結果是(al)=0C5H ,因為進行的是有符如果我們用add 指令進行的是有符號數運算,則98+99=-59這樣的結果讓人無法接受。
造成這種情況的原因,就是實際的結果 197,作為一個有符號數,在 8 位寄存器al中存放不下。
由於在進行有符號數運算時,可能發生溢出而造成結果的錯誤。
則CPU需要對指令執行后是否產生溢出進行記錄。
flag的第11位是OF,溢出標志位。
一般情況下,OF記錄了有符號數運算的結果是否發生了溢出。如果發生溢出,OF=1,如果沒有,OF=0。
一定要注意CF和OF的區別:
CF是對無符號數運算有意義的標志位,對於無符號數運算,CPU用CF位來記錄是否產生了進位;
而OF是對有符號數運算有意義的標志位,對於有符號數運算,CPU 用 OF 位來記錄是否產生了溢出,當然,還要用SF位來記錄結果的符號。
判斷OF是否為1的方法:如果兩個正8位數據相加,值為負數時或兩個負8位數據相加,值為時數時OF的值為1

1 al CF OF SF ZF PF 2 sub al,al 0h/0000 0000b 0 0 0 1 1 3 mov al,10h 10h/0010 0000b 0 0 0 1 1 4 add al,90h a0h/1010 0000b 0 0 1 0 1 5 mov al,80h 80h/1000 0000b 0 0 1 0 1 6 add al,80h 0h/0000 0000b 1 1 0 1 1 7 mov al,0fch 0fch/1111 1100b 1 1 0 1 1 8 add al,05h 1h/0000 0001b 1 0 0 0 0 9 mov al,7dh 7dh/1111 1101b 1 0 0 0 0 10 add al,0bh 88h/1000 1000b 0 1 1 0 1
指令
adc指令
adc是帶進位加法指令 ,它利用了CF位上記錄的進位值。
格式:adc 操作對象1,操作對象2
功能:操作對象1=操作對象1+操作對象2+CF
比如:adc ax,bx 實現的功能是:(ax)=(ax)+(bx)+CF
我們來看一下兩個數據:0198H和0183H如何相加的:
01 98
+ 01 83
1
-----------------
03 1B
可以看出,加法可以分兩步來進行:
(1)低位相加;
(2)高位相加再加上低位相加產生的進位值。
下面的指令和add ax , bx具有相同的結果:
add al,bl ; 低位相加產生進位
adc ah,bh ; 再用adc,高位相加時,加上進位
看來CPU提供 adc 指令的目的,就是來進行加法的第二步運算的。
adc指令和add指令相配合就可以對更大的數據進行加法運算。
sbb指令
sbb是帶借位減法指令,它利用了CF位上記錄的借位值。
格式:sbb 操作對象1,操作對象2
功能:操作對象1=操作對象1–操作對象2–CF
比如:sbb ax,bx
實現功能:(ax) = (ax) – (bx) – CF
cmp指令***
cmp 是比較指令,功能相當於減法指令,只是不保存結果。
cmp 指令執行后,將對標志寄存器產生影響。
可以通過其他相關指令通過識別這些被影響的標志寄存器位來得知比較結果。
格式:cmp 操作對象1,操作對象2
功能:計算操作對象1–操作對象2 但並不保存結果,僅僅根據計算結果對標志寄存器進行設置。
其實,我們通過cmp 指令執行后,相關標志位的值就可以看出比較的結果。
例如:cmp ax,bx

以上可以得出:

上面有CF的值可以判斷大小,那么通過OF和SF也可以知道(了解就行)
(1)如果SF=1,而OF=0
OF=0,說明沒有溢出,邏輯上真正結果的正負=實際結果的正負;
因SF=1,實際結果為負,所以邏輯上真正的結果為負,所以(ah)<(bh)。
(2)如果SF=1,而OF=1
OF=1 ,說明有溢出,邏輯上真正結果的正負≠實際結果的正負;(即OF只要是1,那么邏輯結果就是反的)
因 SF=1 ,實際結果為負,實際結果為負,而又有溢出,這說明是由於溢出導致了實際結果為負,
簡單分析一下,就可以看出,如果因為溢出導致了實際結果為負,那么邏輯上真正的結果必然為正。這樣,SF=1,OF = 1 ,說明了(ah)>(bh)。
(3)如果SF=0,而OF=1
OF=1 ,說明有溢出,邏輯上真正結果的正負≠實際結果的正負;
因SF=0,實際結果非負,而OF=1說明有溢出,則結果非 0 ,所以,實際結果為正。實際結果為正,而又有溢出,這說明是由於溢出導致了實際結果非負,
簡單分析一下,就可以看出,如果因為溢出導致了實際結果為正,那么邏輯上真正的結果必然為負。這樣,SF=0,OF = 1 ,說明了(ah)<(bh)。
(4)如果SF=0,而OF=0
OF=0,說明沒有溢出,邏輯上真正結果的正負=實際結果的正負;
因SF=0,實際結果非負,所以邏輯上真正的結果必然非負。所以(ah)≥(bh)。
檢測比較結果的條件轉移指令
轉移時 轉移指令 + 標號




DF標志和串傳送指令
flag的第10位是DF,方向標志位。
在串處理指令中,控制每次操作后si,di的增減。
DF = 0:每次操作后si,di遞增;
DF = 1:每次操作后si,di遞減。
格式1: movsb
功能:(以字節為單位傳送)
相當於匯編指令:mov es:[di],byte ptr ds:[si];8086
(1) ((es)×16 + (di)) = ((ds) ×16 + (si))
(2) 如果DF = 0則: (si) = (si) + 1,(di) = (di) + 1 相當於 如果DF=0:inc si,inc di
如果DF = 1則: (si) = (si) - 1,(di) = (di) - 1 相當於 如果DF=1:dec si,dec di
movsb 的功能是將 ds:si 指向的內存單元中的字節送入 es:di中,然后根據標志寄存器DF位的值,將 si和di遞增或遞減。
格式2:movsw
功能:(以字為單位傳送)
相當於匯編指令:mov es:[di],word ptr ds:[si]
(1) ((es)×16 + (di)) = ((ds) ×16 + (si))
(2) 如果DF = 0則: (si) = (si) + 2,(di) = (di) + 2 相當於 如果DF=0:add si,2 add di,2
如果DF = 1則: (si) = (si) - 2,(di) = (di) - 2 相當於 如果DF=1:add si,2 add di,2
movsw 的功能是將 ds:si 指向的內存單元中的字送入 es:di中,然后根據標志寄存器DF位的值,將 si和di遞增或遞減。
movsb 和 movsw與rep配合使用
rep movsb
用匯編語法來描述rep movsb的功能就是:
s : movsb
loop s
rep movsw
用匯編語法來描述rep movsw的功能就是:
s : movsw
loop s
rep的作用是根據cx的值,重復執行后面的串傳送指令。
由於每執行一次movsb指令si和di都會遞增或遞減指向后一個單元或前個單元,則rep movsb就可以循環實現(cx)個字符的傳送。
由於flag的DF位決定着串傳送指令執行后,si和di改變的方向,所以我們可以通過DF的值來改變傳送的方向
相關指令:
cld指令:將標志寄存器的DF位置0
std指令:將標志寄存器的DF位置1
示例1:用串傳送指令,將data段中的第一個字符串復制到它后面的空間中。
data segment
db ‘Welcome to masm!
db 16 dup (0)
data ends
1 mov ax,data 2 mov ds,ax 3 mov si,0 ;ds:si指向data:0 4 mov es,ax 5 mov di,16 ;es:di指向data:16 6 mov cx ,16 ;(cx)=16,rep循環16次 7 cld ;設置DF=0,正向傳送 8 rep movsb
示例二:用串傳送指令,將F000H段中的最后16個字符復制到data段中。
data segment
db 16 dup (0)
data ends
1 mov ax,0f000h 2 mov ds,ax 3 mov si,0ffffh ;ds:si指向f000:ffff 4 mov ax,data 5 mov es,ax 6 mov di,15 ;es:di指向data:15 7 mov cx ,16 ;(cx)=16,rep循環16次 8 std ;設置DF=1,逆向傳送 9 rep movsb
pushf與popf
pushf :將標志寄存器的值壓棧;
popf :從棧中彈出數據,送入標志寄存器中。
pushf和popf,為直接訪問標志寄存器提供了一種方法。


