Page 1 of 1

Overflow flag

Posted: Wed Oct 01, 2008 1:01 pm
by kestaz
I am writing simple emulator. But i'm stuck. I don't know how to implement overflow flag on 8086 ?

I wrote this code in emu8086:

mov al, 0xfc
add al, 0x1

Emu8086 gives just Signed flag. But my *bad* code gives Signed and Overflow flags ? Which is correct ?

Which page http://intelliwiki.kylesblog.com/index. ... rflow_Flag talks about overflow flag. Still i can't impelement my overflow flag correctly. Any suggestions, advices would be great.

Re: Overflow flag

Posted: Wed Oct 01, 2008 2:37 pm
by Brendan
Hi,
kestaz wrote:I wrote this code in emu8086:

mov al, 0xfc
add al, 0x1

Emu8086 gives just Signed flag. But my *bad* code gives Signed and Overflow flags ? Which is correct ?
Um, "0xFC + 0x01 = 0xFD", so the carry flag would be clear and the overflow flag would also be clear. For unsigned addition it'd be "252 + 1 = 253" and for signed addition it'd be "(-4) + (+1) = (-3)".

For addition and subtraction, the CPU uses the same instructions for both signed arithmetic and unsigned arithmetic; where the only difference is which flags you test after doing the addition/subtraction (carry for unsigned arithmetic, and overflow for signed arithmetic).

For addition, for "A = B + C" treat A, B and C as unsigned integers and do unsigned addition, The carry flag is the fictitious ninth bit, and the overflow flag can be found with "overflow_flag = A.sign ^ B.sign ^ C.sign" (or just "overflow_flag = (A ^ B ^ C) >> 7").

If you can't get the fictitious ninth bit, you can do this:

Code: Select all

    if( (A < B) && (A < C) ) carry_flag = 1;
    else carry_flag = 0;
So, for 8-bit addition in C you'd do something like this:

Code: Select all

unsigned char addition_8bit(unsigned char b, unsigned char c) {
    unsigned char a;
    unsigned char temp_parity;

    a = b + c;
    if( (a < b) && (a < c) ) carry_flag = 1;
    else carry_flag = 0;
    overflow_flag = (a ^ b ^ c) >> 7;
    sign_flag = a >> 7;
    temp_parity = (a & 0x0F) ^ (a >> 4);
    temp_parity = (temp_parity & 0x03) ^ (temp_parity >> 2);
    parity_flag = (temp_parity & 0x01) ^ (temp_parity >> 1);
    if(a == 0) zero_flag = 1;
    else zero_flag = 0;
    return a;
}
If you're not using C and you're writing it in assembly (or inline assembly), then you could just get the flags directly from EFLAGS; which would be faster and easier (but a lot less portable).

If you need to be portable, then most emulators don't bother working out the flags *until* they emulate an instruction that relies on the previous flags. This improves performance because most of the time the flags aren't used and the code to set flags correctly can be skipped entirely. In this case you'd probably need to store the size of the operation, the result and the input values so that you can work out the flags later if necessary (although you may need to store the type of operation too - I haven't thought much about it).


Cheers,

Brendan

Re: Overflow flag

Posted: Thu Oct 02, 2008 11:36 am
by kestaz
Thanks for your quick reply. Actually i implemented addition8bit function by my own. And it looks like this:

Code: Select all

int emulator::arithm_flags8( unsigned  char  x, unsigned char y, int p )
{
    if (((p & 0x100) >> 8) == 1) flags |= 1 ; //cary flag
    else flags &= 0xfe ; 
    p = (unsigned  char) p ; 
    if (parity_flag(p)) flags |= 0x04; //parity flag
    else flags &= 0xfb ;
    if (((x^y^p) & 0x10) != 0) flags |= 0x10 ; //aux flag
    else flags &= 0xef ; 
    if (p == 0)   flags |= 0x40 ; // zero flag
    else flags &= 0xbf ; 
   if (sign(p)) flags |= 0x80 ; // sign flag 
   else flags &= 0x7f ; 
    // overflow flag
     if ((((x^(~v))&(x^y)) & 0x80) != 0) flags |=0x800 ;  // i looked for this function from retro emulator.. but seems // //something don't work correct
	else flags &= 0xf7ff ;
	    
}
But find that overflow flag doesn't works correctly. I posted test values in my previous post. Maybe you know why ?
And few tips from you post: Just wrote simple code to check if your solution( A ^ B ^ C) is correct:

Code: Select all

#include <stdio.h>

int main()
{
   for (int i=0; i <=1; i++)
   {
      for (int j=0; j<=1; j++)
      {
        for (int k=0; k<=1; k++)
        {
           printf("%d %d %d = %d \n", i, j, k, i ^ j ^ k)  ;
        }
      }
   }
}
programs gives:
0 0 0 = 0 
0 0 1 = 1 
0 1 0 = 1 
0 1 1 = 0 
1 0 0 = 1 
1 0 1 = 0 
1 1 0 = 0 
1 1 1 = 1 
And it's not right as http://intelliwiki.kylesblog.com/index.php/Overflow_Flag logic A ^ C ^ B expression truetable.
And if A ^ B ^C expression good that i'm did wrong ? And can you post overflow check for Subtraction ?
Actually now i looking for simple solution and it's like this:

Code: Select all

 
if (!sign(a) && !sign(b) && sign(c)) overflow = 1 ; 
else if (sign(a) && sign(b) && !sign(c)) overflow = 1 ;
else overflow = 0  ; 
Just looked in overflow truetable and write all variations
And one things intel manauls says:
imm8 — An immediate byte value. The imm8 symbol is a signed number
between –128 and +127 inclusive. For instructions in which imm8 is combined
with a word or doubleword operand, the immediate value is sign-extended to
form a word or doubleword. The upper byte of the word is filled with the topmost
bit of the immediate value.
• imm16 — An immediate word value used for instructions whose operand-size
attribute is 16 bits. This is a number between –32,768 and +32,767 inclusive.

I i'm reading imm8 as unsigned char in my emu project. So maybe unsigned/signed problem ? But check all sign's in my arithm_flags8 function and all signs look good. So maybe there's bug in this function if ((((x^(~v))&(x^y)) & 0x80) != 0) ; ?

Thanks again

Re: Overflow flag

Posted: Fri Oct 03, 2008 6:15 am
by Brendan
Hi,

Doh. I was expecting the answer to be relatively simple... :oops:

I had another go and came up with "overflow = !(i ^ j) & (k ^ i)" (or alternatively, "overflow = !(i ^ j) & (k ^ j)"). For subtraction, I came up with "overflow = (i ^ j) & !(i ^ k)", which is equally ugly/complex.
kestaz wrote:So maybe there's bug in this function if ((((x^(~v))&(x^y)) & 0x80) != 0) ;
I checked, and that function (or "overflow =(i^(~k))&(i^j)") also works correctly for subtraction (but not addition).

Note: For all of the above, i is the sign bit for first operand, j is the sign bit for the second operand, and k is the sign bit for the result. In all cases you can use 8-bit boolean operations and then mask/shift once (instead of masking/shifting 3 variables and then doing the boolean operations).

I'm not too sure about the imm8 stuff. From memory, I can't think of any instructions where imm8 is combined with a word or doubleword operand; except for MOVSX and MOVSZ (where zero extension or sign extension is explictly chosen by the programmer), and shift/rotate instructions (where the imm8 is unsigned and is truncated/masked to 6-bits or less depending on the size of the other operand), and MMX/SSE instructions (where the imm8 is probably unsigned and truncated/masked to 4-bits or less). Are you sure you're not thinking about disp8?


Cheers,

Brendan