Overflow detection

Discuss emulation of the Nintendo Entertainment System and Famicom.

Moderator: Moderators

Post Reply
johnnie
Posts: 16
Joined: Fri Nov 09, 2007 10:38 am

Overflow detection

Post by johnnie »

Which is the easiest way to detect overflow? I can imagine a construct of ifs, but this is quite inefficient. Is there a bitwise mask you can operate on the operands to predict the result? If so, how did you obtain it? I'm working on ADC and got everything (including the carry, which is just set to one if the result exceeds 0xFF) sorted except for the V-flag, which is giving me headaches.

Thanks for the help so far, it's appreciated :)
User avatar
Disch
Posts: 1848
Joined: Wed Nov 10, 2004 6:47 pm

Post by Disch »

V logic for ADC:

set when: positive + positive = negative
or when: negative + negative = positive

therefore, you can check for the sum having mismatching signs as the two values being added.

Pseudo-code:

Code: Select all

temp = A + val;
if( carry_set )
  temp += 1;

V_flag = (temp ^ A) & (temp ^ val) & 0x80;
here, V_flag will be nonzero (0x80) when V is to be set and 0 when it is to be cleared.


SBC works similarly, but logic is slightly different:

positive - negative = negative
negative - positive = positive

here, 'A' is the odd one out, not the final value. Therefore:

Code: Select all

V_flag = (A ^ temp) & (A ^ val) & 0x80;
johnnie
Posts: 16
Joined: Fri Nov 09, 2007 10:38 am

Post by johnnie »

OK, thanks. Given immediate addressing, I now have (please bear with me):

Code: Select all

case ADC:
  M=READMEM(rPC+1);
  R=M + rA + (fC ? 1 : 0);
  fV = (rA^R) & (M^R) & 0x80;
  rA = R&0x00FF; /* Copies the LSB of R into the accumulator */
  fC = R>>8; /* Stores MSB of result into carry */
  STEP(2,2); /* Macro that increases the PC and decreases the cycles */
  break;
Where:

R, M = 16-bits temp variables to store memory reads and results.
rA = accumulator register (#defined for readability)
rPC = program counter
fV = V-flag
fC = carry flag

So, is this any good? I suppose I can make a macro out of some of this, but this is just for verification. What I am kinda uncertain about, is whether moving a 16 bit integer into a single byte yields a predictable result, even when the MSB of the 16-bit integer is zero (as is the case in my operations).
Last edited by johnnie on Tue Nov 13, 2007 2:50 pm, edited 1 time in total.
User avatar
Disch
Posts: 1848
Joined: Wed Nov 10, 2004 6:47 pm

Post by Disch »

Looks good to me. Only thing you're missing is setting N and Z according to the result.
johnnie wrote:What I am kinda uncertain about, is whether moving a 16 bit integer into a single byte yields a predictable result, even when the MSB of the 16-bit integer is zero (as is the case in my operations).
To my knowledge, casting to an integer data type of smaller size truncates the value by removing the most significant bits. So the result would be predictable.

I never actually confirmed that -- but I'm pretty confident such behavior would be standardized in C/C++.
johnnie
Posts: 16
Joined: Fri Nov 09, 2007 10:38 am

Post by johnnie »

Talking about subtraction, my reference states that carry should be cleared "if overflow in bit 7". In other words, when my unsigned result > 255, I clear carry. However, it is nowhere said that carry should be set if this overflow did not occur. I have seen several cores (eg. FakeNES) doing just that by setting the carry storage byte to the MSB+1. This correctly clears the carry on overflow of bit 7, but implies setting carry when no overflow occurs. It appears to me that this is incorrect behaviour, or am I wrong?
User avatar
Disch
Posts: 1848
Joined: Wed Nov 10, 2004 6:47 pm

Post by Disch »

Instructions that change flag states -- always change flag states (that is, they either set them or clear them -- they never leave them untouched). So SBC should be set when subtraction results in >= 0, and cleared otherwise. Note this applies only to flags that the instruction affects -- flags that it does not affect are never changed.

In short: FakeNES is doing it properly.
User avatar
blargg
Posts: 3715
Joined: Mon Sep 27, 2004 8:33 am
Location: Central Texas, USA
Contact:

Post by blargg »

johnnie wrote: What I am kinda uncertain about, is whether moving a 16 bit integer into a single byte yields a predictable result, even when the MSB of the 16-bit integer is zero (as is the case in my operations).
As long as the destination type is unsigned, it just truncates upper bits. If unsigned char is 8 bits on your machine (which it is on almost everything these days),

(unsigned char) foo

is equivalent to

(unsigned char) (foo & 0xFF)
Post Reply