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.
Overflow flag
Re: Overflow flag
Hi,
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:
So, for 8-bit addition in C you'd do something like this:
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
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)".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 ?
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;
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 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
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
Re: Overflow flag
Thanks for your quick reply. Actually i implemented addition8bit function by my own. And it looks like this:
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:
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:
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
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 ;
}
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.
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
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
Hi,
Doh. I was expecting the answer to be relatively simple...
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.
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
Doh. I was expecting the answer to be relatively simple...
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.
I checked, and that function (or "overflow =(i^(~k))&(i^j)") also works correctly for subtraction (but not addition).kestaz wrote:So maybe there's bug in this function if ((((x^(~v))&(x^y)) & 0x80) != 0) ;
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
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.