It is currently Thu Oct 02, 2014 9:35 am

All times are UTC - 7 hours




Post new topic Reply to topic  [ 18 posts ]  Go to page 1, 2  Next
Author Message
PostPosted: Tue Apr 27, 2010 7:44 pm 
Offline
User avatar

Joined: Mon Dec 22, 2008 10:45 pm
Posts: 286
Location: Argentina
obelisk.demon.co.uk/6502 says 'Overflow Flag Set if sign bit is incorrect' which is vague and I really don't see clearly what means that 'sign bit is incorrect'.

The 6502 documentation by _Bnu, in the other hand, is very specific, it says that the overflow flag after an ADC without decimal mode is this:
Code:
(!((AC ^ src) & 0x80) && ((AC ^ temp) & 0x80))

(AC is accumulator, src is a value from memory, temp is AC + src + carry, and 0x80 is bit 7 set )

Ok, I understand bitwise operations, but I don't get the logic behind this expression.

So the ultimate question is, conceptually, when should the overflow flag be set for ADC and when should it be unset? (what is a correct sign?)

I could just paste that expression in my code and it may work perfectly, but I'd like to understand what my code is doing.

PS: the carry flag is set when the addition overflows. So the overflow flag doesn't actually mean overflow, it means something else.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Apr 27, 2010 8:11 pm 
Offline
User avatar

Joined: Wed Nov 10, 2004 6:47 pm
Posts: 1694
Carry indicates unsigned overflow
Overflow indicates signed overflow.

When you figure that $81 can be -127 and $FF can be -1..

When adding two unsigned numbers results in > $FF, C is set
When adding two signed numbers results in > 127 ($7F) or < -128 ($80), V is set


In emulation, this can be easily checked by looking at the high bits. Basically:

Overflow is set if:
Positive + Positive = Negative
or
Negative + Negative = Positive

Overflow is cleared in all other instances.

Here's example code:

Code:
// A = Accumulator before the addition
// v = the value adding to the accumulator
// s = the sum of the addition (A+v+C)

if( (A ^ s) & (v ^ s) & 0x80 )
  Set_V();
else
  Clear_V();


EDIT:

err... duh, you already posted example code.

Anyway as for how the code works...

Pos+Pos=Neg and Neg+Neg=Pos

Both conditions have the "sum" as the odd one out. So if the sign of the sum matches either the sign of A or the sign of v, then you don't overflow.

So in my example code:

Code:
if( (A ^ s) & (v ^ s) & 0x80 )


All we're really interested in is the high bit... so ignore all the other bits in A,v,s.

A^s will have the high bit set if the signs mismatch
ditto for v^s

so... (A^s) & (v^s) ... the AND operation check to make sure both of those conditions had the high bit set (ie: s high bit didn't match A or v). If the AND results in the high bit set, the we know that we have overflow

The following & 0x80 just extracts the high bit.


Last edited by Disch on Tue Apr 27, 2010 8:22 pm, edited 1 time in total.

Top
 Profile  
 
 Post subject:
PostPosted: Tue Apr 27, 2010 8:16 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 6709
Location: Rio de Janeiro - Brazil
As I understand it, the carry flag can detect overflows and underflows of unsigned numbers, while the V flag is used for signed numbers.

When you add 1 to 127, the result is 128, which is correct if you treat the numbers as unsigned, but in signed numbers 128 is actually -128, so that's an overflow. Same goes for underflows: if you subtract 1 from -128 the result is -129, which doesn't fit in a byte. Crossing between 0 and 255 (-1) should be OK though, if the numbers are signed.

IIRC, there is a simple rule for setting the V flag, but I can't remember what it is (I program games, not emulators!) so I'll let someone else give it to you.

EDIT: Too late! =)


Top
 Profile  
 
 Post subject:
PostPosted: Wed Apr 28, 2010 5:55 am 
Offline
User avatar

Joined: Mon Dec 22, 2008 10:45 pm
Posts: 286
Location: Argentina
Thanks! great answers!


Top
 Profile  
 
 Post subject:
PostPosted: Wed Apr 28, 2010 8:57 am 
Offline
User avatar

Joined: Mon Sep 27, 2004 8:33 am
Posts: 3711
Location: Central Texas, USA
This has been discussed many times before, with lots of useful explanations and code. I highly recommend you seek out these previous discussions.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Apr 28, 2010 11:22 am 
Offline
User avatar

Joined: Mon Dec 22, 2008 10:45 pm
Posts: 286
Location: Argentina
I actually made some calculations and both algorithms throw different results.
Which one is right? ( Disch's or _Bnu's )

Image

Reference:
A: Accumulator
M: Value from memory
C: Carry
ADC: Result of A+M+C
ADC8: ADC truncated to 8 bits
V: Overflow flag from Disch's algorithm
V2: Overflow flag from _Bnu's algorithm
+: sign bit 7 is set
-: sign bit 7 is reset

