← 返回 计组与微机控制

计组与微机控制

5.7 标志寄存器续

5.7 标志寄存器续

一、图 2.8:FLAGS 标志寄存器

5.7 标志寄存器续 图 1

图 2.8,画的是 8086/8088 的 FLAGS 标志寄存器。

FLAGS 是 16 位寄存器,但不是 16 位都用。常用的 9 个标志位是:

OF DF IF TF SF ZF AF PF CF

它们大致分成两类:

状态标志:CF、PF、AF、ZF、SF、OF控制标志:TF、IF、DF

状态标志是 CPU 算完之后自动反映结果状态的。

比如有没有进位、结果是不是 0、结果是不是负数、有没有溢出。

控制标志是用来控制 CPU 行为的。

比如是否允许中断、字符串操作方向是递增还是递减、是否单步调试。

二、AF:辅助进位标志

课本第 3 个讲的是:

辅助进位标志位 AF,Auxiliary Carry Flag。

它的定义是:当低 4 位向高 4 位产生进位,或者高 4 位向低 4 位产生借位时,AF = 1,否则 AF = 0。

你可以先记成:

AF 看的是低半字节,也就是低 4 位。

一个字节有 8 位:

bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0

低 4 位就是:bit3 bit2 bit1 bit0

高 4 位就是:bit7 bit6 bit5 bit4

AF 就是看低 4 位运算时,有没有从 bit3 向 bit4 进位,或者从 bit4 向 bit3 借位。

2. 举个加法例子

比如:09H + 01H = 0AH 二进制:

0000 1001+0000 0001=0000 1010

低 4 位是:1001 + 0001 = 1010

没有从低 4 位向高 4 位进位,所以 AF = 0。

再看:0FH + 01H = 10H

二进制:

0000 1111+0000 0001=0001 0000

低 4 位:

1111 + 0001 = 1 0000

这里从 bit3 向 bit4 产生了进位,所以:

AF = 1

AF 主要用于什么?

课本说它用于十进制运算调整。

也就是和 BCD 码有关。

AF 一般不是我们判断普通加减法对错最常用的标志,它主要服务于 BCD 十进制调整。

平时做题更常考的是 CF、ZF、SF、OF。

ZF:零标志

ZF 是 Zero Flag,零标志。

定义很简单:如果运算结果为 0,则 ZF = 1;否则 ZF = 0。

注意,是看“结果是不是 0”。

例子

AL = 05H SUB AL, 05H

结果:AL = 00H 所以:ZF = 1

再如:

AL = 05H SUB AL, 03H

结果:AL = 02H不为 0,所以:ZF = 0

ZF 常用于条件跳转

比如:

CMP AX, BX JE equal

CMP AX, BX 本质上做的是:AX - BX

但不保存结果,只修改标志位。

如果 AX 和 BX 相等,那么:AX - BX = 0

所以:ZF = 1

于是 JE equal 就会跳转。

所以 ZF 经常用来判断:是否相等,结果是否为 0,循环是否结束

SF:符号标志

SF 是 Sign Flag,符号标志。

定义是:如果运算结果最高位为 1,则 SF = 1;如果最高位为 0,则 SF = 0。

它反映的是结果看成有符号数时的正负。

字节运算看第 7 位

如果是 8 位结果,最高位是 bit7。

0111 1111 最高位是 0,所以 SF = 0,表示正数。

1000 0000最高位是 1,所以 SF = 1,表示负数。

字运算看第 15 位

如果是 16 位结果,最高位是 bit15。

例如:7FFFH = 0111 1111 1111 1111B

最高位是 0,所以 SF = 0。

8000H = 1000 0000 0000 0000B

最高位是 1,所以 SF = 1。

SF 只是看最高位,不等于“运算一定错了”

比如 8 位有符号数中:

80H = -128FFH = -1

它们最高位都是 1,所以 SF = 1。

这只是说明结果按有符号数解释是负数,不表示结果错误。

判断有符号数是否超范围,要看 OF。

OF:溢出标志

OF 是 Overflow Flag,溢出标志。

这个是重点,也是最容易和 CF 混的地方。

课本说:当运算结果超过机器用补码所能表示的范围时,OF = 1,否则 OF = 0。

这里关键词是:

补码有符号数表示范围

所以 OF 主要用于判断 有符号数运算是否溢出。

8 位有符号数范围 8 位补码能表示:-128 ~ +127

所以如果两个 8 位有符号数相加,数学结果超过这个范围,就发生溢出。

16 位有符号数范围

16 位补码能表示:-32768 ~ +32767

超过这个范围,OF = 1。

OF 的直观判断方法

对于加法:

两个正数相加,结果却变成负数 → OF = 1两个负数相加,结果却变成正数 → OF = 1一正一负相加,不会产生有符号溢出

对于减法:

正数 - 负数,结果却变成负数 → OF = 1负数 - 正数,结果却变成正数 → OF = 1同号相减,一般不会产生有符号溢出

简单记:OF 看有符号数结果是否超出范围。

CF 和 OF 的区别

