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 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
how to set properly the flags v and c
Moderator: Moderators
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:
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:
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:
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:
-----------------------------------------
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:
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);
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);
-------------------------------
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);
}
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;
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.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!
Here is WedNESday's (pre Binary Translation)
(Accumulator and Databus are both unsigned and 8-bit)
Here is WedNESday's (post Binary Translation)
(Puts on his shades) 8)
(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;
Code: Select all
seto OF
setc CF
Disch told you everything, but this post should help you too:
http://nesdev.com/bbs/viewtopic.php?t=6 ... light=flag
http://nesdev.com/bbs/viewtopic.php?t=6 ... light=flag
ANes