CPU內部的寄存器中,有一種特殊的寄存器(對於不同的機器,個數和結構都有可能不同)具有以下三個功能:
- 用來存儲某些相關指令的執行結果
- 用來為CPU執行相關的指令提供行為依據
- 用來控制CPU的相關工作方式
這種特殊的寄存器在8086CPU中稱為標志寄存器。8086的標志寄存器有16位,其中存儲的信息通常被稱為程序狀態字(PSW)。
標志寄存器與其他寄存器不一樣,其他寄存器是用來放數據的,都是整個寄存器具有一個含義,而標志寄存器是按位起作用的。
8086中的標志寄存器的結構如下圖所示:
其中1、3、4、12、13、14、15位在8086中沒有使用。另外對於有確切含義的每一位,我們稱為標志位
ZF標志
標志寄存器的第六位是ZF,零標志位。他是記錄相關指令執行后,其結果是否位零。如果為零,那么zf=1,如果不為零,那么zf=0
比如指令:
mov ax, 1
sub ax, 1
執行后,ax的結果為0,所以zf=1
再比如:
mov ax, 2
sub ax, 1
執行后,ax的結果不為0,所以zf=0
在這里,有一點需要注意:在8086的指令集中,有的指令的執行是影響標志位的,比如add、sub、mul、div、inc、or、and等,它們大都是運算指令(進行邏輯或算數運算);有的指令的執行對標志寄存器沒有影響,比如mov、push、pop等,它們大都是傳送指令。
PF標志
標志寄存器的第二位是PF,奇偶標志位。它記錄相關指令執行后,其結果的所有bit位中1的個數是否位偶數。如果是偶數,pf=1,如果位奇數,pf=0
比如指令:
mov al, 1
add al, 10
執行后,al為00001011B,其中有3個1,所以pf=0
再比如:
mov al, 1
or al, 2
執行后結果為00000011B,其中有2個1,所以pf=1
SF標志
標志寄存器的第七位是SF,符號標志位。它記錄相關指令執行后,其結果是否為負。如果為負,sf=1,如果非負,sf=0
這里要明確一點,在計算機中,通常用補碼來表示有符號的數據,計算機中的一個數據既可以看作有符號數,也可以看作無符號數。不管我們如何看待,當CPU在進行運算的時候,就已經包含了兩種含義,也將的到同一種信息來記錄的兩種結果。關鍵在於我們的程序需要那一種。
SF標志,是CPU對有符號數運算結果一種記錄。如果我們將數據當作無符號數來運算,SF標志位則沒有意義,雖然計算過程中影響了他的值。
我個人在這里的更簡單寫的理解是計算后結果的最高位是否為1,為1,這sf=1,否則,sf=0
比如指令:
mov al, 100000001B
add al, 1
執行后結果為10000010B,sf=1,表示如果進行的是有符號運算的話,則結果為負
再比如
mov al, 10000001B
add al, 01111111B
執行后,結果為0,sf=0,表示,如果進行的是有符號運算,這結果為非負
CF標志
標志寄存器的第0為是CF,僅為標志位。一般情況下,在進行 無符號 運算的時候,它記錄了運算結果的最高有效位向更高有效位的進位,或從更高有效位的借位。
比如指令:
mov al, 98H
add al, al ; 執行后(al)=30H, CF=1, 產生進位
add al, al ; 執行后(al)=60H, CF=0, 沒有進位,或者說進位為0
再比如:
mov al, 97H
sub al, 98H ; 執行后(al)=FFH, CF=1, 產生借位
sub al, al ; 執行后(al)=0, CF=0, 借位為0
OF標志
標志寄存器的第11位是OF,溢出標志位。一般情況下,OF記錄了 有符號數 的運算結果是否發生了溢出。如果發生了溢出,of=1,如果沒有,of=0
{% note success %} 這里一定要注意的是CF和OF的區別,CF是對無符號數運算有意義的標志位,而OF是對有符號數運算有意義的標志位。 它們之間沒有任何關系 {% endnote %}
比如指令:
mov al, 98
add al, 99
執行后,of=1,發生溢出,沒有進位
再比如:
mov al, 0F0H
add al, 78H
執行后:of=0,沒有溢出
DF標志
標志寄存器的第10位是DF,方向標志位。在串傳送指令中,控制每次操作后si、di的增減。
df=0,每次操作后si、di遞增
df=1,每次操作后si、di遞減
例如串傳送指令movsb
:
-
格式:
movsb
-
功能:執行下面幾步操作:1、((es) x 16 + (di)) = ((ds) x 16 + (si)) 2、如果df=0,(si)=(si)+1, (di)=(di)+1。如果df=1,則(si)=(si)-1, (di)=(di)-1
另外還有movsw
,這時候就是一次傳送一個字了,相應的si和di的+1-1也就變更成了+2-2
一般,movsb
和movsw
一般配合指令rep
指令使用,如rep movsb
, 相當於
s: movsb ; 當然啦,在此之前要先設置cx寄存器
loop s
adc、sbb、cmp、pushf和popf指令
再沒有標志寄存器的時候,我們進行加減運算最多只能進行16位的加減運算,這在實際的應用中顯然是不夠的,那么有了標志寄存器,在結合adc
和sbb
指令,我們就可以進行任意多位的數的加減法了
adc指令
adc是帶進位的加法指令,它利用了CF上記錄的進位值
- 指令格式:adc 操作對象1,操作對象2
- 功能: 操作對象1 = 操作對象1 + 操作對象2 + CF
比如:計算1EF000H + 201000H,結果放在ax(高16位)和bx(低16位)中:
mov ax, 001EH
mov bx, 0F000H
add bx, 1000H
adc ax, 0020H
更多位數的數相加和以上同理
sbb指令
sbb是借位減法指令,它利用了CF位上記錄的借位值
- 指令格式:sbb 操作對象1,操作對象2
- 功能:操作對象1 = 操作對象1 - 操作對象2 - CF
比如:計算003E1000H - 00202000H,結果保存在ax,bx中
mov bx, 1000H
mov ax, 003EH
sub bx, 2000H
sbb ax, 0020H
cmp指令
cmp是比較指令,功能相當於減法指令,只是不保存結果。執行后,對標志寄存器產生影響
- cmp指令格式:cmp 操作對象1,操作對象2
- 功能:計算操作對象1 - 操作對象2,但不保存結果
經過cmp
計算后,我們就可以用je
、jne
、jb
、jnb
、ja
、jna
指令進行跳轉了。
因為比較復雜,在這里就不具體說實現的細節了,具體在更。
pushf和popf指令
pushf的功能是將標志寄存器的值壓棧,而popf是從棧中彈出數據送入標志寄存器
這兩個指令為直接訪問寄存器提供了一種方法
在這里,我們討論了六種寄存器,另外還有IF,TF,和AF沒有討論,具體再更
完