简介:
CPU内部的寄存器中,有一种特殊的寄存器(对于不同的处理机,个数和结构都可能不同)具有三种作用。
(1)用来存储相关指令的某些执行结果。
(2)用来为CPU执行相关指令提供行为依据。
(3)用来控制CPU的相关工作方式。
这种特殊的寄存器在8086CPU中,被称为标志寄存器(以下简称flag)。8086CPU的标志寄存器有16位,其中存储的信息通常被称为程序状态字(PSW)。8086CPU的flag寄存器的结构如图所示。
注意:在8086的指令集中,有的指令的执行是影响标志寄存器的,比如add、sub、mul、div、inc、or、and等,它们大都是运算指令(进行逻辑或算术运算)。有的指令的执行对标志寄存器没有影响,比如mov、push、pop等,它们大都是传送指令。在使用一条指令的时候,要注意执行结果对标志寄存器的哪些标志位造成影响。而且定要注意,状态标志中用6位来反映EU执行的的结果特征,这6位都是
逻辑值!!!!(CF,AF,ZF,SF,PF,DF)
11.1 ZF标志位
flag的第6位是ZF,零标志位。它记录相关指令执行后,其计算结果是否为0。如果结果为0,那么ZF=1;如果结果不为0,那么ZF=0。
11.2 PF标志位
flag的第2位是PF,奇偶标志位。它记录相关指令执行后,其结果的所有二进制位中1的个数是否为偶数。如果1的个数为偶数,PF=1;如果为奇数,PF=0。
11.3 SF标志位
flag的第7位是SF,符号标志位。它记录相关指令执行后,其结果是否为负。如果结果为负,SF=1;如果非负,SF=0。
11.4 CF标志位
flag的第0位是CF,进位标志位。一般情况下,它记录了运算结果的最高有效位向更高位的进位值,或从更高位的借位值。
11.5 OF标志位
flag的第11位是OF,溢出标志位。一般情况下,OF记录了有符号数运算的结果是否发生了溢出。如果发生溢出,OF=1;如果没有溢出,OF=0。
在进行有符号数运算的时候,如结果超过了机器所能表示的范围,称为溢出。
溢出只是对有符号数运算而言。由于在进行有符号数运算时,可能发生溢出而造成结果的错误,则CPU需要对指令执行后是否产生溢出进行记录。
对于8位的有符号数据,机器所能表示的范围是-128~127。
对于16位有符号数,机器所能表示的范围是-32768~32767。
注意CF和OF的区别:CF是对无符号数运算有意义的标志位,OF是对有符号数运算有意义的标志位。CF和OF所表示的进位和溢出,是分别对无符号数和有符号数运算而言的,它们之间没有任何关系。
11.6 adc指令
adc是带进位加法指令,它利用了CF位上记录的进位值。
格式:adc 操作对象1,操作对象2
功能:操作对象1 = 操作对象1 + 操作对象2 + CF
11.7 sbb指令
sbb是带借位减法指令,它利用了CF位上记录的借位值。
格式:sbb 操作对象1,操作对象2
功能:操作对象1 = 操作对象1 – 操作对象2 – CF
11.8 cmp指令
cmp是比较指令,cmp的功能相当于减法指令,只是不保存结果。cmp指令执行后,将对标志寄存器产生影响。其他相关指令通过识别这些被影响的标志寄存器位来得知比较结果。
格式:cmp 操作对象1,操作对象2
功能:计算操作对象1–操作对象2,但并不保存结果,仅仅根据计算结果对标志寄存器进行设置。
(1)比较无符号数(cmp 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);
(2)比较有符号数(cmp ah,bh)
SF=1且OF=0,说明(ah)<(bh)
SF=1且OF=1,说明(ah)>(bh)
SF=0且OF=1,说明(ah)<(bh)
SF=0且OF=0,说明(ah)>=(bh)
11.9 检测比较结果的条件转移指令
“转移”指的是它能够修改IP,而“条件”指的是它可以根据某种条件,决定是否修改IP。这些条件转移指令通常都和cmp相配合使用,就好像call和ret指令通常相配合使用一样。
例如:jcxz就是一个条件转移指令,它可以检测cx中的数值。如果(cx)= 0,就修改IP,否则什么也不做。
因为cmp指令可以同时进行两种比较,无符号数比较和有符号数比较,所以根据cmp指令的比较结果进行转移的指令也分为两种,即:根据无符号数的比较结果进行转移的条件转移指令,它们检测ZF、CF的值;和根据有符号数的比较结果进行转移的条件转移指令,它们检测SF、OF和ZF的值。
11.10 DF标志位和串传送指令
1、flag的第10位是DF,方向标志位。在串处理指令中,控制每次操作后si,di的增减。
DF=0,每次操作后si,di递增;
DF=1,每次操作后si,di递减。
2、串传送指令
(1)格式:movsb(传送一个字节)
功能:movsb的功能是将ds:di指向的内存字单元中的字节送入es:di中,然后根据标志寄存器DF位的值,将si和di递增或递减。
操作:<1>((es)*16+(di)) = ((ds)*16+(si))
<2>如果DF=0则:(si)=(si)+1、(di)=(di)+1
如果DF=1则:(si)=(si)-1、(di)=(di)-1
即:mov es:[di], byte ptr ds:[si](8086并不支持这样的指令,这里只是个描述。)
如果DF=0:inc si、inc di
如果DF=1:dec si、dec di
(2)格式:movsw(传送一个字)
功能:movsw的功能是将ds:di指向的内存字单元中的word送入es:di中,然后根据标志寄存器DF位的值,将si和di递增2或递减2。
即:mov es:[di], word ptr ds:[si](8086并不支持这样的指令,这里只是个描述。)
如果DF=0:add si, 2、add di,2
如果DF=1:sub si, 2、sub di, 2
(3)movsb和movsw进行的是串传送操作中的一个步骤,一般来说,movsb和movsw都和rep配合使用。
格式:rep movsb
即:s: movsb
loop s
操作:rep的作用是根据cx的值,重复执行后面的串传送指令。rep movsb可以循环实现(cx)个字符的传送。
由于flag的DF位决定着串传送指令执行后,si和di改变的方向,所以CPU提供了相应的指令来对DF位进行设置,从而使程序员能够决定传送的方向。8086CPU提供下列两条指令对DF位进行设置:
cld指令:将标志寄存器的DF位置0。
std指令:将标志寄存器的DF位置1。
11.11 pushf和popf
pushf:将标志寄存器的值压栈。
popf:从栈中弹出数据,送入标志寄存器中。
pushf和popf为直接访问标志寄存器提供了一种方法。
//
应用实例:
访问条件码指令:
指令 | 同义名 | 效果 | 设置条件 |
sete D | setz | D = ZF | 相等/零 |
setne D | setnz | D = ~ZF | 不等/非零 |
sets D | | D = SF | 负数 |
setns D | | D = ~SF | 非负数 |
setg D | setnle | D = ~(SF ^OF) & ZF | 大于(有符号>) |
setge D | setnl | D = ~(SF ^OF) | 大于等于(有符号>=) |
setl D | setnge | D = SF ^ OF | 小于(有符号<) |
setle D | setng | D = (SF ^ OF) | ZF | 小于等于(有符号<=) |
seta D | setnbe | D = ~CF & ~ZF | 超过(无符号>) |
setae D | setnb | D = ~CF | 超过或等于(无符号>=) |
setb D | setnae | D = CF | 低于(无符号<) |
setbe D | setna | D = CF | ZF | 低于或等于(无符号<=) |
test esi,esi
setge al //return (esi >= 0);
这里的test esi,esi 相当于执行的 and esi,esi
情况1:如果ESI等于0 则SF=0 OF=0 -> al等于1
情况2:如果ESI大于0 则SF=0 OF=0 -> al等于1
情况3:如果ESI小于0 则SF=1 OF=0 -> al等于0
如果这两句指令等价于
return (esi >= 0);