how to set properly the flags v and c

Discuss emulation of the Nintendo Entertainment System and Famicom.

Moderator: Moderators

Post Reply
User avatar
dreampeppers99
Posts: 77
Joined: Mon Aug 21, 2006 4:19 am

how to set properly the flags v and c

Post by dreampeppers99 »

Flags: overflown and carry!
I still don't get it!
I always thought overflow is caused by ... for example: we have an register accumulator (8bits wide) and then one operation is add some number to acc and in the addition process the result number is bigger than 8bits (0x1F0) so here the overflown was to be setted...
And carry :roll: well I guess it should work like in the old math classes!
How can I take care of it?

Comparisons:
On this kind of operations the way to set V C flag is different? (and even the sign flag too?)

thanks in advance
User avatar
Disch
Posts: 1848
Joined: Wed Nov 10, 2004 6:47 pm

Post by Disch »

for ADC:

Carry is set if the addition resulted in an unsigned overflow (sum > 255), and is cleared otherwise (<= 255).

Overflow is set if the addition resulted in a signed overflow (sum > 127, or < -128), and is cleared otherwise (sum >= -128 and sum <= 127).

In an emu you probably have all your numbers as unsigned, so checking for Carry is pretty simple:

Code: Select all

C = (sum > 0xFF);
A = (sum & 0xFF);
Overflow is a bit weirder if you're dealing with unsigned logic. The common way to do it is check to see if:

Positive + Positive = Negative
or
Negative + Negative = Positive

If either of those are true, you set V, otherwise you clear it. In this case "negative" just means that the high bit is set. So:

Code: Select all

V = ((sum ^ val) & (sum ^ A) & 0x80) != 0;
C = (sum > 0xFF);
A = (sum & 0xFF);
where 'val' is the value being added to A, 'A' is the accumulator before addition, and 'sum' is the resulting sum of A+val+C.

-------------------------------
for SBC:

SBC logic is just ADC inverted. You can implement SBC with the following, and it will work perfectly (provided your ADC is implemented correctly:

Code: Select all

void DoSBC(u8 val)
{
  DoADC(val ^ 0xFF);
}
Or if you want to implement SBC on its own:

C is set if the unsigned result was >= 0, and is cleared if the unsigned result was < 0.

V is set under same conditions as for ADC (result caused signed overflow). Logic to implement this with unsigned types:

Positive - Negative = Negative
Negative - Positive = Positive

Ways to implement this:

Code: Select all

C = (dif >= 0);   // note 'dif' would have to be a signed type
C = (dif > 0xFF); // otherwise you can do this if 'dif' is unsigned

V = ((A ^ dif) & (A ^ val) & 0x80) != 0;
-----------------------------------------
for CMP/CPX/CPY

Do not change V at all.

C is set the same as it is for SBC -- however note that while SBC will subtract an extra 1 if C is clear, CMP/CPX/CPY never subtract that extra 1.

------------------------------------------
for ASL/LSR/ROL/ROR

C is set or cleared as a result of the bit shifted out.
V is unchanged.

-----------------------------------------
the N flag (sign / negative flag)

is just set if the high bit (bit 7: 0x80) of the result is set, and is cleared otherwise:

Code: Select all

N = (result & 0x80) != 0;
User avatar
dreampeppers99
Posts: 77
Joined: Mon Aug 21, 2006 4:19 am

Post by dreampeppers99 »

thanks so much! :wink:
User avatar
blargg
Posts: 3715
Joined: Mon Sep 27, 2004 8:33 am
Location: Central Texas, USA
Contact:

Post by blargg »

I always thought overflow is caused by ... for example: we have an register accumulator (8bits wide) and then one operation is add some number to acc and in the addition process the result number is bigger than 8bits (0x1F0) so here the overflown was to be setted...

And carry well I guess it should work like in the old math classes!
Do you see how carry works just like you thought overflow should, if the value exceeds the available space, you have a carry out? That is, carry is for unsigned overflow. Since signed values are represented as negative values basically being carry+00000...-magnitude, you can see how having a carry from a signed addition doesn't tell you much useful.
WedNESday
Posts: 1292
Joined: Thu Sep 15, 2005 9:23 am
Location: London, England

Post by WedNESday »

Here is WedNESday's (pre Binary Translation)

(Accumulator and Databus are both unsigned and 8-bit)

Code: Select all

if (Accumulator + Databus > 0xFF)
	CF = 1; else CF = 0;

temp = (signed char)A8 + (signed char)Databus + CF;
	if (temp < -128 || temp > 127)
		Overflow = 1; else Overflow = 0;
Here is WedNESday's (post Binary Translation)

Code: Select all

seto OF
setc CF
(Puts on his shades) 8)
User avatar
Anes
Posts: 703
Joined: Tue Dec 21, 2004 8:35 pm
Location: Mendoza, Argentina

Post by Anes »

Disch told you everything, but this post should help you too:

http://nesdev.com/bbs/viewtopic.php?t=6 ... light=flag
ANes
Post Reply