计组与微机控制
5.6 段寄存器、指令寄存器和标志寄存器
5.6 段寄存器、指令寄存器和标志寄存器

CPU 要访问某个内存单元,必须知道:
它在哪个段?它在这个段内偏移多少?
也就是:段地址 + 偏移地址
段地址由段寄存器提供。
偏移地址由 IP、SP、BP、SI、DI、BX 或指令中的位移量等提供。所以一个内存地址通常写成:段寄存器:偏移地址
例如:CS:IP DS:BX SS:SP ES:DI
一个程序可以有很多段,但当前最多有 4 个段
课本说,一个程序可以分成很多个存储段。
但是 CPU 运行的任意时刻,最多只能有 4 个“当前段”。
这 4 个当前段由 4 个段寄存器指出:
CS:当前代码段
DS:当前数据段
ES:当前附加段
SS:当前堆栈段可以这样理解:
内存里可能有很多个房间。 但 CPU 手里当前只有 4 张“门牌号卡片”。 这 4 张卡片分别指向当前代码、当前数据、当前附加数据、当前堆栈。
CS、DS、ES、SS 的角色不能随便混
课本强调,这 4 个当前段的作用不能随便调换。
意思是:
CS 通常必须指向代码段,因为 CPU 取指令靠 CS:IP。
SS 通常必须指向堆栈段,因为 PUSH、POP、CALL、RET 等栈操作靠 SS:SP。
DS 和 ES 通常指向数据段或附加数据段。尤其是 CS 很特殊。
你不能像普通寄存器一样直接:
MOV CS, AX这在 8086 里是不允许的。
CS 通常通过跳转、调用、返回、中断等方式改变。
图 2.6:用段寄存器寻找存储段
图 2.6 左边画了 CS、DS、SS、ES 四个段寄存器。
右边是一条从:00000H 到 FFFFFH的内存空间。
因为 8086 有 20 位地址线,所以内存物理地址范围是:
00000H ~ FFFFFH
也就是 1MB。图中每个段寄存器都指向内存中的某个段基址。
然后通过偏移量找到段内具体单元。
段基址和偏移量
如果:DS = 2000H
偏移量 = 1234H那么物理地址是:2000H × 10H + 1234H = 20000H + 1234H = 21234H
所以:DS:1234H → 物理地址 21234H
注意,这里的 2000H 不是直接作为物理地址用,而是要左移 4 位。
IP:指令指针寄存器
IP 是 Instruction Pointer,指令指针。
它的作用是:保存下一条将要执行的指令在当前代码段中的偏移地址。
所以取指令时用的是:CS:IP
CS 给出代码段的段基址。
IP 给出下一条指令在代码段内的偏移量。IP 会自动变化
程序运行时,CPU 会自动修改 IP。
比如当前执行的指令长度是 3 个字节。
假设执行前:IP = 0100H
CPU 取完这条 3 字节指令后,IP 会自动变成:
IP = 0103H
这样下一次就能取下一条指令。
所以 IP 的变化通常不需要程序员手动完成。
普通程序不能直接访问 IP
课本强调:
一般编制的程序不能直接访问 IP。
也就是说,不能这样写:
MOV AX, IP
MOV IP, AX这是不允许的。但是程序可以通过控制转移指令间接改变 IP。
比如:
JMP label
CALL subroutine
RET
INT 21H这些指令会改变程序执行位置,所以会影响 IP。
图 2.7:IP 的功能
图 2.7 表达的是:
CS 指向代码段基址。
IP 指向代码段内某个偏移位置。
CS:IP 合起来找到正在执行或将要执行的指令。执行完当前指令后,IP 自动指向下一条指令。
所以可以把 IP 想成:CPU 读代码时的书签。
CPU 执行程序就像读书,IP 指向下一句要读的位置。
----FLAGS:标志寄存器----
FLAGS 是 16 位标志寄存器,也叫程序状态字 PSW。
它的作用是:反映 CPU 执行运算后的状态,并控制某些 CPU 行为。
8086/8088 中常用的标志有 9 个。

