snes9x/cpumacro.h

675 lines
14 KiB
C
Raw Permalink Normal View History

/*****************************************************************************\
Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
This file is licensed under the Snes9x License.
For further information, consult the LICENSE file in the root directory.
\*****************************************************************************/
2010-09-25 15:46:12 +00:00
#ifndef _CPUMACRO_H_
#define _CPUMACRO_H_
#define rOP8(OP, ADDR, WRAP, FUNC) \
static void Op##OP (void) \
{ \
uint8 val = OpenBus = S9xGetByte(ADDR(READ)); \
FUNC(val); \
}
#define rOP16(OP, ADDR, WRAP, FUNC) \
static void Op##OP (void) \
{ \
uint16 val = S9xGetWord(ADDR(READ), WRAP); \
OpenBus = (uint8) (val >> 8); \
FUNC(val); \
}
#define rOPC(OP, COND, ADDR, WRAP, FUNC) \
static void Op##OP (void) \
{ \
if (Check##COND()) \
{ \
uint8 val = OpenBus = S9xGetByte(ADDR(READ)); \
FUNC(val); \
} \
else \
{ \
uint16 val = S9xGetWord(ADDR(READ), WRAP); \
OpenBus = (uint8) (val >> 8); \
FUNC(val); \
} \
}
#define rOPM(OP, ADDR, WRAP, FUNC) \
rOPC(OP, Memory, ADDR, WRAP, FUNC)
#define rOPX(OP, ADDR, WRAP, FUNC) \
rOPC(OP, Index, ADDR, WRAP, FUNC)
#define wOP8(OP, ADDR, WRAP, FUNC) \
static void Op##OP (void) \
{ \
FUNC##8(ADDR(WRITE)); \
}
#define wOP16(OP, ADDR, WRAP, FUNC) \
static void Op##OP (void) \
{ \
FUNC##16(ADDR(WRITE), WRAP); \
}
#define wOPC(OP, COND, ADDR, WRAP, FUNC) \
static void Op##OP (void) \
{ \
if (Check##COND()) \
FUNC##8(ADDR(WRITE)); \
else \
FUNC##16(ADDR(WRITE), WRAP); \
}
#define wOPM(OP, ADDR, WRAP, FUNC) \
wOPC(OP, Memory, ADDR, WRAP, FUNC)
#define wOPX(OP, ADDR, WRAP, FUNC) \
wOPC(OP, Index, ADDR, WRAP, FUNC)
#define mOP8(OP, ADDR, WRAP, FUNC) \
static void Op##OP (void) \
{ \
FUNC##8(ADDR(MODIFY)); \
}
#define mOP16(OP, ADDR, WRAP, FUNC) \
static void Op##OP (void) \
{ \
FUNC##16(ADDR(MODIFY), WRAP); \
}
#define mOPC(OP, COND, ADDR, WRAP, FUNC) \
static void Op##OP (void) \
{ \
if (Check##COND()) \
FUNC##8(ADDR(MODIFY)); \
else \
FUNC##16(ADDR(MODIFY), WRAP); \
}
#define mOPM(OP, ADDR, WRAP, FUNC) \
mOPC(OP, Memory, ADDR, WRAP, FUNC)
#define bOP(OP, REL, COND, CHK, E) \
static void Op##OP (void) \
{ \
pair newPC; \
newPC.W = REL(JUMP); \
if (COND) \
{ \
AddCycles(ONE_CYCLE); \
if (E && Registers.PCh != newPC.B.h) \
AddCycles(ONE_CYCLE); \
if ((Registers.PCw & ~MEMMAP_MASK) != (newPC.W & ~MEMMAP_MASK)) \
S9xSetPCBase(ICPU.ShiftedPB + newPC.W); \
else \
Registers.PCw = newPC.W; \
} \
}
static inline void SetZN (uint16 Work16)
{
ICPU._Zero = Work16 != 0;
ICPU._Negative = (uint8) (Work16 >> 8);
}
static inline void SetZN (uint8 Work8)
{
ICPU._Zero = Work8;
ICPU._Negative = Work8;
}
static inline void ADC (uint16 Work16)
{
if (CheckDecimal())
{
2018-10-02 22:16:06 +00:00
uint32 result;
uint32 carry = CheckCarry();
result = (Registers.A.W & 0x000F) + (Work16 & 0x000F) + carry;
if (result > 0x0009)
result += 0x0006;
carry = (result > 0x000F);
result = (Registers.A.W & 0x00F0) + (Work16 & 0x00F0) + (result & 0x000F) + carry * 0x10;
if (result > 0x009F)
result += 0x0060;
carry = (result > 0x00FF);
result = (Registers.A.W & 0x0F00) + (Work16 & 0x0F00) + (result & 0x00FF) + carry * 0x100;
if (result > 0x09FF)
result += 0x0600;
carry = (result > 0x0FFF);
2010-09-25 15:46:12 +00:00
2018-10-02 22:16:06 +00:00
result = (Registers.A.W & 0xF000) + (Work16 & 0xF000) + (result & 0x0FFF) + carry * 0x1000;
2010-09-25 15:46:12 +00:00
2018-10-02 22:16:06 +00:00
if ((Registers.A.W & 0x8000) == (Work16 & 0x8000) && (Registers.A.W & 0x8000) != (result & 0x8000))
2010-09-25 15:46:12 +00:00
SetOverflow();
else
ClearOverflow();
2018-10-02 22:16:06 +00:00
if (result > 0x9FFF)
result += 0x6000;
if (result > 0xFFFF)
SetCarry();
else
ClearCarry();
Registers.A.W = result & 0xFFFF;
2010-09-25 15:46:12 +00:00
SetZN(Registers.A.W);
}
else
{
uint32 Ans32 = Registers.A.W + Work16 + CheckCarry();
ICPU._Carry = Ans32 >= 0x10000;
if (~(Registers.A.W ^ Work16) & (Work16 ^ (uint16) Ans32) & 0x8000)
SetOverflow();
else
ClearOverflow();
Registers.A.W = (uint16) Ans32;
SetZN(Registers.A.W);
}
}
static inline void ADC (uint8 Work8)
{
if (CheckDecimal())
{
2018-10-02 22:16:06 +00:00
uint32 result;
uint32 carry = CheckCarry();
2010-09-25 15:46:12 +00:00
2018-10-02 22:16:06 +00:00
result = (Registers.AL & 0x0F) + (Work8 & 0x0F) + carry;
if ( result > 0x09 )
result += 0x06;
carry = (result > 0x0F);
2010-09-25 15:46:12 +00:00
2018-10-02 22:16:06 +00:00
result = (Registers.AL & 0xF0) + (Work8 & 0xF0) + (result & 0x0F) + (carry * 0x10);
if ((Registers.AL & 0x80) == (Work8 & 0x80) && (Registers.AL & 0x80) != (result & 0x80))
2010-09-25 15:46:12 +00:00
SetOverflow();
else
ClearOverflow();
2018-10-02 22:16:06 +00:00
if (result > 0x9F)
result += 0x60;
if (result > 0xFF)
SetCarry();
else
ClearCarry();
Registers.AL = result & 0xFF;
2010-09-25 15:46:12 +00:00
SetZN(Registers.AL);
}
else
{
uint16 Ans16 = Registers.AL + Work8 + CheckCarry();
ICPU._Carry = Ans16 >= 0x100;
if (~(Registers.AL ^ Work8) & (Work8 ^ (uint8) Ans16) & 0x80)
SetOverflow();
else
ClearOverflow();
Registers.AL = (uint8) Ans16;
SetZN(Registers.AL);
}
}
static inline void AND (uint16 Work16)
{
Registers.A.W &= Work16;
SetZN(Registers.A.W);
}
static inline void AND (uint8 Work8)
{
Registers.AL &= Work8;
SetZN(Registers.AL);
}
static inline void ASL16 (uint32 OpAddress, s9xwrap_t w)
{
uint16 Work16 = S9xGetWord(OpAddress, w);
ICPU._Carry = (Work16 & 0x8000) != 0;
Work16 <<= 1;
AddCycles(ONE_CYCLE);
S9xSetWord(Work16, OpAddress, w, WRITE_10);
OpenBus = Work16 & 0xff;
SetZN(Work16);
}
static inline void ASL8 (uint32 OpAddress)
{
uint8 Work8 = S9xGetByte(OpAddress);
ICPU._Carry = (Work8 & 0x80) != 0;
Work8 <<= 1;
AddCycles(ONE_CYCLE);
S9xSetByte(Work8, OpAddress);
OpenBus = Work8;
SetZN(Work8);
}
static inline void BIT (uint16 Work16)
{
ICPU._Overflow = (Work16 & 0x4000) != 0;
ICPU._Negative = (uint8) (Work16 >> 8);
ICPU._Zero = (Work16 & Registers.A.W) != 0;
}
static inline void BIT (uint8 Work8)
{
ICPU._Overflow = (Work8 & 0x40) != 0;
ICPU._Negative = Work8;
ICPU._Zero = Work8 & Registers.AL;
}
static inline void CMP (uint16 val)
{
int32 Int32 = (int32) Registers.A.W - (int32) val;
ICPU._Carry = Int32 >= 0;
SetZN((uint16) Int32);
}
static inline void CMP (uint8 val)
{
int16 Int16 = (int16) Registers.AL - (int16) val;
ICPU._Carry = Int16 >= 0;
SetZN((uint8) Int16);
}
static inline void CPX (uint16 val)
{
int32 Int32 = (int32) Registers.X.W - (int32) val;
ICPU._Carry = Int32 >= 0;
SetZN((uint16) Int32);
}
static inline void CPX (uint8 val)
{
int16 Int16 = (int16) Registers.XL - (int16) val;
ICPU._Carry = Int16 >= 0;
SetZN((uint8) Int16);
}
static inline void CPY (uint16 val)
{
int32 Int32 = (int32) Registers.Y.W - (int32) val;
ICPU._Carry = Int32 >= 0;
SetZN((uint16) Int32);
}
static inline void CPY (uint8 val)
{
int16 Int16 = (int16) Registers.YL - (int16) val;
ICPU._Carry = Int16 >= 0;
SetZN((uint8) Int16);
}
static inline void DEC16 (uint32 OpAddress, s9xwrap_t w)
{
uint16 Work16 = S9xGetWord(OpAddress, w) - 1;
AddCycles(ONE_CYCLE);
S9xSetWord(Work16, OpAddress, w, WRITE_10);
OpenBus = Work16 & 0xff;
SetZN(Work16);
}
static inline void DEC8 (uint32 OpAddress)
{
uint8 Work8 = S9xGetByte(OpAddress) - 1;
AddCycles(ONE_CYCLE);
S9xSetByte(Work8, OpAddress);
OpenBus = Work8;
SetZN(Work8);
}
static inline void EOR (uint16 val)
{
Registers.A.W ^= val;
SetZN(Registers.A.W);
}
static inline void EOR (uint8 val)
{
Registers.AL ^= val;
SetZN(Registers.AL);
}
static inline void INC16 (uint32 OpAddress, s9xwrap_t w)
{
uint16 Work16 = S9xGetWord(OpAddress, w) + 1;
AddCycles(ONE_CYCLE);
S9xSetWord(Work16, OpAddress, w, WRITE_10);
OpenBus = Work16 & 0xff;
SetZN(Work16);
}
static inline void INC8 (uint32 OpAddress)
{
uint8 Work8 = S9xGetByte(OpAddress) + 1;
AddCycles(ONE_CYCLE);
S9xSetByte(Work8, OpAddress);
OpenBus = Work8;
SetZN(Work8);
}
static inline void LDA (uint16 val)
{
Registers.A.W = val;
SetZN(Registers.A.W);
}
static inline void LDA (uint8 val)
{
Registers.AL = val;
SetZN(Registers.AL);
}
static inline void LDX (uint16 val)
{
Registers.X.W = val;
SetZN(Registers.X.W);
}
static inline void LDX (uint8 val)
{
Registers.XL = val;
SetZN(Registers.XL);
}
static inline void LDY (uint16 val)
{
Registers.Y.W = val;
SetZN(Registers.Y.W);
}
static inline void LDY (uint8 val)
{
Registers.YL = val;
SetZN(Registers.YL);
}
static inline void LSR16 (uint32 OpAddress, s9xwrap_t w)
{
uint16 Work16 = S9xGetWord(OpAddress, w);
ICPU._Carry = Work16 & 1;
Work16 >>= 1;
AddCycles(ONE_CYCLE);
S9xSetWord(Work16, OpAddress, w, WRITE_10);
OpenBus = Work16 & 0xff;
SetZN(Work16);
}
static inline void LSR8 (uint32 OpAddress)
{
uint8 Work8 = S9xGetByte(OpAddress);
ICPU._Carry = Work8 & 1;
Work8 >>= 1;
AddCycles(ONE_CYCLE);
S9xSetByte(Work8, OpAddress);
OpenBus = Work8;
SetZN(Work8);
}
static inline void ORA (uint16 val)
{
Registers.A.W |= val;
SetZN(Registers.A.W);
}
static inline void ORA (uint8 val)
{
Registers.AL |= val;
SetZN(Registers.AL);
}
static inline void ROL16 (uint32 OpAddress, s9xwrap_t w)
{
uint32 Work32 = (((uint32) S9xGetWord(OpAddress, w)) << 1) | CheckCarry();
ICPU._Carry = Work32 >= 0x10000;
AddCycles(ONE_CYCLE);
S9xSetWord((uint16) Work32, OpAddress, w, WRITE_10);
OpenBus = Work32 & 0xff;
SetZN((uint16) Work32);
}
static inline void ROL8 (uint32 OpAddress)
{
uint16 Work16 = (((uint16) S9xGetByte(OpAddress)) << 1) | CheckCarry();
ICPU._Carry = Work16 >= 0x100;
AddCycles(ONE_CYCLE);
S9xSetByte((uint8) Work16, OpAddress);
OpenBus = Work16 & 0xff;
SetZN((uint8) Work16);
}
static inline void ROR16 (uint32 OpAddress, s9xwrap_t w)
{
uint32 Work32 = ((uint32) S9xGetWord(OpAddress, w)) | (((uint32) CheckCarry()) << 16);
ICPU._Carry = Work32 & 1;
Work32 >>= 1;
AddCycles(ONE_CYCLE);
S9xSetWord((uint16) Work32, OpAddress, w, WRITE_10);
OpenBus = Work32 & 0xff;
SetZN((uint16) Work32);
}
static inline void ROR8 (uint32 OpAddress)
{
uint16 Work16 = ((uint16) S9xGetByte(OpAddress)) | (((uint16) CheckCarry()) << 8);
ICPU._Carry = Work16 & 1;
Work16 >>= 1;
AddCycles(ONE_CYCLE);
S9xSetByte((uint8) Work16, OpAddress);
OpenBus = Work16 & 0xff;
SetZN((uint8) Work16);
}
static inline void SBC (uint16 Work16)
{
if (CheckDecimal())
{
2018-10-02 22:16:06 +00:00
int result;
int carry = CheckCarry();
Work16 ^= 0xFFFF;
result = (Registers.A.W & 0x000F) + (Work16 & 0x000F) + carry;
if (result < 0x0010)
result -= 0x0006;
carry = (result > 0x000F);
result = (Registers.A.W & 0x00F0) + (Work16 & 0x00F0) + (result & 0x000F) + carry * 0x10;
if (result < 0x0100)
result -= 0x0060;
carry = (result > 0x00FF);
result = (Registers.A.W & 0x0F00) + (Work16 & 0x0F00) + (result & 0x00FF) + carry * 0x100;
if (result < 0x1000)
result -= 0x0600;
carry = (result > 0x0FFF);
2010-09-25 15:46:12 +00:00
2018-10-02 22:16:06 +00:00
result = (Registers.A.W & 0xF000) + (Work16 & 0xF000) + (result & 0x0FFF) + carry * 0x1000;
2010-09-25 15:46:12 +00:00
2018-10-02 22:16:06 +00:00
if (((Registers.A.W ^ Work16) & 0x8000) == 0 && ((Registers.A.W ^ result) & 0x8000))
2010-09-25 15:46:12 +00:00
SetOverflow();
else
ClearOverflow();
2018-10-02 22:16:06 +00:00
if (result < 0x10000)
result -= 0x6000;
if (result > 0xFFFF)
SetCarry();
else
ClearCarry();
Registers.A.W = result & 0xFFFF;
2010-09-25 15:46:12 +00:00
SetZN(Registers.A.W);
}
else
{
int32 Int32 = (int32) Registers.A.W - (int32) Work16 + (int32) CheckCarry() - 1;
ICPU._Carry = Int32 >= 0;
if ((Registers.A.W ^ Work16) & (Registers.A.W ^ (uint16) Int32) & 0x8000)
SetOverflow();
else
ClearOverflow();
Registers.A.W = (uint16) Int32;
SetZN(Registers.A.W);
}
}
static inline void SBC (uint8 Work8)
{
if (CheckDecimal())
{
2018-10-02 22:16:06 +00:00
int result;
int carry = CheckCarry();
Work8 ^= 0xFF;
result = (Registers.AL & 0x0F) + (Work8 & 0x0F) + carry;
if (result < 0x10)
result -= 0x06;
carry = (result > 0x0F);
2010-09-25 15:46:12 +00:00
2018-10-02 22:16:06 +00:00
result = (Registers.AL & 0xF0) + (Work8 & 0xF0) + (result & 0x0F) + carry * 0x10;
2010-09-25 15:46:12 +00:00
2018-10-02 22:16:06 +00:00
if ((Registers.AL & 0x80) == (Work8 & 0x80) && (Registers.AL & 0x80) != (result & 0x80))
2010-09-25 15:46:12 +00:00
SetOverflow();
else
ClearOverflow();
2018-10-02 22:16:06 +00:00
if (result < 0x100 )
result -= 0x60;
if (result > 0xFF)
SetCarry();
else
ClearCarry();
Registers.AL = result & 0xFF;
2010-09-25 15:46:12 +00:00
SetZN(Registers.AL);
}
else
{
int16 Int16 = (int16) Registers.AL - (int16) Work8 + (int16) CheckCarry() - 1;
ICPU._Carry = Int16 >= 0;
if ((Registers.AL ^ Work8) & (Registers.AL ^ (uint8) Int16) & 0x80)
SetOverflow();
else
ClearOverflow();
Registers.AL = (uint8) Int16;
SetZN(Registers.AL);
}
}
static inline void STA16 (uint32 OpAddress, enum s9xwrap_t w)
{
S9xSetWord(Registers.A.W, OpAddress, w);
OpenBus = Registers.AH;
}
static inline void STA8 (uint32 OpAddress)
{
S9xSetByte(Registers.AL, OpAddress);
OpenBus = Registers.AL;
}
static inline void STX16 (uint32 OpAddress, enum s9xwrap_t w)
{
S9xSetWord(Registers.X.W, OpAddress, w);
OpenBus = Registers.XH;
}
static inline void STX8 (uint32 OpAddress)
{
S9xSetByte(Registers.XL, OpAddress);
OpenBus = Registers.XL;
}
static inline void STY16 (uint32 OpAddress, enum s9xwrap_t w)
{
S9xSetWord(Registers.Y.W, OpAddress, w);
OpenBus = Registers.YH;
}
static inline void STY8 (uint32 OpAddress)
{
S9xSetByte(Registers.YL, OpAddress);
OpenBus = Registers.YL;
}
static inline void STZ16 (uint32 OpAddress, enum s9xwrap_t w)
{
S9xSetWord(0, OpAddress, w);
OpenBus = 0;
}
static inline void STZ8 (uint32 OpAddress)
{
S9xSetByte(0, OpAddress);
OpenBus = 0;
}
static inline void TSB16 (uint32 OpAddress, enum s9xwrap_t w)
{
uint16 Work16 = S9xGetWord(OpAddress, w);
ICPU._Zero = (Work16 & Registers.A.W) != 0;
Work16 |= Registers.A.W;
AddCycles(ONE_CYCLE);
S9xSetWord(Work16, OpAddress, w, WRITE_10);
OpenBus = Work16 & 0xff;
}
static inline void TSB8 (uint32 OpAddress)
{
uint8 Work8 = S9xGetByte(OpAddress);
ICPU._Zero = Work8 & Registers.AL;
Work8 |= Registers.AL;
AddCycles(ONE_CYCLE);
S9xSetByte(Work8, OpAddress);
OpenBus = Work8;
}
static inline void TRB16 (uint32 OpAddress, enum s9xwrap_t w)
{
uint16 Work16 = S9xGetWord(OpAddress, w);
ICPU._Zero = (Work16 & Registers.A.W) != 0;
Work16 &= ~Registers.A.W;
AddCycles(ONE_CYCLE);
S9xSetWord(Work16, OpAddress, w, WRITE_10);
OpenBus = Work16 & 0xff;
}
static inline void TRB8 (uint32 OpAddress)
{
uint8 Work8 = S9xGetByte(OpAddress);
ICPU._Zero = Work8 & Registers.AL;
Work8 &= ~Registers.AL;
AddCycles(ONE_CYCLE);
S9xSetByte(Work8, OpAddress);
OpenBus = Work8;
}
#endif