11 标志寄存器

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/fallfeather/article/details/82811396

1、CPU内部的寄存器中,有一种特殊的寄存器(对于不同的处理机,个数和结构都可能不同)具有下面三种作用

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

(2)用来为CPU执行相关指令提供行为依据;

(3)用来控制CPU的相关工作方式。

这种特殊的寄存器在8086CPU中,被称为标志寄存器。8086CPU的标志寄存器有16位,其中存储的信息通常被称为程序状态字(PSW)。我们已经使用过8086CPU的ax,bx,cx,dx,si,di,bp,sp,IP,cs,ss,ds,es等13个寄存器了,接下来我们要学最后一个寄存器(flag)

flag和其他寄存器不一样,其他寄存器是用来存放数据的,都是整个寄存器具有一个含义。而flag寄存器是按位起作用的,也就是说,它的每一位都有专门的含义,记录特定的信息


这一节,我们学习CF、PF、ZF、SF、OF、DF

2、ZF标志

flag的第六位是ZF,零标志位。他记录i相关指令执行后,其结果是否为0.如果结果为0,那么ZF=1;如果其结果不为0,那么ZF=0

在8086CPU的指令集中,有的指令的执行是影响标志寄存器的,比如,add、sub、mul、div、inc、or、and等,他们大都是运算指令(进行逻辑或算术运算);有的指令的执行对标志寄存器没有影响,比如mov、push、pop等,他们大都是传送指令。在使用一条指令的时候,要注意这条指令的全部功能,其中包括,执行结果对标志寄存器的哪些标志位造成影响

3、PF标志

flag的第二位是PF,奇偶标志位,他记录相关指令执行后,其结果的所有bit位中1的个数是否为偶数。如果1的个数为偶数,pf=1,如果为奇数,那么pf=0.

4、SF标志

flag的第七位是SF,符号标志位。他记录相关指令执行后,其结果是否为负。如果结果为负,sf=1;如果非负,sf=0。

5、CF,OF标志位

flag的第零位是CF,进位标志位。一般情况下,在进行无符号运算的时候,他记录了运算结果的最高有效位向更高的进位值,或从更高的借位值。

flag的第11位是OF,溢出标志位。一般情况下,OF记录了有符号数运算的结果是否发生了溢出。如果发生溢出,OF=1;如果没有,OF=0.

一定要注意CF和OF的区别:CF是对无符号数运算有意义的标志位,而OF是对有符号数运算有意义的标志位

6、adc指令

adc是带进位的加法指令,他利用了CF位上记录的进位值

如:adc ax.bx实现的功能是:ax = ax + bx + CF

可以看出,adc指令比add指令多家了一个CF位的值。为什么要加上CF的值呢?CPU为什么要提供这样一条指令呢?

加法分两步来进行

(1)低位相加

(2)高位相加在加上低位相加产生的进位值

add ax,bx相当于

add al,bl

adc ah,bh

看起来CPU提供adc指令的目的,就是俩进行加法的第二步运算的。adc指令和add指令相配合皆可以对更大的数据进行加法运算

7、sbb指令

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

sbb ax,bx实现的功能是:ax = ax - bx - CF

sbb和adc是基于同样思想的两条指令,在应用思想上和adc类似

8、cmp指令

cmp是比较指令,cmp的功能相当于减法指令,只是不保存结果。cmp指令执行后,将对标志寄存器产生影响。其他相关指令通过识别这些被影响的标志寄存器位来得知比较结果

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

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

有如下结论:

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 操作对象 1 ,操作对象2指令执行后sf= 1,就说明操作对象1<作对象2?

所得到的相应结果的正负,并不能说明,运算所得到的结果的正负,这是因为在运算的过程中可能发生溢出。如果有这样的情况发生,那么sf的值就不能说明任何问题,比如:

mov ah,22h

mov bh 0A0h

sub ah,bh

结果sf=1,,运算实际得到的结果是ah=82H。但是在逻辑上,运算所应该得到的结果是34-(-96)=130,就是因为130这个结果作为一个有符号数超出了-128~127这个范围,在ah中不能表示,而ah中的结果被CPU当作有符号数解释为-126.而sf被用来记录这个实际结果的正负,所以sf=1,但sf=1不能能说明在逻辑上,运算所得的正确结果的正负

