Page 1 of 1

Math issue with overflow flag

Posted: Wed Dec 10, 2014 3:09 am
by BobLoblaw0101
I'm running a 6502 expression in a simulator and it's reporting that the overflow flag is getting set, even though I don't expect it to be set. Consider the following:

Carry flag is on.
acc = 0x7f

So I run the expression:

SBC #$ff

And the overflow flag gets set, and acc is 0x80.

I thought the way to calculate the V flag is to use the formula from here (http://www.righto.com/2012/12/the-6502- ... ained.html):

(M^result)&(N^result)&0x80

If I take the information supplied above and use it;

((0xff^0x80)&(0x7f^0x80))&0x80

I get 0, which means that the overflow flag is off.

Re: Math issue with overflow flag

Posted: Wed Dec 10, 2014 3:22 am
by MichaelM
I believe that you should consider the operation that you are requesting in a decimal representation:

$7F => 127 decimal
$FF => -1 decimal

the operation you are performing is 127 - (-1) = +128 which can not be represented in an 8-bit register. Hence the V flag should be set. Furthermore, the value of $80 you are reporting being returned in A is equal to -128 not +128.

If your intention was to decrement the $7F value while the Cy is set, you should do an SBC #$01 instruction instead.

The overflow flag is a signed arithmetic flag. The method that I use to set the overflow flag is based on the carries into and out of bit 7. When there's a carry from bit 6 into bit 7 and no carry out of from bit 7, an overflow has occurred.

The other method uses the sign of the operands of an "addition". Subtraction by 2's complement can be accomplished by taking the 2's complement of one number and then adding it to the other number. In this situation, the 2's complement of $FF is computed by taking its complement, i.e. $00, and adding 1, which is done in your situation because the carry is set. Thus, the two's complement of $FF is $01. In this case, the sign of the first number ($7F) is a 0, i.e. positive, and the sign of the second number ($01) is also 0. However, the sign of the result ($80) is a 1, i.e. negative. Thus, an overflow occurred.

Hope this helps.

Re: Math issue with overflow flag

Posted: Wed Dec 10, 2014 3:33 am
by BobLoblaw0101
MichaelM wrote:
I believe that you should consider the operation that you are requesting in a decimal representation:

$7F => 127 decimal
$FF => -1 decimal

the operation you are performing is 127 - (-1) = +128 which can not be represented in an 8-bit register. Hence the V flag should be set. Furthermore, the value of $80 you are reporting being returned in A is equal to -128 not +128.

If your intention was to decrement the $7F value while the Cy is set, you should do an SBC #$01 instruction instead.
I suppose my question was more about understanding why Ken Shirriff's formula does not work on that expression. It has worked on everything else I've tried, but for some reason, it fails to calculate the V flag when the condition I stated is present.

Re: Math issue with overflow flag

Posted: Wed Dec 10, 2014 3:49 am
by MichaelM
Bob:

I edited my response to include some other material that should make clear the reason. Please refer to the second part of of my previous response.

Re: Math issue with overflow flag

Posted: Wed Dec 10, 2014 3:56 am
by barrym95838
I haven't studied the issue in depth, but could this comment from Ken Shirrif's blog be an important clue, in reference to the add ones-complement nature of SBC?
Quote:
Anonymous said...
Thank you for the very informative article. I referenced it trying to figure out a problem in my emulator. One note that might be helpful to others is that in the "Formulas for the overflow flag" section it wasn't completely clear to me that in the "(M^result) & (N^result) & 0x80" formula, the N is ones-complement of the target, not the target. It took several readings and much comprehension to give that a try.
May 23, 2013 at 7:45 PM
Mike

Re: Math issue with overflow flag

Posted: Wed Dec 10, 2014 4:10 am
by MichaelM
That's only partially true.

In terms of the actual implementation of the 6502 ALU, the SBC instruction only complements the operand.

If this was the only action taken, the resulting operation would be a 1's complement subtraction, with the programmer being required to add in any carries from the most significant bit of the result in order to get the correct result. Further, there would essentially be two values of 0. A positive 0 consisting of all 0s, and a negative 0 consisting of all 1s.

However, the programmer is required to set the carry flag before subtraction (or the first subtraction of a multi-precision subtraction). This requirement allows the 6502 to compute the desired 2's complement difference.

Re: Math issue with overflow flag

Posted: Wed Dec 10, 2014 4:32 am
by barrym95838
My point is that ADC is (or at least should be) the heavy lifter, and it is the only one that needs to update the accumulator and set the flags.
I am saying this because, if I'm not mistaken, SBC is implemented as a trivial operation: ones-complement the operand and pass everything else unchanged straight to ADC for all the rest of the work. This method should even work in decimal mode if the nines-complement (of the operand) is used instead, right?

Mike

[Edit: This technique can be utilized at the emulator code level or the hardware level with equal effectiveness. I don't see any reason for SBC to be any more complicated than, for example:

Code: Select all

sbc() {
    operand = D_FLAG ? 0x99-operand : ~operand;
    adc();
}
Anything more is a waste of effort, IMO.]

Re: Math issue with overflow flag

Posted: Wed Dec 10, 2014 5:17 am
by MichaelM
Your suggestion is correct, but by setting the carry, the value passed to ADC is a 2's Complement value. It is the sign bits of the values passed to add ADC that should be used for determining overflow.

Re: Math issue with overflow flag

Posted: Wed Dec 10, 2014 7:12 am
by GARTHWILSON
This topic should clarify it:
viewtopic.php?f=1&t=62