标志寄存器

标志寄存器(8086CPU)

作用

  1. 用来存储相关指令的某些执行结果
  2. 用来为CPU执行相关指令提供行为依据
  3. 用来控制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

执行后,结果为10000010Bsf = 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等指令的时候,就包含了两种含义:

  1. 无符号数运算
  2. 有符号数运算

对于无符号数运算,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位的值,将sidi递增或递减

格式:movsb

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

  1. ((es) * 16 + (di)) = ((ds) * 16 + (si))
  2. 如果df = 0则:(si) = (si) + 1, (di) = (di) + 1
  3. 如果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位的值,将sidi递增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进行的是串传送操作中的一个步骤,一般来说,movsbmovsw都和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

image-20191116100944518

可以看出加法是分两步进行的

  1. 低位相加
  2. 高位相加再加上低位相加产生的进位值

下面的指令和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,为直接访问标志寄存器提供了一种方法

标志寄存器在debug中的表示

原文地址:https://www.cnblogs.com/songyaqi/p/11888126.html