11-标志寄存器+adc/sbb+cmp+条件转移指令

一、 标志寄存器

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

  1. 用来存储相关指令的某些执行结果
  2. 用来为CPU执行相关指令提供行为依据
  3. 用来控制CPU的相关工作方式

这种特殊的寄存器在8086CPU中,被称为标志寄存器。8086CPU的标志寄存器有16位,其中存储的信息通常被称为程序状态字(PSW)。在后面我们将标志寄存器简称为flag。

flag和其他寄存器不一样,它是按位起作用的,每一位都有专门的含义,记录特定的信息。

8086CPU的flag寄存器的结构如下图所示:
在这里插入图片描述

flag的1、3、5、12、13、14、15位在8086CPU中没有使用,不具有任何含义。而0、2、4、6、7、8、9、10、11位都具有特殊的含义。

1.1 ZF标志

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

比如,指令:

mov ax,1
sub ax,1

执行后,结果为0,则zf=1

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

1.2 PF标志

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

比如,指令:

mov al,1
add al,10

执行后,结果为00001011B,其中有3个1,则pf=0

1.3 SF标志

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

计算机中通常用补码来表示有符号数据。计算机中的一个数据可以看作是有符号数,也可以看成是无符号数。这也就是说,对于同一个二进制数据,计算机可以将它当作无符号数据来运算,也可以当作有符号数据来运算,比如:

mov al,10000001B
add al,1

结果:(al)=10000010B

可以将add指令进行的运算当作无符号数的运算,那么add指令相当于计算129+1,结果为130(10000010B);也可以将指令进行的运算当作有符号数的运算,那么add指令相当于计算-127+1,结果为-126(10000010B)。

不管我们如何看待,CPU在执行add等指令时,就已经包含了两种含义,也得用同一种信息来记录两种结果。关键在于我们的程序需要哪一种结果。

SF标志,就是CPU对有符号数运算结果的一种记录,它记录数据的正负。在我们将数据当作有符号数来运算的时候,可以通过它来得知结果的正负。如果我们将数据当作无符号数来运算,SF的值则没有意义,虽然相关的指令影响了它的值。

这也就是说,CPU在执行add等指令时,是必然要影响到SF标志位的值的。

比如:

mov al,10000001B
add al,1

执行后,结果为10000010B,sf=1,表示:如果指令进行的是有符号数运算,那么结果为负。

mov al,10000001B
add al,01111111B

执行后,结果为0,sf=0,表示:如果指令进行的是有符号数运算,那么结果为负。

1.4 CF标志

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

对于位数为N的无符号数来说,其对应的二进制信息的最高位,即第N-1位,就是它的最高有效位,而假想存在的第N位,就是相当于最高有效位的更高位,如图11.2所示:
在这里插入图片描述
当两个数据相加的时候,有可能产生从最高有效位向更高位的进位。比如,两个8位数据:98H+98H,将产生进位。但是这个进位值在8位数中无法保存,注意CPU在运算的时候,并不丢弃这个进位值,而是记录在一个特殊的寄存器的某一位上,8086CPU就用flag的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。而flag的CF位也可以用来记录这个借位值。比如,下面的指令:

mov al,97H
sub al,98H			;执行后,(al)=FFH,CF=1,CF记录了向更高位的借位值
sub al,al			;执行后,(al)=0, CF=0,CF记录了向更高位的借位值

1.5 OF标志

在进行有符号数运算的时候,如果结果超过了机器所能表示的范围称为溢出。

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

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

mov al,98
add al,99

执行后结果为98+99=197,超过了8位有符号数的范围-128~127,但是没有超过无符号数的范围0~256,所以add指令执行后,CF=0,OF=1。CPU在执行add等指令的时候,就包含了两种含义:无符号运算和有符号运算。对于无符号运算,CPU用CF位来记录是否产生了进位;对于有符号数运算,CPU用OF位来记录是否产生了溢出,当然,还要用SF位来记录结果的符号。

CF和OF所表示的进位和溢出,是分别对无符号数和有符号数运算而言的,它们之间没有任何关系。

二、adc指令

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

功能格式:adc 操作对象1,操作对象2
功能:操作对象1=操作对象1+操作对象2+CF

例:

mov ax,2
mov bx,1
sub bx,ax
adc ax,1

执行后,(ax)=4

为什么要加上CF的值呢?先来看下CF的值的含义,在执行adc指令的时候加上的CF的值的含义,是由adc指令前面的指令决定的,也就是说,关键在于所加上的CF值是被什么指令设置的。显然,如果CF的值是被sub指令设置的,那么它的含义就是错位值;如果是被add指令设置的,那么它的含义就是进位值。所以adc指令和add指令相配合就可以对更大的数据进行加法运算,看下这个例子:

计算1EF000H+201000H,结果放在ax(高16位)和bx(低16位)中。

因为两个数据的位数都大于16,用add指令无法进行计算。我们将计算分两步进行,先将低16位相加,然后将高16位和进位值相加,程序如下:

mov ax,001EH
mov bx,0F000H
add bx,1000H
adc ax,0020H

adc指令执行后,也可能产生进位值,所以也会对CF进行设置。由于有这样的功能,我们就可以对任意大的数据进行加法运算。

三、sbb指令

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

指令格式:sbb 操作对象1,操作对象2
功能:操作对象1=操作对象1-操作对象2-CF

sbb和adc是基于同样的思想设计的两条指令。