但是逻辑上结果的正负,才是cmp指令所求的正确结果,因为我们就是要靠他得到两个操作对象的比较心细。所以cmp指令所作的比较结果,不仅仅靠cf就能记录的,因为它只能记录实际结果的正负,而二者之间有多大的距离呢,我们知道,实际结果的正负,之所以不能说明逻辑上真正的正负,关键的原因在于发生了溢出。如果没有溢出发生的话,那么,实际结果的正负和逻辑上结果的正负就一致了。

所以,我们应该考察sf(得知实际结果的正负)的同时考察of(得知有没有溢出),就可以得知逻辑上真正结果的正负,同时就可以知道比较的结果

下面,我们一cmp ah,bh为例,总结一下CPU执行cmp指令后,sf和of的值是如何来说明比较的结果的。

(1)如果sf=1,而of=0

of=0,说明没有溢出,逻辑上真正结果的正负=实际结果的正负;

因为sf=1,实际结果为负,所以逻辑上真正的结果为负,所以ah<bh

(2)如果sf=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

(1)如果sf=0,而of=0

of=0,说明没有溢出,逻辑上真正结果的正负=实际结果的正负;

因为sf=0,实际结果非负,所以逻辑上真正的结果非负,所以ah>=bh

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

“转移”指的是他能够修改IP,而“条件”指的是他可以根据某种条件,决定是否修改IP

比如jxcz就是一个条件转移指令,它可以检测cx中的数值,如果cx=0,就修改IP,否则什么都不做。所有条件转移指令的转移位移都是【-128,127】

除了jcxz之外,CPU还提供了其他条件转移指令,大多数条件转移指令都检测标志寄存器的相关标志位,根据检测的结果决定是否修改IP。他们检测的是哪些标志位呢?就是被cmp指令影响的那些,表示比较结果的标志位。这些条件转移指令通常和cmp相配合使用,就好像call和ret指令通常去相配合使用一样

因为cmp指令可以同时进行两种比较:无符号数和有符号数的比较,所以根据cmp指令的比较结果进行转移的指令也分两种,即根据有符号数的比较结果进行条件转移指令(他们检测zf,cf的值)和根据有符号数的比较结果进行转移的条件转移指令(他们检测sf,of,和zf的值)

下面是一些常用的检测比较结果的条件转移指令

指令 含义 检测的相关标志位
je 等于则转移 zf=1
jne 不等于则转移

zf=0

jb 低于则转移 cf=1
jnb 不低于则转移 cf=0
ja 高于则转移 cf=0且zf=0
jna 不高于则转移 cf=1或zf=1

10、DF标志位和串传送指令

flag的第十位是DF,方向标志位。在串处理指令中,控制每次操作后si,di的增减

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

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

格式:movsb

功能:执行movsb指令相当于进行下面几步操作

(1)es*16+di=ds*16+si

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

                               di=di+1

          如果df=1,则si=si-1

                               di=di-1

可以看出,movsb的功能是将ds:si指向的内存单元中的字节送入es:di中,然后根据标志寄存器df位的值,将si和di递增或递减

当然也可以传送一个字

格式:movsw

movsw的功能是将ds:si指向的内存单元中的字送入es:di中,然后根据标志寄存器df位的值,将si和di递增2或递减2

还有个命令:rep

rep的作用是根据cx的值,重复执行后面的串传送指令。由于每执行一次movsb之林那个si和di都会递增或递减指向后一个单元或前一个单元,则rep movsb就可以循环实现cx个字符的传送,同理也可以使用 rep movsw

由于flag的df位决定着串传送指令执行后,si和di改变的方向,所以CPU应该提供相应的指令来对df位进行设置,从而使程序员能够决定传送的方向

8086CPU提供下面两条指令对df位进行设置

cld指令:将标志寄存器的df位置0

std指令:将标志寄存器的df位置1

11、pushf和popf

pushf的功能是将标志寄存器的值压栈,而popf是从栈中弹出数据,送入标志寄存器中

pushf和popf,为直接访问标志寄存器提供了一个方法

12、标志寄存器在Debug中的表示

在Debug中,标志寄存器是按照有意义的各个标志位单独表示的。

下面列出Debug对我们已知的标志位的表示

标志 值为1的标记 值为0的标记
of OV NV
sf NG PL
zf ZR NZ
pf PE PO
cf CY NC
df DN UP

猜你喜欢

转载自blog.csdn.net/fallfeather/article/details/82811396