Algorithms used: ( if I coded them wrong, sorry! )

Disch's:
Code:
$v = (int) (bool) ( ( $a ^ $adc ) & ( $m ^ $adc ) & 0x80 );

_Bnu's:
Code:
(int) (bool) ( ( ( $a ^ $m ) & 0x80 ) && ( ( $a ^ $adc ) & 0x80 ) );




blargg wrote:
This has been discussed many times before, with lots of useful explanations and code. I highly recommend you seek out these previous discussions.

I'm sorry, you're right. But either I suck at forum searching or some posters suck at writing meaningful thread titles. I suspect a little of both ;D


Edit: Disch: I see that you already posted the same algorith, so it's most likely the right one. I'll go with that.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Apr 28, 2010 12:03 pm 
Offline

Joined: Sun Sep 19, 2004 11:07 pm
Posts: 152
Your table calculations are wrong, as you forgot the ! in Bnu's.
Disch's, in english, is (overflow if the sign of the result does not match the sign of either input), Bnu's is (overflow if the sign of the inputs are the same, and do not match the sign of the result).

for the case of FF+00+0, result is 0, FF. A & 80 = 1, M & 80 = 0, R & 80 = 1. !(A^M) & (A^R) & 80 = !1 & 0 = 0 & 0 = 0
A^R & M^R & 80 = 0 & 1 = 0
FF+00+1: A=1, M=0, R=0
!(A^M) & A^R = !1 & 0 = 0
A^R & M^R = 1^0 & 0^0 = 1 & 0 = 0

etc.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Apr 28, 2010 12:09 pm 
Offline
User avatar

Joined: Mon Dec 22, 2008 10:45 pm
Posts: 286
Location: Argentina
Oh, I didn't see that bastard `!`
Thanks!


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 29, 2010 10:11 am 
Offline
User avatar

Joined: Mon Sep 27, 2004 8:33 am
Posts: 3711
Location: Central Texas, USA
Just be glad the NES doesn't have a decimal mode. The flag setting for that differs between the 6502, 65C02, and 65816. It's a nightmare.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 29, 2010 10:51 am 
Offline

Joined: Wed Jul 04, 2007 8:40 am
Posts: 36
To stir the pot more: Which one is faster? :)


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 29, 2010 11:14 am 
Online
Site Admin
User avatar

Joined: Sun Sep 19, 2004 9:28 pm
Posts: 1872
Location: Mountain View, CA, USA
Thing to note: _Bnu did not write that document, he simply corrected all the spelling errors. So if there's mistakes in the technical aspects, don't hold him responsible. :-)


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 29, 2010 11:38 am 
Offline
User avatar

Joined: Mon Dec 22, 2008 10:45 pm
Posts: 286
Location: Argentina
blargg wrote:
Just be glad the NES doesn't have a decimal mode. The flag setting for that differs between the 6502, 65C02, and 65816. It's a nightmare.

Halleluya!

koitsu wrote:
Thing to note: _Bnu did not write that document, he simply corrected all the spelling errors. So if there's mistakes in the technical aspects, don't hold him responsible. :-)

And who wrote that document? there has to be someone I can sue for that!


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 29, 2010 11:46 am 
Offline
User avatar

Joined: Mon Sep 27, 2004 8:33 am
Posts: 3711
Location: Central Texas, USA
Hamburgler wrote:
To stir the pot more: Which one is faster? :)

To counter that stirring, ADC and SBC are not instructions that are used very often.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 29, 2010 11:55 am 
Offline
User avatar

Joined: Mon Dec 22, 2008 10:45 pm
Posts: 286
Location: Argentina
I wouldn't care too much about the speed of a few bitwise operations, I'll surely have worst bottlenecks in other parts of the emulator.


Top
 Profile  
 
 Post subject:
PostPosted: Mon May 24, 2010 12:03 pm 
Offline
User avatar

Joined: Tue Mar 09, 2010 11:12 pm
Posts: 83
Location: Rosario, Argentina
i guess the clearest way to set or reset the V flag in ADC and SBC instructiones is by testing if the result is major than 0x7f. it works in both instructions.

ADC Immediate:
Code:
auxbyte = ACC;
ACC += (Mem[++PC] + C_FLAG);
if(auxbyte + Mem[PC] + C_FLAG > 127) V_FLAG = 1;
else V_FLAG = 0;


SBC Immediate:
Code:
auxbyte = ACC;
ACC -= (Mem[++PC] - C_FLAG);
if(auxbyte - Mem[PC] - C_FLAG > 127) V_FLAG = 1;
else V_FLAG = 0;


of course this is not the faster way, but is the easiest way to the understand how V flag works

_________________
sorry about my english, i'm from argentina...

http://nestate.uuuq.com


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 18 posts ]  Go to page 1, 2  Next

All times are UTC - 7 hours


Who is online

Users browsing this forum: No registered users and 2 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group