这一页最重要的地方就是:CF 和 OF 不是一回事。

CF 是进位/借位标志,主要服务于 无符号数。

OF 是溢出标志,主要服务于 有符号数。

同一个二进制结果,如果把它当无符号数看,可能是对的;当有符号数看,可能是错的。

反过来也一样。

例子一:100 + 100

按 8 位计算:

100D = 64H = 0110 0100B100D = 64H = 0110 0100B

相加:

0110 0100+0110 0100=1100 1000

结果是:C8H

从无符号角度看:

100 + 100 = 200

8 位无符号数能表示 0 ~ 255,所以 200 没超范围。

没有从最高位向外进位,所以:

CF = 0

但是从有符号角度看:

8 位有符号数范围是:

-128 ~ +127

100 + 100 = 200,超过 +127。

而且结果 1100 1000B 最高位是 1,被解释成负数。

两个正数相加,结果变成负数,这就是有符号溢出。

所以:OF = 1

这就是表 2.2 第一行想表达的意思:

CF = 0,但 OF = 1

无符号没错,有符号错了。

例子二:-85 + -1

8 位补码中:

-85 = ABH = 1010 1011B-1 = FFH = 1111 1111B

相加:

1010 1011+1111 1111=1 1010 1010

低 8 位结果是:

1010 1010B = AAH

这正好是:-86

这里从最高位向外产生了进位,所以:

CF = 1

但是有符号数看:

-85 + -1 = -86

仍然在 -128 ~ +127 范围内,没有有符号溢出。

所以:OF = 0

这说明:CF = 1 不代表有符号运算错了。

例子三:两个负数相加,结果变成正数

假设两个 8 位负数相加,数学结果小于 -128。

比如:-85 + -117 = -202

-202 超出 8 位有符号数范围。

所以有符号数一定溢出:

OF = 1

二进制运算中也可能产生最高位向外的进位,所以可能:

CF = 1 OF = 1

这说明:CF 和 OF 可以同时为 1,但含义不同。

总结 CF 和 OF

标志  |  主要看什么  |  面向哪类数  |  什么时候置 1
CF  |  最高位向外进位/借位  |  无符号数  |  无符号运算超范围
OF  |  有符号结果超出补码范围  |  有符号数  |  正正得负,负负得正等

一句话记:

CF 管无符号进位,OF 管有符号溢出。

TF:单步标志

TF 是 Trace Flag,单步标志,也叫跟踪标志。

课本说:

当 TF = 1 时,CPU 每执行完一条指令,就产生一次单步中断。

这个主要用于调试程序。

什么叫单步执行?

正常执行程序时,CPU 会连续执行很多条指令。

但调试程序时,我们希望:

执行一条,停一下。再执行一条,再停一下。

这样可以观察每条指令执行后寄存器、内存、标志位的变化。

这就叫单步执行。

TF 的作用

如果:TF = 1

CPU 每执行完一条指令,就触发单步中断,调试程序就能接管,显示当前状态。

如果:TF = 0

CPU 正常连续执行。

所以 TF 不是用来算术判断的,而是用于调试。

IF:中断允许标志

IF 是 Interrupt-enable Flag,中断允许标志。

定义是:IF = 1:允许响应可屏蔽中断IF = 0:不允许响应可屏蔽中断

注意是 可屏蔽中断。

8086 里有些中断可以被 IF 屏蔽,有些不能。

什么叫可屏蔽中断?可屏蔽中断就是 CPU 可以暂时不响应的外部中断。

比如某些外设发来的中断请求,CPU 可以根据 IF 决定是否响应。

如果:IF = 1

CPU 允许响应这些中断。

如果:IF = 0

CPU 暂时不响应这些可屏蔽中断。

IF 常见控制指令

通常有两条指令:

STICLI

STI:Set Interrupt Flag,置 IF = 1,开中断。CLI:Clear Interrupt Flag,清 IF = 0,关中断。

DF:方向标志

DF 是 Direction Flag,方向标志。它控制的是 串操作指令 中 SI、DI 的变化方向。

课本说:

DF = 0:串操作后 SI/DI 自动增量DF = 1:串操作后 SI/DI 自动减量

1. DF = 0:从低地址到高地址

比如串传送:

MOVSB

默认是:

DS:SI → ES:DI

如果 DF = 0,传完一个字节后:

SI = SI + 1DI = DI + 1

也就是从低地址往高地址处理。

DF = 1:从高地址到低地址

如果 DF = 1,执行 MOVSB 后:

SI = SI - 1DI = DI - 1

也就是从高地址往低地址处理。

字操作时加减多少?

如果是字节串操作,比如 MOVSB:

SI/DI 每次变化 1

如果是字串操作,比如 MOVSW:

SI/DI 每次变化 2

因为一个字是 2 个字节。

DF 常见控制指令

C LDSTD

CLD:Clear Direction Flag,清 DF = 0,正向处理。STD:Set Direction Flag,置 DF = 1,反向处理。

考试里常问:

DF = 0,SI/DI 增加DF = 1,SI/DI 减少