设置溢出标志的解释

Explanation of setting the overflow flag

在 Kip Irvine 的书中,他谈到了设置溢出标志的机制,他写道:

The CPU uses an interesting mechanism to determine the state of the Overflow flag after an addition or subtraction operation. The Carry flag is exclusive ORed with the high bit of the result. The resulting value is placed in the Overflow flag.

我写了一个简单的程序,显示在 al 寄存器中将 5 加到 127 会设置溢出标志:

0111 1111 + 0000 0101 = 1000 0100 carry flag = 0, high bit = 1, overflow = 1

然而,在 al 寄存器中将 5 加到 255 不会设置溢出标志:

1111 1111 + 0000 0101 = 0000 0100 carry flag = 1, high bit = 0, overflow = 0

为什么第二个例子中没有设置溢出标志是条件语句不满足即;进位标志 = 1 和高位 = 0?

在你的第二个例子中没有设置溢出标志的原因255 + 5是因为它与带符号的算术有关。您添加的 -1 + 5 给出了 4。没有溢出:结果是正确的。正如@Jester 评论的那样,你的书一定有错误。

我的 8086 书中提到了溢出标志:

It will be set if there is an internal carry from bit 6 to bit 7 (the sign bit) and there is no external Carry. It will also be set when there is no internal carry from bit 6 to bit 7 and there is an external Carry.

编辑

段落继续:

For the technically minded reader, the overflow flag is set by XOR-ing the carry-in and the carry-out of bit 7 (the sign bit).

第二个例子,1进位(进位标志位),因为所有位都置位,内部加法时肯定有内部进位,即使结果b7为0 .

你可以编写一个简单的程序来检查逻辑将用 3 位做什么 addition/subtraction。

#include <stdio.h>
int main ( void )
{
    unsigned int ra;
    unsigned int rb;
    unsigned int rc;
    unsigned int rd;
    unsigned int re;
    unsigned int cy;
    unsigned int ov;
    unsigned int ovx;
    unsigned int ovy;
    int sa;
    int sb;
    int sc;
    int sd;
    for(ra=0;ra<8;ra++)
    {
        for(rb=0;rb<8;rb++)
        {
            printf("%u%u%u",(ra>>2)&1,(ra>>1)&1,(ra>>0)&1);
            printf(" + ");
            printf("%u%u%u",(rb>>2)&1,(rb>>1)&1,(rb>>0)&1);
            printf(" :");
            if(ra&4) sa=(ra|((-1)<<3)); else sa=ra;
            if(rb&4) sb=(rb|((-1)<<3)); else sb=rb;
            sc = sa + sb;
            //printf("%u(%2d) + %u(%2d)",ra,sa,rb,sb);
            printf("%2d + %2d = %2d",sa,sb,sc);
            printf("  :");
            rc=rb;
            printf("%u%u%u",(ra>>2)&1,(ra>>1)&1,(ra>>0)&1);
            printf(" + ");
            printf("%u%u%u",(rc>>2)&1,(rc>>1)&1,(rc>>0)&1);
            printf(" + 0 = ");
            rd=ra+rc+0;
            if(rd&4) sd=(rd|((-1)<<3)); else sd=rd;
            re=(ra&3)+(rc&3)+0;
            ov=0;
            if((ra&4)==(rc&4)) ov = ((rd>>3)&1) ^ ((rd>>2)&1);
            ovy=0;
            if((ra&4)==(rc&4)) if((rd&4) != (ra&4)) ovy=1;
            ovx = ((rd>>3)&1) ^ ((re>>2)&1);
            printf("%u%u%u",(rd>>2)&1,(rd>>1)&1,(rd>>0)&1);
            printf(" C %u O %u %u %u ",(rd>>3)&1,ov,ovx,ovy);
            if(sc>3) printf("X");
            if(sc<(-4)) printf("X");
            printf("\n");
        }
    }
    for(ra=0;ra<8;ra++)
    {
        for(rb=0;rb<8;rb++)
        {
            printf("%u%u%u",(ra>>2)&1,(ra>>1)&1,(ra>>0)&1);
            printf(" - ");
            printf("%u%u%u",(rb>>2)&1,(rb>>1)&1,(rb>>0)&1);
            printf(" :");
            if(ra&4) sa=(ra|((-1)<<3)); else sa=ra;
            if(rb&4) sb=(rb|((-1)<<3)); else sb=rb;
            sc = sa - sb;
            //printf("%u(%2d) - %u(%2d)",ra,sa,rb,sb);
            printf("%2d - %2d = %2d",sa,sb,sc);
            printf(" : ");
            rc=(~rb)&7;
            printf("%u%u%u",(ra>>2)&1,(ra>>1)&1,(ra>>0)&1);
            printf(" + ");
            printf("%u%u%u",(rc>>2)&1,(rc>>1)&1,(rc>>0)&1);
            printf(" + 1 = ");
            rd=ra+rc+1;
            if(rd&4) sd=(rd|((-1)<<3)); else sd=rd;
            re=(ra&3)+(rc&3)+1;
            ov=0;
            if((ra&4)==(rc&4)) ov = ((rd>>3)&1) ^ ((rd>>2)&1);
            ovx = ((rd>>3)&1) ^ ((re>>2)&1);
            ovy=0;
            if((ra&4)==(rc&4)) if((rd&4) != (ra&4)) ovy=1;
            printf("%u%u%u",(rd>>2)&1,(rd>>1)&1,(rd>>0)&1);
            printf(" C %u O %u %u %u ",(rd>>3)&1,ov,ovx,ovy);
            sc = sa - sb;
            if(sc>3) printf("X");
            if(sc<(-4)) printf("X");
            printf("\n");
        }
    }
}

