• 标志寄存器


    标志寄存器


    1.标志寄存器概念

    CPU内部的寄存器中,有一种特殊的寄存器(对于不同的处理机,个数和结构都可能不同),这种特殊的寄存器在8086CPU中,被称为标志寄存器(flag),其具有以下3种作用:

    1. 用来存储相关指令的某些执行结果
    2. 用来为CPU执行相关指令提供行为依据
    3. 用来控制CPU的相关工作方式

    8086CPU的标志寄存器有16位,其中存储的信息通常被称为程序状态字(PSW-Program Status Word),flag寄存器是按位起作用的,它的每一位都有专门的含义,记录特定的信息

    请添加图片描述


    1.1 零标志位(ZF)

    1. 零标志位(Zero Flag):它记录相关指令执行后,其结果是否为0
    2. 如果结果为0,那么zf = 1(表示结果是0);如果结果不为0,那么zf = 0
    mov ax, 1
    sub ax, 1 ;执行后,结果为0,则zf = 1
    
    mov ax, 2
    sub ax, 1 ;执行后,结果不为0,则zf = 0
    
    • 1
    • 2
    • 3
    • 4
    • 5

    1.2 奇偶标志位(PF)

    1. 奇偶标志位(Parity Flag):它记录相关指令执行后,其结果的所有bit位中1的个数是否为偶数
    2. 如果1的个数为偶数,pf = 1,如果为奇数,那么pf = 0
    mov al, 1
    add al, 10 ;执行后,结果为00001011B,其中有3(奇数)个1,则pf = 0;
    
    mov al, 1
    or al, 2  ;执行后,结果为00000011B,其中有2(偶数)个1,则pf = 1
    • 1
    • 2
    • 3
    • 4
    • 5

    1.3 符号标志符(SF)

    1. 符号标志位(Symbol Flag):它记录相关指令执行后,其结果是否为负
    2. 如果结果为负,sf = 1;如果非负,sf = 0
    3. 计算机中通常用补码来表示有符号数据。计算机中的一个数据可以看作是有符号数,也可以看成是无符号数
      • 00000001B,可以看作为无符号数1,或有符号数+1
      • 10000001B,可以看作为无符号数129,也可以看作有符号数-127
    4. 对于同一个二进制数据,计算机可以将它当作无符号数据来运算,也可以当作有符号数据来运算
    5. CPU在执行add等指令的时候,就包含了两种含义:可以将add指令进行的运算当作无符号数的运算,也可以将add指令进行的运算当作有符号数的运算
    6. SF标志:就是CPU对有符号数运算结果的一种记录,它记录数据的正负。在我们将数据当作有符号数来运算的时候,可以通过它来得知结果的正负。如果我们将数据当作无符号数来运算,SF的值则没有意义,虽然相关的指令影响了它的值
    mov al, 10000001B 
    add al, 1   ;执行后,结果为10000010B,sf = 1,表示:如果指令进行的是有符号数运算,那么结果为负;
    
    mov al, 10000001B
    add al, 01111111B   ;执行后,结果为0,sf = 0,表示:如果指令进行的是有符号数运算,那么结果为非负
    
    • 1
    • 2
    • 3
    • 4
    • 5

    1.4 进位标志符(CF)

    1. 进位标志位(Carry Flag):一般情况下,在进行无符号数运算的时候,它记录了运算结果的最高有效位向更高位的进位值,或从更高位的借位值

    请添加图片描述


    1.5溢出标志符(OF)

    1. 溢出标志位(Overflow Flag):一般情况下,OF记录了有符号数运算的结果是否发生了溢出
    2. 如果发生溢出,OF = 1;如果没有,OF = 0
    3. CF和OF的区别:CF是对无符号数运算有意义的标志位,而OF是对有符号数运算有意义的标志位
    4. CPU在执行add等指令的时候,就包含了两种含义:无符号数运算和有符号数运算
      • 对于无符号数运算,CPU用CF位来记录是否产生了进位
      • 对于有符号数运算,CPU用OF位来记录是否产生了溢出,当然,还要用SF位来记录结果的符号
    mov al, 98
    add al, 99   ;执行后将产生溢出。因为进行的"有符号数"运算是:(al)=(al)+ 99 = 98 + 99=197 = C5H 为-59的补码
                 ;而结果197超出了机器所能表示的8位有符号数的范围:-128-127;add 指令执行后:无符号运算没有进位CF=0,有符号运算溢出OF=1
                 ;当取出的数据C5H按无符号解析C5H = 197, 当按有符号解析通过SP得知数据为负,即C5H为-59补码存储,
                 
    mov al,0F0H  ;F0H,为有符号数-16的补码   -Not(F0 - 1)
    add al,088H  ;88H,为有符号数-120的补码   -Not(88- 1)
                  ;执行后,将产生溢出。因为add al, 088H进行的有符号数运算结果是:(al)= -136 
                  ;而结果-136超出了机器所能表示的8位有符号数的范围:-128-127;add 指令执行后:无符号运算有进位CF=1,有符号运算溢出OF=1
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    2.adc指令和sbb指令

    adc指令的详解:

    1. adc是带进位加法指令,它利用了CF位上记录的进位值
    2. 指令格式: adc 操作对象1, 操作对象2
    3. 功能:操作对象1 = 操作对象1 + 操作对象2 + CF
    mov ax, 2
    mov bx, 1
    sub bx, ax  ;无符号运算借位CF=1,有符号运算OF = 0
    adc ax, 1   ;执行后,(ax)= 4。adc执行时,相当于计算:(ax)+1+CF = 2+1+1 = 4
    • 1
    • 2
    • 3
    • 4

    请添加图片描述

    ;计算1EF000H+201000H,结果放在ax(高16位)和bx(低16位)中
    ;将计算分两步进行,先将低16位相加,然后将高16位和进位值相加
    
    mov ax, 001EH 
    mov bx, 0F000H 
    add bx, 1000H
    adc ax, 0020H
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    sbb指令的详解:

    1. sbb是带借位减法指令,它利用了CF位上记录的借位值
    2. 指令格式: sbb 操作对象1, 操作对象2
    3. 功能:操作对象1 = 操作对象1 - 操作对象2 - CF
    ;计算 003E1000H - 00202000H,结果放在ax,bx中,程序如下:
    
    mov bx, 1000H
    mov ax, 003EH
    sub bx, 2000H
    sbb ax, 0020H
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    3.cmp指令

    1. cmp是比较指令,cmp的功能相当于减法指令,只是不保存结果。cmp指令执行后,将对标志寄存器产生影响
    2. 其他相关指令通过识别这些被影响的标志寄存器位来得知比较结果
    3. cmp指令格式: cmp 操作对象1,操作对象2
      • 例如:指令cmp ax, ax,做(ax)-(ax)的运算,结果为0,但并不在ax中保存,仅影响flag的相关各位。 指令执行后:zf=1,pf=1,sf=0,cf=0,of=0
    4. CPU在执行cmp指令的时候,也包含两种含义:进行无符号数运算和进行有符号数运算

    如果用cmp来进行有符号数比较时,SF只能记录实际结果的正负,发生溢出的时候,实际结果的正负不能说明逻辑上真正结果的正负。但是逻辑上的结果的正负,才是cmp指令所求的真正结果,所以我们在考察SF的同时考察OF,请添加图片描述
    就可以得知逻辑上真正结果的正负,同时就知道比较的结果

    mov ah, 08AH  ; -Not(8A-1) = -118  即当成有符号数时为-118
    mov bh, 070H  ; 有符号数时最高位为0为正数, 70H = 112
    cmp ah, bh    ;(ah)-(bh)实际得到的结果是1AH 
    		      ; 在逻辑上,运算所应该得到的结果是:(-118- 112 = -230
    		      ; sf记录实际结果的正负,所以sf=0
    
    • 1
    • 2
    • 3
    • 4
    • 5

    对于cmp ah,bh的理解:

    1. 如果sf=1,而of=0 。 of=0说明没有溢出,逻辑上真正结果的正负=实际结果的正负; sf=1,实际结果为负,所以逻辑上真正的结果为负,所以(ah)<(bh)
    2. 如果sf=1,而of=1: of=1,说明有溢出,逻辑上真正结果的正负≠实际结果的正负; sf=1,实际结果为负。实际结果为负,而又有溢出,这说明是由于溢出导致了实际结果为负,,如果因为溢出导致了实际结果为负,那么逻辑上真正的结果必然为正。 这样,sf=1,of=1,说明了(ah)>(bh)
    3. 如果sf=0,而of=1。of=1,说明有溢出,逻辑上真正结果的正负≠实际结果的正负;sf=0,实际结果非负。而of=1说明有溢出,则结果非0,所以,实际结果为正。实际结果为正,而又有溢出,这说明是由于溢出导致了实际结果非负,如果因为溢出导致了实际结果为正,那么逻辑上真正的结果必然为负。这样,sf=0,of=1,说明了(ah)<(bh)
    4. 如果sf=0,而of=0,of=0,说明没有溢出,逻辑上真正结果的正负=实际结果的正负;sf=0,实际结果非负,所以逻辑上真正的结果非负,所以(ah)≥(bh)

    4.检测比较结果的条件转移指令

    1. “转移”指的是它能修改IP,而“条件”指的是它可以根据某种条件,决定是否修改IP
    2. 比如:jcxz它可以检测cx中的数值,如果(cx)=0,就修改IP,否则什么也不做
    3. 所有条件转移指令的转移位移都是[-128,127]
    4. 多数条件转移指令都检测标志寄存器的相关标志位,根据检测的结果来决定是否修改IP
    5. 这些条件转移指令通常都和cmp相配合使用,它们所检测的标志位,都是cmp指令进行无符号数比较的时记录比较结果的标志位
    6. 根据无符号数的比较结果进行转移的条件转移指令(它们检测zf、cf的值)

    请添加图片描述

    简写指令补充:j:jump,e:equal,b:below,a:above,n:not

    ;编程,统计data段中数值为8的字节的个数,用ax保存统计结果。
    mov ax, data 
    mov ds, ax 
    mov bx, 0   ;ds:bx指向第一个字节
    mov ax, 0   ;初始化累加器mov cx,8
    
    s:
    	cmp byte ptr [bx], 8   ;8进行比较
    	jne next  ;如果不相等转到next,继续循环
    	inc ax  ;如果相等就将计数值加1
    next:
    	inc bx
    	loop s ;程序执行后:(ax)=3
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    5.DF标志和串传送指令

    1. flag的第10位是DF,方向标志位。在串处理指令中,控制每次操作后si、di的增减
      • df = 0每次操作后si、di递增
      • df = 1每次操作后si、di递减
    2. 格式:movsb,功能:将ds:si指向的内存单元中的字节送入es:di中,然后根据标志寄存器df位的值,将si和di递增或递减
    3. 格式:movsw,功能:将ds:si指向的内存字单元中的字送入es:di中,然后根据标志寄存器df位的值,将si和di递增2或递减2
    4. 格式:rep movsb,movsb和movsw进行的是串传送操作中的一个步骤,一般来说,movsb和movsw都和rep配合使用,功能:rep的作用是根据cx的值,重复执行后面的串传送指令
    5. 8086CPU提供下面两条指令对df位进行设置:
      • cld指令:将标志寄存器的df位置0
      • std指令:将标志寄存器的df位置1
    ;将data段中的第一个字符串复制到它后面的空间中。
    data segment 
    	db 'Welcome to masm!'
    	db 16 dup (0)
    data ends
    
    mov ax, data 
    mov ds, ax 
    mov si, 0   ;ds:si 指向data:0
    mov es, ax 
    mov di, 16  ;es:di指向data:0010
    
    mov cx, 16  ;(cx)=16,rep循环16次
    cld  ;设置df=0,正向传送
    rep movsb
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    6.pushf和popf

    1. pushf的功能是将标志寄存器的值压栈,而popf是从栈中弹出数据,送入标志寄存器中
    2. pushf和popf,为直接访问标志寄存器提供了一种方法
  • 相关阅读:
    计算机中的编码问题
    非科班,补基础
    TX Text Control ActiveX 32.0 For VB6 Crack
    Mysql 执行 sql 文件导入数据时报错: Got a packet bigger than ‘max_allowed_packet‘ bytes
    MySQL中 LBCC 和 MVCC 的理解,常见问题及示例:
    Python快速而美丽[v1.0.0][命令行工具]
    11.21序列检测,状态机比较与代码,按键消抖原理
    【周末闲谈】什么是云计算?
    现在都这么狂吗?今天面试了一个工作4年的测试工程师,一问连自动化基础都不知道,还反过来怼我..
    【Redis高可用】
  • 原文地址:https://blog.csdn.net/qq_29678157/article/details/127929394