其中 6 个是状态标志:
CF、PF、AF、ZF、SF、OF
其中 3 个是控制标志:
TF、IF、DF
这页开始讲 CF 和 PF。
状态标志和控制标志有什么区别?
状态标志是 CPU 运算后自动产生的结果状态。
比如:有没有进位?结果是不是 0? 结果符号是正还是负? 有没有溢出?
控制标志则是用来控制 CPU 行为的。
比如:
是否允许中断? 字符串操作方向是递增还是递减? 是否单步执行?
所以:
状态标志:反映结果 控制标志:控制行为
CF:进位标志 Carry Flag
CF 是 Carry Flag,进位标志。
它主要用于无符号运算。
课本说:当进行算术运算时,如果最高位产生进位或借位,则 CF = 1,否则 CF = 0。
对于字节操作,最高位是第 7 位。 对于字操作,最高位是第 15 位。
加法中的 CF
例如 8 位加法:AL = FFH AL + 01H
FFH 是二进制:1111 1111
加 1 后:1 0000 0000
低 8 位结果是:0000 0000
但是从第 7 位向外产生了进位。
所以:AL = 00H CF = 1
这表示无符号数加法超过了 8 位能表示的范围。
没有进位时 CF = 0
例如:AL = 12H AL + 34H = 46H
没有超过 8 位范围,没有向最高位外进位。
所以:CF = 0
减法中的 CF 表示借位
例如:AL = 00H AL - 01H
0 减 1 不够减,需要借位。
结果低 8 位会变成:FFH
并且:CF = 1
所以在减法中,CF = 1 表示发生借位。
CF 和无符号数有关
这个一定要注意。CF 主要用来看无符号数运算是否超范围。
比如 8 位无符号数范围是:0 ~ 255
如果:255 + 1 = 256
8 位装不下,CF = 1。
但如果你把数看成有符号数,就要更多关注 OF,而不是 CF。
这个后面讲 OF 时会更清楚。
移位指令中 CF 的作用
课本还说,CF 也可以在移位类指令中使用。
例如左移:1000 0001 左移 1 位
最高位的 1 被移出去。
这个被移出去的位会进入 CF。
所以 CF 还可以保存:
左移时从最高位移出的位,或右移时从最低位移出的位。
PF:奇偶标志 Parity Flag
PF 是 Parity Flag,奇偶标志。
课本说:当操作结果低 8 位中 1 的个数为偶数时,PF = 1;否则 PF = 0。
这里有两个关键词:
低 8 位 1 的个数为偶数
PF 只看低 8 位
这点很容易考。不管你做的是 8 位运算还是 16 位运算,PF 都只检查结果的低 8 位。
比如结果是:AX = 1234H
低 8 位是:34H
所以 PF 只看 34H 对应的二进制,不看 12H。
偶数个 1,则 PF = 1
例如结果低 8 位是:0000 0011
里面有两个 1。 2 是偶数,所以:
PF = 1,再比如:
1010 0001 里面有 3 个 1。
3 是奇数,所以:PF = 0
PF 的名字为什么叫“奇偶”?
它检测的是结果中 1 的个数是奇数还是偶数。但要注意:
8086 中是 偶校验逻辑:
偶数个 1 → PF = 1
奇数个 1 → PF = 0很多人会误以为“奇偶标志”里“奇”对应 1,这是错的。
要记:偶数个 1,PF 置 1。
这几页新增重点其实可以压缩成下面几条。
第一,通用寄存器按常见用途分成三类:
AX、BX、CX、DX:数据寄存器
SP、BP:指针寄存器
SI、DI:变址寄存器第二,AX、BX、CX、DX 可以拆成高低 8 位:
AH/AL,BH/BL,CH/CL,DH/DL
第三,某些指令会隐含使用固定寄存器:
LOOP 默认使用 CX
移位次数默认用 CL
乘除法常用 AX、DX
PUSH/POP 默认用 SP
串操作源地址用 SI,目的地址用 DI第四,SP 和 BP 都常用于栈:
SS:SP 指向栈顶
BP 常用于访问栈中数据第五,SI 和 DI 常用于串操作:
DS:SI → ES:DI
第六,段寄存器指出当前段:
CS:代码段
DS:数据段
ES:附加段
SS:堆栈段第七,IP 指向下一条指令的偏移地址:
CS:IP
第八,FLAGS 记录状态和控制 CPU 行为,目前讲了:
CF:进位/借位标志
PF:低 8 位中 1 的个数为偶数则置 1题型 1:哪些寄存器可以拆成 8 位?
答案:AX、BX、CX、DX
对应:AH/AL,BH/BL,CH/CL,DH/DL
SP、BP、SI、DI 不能这样拆。
题型 2:LOOP 指令默认使用哪个寄存器?
答案:CX
执行一次 LOOP,CX 减 1。
如果 CX 不为 0,就跳转。
如果 CX 为 0,就继续向下执行。题型 3:移位次数大于 1 时,次数放在哪里?
答案:CL
例如:SHL AX, CL SAR AX, CL
题型 4:PUSH、POP 隐含使用哪个寄存器?
答案:SP
并且栈地址由:SS:SP决定。
题型 5:串操作中源地址和目的地址分别由谁给出?
答案:源地址:DS:SI 目的地址:ES:DI
题型 6:下一条指令地址由什么决定?
答案:CS:IP
CS 给代码段基址。
IP 给段内偏移量。题型 7:CF 什么时候置 1?
答案:加法最高位产生进位时,CF = 1。
减法最高位产生借位时,CF = 1。
移位时,移出的那一位也可能进入 CF。题型 8:PF 看什么?
答案:PF 只看结果低 8 位中 1 的个数。
偶数个 1 → PF = 1
奇数个 1 → PF = 0