標志寄存器(8086CPU)
作用
- 用來存儲相關指令的某些執行結果
- 用來為CPU執行相關指令提供行為依據
- 用來控制CPU的相關工作方式
大小
標志寄存器有16位
使用方式
標志寄存器是按位起作用,也就是說每一個位都有專門的含義,記錄特定的i西南西
flag的1、3、5、12、13、14、15位在8086CPU中沒有使用,不具有任何含義。而0、2、4、6、7、8、9、10、11位都具有特殊的含義
ZF標志,在第6位,結果為0則為1,否則為0
zf (Zero Flag) 是零標志位,在第6位;它記錄相關指令執行后,其結果是否為0,如果為0,那么
zf = 1
;否則zf = 0
例如
mov ax, 1
sum ax, 1
執行后, 結果為0,則zf = 1
mov ax, 2
sum ax, 1
執行后,結果不為0,則zf = 0
注意
在指令執行的過程中,有些指令對標志寄存器有影響,比如:add、sum、mul、div、inc、or、and等,他們大都是運算指令;而有些指令對標志寄存器沒有影響,比如:mov、push、pop等,他們大都是傳送指令。在使用一條指令的時候,要注意這條指令的全部功能,其中包括,執行結果對標志寄存器的哪些標志位產生了影響。
PF標志,在第2位,結果中1的個數為偶數則為1,否則為0
pf( Parity Flag)表示奇偶標志位,在第2位;他記錄的是相關指令執行后,如果所有的bit位中1的個數是否為偶數。如果1的個數位偶數,
pf = 1
,如果為奇數,那么pf = 0
例如:
mov al, 1
add al, 10
執行后結果為1011B,其中有3(奇數)個1,則pf = 0
mov al, 1
or al, 2
執行后,結果為:11B,其中有2(偶數)個1,則pf = 1
SF 標志,在第7位,結果為負則為1,否則為0;有符號運算有效
sf(Symbol Flag)表示符號標志位,在第7位;它記錄相關指令執行后,其結果是否為負。如果為負,則
sf = 1
;如果非負,sf = 0
通常CPU計算的時候有兩種方式,一種是有符號的計算,一種是無符號的計算。
SF標志,就是CPU對有符號數運算結果的一種記錄,他記錄數據的正負。
如果我們將數據進行無符號運算,SF的值則沒有意義,雖然相關指令影響了他的值
例子:
mov al, 10000001B
add al, 1
執行后,結果為10000010B
,sf = 1
,表示:如果指令進行是有符號運算,那么結果為負
mov al, 10000001B
add al, 01111111B
執行后,結果為0,sf = 0;表示:如果指令記性的是有符號數運算,那么結果為0
CF標志,在第0位,存儲進位或借位的值
cf(Carry Flag)表示進位標志位,在第0位。在進行無符號運算的時候,他記錄了運算結果的最高有效位向更高位的進位值,或從更高位的借位值
對於位數為N的無符號數來說,其對應的二進制信息的最高位,即第N-1為,就是他的最高位,而假想存在的第N位,就是相對於最高有效位的更高位
我們都知道,在兩個數相加的時候,會往更高的位進位;比如98H + 98H
,將產生進位。由於這個進位值在8位數中無法進行報錯。我之前認為這個數就丟失了。其實CPU在運算的時候,並不丟棄這個值,而是記錄在CF標志位上面。
例如
mov al, 98H
add al, al
執行后:(al) = 30H, CF = 1
,CF 記錄了從最高有效位向更高位的進位值
再次執行add al, al
執行后:(al) = 60H, CF = 0
, CF記錄了從最高有效位向更高位的進位值
而在做減法的時候,有可能向更高位借位;比如,兩個8位數據97H - 98H
,將產生借位。借位后相當於計算197H-98H
;CF來記錄這個借位值,例如下面的指令
mov al, 97H
sub al, 98H ; 執行后:(al) = FFH, CF=1, CF記錄了向更高位的借位值
sum al, al ; 執行后:(al) = 0, CF = 0, CF 記錄了向更高位的借位值
OF標志,在第11位,結果溢出則為1,否則為0;沒理解透徹
of( Overflow Flag)表示溢出標志位,在第11位。它記錄了有符號數運算的結果是否產生了溢出,如果產生了溢出,
of = 1
;如果沒有,OF = 0
CPU在執行add等指令的時候,就包含了兩種含義:
- 無符號數運算
- 有符號數運算
對於無符號數運算,CPU用CF來記錄是否產生了進位;對於有符號數運算,CPU用OF來記錄是否產生了溢出。當然還要用SF來記錄結果的符號。對於無符號數運算98+99沒有進位,CF = 0
;對於有符號數運算,98 + 99發生溢出,OF= 1
mov al, 0F0H
add al, 88H
add指令執行后:CF = 1, OF= 1
。對於無符號數運算,0F0 + 88H
有進位CF= 1
, 對於有符號運算,0F0H + 88H
發生溢出,OF = 1
mov al, 0F0H
add al, 78H
add指令執行后:CF = 1, OF = 0
。對於無符號運算,0F0 + 78H
有進位,CF = 1
;對於有符號運算,0F0 + 78H
不會發生溢出, OF = 0
每一個有符號數,似乎都對應着一個無符號數,我們如何知道CPU在執行運算指令的時候,進行的是有符號運算還是無符號運算呢??????????????
DF標志
df( Direction Flag), 第10位。在串處理指令中, 控制每次操作后si、di的遞減
df = 0
: 每次操作后si、di遞增
df = 1
:每次操作后si、di遞減
通過cld和std指令來進行設置DF的標志
然后用req movsb/movsw進行復制數據
串傳送指令movsb
將
ds:si
指向的內存單元中的字節送入es:di
中,然后根據標志寄存器df
位的值,將si
和di
遞增或遞減
格式:movsb
功能:執行movsb
指令相當於執行下面幾步操作
((es) * 16 + (di)) = ((ds) * 16 + (si))
- 如果
df = 0
則:(si) = (si) + 1
,(di) = (di) + 1
- 如果
df = 1
則:(si) = (si) - 1
,(di) = (di) - 1
movsb
的功能可以這樣描述mov es:[di], byte ptr ds:[si]
,但是8086CPU沒有這樣的指令。
如果df = 0
inc si
inc di
如果df = 1
dec si
dec di
串傳送指令movsw
movsw功能是將
ds:si
指向的內存單元中的字節送入es:di
中,然后根據標志寄存器df
位的值,將si
和di
遞增2或遞減2
movsw
的功能可以這樣描述mov es:[di]. word ptr es:[si]
8086不支持這樣的指令,這里只是描述
如果df = 0
add si, 2
add di, 2
如果df = 1
sub si, 2
sub di, 2
movsb和movsw進行的是串傳送操作中的一個步驟,一般來說,movsb
和movsw
都和req
配合使用,格式如下
reg movsb
用匯編語法來描述req movsb
的功能是:
s:
movsb
loop s
cld和std設置DF標志位
cld 指令:將標志寄存器df位,置0
std 指令:將標志寄存器的df位,置1
adc 指令,帶位加法指令,用於計算特別大的數據
帶進位加法指令,它利用了CF位上記錄的進位值
指令格式:abc 操作對象1, 操作對象了
功能:操作對象1 = 操作對象1 + 操作對象2 + CF
比如指令:adc ax, bx
實現的功能就是:(ax) = (ax) + (bx) + CF
例:
mov ax, 2
mov bx, 1
sub bx, ax
adc ax, 1
執行后,(ax) = 4
。adc執行時,相當於計算:(ax) + 1 + CF = 2 + 1 + 1 = 4
mov ax, 1
add ax, ax
adc ax, 3
執行后,(ax = 5)
. adc執行時,相當於計算: (ax) + 3 + CF = 2 + 3 + 0 = 5
mov al, 98H
add al, al
adc al, 3
執行后,(al) = 34H
。adc執行時,相當於計算:(al) + 3 + CF = 30H + 3 + 1 = 34H
可以看出,adc指令比add指令多加了一個CF位的值。
為啥要加呢?為啥要有這樣一條指令呢? 看一下兩個數據0198H和0183H
可以看出加法是分兩步進行的
- 低位相加
- 高位相加再加上低位相加產生的進位值
下面的指令和add ax, bx
具有相同的值
add al, bl
adc ah, bh
CPU提供adc指令的目的,就是來進行加法的第二步運算的,比如我們需要計算特別大的數據的時候可以采用這種方式
sbb 指令, 帶借位減法指令,用於運算特別大的數據
帶位減法指令,利用CF位上記錄的借位值
指令格式: sbb 操作對象1,操作對象2
功能:操作對象1 = 操作對象1 - 操作對象2 - CF
比如指令sbb ax, bx
實現的功能是:(ax) = (ax) - (bx) - CF
cmp指令,這個玩意有點復雜(P234, 11.8)
cmp是比較指令,cmp的功能相當於減法指令,只是不保存結果。指令執行后將對標志寄存器產生影響
指令格式: cmp 操作對象1,操作對象2
功能:計算操作對象1-操作對象2但並不保存結果,僅僅根據計算結果對標志寄存器進行設置。
比如,指令cmp ax, ax
做(ax)-(ax)
的運算,結果為0,但並不在ax中保存,僅僅影響flag的想改給為。指令執行后:zf = 1, pf = 1, sf = 0, cf = 0, of = 0
下面的指令:
mov ax, 8
mov bx, 3
cmp ax, bx
執行后:(ax) = 8, zf = 0, pf = 1, sf = 0, cf = 0, of = 0
其實我們通過cmp指令執行后,相關標志位的值就可以看出比較的結果
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 = 1並且zf = 0
;
如果(ax) <= (bx)
則(ax) - (bx) 既可能借位,結果可能為0
, 所以cf = 1或zf = 1
;
指令cmp ax, bx
的邏輯含義是比較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)
以上是無符號的比較邏輯
cmp既可以對無符號進行比較,也可以對有符號進行比較,上面所說的是對無符號數進行比較時,相關標志位對比結果的記錄
有符號的比較結果
如果因為溢出導致實際結果為負,那么邏輯上真正的結果必然為正。
如果因為溢出導致實際結果為正,那么邏輯上真正的結果必然為負
pushf和popf
pushf的功能是將標志寄存器的值壓棧,而popf是從棧中彈出數據,送入標志寄存器中
pushf和popf,為直接訪問標志寄存器提供了一種方法