给予

000 + 000 : 0 +  0 =  0  :000 + 000 + 0 = 000 C 0 O 0 0 0 
000 + 001 : 0 +  1 =  1  :000 + 001 + 0 = 001 C 0 O 0 0 0 
000 + 010 : 0 +  2 =  2  :000 + 010 + 0 = 010 C 0 O 0 0 0 
000 + 011 : 0 +  3 =  3  :000 + 011 + 0 = 011 C 0 O 0 0 0 
000 + 100 : 0 + -4 = -4  :000 + 100 + 0 = 100 C 0 O 0 0 0 
000 + 101 : 0 + -3 = -3  :000 + 101 + 0 = 101 C 0 O 0 0 0 
000 + 110 : 0 + -2 = -2  :000 + 110 + 0 = 110 C 0 O 0 0 0 
000 + 111 : 0 + -1 = -1  :000 + 111 + 0 = 111 C 0 O 0 0 0 
001 + 000 : 1 +  0 =  1  :001 + 000 + 0 = 001 C 0 O 0 0 0 
001 + 001 : 1 +  1 =  2  :001 + 001 + 0 = 010 C 0 O 0 0 0 
001 + 010 : 1 +  2 =  3  :001 + 010 + 0 = 011 C 0 O 0 0 0 
001 + 011 : 1 +  3 =  4  :001 + 011 + 0 = 100 C 0 O 1 1 1 X
001 + 100 : 1 + -4 = -3  :001 + 100 + 0 = 101 C 0 O 0 0 0 
001 + 101 : 1 + -3 = -2  :001 + 101 + 0 = 110 C 0 O 0 0 0 
001 + 110 : 1 + -2 = -1  :001 + 110 + 0 = 111 C 0 O 0 0 0 
001 + 111 : 1 + -1 =  0  :001 + 111 + 0 = 000 C 1 O 0 0 0 
010 + 000 : 2 +  0 =  2  :010 + 000 + 0 = 010 C 0 O 0 0 0 
010 + 001 : 2 +  1 =  3  :010 + 001 + 0 = 011 C 0 O 0 0 0 
010 + 010 : 2 +  2 =  4  :010 + 010 + 0 = 100 C 0 O 1 1 1 X
010 + 011 : 2 +  3 =  5  :010 + 011 + 0 = 101 C 0 O 1 1 1 X
010 + 100 : 2 + -4 = -2  :010 + 100 + 0 = 110 C 0 O 0 0 0 
010 + 101 : 2 + -3 = -1  :010 + 101 + 0 = 111 C 0 O 0 0 0 
010 + 110 : 2 + -2 =  0  :010 + 110 + 0 = 000 C 1 O 0 0 0 
010 + 111 : 2 + -1 =  1  :010 + 111 + 0 = 001 C 1 O 0 0 0 
011 + 000 : 3 +  0 =  3  :011 + 000 + 0 = 011 C 0 O 0 0 0 
011 + 001 : 3 +  1 =  4  :011 + 001 + 0 = 100 C 0 O 1 1 1 X
011 + 010 : 3 +  2 =  5  :011 + 010 + 0 = 101 C 0 O 1 1 1 X
011 + 011 : 3 +  3 =  6  :011 + 011 + 0 = 110 C 0 O 1 1 1 X
011 + 100 : 3 + -4 = -1  :011 + 100 + 0 = 111 C 0 O 0 0 0 
011 + 101 : 3 + -3 =  0  :011 + 101 + 0 = 000 C 1 O 0 0 0 
011 + 110 : 3 + -2 =  1  :011 + 110 + 0 = 001 C 1 O 0 0 0 
011 + 111 : 3 + -1 =  2  :011 + 111 + 0 = 010 C 1 O 0 0 0 
100 + 000 :-4 +  0 = -4  :100 + 000 + 0 = 100 C 0 O 0 0 0 
100 + 001 :-4 +  1 = -3  :100 + 001 + 0 = 101 C 0 O 0 0 0 
100 + 010 :-4 +  2 = -2  :100 + 010 + 0 = 110 C 0 O 0 0 0 
100 + 011 :-4 +  3 = -1  :100 + 011 + 0 = 111 C 0 O 0 0 0 
100 + 100 :-4 + -4 = -8  :100 + 100 + 0 = 000 C 1 O 1 1 1 X
100 + 101 :-4 + -3 = -7  :100 + 101 + 0 = 001 C 1 O 1 1 1 X
100 + 110 :-4 + -2 = -6  :100 + 110 + 0 = 010 C 1 O 1 1 1 X
100 + 111 :-4 + -1 = -5  :100 + 111 + 0 = 011 C 1 O 1 1 1 X
101 + 000 :-3 +  0 = -3  :101 + 000 + 0 = 101 C 0 O 0 0 0 
101 + 001 :-3 +  1 = -2  :101 + 001 + 0 = 110 C 0 O 0 0 0 
101 + 010 :-3 +  2 = -1  :101 + 010 + 0 = 111 C 0 O 0 0 0 
101 + 011 :-3 +  3 =  0  :101 + 011 + 0 = 000 C 1 O 0 0 0 
101 + 100 :-3 + -4 = -7  :101 + 100 + 0 = 001 C 1 O 1 1 1 X
101 + 101 :-3 + -3 = -6  :101 + 101 + 0 = 010 C 1 O 1 1 1 X
101 + 110 :-3 + -2 = -5  :101 + 110 + 0 = 011 C 1 O 1 1 1 X
101 + 111 :-3 + -1 = -4  :101 + 111 + 0 = 100 C 1 O 0 0 0 
110 + 000 :-2 +  0 = -2  :110 + 000 + 0 = 110 C 0 O 0 0 0 
110 + 001 :-2 +  1 = -1  :110 + 001 + 0 = 111 C 0 O 0 0 0 
110 + 010 :-2 +  2 =  0  :110 + 010 + 0 = 000 C 1 O 0 0 0 
110 + 011 :-2 +  3 =  1  :110 + 011 + 0 = 001 C 1 O 0 0 0 
110 + 100 :-2 + -4 = -6  :110 + 100 + 0 = 010 C 1 O 1 1 1 X
110 + 101 :-2 + -3 = -5  :110 + 101 + 0 = 011 C 1 O 1 1 1 X
110 + 110 :-2 + -2 = -4  :110 + 110 + 0 = 100 C 1 O 0 0 0 
110 + 111 :-2 + -1 = -3  :110 + 111 + 0 = 101 C 1 O 0 0 0 
111 + 000 :-1 +  0 = -1  :111 + 000 + 0 = 111 C 0 O 0 0 0 
111 + 001 :-1 +  1 =  0  :111 + 001 + 0 = 000 C 1 O 0 0 0 
111 + 010 :-1 +  2 =  1  :111 + 010 + 0 = 001 C 1 O 0 0 0 
111 + 011 :-1 +  3 =  2  :111 + 011 + 0 = 010 C 1 O 0 0 0 
111 + 100 :-1 + -4 = -5  :111 + 100 + 0 = 011 C 1 O 1 1 1 X
111 + 101 :-1 + -3 = -4  :111 + 101 + 0 = 100 C 1 O 0 0 0 
111 + 110 :-1 + -2 = -3  :111 + 110 + 0 = 101 C 1 O 0 0 0 
111 + 111 :-1 + -1 = -2  :111 + 111 + 0 = 110 C 1 O 0 0 0 
000 - 000 : 0 -  0 =  0 : 000 + 111 + 1 = 000 C 1 O 0 0 0 
000 - 001 : 0 -  1 = -1 : 000 + 110 + 1 = 111 C 0 O 0 0 0 
000 - 010 : 0 -  2 = -2 : 000 + 101 + 1 = 110 C 0 O 0 0 0 
000 - 011 : 0 -  3 = -3 : 000 + 100 + 1 = 101 C 0 O 0 0 0 
000 - 100 : 0 - -4 =  4 : 000 + 011 + 1 = 100 C 0 O 1 1 1 X
000 - 101 : 0 - -3 =  3 : 000 + 010 + 1 = 011 C 0 O 0 0 0 
000 - 110 : 0 - -2 =  2 : 000 + 001 + 1 = 010 C 0 O 0 0 0 
000 - 111 : 0 - -1 =  1 : 000 + 000 + 1 = 001 C 0 O 0 0 0 
001 - 000 : 1 -  0 =  1 : 001 + 111 + 1 = 001 C 1 O 0 0 0 
001 - 001 : 1 -  1 =  0 : 001 + 110 + 1 = 000 C 1 O 0 0 0 
001 - 010 : 1 -  2 = -1 : 001 + 101 + 1 = 111 C 0 O 0 0 0 
001 - 011 : 1 -  3 = -2 : 001 + 100 + 1 = 110 C 0 O 0 0 0 
001 - 100 : 1 - -4 =  5 : 001 + 011 + 1 = 101 C 0 O 1 1 1 X
001 - 101 : 1 - -3 =  4 : 001 + 010 + 1 = 100 C 0 O 1 1 1 X
001 - 110 : 1 - -2 =  3 : 001 + 001 + 1 = 011 C 0 O 0 0 0 
001 - 111 : 1 - -1 =  2 : 001 + 000 + 1 = 010 C 0 O 0 0 0 
010 - 000 : 2 -  0 =  2 : 010 + 111 + 1 = 010 C 1 O 0 0 0 
010 - 001 : 2 -  1 =  1 : 010 + 110 + 1 = 001 C 1 O 0 0 0 
010 - 010 : 2 -  2 =  0 : 010 + 101 + 1 = 000 C 1 O 0 0 0 
010 - 011 : 2 -  3 = -1 : 010 + 100 + 1 = 111 C 0 O 0 0 0 
010 - 100 : 2 - -4 =  6 : 010 + 011 + 1 = 110 C 0 O 1 1 1 X
010 - 101 : 2 - -3 =  5 : 010 + 010 + 1 = 101 C 0 O 1 1 1 X
010 - 110 : 2 - -2 =  4 : 010 + 001 + 1 = 100 C 0 O 1 1 1 X
010 - 111 : 2 - -1 =  3 : 010 + 000 + 1 = 011 C 0 O 0 0 0 
011 - 000 : 3 -  0 =  3 : 011 + 111 + 1 = 011 C 1 O 0 0 0 
011 - 001 : 3 -  1 =  2 : 011 + 110 + 1 = 010 C 1 O 0 0 0 
011 - 010 : 3 -  2 =  1 : 011 + 101 + 1 = 001 C 1 O 0 0 0 
011 - 011 : 3 -  3 =  0 : 011 + 100 + 1 = 000 C 1 O 0 0 0 
011 - 100 : 3 - -4 =  7 : 011 + 011 + 1 = 111 C 0 O 1 1 1 X
011 - 101 : 3 - -3 =  6 : 011 + 010 + 1 = 110 C 0 O 1 1 1 X
011 - 110 : 3 - -2 =  5 : 011 + 001 + 1 = 101 C 0 O 1 1 1 X
011 - 111 : 3 - -1 =  4 : 011 + 000 + 1 = 100 C 0 O 1 1 1 X
100 - 000 :-4 -  0 = -4 : 100 + 111 + 1 = 100 C 1 O 0 0 0 
100 - 001 :-4 -  1 = -5 : 100 + 110 + 1 = 011 C 1 O 1 1 1 X
100 - 010 :-4 -  2 = -6 : 100 + 101 + 1 = 010 C 1 O 1 1 1 X
100 - 011 :-4 -  3 = -7 : 100 + 100 + 1 = 001 C 1 O 1 1 1 X
100 - 100 :-4 - -4 =  0 : 100 + 011 + 1 = 000 C 1 O 0 0 0 
100 - 101 :-4 - -3 = -1 : 100 + 010 + 1 = 111 C 0 O 0 0 0 
100 - 110 :-4 - -2 = -2 : 100 + 001 + 1 = 110 C 0 O 0 0 0 
100 - 111 :-4 - -1 = -3 : 100 + 000 + 1 = 101 C 0 O 0 0 0 
101 - 000 :-3 -  0 = -3 : 101 + 111 + 1 = 101 C 1 O 0 0 0 
101 - 001 :-3 -  1 = -4 : 101 + 110 + 1 = 100 C 1 O 0 0 0 
101 - 010 :-3 -  2 = -5 : 101 + 101 + 1 = 011 C 1 O 1 1 1 X
101 - 011 :-3 -  3 = -6 : 101 + 100 + 1 = 010 C 1 O 1 1 1 X
101 - 100 :-3 - -4 =  1 : 101 + 011 + 1 = 001 C 1 O 0 0 0 
101 - 101 :-3 - -3 =  0 : 101 + 010 + 1 = 000 C 1 O 0 0 0 
101 - 110 :-3 - -2 = -1 : 101 + 001 + 1 = 111 C 0 O 0 0 0 
101 - 111 :-3 - -1 = -2 : 101 + 000 + 1 = 110 C 0 O 0 0 0 
110 - 000 :-2 -  0 = -2 : 110 + 111 + 1 = 110 C 1 O 0 0 0 
110 - 001 :-2 -  1 = -3 : 110 + 110 + 1 = 101 C 1 O 0 0 0 
110 - 010 :-2 -  2 = -4 : 110 + 101 + 1 = 100 C 1 O 0 0 0 
110 - 011 :-2 -  3 = -5 : 110 + 100 + 1 = 011 C 1 O 1 1 1 X
110 - 100 :-2 - -4 =  2 : 110 + 011 + 1 = 010 C 1 O 0 0 0 
110 - 101 :-2 - -3 =  1 : 110 + 010 + 1 = 001 C 1 O 0 0 0 
110 - 110 :-2 - -2 =  0 : 110 + 001 + 1 = 000 C 1 O 0 0 0 
110 - 111 :-2 - -1 = -1 : 110 + 000 + 1 = 111 C 0 O 0 0 0 
111 - 000 :-1 -  0 = -1 : 111 + 111 + 1 = 111 C 1 O 0 0 0 
111 - 001 :-1 -  1 = -2 : 111 + 110 + 1 = 110 C 1 O 0 0 0 
111 - 010 :-1 -  2 = -3 : 111 + 101 + 1 = 101 C 1 O 0 0 0 
111 - 011 :-1 -  3 = -4 : 111 + 100 + 1 = 100 C 1 O 0 0 0 
111 - 100 :-1 - -4 =  3 : 111 + 011 + 1 = 011 C 1 O 0 0 0 
111 - 101 :-1 - -3 =  2 : 111 + 010 + 1 = 010 C 1 O 0 0 0 
111 - 110 :-1 - -2 =  1 : 111 + 001 + 1 = 001 C 1 O 0 0 0 
111 - 111 :-1 - -1 =  0 : 111 + 000 + 1 = 000 C 1 O 0 0 0

