标志寄存器
标志寄存器通常具有以下三种作用:
1,用来存储相关指令的某些执行效果
2,用来为CPU执行相关指令提供行为依据
3,用来控制CPU的相关工作方式
8086CPU的flag寄存器结构如下图所示:
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
OF | DF | IF | TF | SF | ZF | AF | PF | CF |
在8086的指令集中,运算指令的执行如:add、sub、mul、div、inc、or、and等都会影响标志寄存器;而传送指令的执行如:mov、push、pop都不会影响标志寄存器。
1,ZF标志
flag的第6位是ZF,零标志位。它记录了相关指令执行后,其结果是否为0,如果为0,那么ZF=1,否则,ZF=0。比如当:sub ax,ax执行后,结果为0,就会置ZF为1。
2,PF标志
flag的第2位是PF,奇偶标志位。它记录了相关指令执行后,其结果的所有bit位中1的个数是否为偶数。如果1的个数为偶数,PF=1,否则PF=0。如:sub ax,ax执行后,结果一共有0个1,0为偶数,因此会置ZF为1。
3,SF标志
flag的第7位是SF,符号标志位。它记录了相关指令执行后,其结果是否为负,如果为负,那么SF=1,否则,ZF=0。它会将操作数看作为有符号数(补码表示)的运算来记录结果的正负。如:mov al,10000001B add al,1 执行后,结果为10000010B,SF为1。而:mov al,10000001B add al,01111111B 执行后,-127+127=0,结果为0,它并不是一个负数,故SF为0。
4,CF标志位
flag的第0位是CF,进位标志位。一般情况下,在进行无符号数运算时,它记录了运算结果的最高有效位向更高位的进位值,或从更高位的借位值。
如:mov al,98H add al,al add al,al中第二条指令执行结果为98H+98H=130H,所以(al)=30H,CF=1,CF记录了从最高有效位向更高位的进位值。第三条指令执行结果为30H+30H=60H,所以(al)=60H,CF=0。
而当两个数据做减法时,有可能向更高位借位。
如:两个8位数据97H和98H做减法时,将产生借位,借位(置CF为1)后,97H-98H等价于197H-98H。
5,OF标志位
flag的第11位是OF,溢出标志位。一般情况下,OF记录了有符号数运算的结果是否发生了溢出,如果发生了溢出,OF=1,否则OF=0。
在进行有符号数运算的时候,如果结果超过了机器所能表示的范围称为溢出。8位有符号数补码的表示范围位-128-127。
对于 mov al,98 add al,99执行后,无符号数的结果为197,所以它不产生进位;但作为有符号数的运算,结果为197,它不在8位有符号数的表示范围内,故产生了溢出,其实它是-59的补码。所以OF=1,CF=0。
对于 mov al,0F0H add al,88H执行后,无符号数的结果为178H(376D),它大于255D,所以它产生进位;但作为有符号数的运算,结果为-136,它不在8位有符号数的表示范围内,(且78H为正数,两个负数相加的结果得到了一个正数)故产生了溢出。所以OF=1,CF=1。
下面指令执行后,ZF、PF、SF、CF、OF标志位的值的变化情况。
sub al,al | zf=1 | pf=1 | sf=0 | cf=0 | of=0 | 结果为0,0个1,未进位,正数,未溢出 |
---|---|---|---|---|---|---|
mov al,10H | zf=1 | pf=1 | sf=0 | cf=0 | of=0 | - |
add al,90H | zf=0 | pf=1 | sf=1 | cf=0 | of=0 | 结果非0,有2个1,未进位,有符号数结果为负,未溢出 |
mov al,80H | zf=0 | pf=1 | sf=1 | cf=0 | of=0 | - |
add al,80H | zf=1 | pf=1 | sf=0 | cf=1 | of=1 | 结果为0,0个1,正数,产生进位,两负数相加结果为0,(十进制结果-256<-128)溢出 |
mov al,oFCH | zf=1 | pf=1 | sf=0 | cf=1 | of=1 | - |
add al,05H | zf=0 | pf=0 | sf=0 | cf=1 | of=0 | 结果非0,1个1,正数,产生进位,正数加负数不可能溢出,结果为01H,未溢出 |
mov al,7DH | zf=0 | pf=0 | sf=0 | cf=1 | of=0 | - |
add al,0BH | zf=0 | pf=1 | sf=1 | cf=0 | of=1 | 结果非0,2个1,负数,未产生进位,负数加负数结果为正,(十进制结果136大于127)溢出 |
比较指令和条件转移指令
比较指令 cmp
比较指令 cmp,它的功能相当于减法指令,只是不保存结果。cmp指令的执行结果将对标志寄存器产生影响。其他相关指令(如条件转移指令)通过识别这些被影响的标志寄存器来得知比较结果。
cmp指令格式:cmp op1,op2,效果为:计算op1-op2,但不保存结果,仅影响标志寄存器。如:cmp ax,ax指令执行后:zf=1,pf=1,sf=0,cf=0,of=0。
对于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=0且zf=0;
若(ax)<=(bx),则(ax)-(bx)可能会借位,可能会等于0,所以:zf=1或者zf=1;
当进行有符号数运算时:
若(ax)=(bx),则(ax)-(bx)=0,所以:zf=1;
若(ax)!=(bx),则(ax)-(bx)!=0,所以:zf=0;
若(ax)<(bx),如果没有发生溢出的话,那么实际存储的结果就是真实运算的结果,即of=0且sf=1;如果溢出的话,那么实际存储的结果与真实运算的结果相反,即of=1且sf=0;
若(ax)>(bx),如果没有发生溢出的话,那么实际存储的结果就是真实运算的结果,即of=0且sf=0(当然of=0且sf=0时ax与bx也可能相等);如果溢出的话,那么实际存储的结果与真实运算的结果相反,即of=1且sf=1;
条件转移指令
首先上一篇博文中的jcxz就是一个条件转移指令。
下面是常用的根据无符号数的比较结果进行转移的条件转移指令:
指令 | 含义 | 检测的相关标志位 |
---|---|---|
je | 等于则转移 | zf=1 |
jne | 不等于则转移 | zf=0 |
jb | 低于则转移 | cf=1 |
jnb | 不低于则转移 | cf=0 |
ja | 高于则转移 | cf=0且zf=0 |
jna | 不高于则转移 | cf=1或zf=1 |
其中e:equal,b:below,a,above。
虽然je进行的操作是zf=1时转移,但是我们一般是将cmp和je等条件转移指令联合起来使用,效果为:两数相等则转移。
有符号数的比较和进行条件转移与无符号数的原理相同。这里主要是将cmp、标志寄存器的相关位、条件转移指令进行配合使用。
例:计算F000:0处32个字节中,大小在[32,128]的数据的个数。
mov ax,of000h
mov ds,ax
mov,bx,0
mov dx,0
mov cx,32
s: mov al,[bx]
cmp al,32
jb s0
cmp al,128
ja s0
inc dx
s0:inc bx
loop s