计组与微机控制
5.7 标志寄存器续
5.7 标志寄存器续
一、图 2.8:FLAGS 标志寄存器

图 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 减少