所以对于加法你会有这样一个(根据定义,有符号溢出标志用于当你将这些位解释为有符号时)

011 + 001 : 3 +  1 =  4  :011 + 001 + 0 = 100 C 0 O 1 1 1 X

所以 1 + 3 (001 + 011) = 位模式 100,在三位二进制补码世界中具有值 -4 所以 1 + 3 = -4 这是错误的,所以有符号溢出,我们无法表示a +4 三位。在 x86 上,这相当于 127+1 (0x7F + 0x01) 的 8 位加法。基本上所有正数的组合都会导致 128(或更大)126+2、125+3、124+4 等等。都有这个问题。

010 + 010 : 2 +  2 =  4  :010 + 010 + 0 = 100 C 0 O 1 1 1 X

我做了加减法。减法逻辑上来自二进制补码概念反转和加 1。因此减法 c = a - b 使用 c = a + (-b),从二进制补码我们知道这意味着 c = a + ((~b)+1 ) 或 c = a + ~b + 1。加法是 c = a + b + 0。后者的 1 或 0 是 lsbit 的进位。

现在进一步加法c = a + b + cin,减法c = a + ~b + ~cin。您反转第二个操作数和进位。但这是处理器特定的,因为某些处理器反转进位(我认为 x86 是一个)使其成为 "borrow" 而不是 "carry" 进行减法。如果你有这些指令,那么这就搞乱了进位加进位或借位减法的概念(这些指令的逻辑根本不会在 sbb 上反转 cin)