四、cmp指令

cmp是比较指令,它的功能相当于减法指令,只是不保存结果。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=1, of=0

我们通过cmp指令执行后,相关标志位的值就可以看出比较的结果,以cmp ax,bx为例:

  • 如果(ax)=(bx),则(ax)-(bx)=0,所以:zf=1
  • 如果(ax) ≠ \ne =(bx),则(ax)-(bx) ≠ \ne = 0,所以:zf=0
  • 如果(ax)<(bx),则(ax)-(bx)将产生借位,所以:cf=1
  • 如果(ax)>=(bx),则(ax)-(bx)不会产生借位,所以:cf=0
  • 如果(ax)>(bx),则(ax)-(bx)即不必借位,结果又不为0,所以:cf=0且zf=0
  • 如果(ax)<=(bx),则(ax)-(bx)即可能借位,结果可能为0,所以:cf=1或zf=1

根据上面的标志寄存器的值和cmp结果的对应,我们可以看出比较指令的设计思路,即:通过做减法运算,影响标志寄存器,标志寄存器的相关位记录了比较的结果,反过来看上面的例子,指令cmp ax,bx的逻辑含义是比较ax和bx中的值,如果执行后:

  • zf=1,说明(ax)=(bx)
  • zf=0,说明(ax) ≠ \ne =(bx)
  • cf=1,说明(ax)<(bx)
  • cf=0,说明(ax)>=(bx)
  • cf=0并且zf=0,说明(ax)>(bx)
  • cf=1或zf=1,说明(ax)<=(bx)

同add、sub指令一样,CPU在执行cmp指令时,同样包含两种含义:进行无符号数运算和进行有符号数运算。所以利用cmp指令可以对无符号数进行比较,也可以对有符号数进行比较。上面陈述的都是利用cmp进行无符号数比较时,相关标志位对比较结果的记录。下面我们看下如果用cmp来进行有符号数比较时,CPU用哪些标志位对比较结果进行记录,以cmp ah,bh为例进行说明:

  • 如果(ah)=(bh),则(ah)-(bh)=0,所以:zf=1
  • 如果(ah) ≠ \ne =(bh),则(ah)-(bh)= ≠ \ne = 0,所以:zf=0

所以,根据cmp指令执行后zf标志位的值,我们就可以知道两个数据是否相等,我们继续看,如果(ah)<(bh)则可能发生什么情况:

对于有符号数运算,在(ah)<(bh)的情况下,(ah)-(bh)显然可能引起sf=1,即结果为负,比如(ah)=1, (bh)=2,则(ah)-(bh)=0FFH为-1的补码,因为结果为负,所以SF=1,但是注意,仅仅通过sf=1就判断操作对象1<操作对象2是不成立的,再看下如下的例子:
(ah)=22H, (bh)=0A0H,则(ah)-(bh)=34-(-96)=82H,82H是-126的补码,所以sf=1,这里sf=1,但是显然(ah)>(bh)。

两个有符号数相减,如果A<B,那么得到的肯定是一个负数,这个思路没有错,关键在于我们根据什么来断定得到的是一个负数。CPU将cmp指令得到的结果记录在flag的相关标志位中,我们可以根据指令执行后,相关标志位的值来判断比较的结果。单纯的考察sf的值不可能知道结果的正负,因为sf记录的只是可以在计算机中存放的相应位数的结果的正负。比如add ah,al执行后,sf记录的是ah中的8位二进制信息所表示的数据的正负。cmp ah,bh执行后,sf记录的是(ah)-(bh)所得到的8位结果数据的正负,虽然这个结果没有在我们能够使用的寄存器或内存单元中保存,但是在执行执行的过程中,它暂存在CPU内部的暂存器中。

所得到的相应结果的正负,并不能说明,运算所应该得到的结果的正负。这是因为在运算的过程中可能发生溢出,如果有这样的情况发生,那么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指令所作的比较结果,不是仅仅靠sf就能记录的,因为它只能记录实际结果的正负。

差错就出现在了溢出这里,如果没有溢出发生,那么实际结果的正负和逻辑结果的正负就是完全一致的,所以我们应该在考察sf(得知实际结果的正负)的同时考察of(得知有没有溢出),就可以得知逻辑上真正结果的正负,同时就可以知道比较的结果。

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

  • 如果sf=1,而of=0: of=0,说明没有溢出,逻辑上真正的结果代表实际结果,因为sf=1,实际结果为负,所以逻辑上真正的结果为负,所以(ah)<(bh)
  • 如果sf=1,而of=1: of=1说明有溢出,此时逻辑上真正结果的正负 ≠ \ne =实际结果的正负,因为sf=1,实际结果为负,说明逻辑上真正的结果为正,这样sf=1,of=1,说明了(ah)>(bh)
  • 如果sf=0,而of=1: of=1说明有溢出,sf=0表明实际结果非负,如果因为溢出导致了实际结果为正,那么逻辑上真正的结果必然非负,这样sf=0,of=1,说明了(ah)<(bh)
  • 如果sf=0,而of=0:of=0说明没有溢出,逻辑上真正结果的正负=实际结果的正负,因为sf=0,实际结果为负,所以逻辑上真正的结果非负,所以(ah)>=(bh)

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

”转移“指代可以修改IP,而”条件“指的是指令可以根据某种条件,决定是否修改IP。

比如,jcxz就是一个条件转移指令,它可以检测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

/待补充 238

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值