#ifndef _INL68_ARITHMETIC_H_
#define _INL68_ARITHMETIC_H_
static inline
int68_t inl_add68(emu68_t * const emu68, int68_t s, int68_t d, int68_t c)
{
const int68_t r = ( c += s + d );
c = ( ( r >> SIGN_BIT ) & ( SR_V | SR_C | SR_X | SR_N ) ) ^ SR_V;
s = ( ( s >> SIGN_BIT ) & ( SR_V | SR_C | SR_X ) ) ^ c;
d = ( ( d >> SIGN_BIT ) & ( SR_V | SR_C | SR_X ) ) ^ c;
c &= ~SR_N;
c |= SR_V | ( !r << SR_Z_BIT );
c ^= s | d;
REG68.sr = ( REG68.sr & 0xFF00 ) | c;
return r;
}
static inline
int68_t inl_sub68(emu68_t * const emu68, int68_t s, int68_t d, int68_t c)
{
const int68_t r = d - s - c;
REG68.sr = ( REG68.sr & 0xFF00 )
| (!r << SR_Z_BIT)
| (( r >> SIGN_BIT ) & SR_N)
| (((((d ^ ~r) & (s ^ r)) ^ r) >> SIGN_BIT) & (SR_C|SR_X))
| ((((d ^ r) & (~s ^ r)) >> SIGN_BIT) & SR_V)
;
return r;
}
static inline
void inl_cmp68(emu68_t * const emu68, int68_t s, int68_t d)
{
const int68_t r = d - s;
REG68.sr = ( REG68.sr & ( 0xFF00 | SR_X ) )
| (!r << SR_Z_BIT)
| (( r >> SIGN_BIT ) & SR_N)
| (((((d ^ ~r) & (s ^ r)) ^ r) >> SIGN_BIT) & SR_C)
| ((((d ^ r) & (~s ^ r)) >> SIGN_BIT) & SR_V)
;
}
static inline
int68_t inl_neg68(emu68_t * const emu68, int68_t d, int68_t c)
{
int sr = REG68.sr & 0xFF00;
const int68_t r = ( c = -d - c );
sr |= !r << SR_Z_BIT;
d >>= SIGN_BIT;
c >>= SIGN_BIT;
sr |= c & SR_N;
sr |= ( d | c ) & (SR_C|SR_X);
sr |= ( d & c ) & SR_V;
REG68.sr = sr;
return r;
}
static inline
int68_t inl_muls68(emu68_t * const emu68, int68_t s, int68_t d)
{
d = ( d >> WORD_FIX ) * ( s >> WORD_FIX );
REG68.sr = ( REG68.sr & ( 0xFF00 | SR_X ) )
| ( !d << SR_Z_BIT )
| ( (d >> (31 - SR_N_BIT)) & SR_N );
return d << LONG_FIX;
}
static inline
int68_t inl_mulu68(emu68_t * const emu68, uint68_t s, uint68_t d)
{
d = ( d >> WORD_FIX ) * ( s >> WORD_FIX );
REG68.sr = ( REG68.sr & ( 0xFF00 | SR_X ) )
| ( !d << SR_Z_BIT )
| ( (d >> (31 - SR_N_BIT)) & SR_N );
return d << LONG_FIX;
}
static inline
int68_t inl_divs68(emu68_t * const emu68, int68_t s, int68_t d)
{
int sr = REG68.sr & (0xFF00 | SR_X);
if ( s >>= WORD_FIX ) {
int68_t res, rem;
d >>= LONG_FIX;
res = d / s;
rem = d % s;
if ( (s16)res != res )
sr |= SR_V;
else
d = ( (int68_t) (u16) res ) | ( (int68_t) (u16) rem << 16 );
sr |= !res << SR_Z_BIT;
sr |= ( res >> ( 15 - SR_N_BIT ) ) & SR_N;
REG68.sr = sr;
d <<= LONG_FIX;
} else {
REG68.sr = sr;
inl_exception68(emu68, DIVIDE_VECTOR, -1);
}
return d;
}
static inline
int68_t inl_divu68(emu68_t * const emu68, uint68_t s, uint68_t d)
{
int sr = REG68.sr & (0xFF00 | SR_X);
if ( s >>= WORD_FIX ) {
uint68_t res, rem;
d >>= LONG_FIX;
res = d / s;
rem = d % s;
if ( (u16)res != res )
sr |= SR_V;
else
d = ( res ) | ( rem << 16 );
sr |= !res << SR_Z_BIT;
sr |= ( res >> ( 15 - SR_N_BIT ) ) & SR_N;
REG68.sr = sr;
d <<= LONG_FIX;
} else {
REG68.sr = sr;
inl_exception68(emu68, DIVIDE_VECTOR, -1);
}
return d;
}
static inline
int68_t inl_clr68(emu68_t * const emu68)
{
REG68.sr = ( REG68.sr & ( 0xFF00 | SR_X ) ) | SR_Z;
return 0;
}
#endif