我用三种不同的(真的吗?)方法计算了溢出标志。

    ov=0;
    if((ra&4)==(rc&4)) ov = ((rd>>3)&1) ^ ((rd>>2)&1);
    ovx = ((rd>>3)&1) ^ ((re>>2)&1);
    ovy=0;
    if((ra&4)==(rc&4)) if((rd&4) != (ra&4)) ovy=1;

ov 就像您正在阅读的文本中一样,如果进入加法器的符号相同,则溢出将与结果的 msbit 进行异或运算。

ovx 是溢出进位的定义与 msbit 的进位相比

并且 ovy 是一个快捷方式,如果您想找出溢出但没有用于寄存器的 N+1 位(您如何在看不到进位的语言中使用 32 位变量来找出溢出)出?我在代码中展示了很多方法,但简单地检查 msbits 也能工作)。

然后最后的X也是溢出的定义,如果结果不适合可用的位数那么你就溢出了。对于无符号(进位)和有符号(溢出)溢出为真。因为这是关于溢出那么这是关于有符号数所以对于我的三位系统你只能从 -4 到 +3 任何高于 +3 或小于 -4 的东西都不适合并且打印输出末尾的 X 显示,所以这是在这个简化示例中显示溢出的第四种方式。

同样,上面的输出是通用逻辑的处理方式,然后处理器系列与进位标志有细微差别,有些处理器反转进位以使其成为借位,而有些处理器在执行减法时则不会。真正的真实逻辑会将一堆 3 个输入(两个操作数和进位)两个输出(结果和进位)加法器级联在一起,尽管在 HDL 语言中您可以使用加号运算符并绕过它(并且在这些语言中也需要一个这些不检查进位与进位的快捷方式)

如果您使用布尔方程式,您应该能够发现显示的三种计算溢出的方法是等效的,不仅在实验上如此,而且在数学上也是如此。

好吧,我在您的号码中看到的一件事是号码是“0111 1111”+ “0000 0101”都是正数,因为从左侧开始的第一个数字是 0,但在第二个示例中,第一个数字是“1111 1111”,这意味着它是负数,第二个是“0000 0101”,这也意味着它是正数!请记住:OF(溢出标志)何时设置,两个数字具有相同的符号。在第二个中,由于 2 个不同的数字符号 OF = 0;