mirror of
https://github.com/libretro/snes9x.git
synced 2024-12-04 23:26:22 +00:00
5f56cadafb
This points to the full license in the root directory.
522 lines
11 KiB
C
522 lines
11 KiB
C
/*****************************************************************************\
|
|
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.
|
|
\*****************************************************************************/
|
|
|
|
#ifndef _CPUADDR_H_
|
|
#define _CPUADDR_H_
|
|
|
|
typedef enum
|
|
{
|
|
NONE = 0,
|
|
READ = 1,
|
|
WRITE = 2,
|
|
MODIFY = 3,
|
|
JUMP = 5,
|
|
JSR = 8
|
|
} AccessMode;
|
|
|
|
static inline uint8 Immediate8Slow (AccessMode a)
|
|
{
|
|
uint8 val = S9xGetByte(Registers.PBPC);
|
|
if (a & READ)
|
|
OpenBus = val;
|
|
Registers.PCw++;
|
|
|
|
return (val);
|
|
}
|
|
|
|
static inline uint8 Immediate8 (AccessMode a)
|
|
{
|
|
uint8 val = CPU.PCBase[Registers.PCw];
|
|
if (a & READ)
|
|
OpenBus = val;
|
|
AddCycles(CPU.MemSpeed);
|
|
Registers.PCw++;
|
|
|
|
return (val);
|
|
}
|
|
|
|
static inline uint16 Immediate16Slow (AccessMode a)
|
|
{
|
|
uint16 val = S9xGetWord(Registers.PBPC, WRAP_BANK);
|
|
if (a & READ)
|
|
OpenBus = (uint8) (val >> 8);
|
|
Registers.PCw += 2;
|
|
|
|
return (val);
|
|
}
|
|
|
|
static inline uint16 Immediate16 (AccessMode a)
|
|
{
|
|
uint16 val = READ_WORD(CPU.PCBase + Registers.PCw);
|
|
if (a & READ)
|
|
OpenBus = (uint8) (val >> 8);
|
|
AddCycles(CPU.MemSpeedx2);
|
|
Registers.PCw += 2;
|
|
|
|
return (val);
|
|
}
|
|
|
|
static inline uint32 RelativeSlow (AccessMode a) // branch $xx
|
|
{
|
|
int8 offset = Immediate8Slow(a);
|
|
|
|
return ((int16) Registers.PCw + offset) & 0xffff;
|
|
}
|
|
|
|
static inline uint32 Relative (AccessMode a) // branch $xx
|
|
{
|
|
int8 offset = Immediate8(a);
|
|
|
|
return ((int16) Registers.PCw + offset) & 0xffff;
|
|
}
|
|
|
|
static inline uint32 RelativeLongSlow (AccessMode a) // BRL $xxxx
|
|
{
|
|
int16 offset = Immediate16Slow(a);
|
|
|
|
return ((int32) Registers.PCw + offset) & 0xffff;
|
|
}
|
|
|
|
static inline uint32 RelativeLong (AccessMode a) // BRL $xxxx
|
|
{
|
|
int16 offset = Immediate16(a);
|
|
|
|
return ((int32) Registers.PCw + offset) & 0xffff;
|
|
}
|
|
|
|
static inline uint32 AbsoluteIndexedIndirectSlow (AccessMode a) // (a,X)
|
|
{
|
|
uint16 addr;
|
|
|
|
if (a & JSR)
|
|
{
|
|
// JSR (a,X) pushes the old address in the middle of loading the new.
|
|
// OpenBus needs to be set to account for this.
|
|
addr = Immediate8Slow(READ);
|
|
if (a == JSR)
|
|
OpenBus = Registers.PCl;
|
|
addr |= Immediate8Slow(READ) << 8;
|
|
}
|
|
else
|
|
addr = Immediate16Slow(READ);
|
|
|
|
AddCycles(ONE_CYCLE);
|
|
addr += Registers.X.W;
|
|
|
|
// Address load wraps within the bank
|
|
uint16 addr2 = S9xGetWord(ICPU.ShiftedPB | addr, WRAP_BANK);
|
|
OpenBus = addr2 >> 8;
|
|
|
|
return (addr2);
|
|
}
|
|
|
|
static inline uint32 AbsoluteIndexedIndirect (AccessMode a) // (a,X)
|
|
{
|
|
uint16 addr = Immediate16Slow(READ);
|
|
|
|
AddCycles(ONE_CYCLE);
|
|
addr += Registers.X.W;
|
|
|
|
// Address load wraps within the bank
|
|
uint16 addr2 = S9xGetWord(ICPU.ShiftedPB | addr, WRAP_BANK);
|
|
OpenBus = addr2 >> 8;
|
|
|
|
return (addr2);
|
|
}
|
|
|
|
static inline uint32 AbsoluteIndirectLongSlow (AccessMode a) // [a]
|
|
{
|
|
uint16 addr = Immediate16Slow(READ);
|
|
|
|
// No info on wrapping, but it doesn't matter anyway due to mirroring
|
|
uint32 addr2 = S9xGetWord(addr);
|
|
OpenBus = addr2 >> 8;
|
|
addr2 |= (OpenBus = S9xGetByte(addr + 2)) << 16;
|
|
|
|
return (addr2);
|
|
}
|
|
|
|
static inline uint32 AbsoluteIndirectLong (AccessMode a) // [a]
|
|
{
|
|
uint16 addr = Immediate16(READ);
|
|
|
|
// No info on wrapping, but it doesn't matter anyway due to mirroring
|
|
uint32 addr2 = S9xGetWord(addr);
|
|
OpenBus = addr2 >> 8;
|
|
addr2 |= (OpenBus = S9xGetByte(addr + 2)) << 16;
|
|
|
|
return (addr2);
|
|
}
|
|
|
|
static inline uint32 AbsoluteIndirectSlow (AccessMode a) // (a)
|
|
{
|
|
// No info on wrapping, but it doesn't matter anyway due to mirroring
|
|
uint16 addr2 = S9xGetWord(Immediate16Slow(READ));
|
|
OpenBus = addr2 >> 8;
|
|
|
|
return (addr2);
|
|
}
|
|
|
|
static inline uint32 AbsoluteIndirect (AccessMode a) // (a)
|
|
{
|
|
// No info on wrapping, but it doesn't matter anyway due to mirroring
|
|
uint16 addr2 = S9xGetWord(Immediate16(READ));
|
|
OpenBus = addr2 >> 8;
|
|
|
|
return (addr2);
|
|
}
|
|
|
|
static inline uint32 AbsoluteSlow (AccessMode a) // a
|
|
{
|
|
return (ICPU.ShiftedDB | Immediate16Slow(a));
|
|
}
|
|
|
|
static inline uint32 Absolute (AccessMode a) // a
|
|
{
|
|
return (ICPU.ShiftedDB | Immediate16(a));
|
|
}
|
|
|
|
static inline uint32 AbsoluteLongSlow (AccessMode a) // l
|
|
{
|
|
uint32 addr = Immediate16Slow(READ);
|
|
|
|
// JSR l pushes the old bank in the middle of loading the new.
|
|
// OpenBus needs to be set to account for this.
|
|
if (a == JSR)
|
|
OpenBus = Registers.PB;
|
|
|
|
addr |= Immediate8Slow(a) << 16;
|
|
|
|
return (addr);
|
|
}
|
|
|
|
static inline uint32 AbsoluteLong (AccessMode a) // l
|
|
{
|
|
uint32 addr = READ_3WORD(CPU.PCBase + Registers.PCw);
|
|
AddCycles(CPU.MemSpeedx2 + CPU.MemSpeed);
|
|
if (a & READ)
|
|
OpenBus = addr >> 16;
|
|
Registers.PCw += 3;
|
|
|
|
return (addr);
|
|
}
|
|
|
|
static inline uint32 DirectSlow (AccessMode a) // d
|
|
{
|
|
uint16 addr = Immediate8Slow(a) + Registers.D.W;
|
|
if (Registers.DL != 0)
|
|
AddCycles(ONE_CYCLE);
|
|
|
|
return (addr);
|
|
}
|
|
|
|
static inline uint32 Direct (AccessMode a) // d
|
|
{
|
|
uint16 addr = Immediate8(a) + Registers.D.W;
|
|
if (Registers.DL != 0)
|
|
AddCycles(ONE_CYCLE);
|
|
|
|
return (addr);
|
|
}
|
|
|
|
static inline uint32 DirectIndirectSlow (AccessMode a) // (d)
|
|
{
|
|
uint32 addr = S9xGetWord(DirectSlow(READ), (!CheckEmulation() || Registers.DL) ? WRAP_BANK : WRAP_PAGE);
|
|
if (a & READ)
|
|
OpenBus = (uint8) (addr >> 8);
|
|
addr |= ICPU.ShiftedDB;
|
|
|
|
return (addr);
|
|
}
|
|
|
|
static inline uint32 DirectIndirectE0 (AccessMode a) // (d)
|
|
{
|
|
uint32 addr = S9xGetWord(Direct(READ));
|
|
if (a & READ)
|
|
OpenBus = (uint8) (addr >> 8);
|
|
addr |= ICPU.ShiftedDB;
|
|
|
|
return (addr);
|
|
}
|
|
|
|
static inline uint32 DirectIndirectE1 (AccessMode a) // (d)
|
|
{
|
|
uint32 addr = S9xGetWord(DirectSlow(READ), Registers.DL ? WRAP_BANK : WRAP_PAGE);
|
|
if (a & READ)
|
|
OpenBus = (uint8) (addr >> 8);
|
|
addr |= ICPU.ShiftedDB;
|
|
|
|
return (addr);
|
|
}
|
|
|
|
static inline uint32 DirectIndirectIndexedSlow (AccessMode a) // (d),Y
|
|
{
|
|
uint32 addr = DirectIndirectSlow(a);
|
|
if (a & WRITE || !CheckIndex() || (addr & 0xff) + Registers.YL >= 0x100)
|
|
AddCycles(ONE_CYCLE);
|
|
|
|
return (addr + Registers.Y.W);
|
|
}
|
|
|
|
static inline uint32 DirectIndirectIndexedE0X0 (AccessMode a) // (d),Y
|
|
{
|
|
uint32 addr = DirectIndirectE0(a);
|
|
AddCycles(ONE_CYCLE);
|
|
|
|
return (addr + Registers.Y.W);
|
|
}
|
|
|
|
static inline uint32 DirectIndirectIndexedE0X1 (AccessMode a) // (d),Y
|
|
{
|
|
uint32 addr = DirectIndirectE0(a);
|
|
if (a & WRITE || (addr & 0xff) + Registers.YL >= 0x100)
|
|
AddCycles(ONE_CYCLE);
|
|
|
|
return (addr + Registers.Y.W);
|
|
}
|
|
|
|
static inline uint32 DirectIndirectIndexedE1 (AccessMode a) // (d),Y
|
|
{
|
|
uint32 addr = DirectIndirectE1(a);
|
|
if (a & WRITE || (addr & 0xff) + Registers.YL >= 0x100)
|
|
AddCycles(ONE_CYCLE);
|
|
|
|
return (addr + Registers.Y.W);
|
|
}
|
|
|
|
static inline uint32 DirectIndirectLongSlow (AccessMode a) // [d]
|
|
{
|
|
uint16 addr = DirectSlow(READ);
|
|
uint32 addr2 = S9xGetWord(addr);
|
|
OpenBus = addr2 >> 8;
|
|
addr2 |= (OpenBus = S9xGetByte(addr + 2)) << 16;
|
|
|
|
return (addr2);
|
|
}
|
|
|
|
static inline uint32 DirectIndirectLong (AccessMode a) // [d]
|
|
{
|
|
uint16 addr = Direct(READ);
|
|
uint32 addr2 = S9xGetWord(addr);
|
|
OpenBus = addr2 >> 8;
|
|
addr2 |= (OpenBus = S9xGetByte(addr + 2)) << 16;
|
|
|
|
return (addr2);
|
|
}
|
|
|
|
static inline uint32 DirectIndirectIndexedLongSlow (AccessMode a) // [d],Y
|
|
{
|
|
return (DirectIndirectLongSlow(a) + Registers.Y.W);
|
|
}
|
|
|
|
static inline uint32 DirectIndirectIndexedLong (AccessMode a) // [d],Y
|
|
{
|
|
return (DirectIndirectLong(a) + Registers.Y.W);
|
|
}
|
|
|
|
static inline uint32 DirectIndexedXSlow (AccessMode a) // d,X
|
|
{
|
|
pair addr;
|
|
addr.W = DirectSlow(a);
|
|
if (!CheckEmulation() || Registers.DL)
|
|
addr.W += Registers.X.W;
|
|
else
|
|
addr.B.l += Registers.XL;
|
|
|
|
AddCycles(ONE_CYCLE);
|
|
|
|
return (addr.W);
|
|
}
|
|
|
|
static inline uint32 DirectIndexedXE0 (AccessMode a) // d,X
|
|
{
|
|
uint16 addr = Direct(a) + Registers.X.W;
|
|
AddCycles(ONE_CYCLE);
|
|
|
|
return (addr);
|
|
}
|
|
|
|
static inline uint32 DirectIndexedXE1 (AccessMode a) // d,X
|
|
{
|
|
if (Registers.DL)
|
|
return (DirectIndexedXE0(a));
|
|
else
|
|
{
|
|
pair addr;
|
|
addr.W = Direct(a);
|
|
addr.B.l += Registers.XL;
|
|
AddCycles(ONE_CYCLE);
|
|
|
|
return (addr.W);
|
|
}
|
|
}
|
|
|
|
static inline uint32 DirectIndexedYSlow (AccessMode a) // d,Y
|
|
{
|
|
pair addr;
|
|
addr.W = DirectSlow(a);
|
|
if (!CheckEmulation() || Registers.DL)
|
|
addr.W += Registers.Y.W;
|
|
else
|
|
addr.B.l += Registers.YL;
|
|
|
|
AddCycles(ONE_CYCLE);
|
|
|
|
return (addr.W);
|
|
}
|
|
|
|
static inline uint32 DirectIndexedYE0 (AccessMode a) // d,Y
|
|
{
|
|
uint16 addr = Direct(a) + Registers.Y.W;
|
|
AddCycles(ONE_CYCLE);
|
|
|
|
return (addr);
|
|
}
|
|
|
|
static inline uint32 DirectIndexedYE1 (AccessMode a) // d,Y
|
|
{
|
|
if (Registers.DL)
|
|
return (DirectIndexedYE0(a));
|
|
else
|
|
{
|
|
pair addr;
|
|
addr.W = Direct(a);
|
|
addr.B.l += Registers.YL;
|
|
AddCycles(ONE_CYCLE);
|
|
|
|
return (addr.W);
|
|
}
|
|
}
|
|
|
|
static inline uint32 DirectIndexedIndirectSlow (AccessMode a) // (d,X)
|
|
{
|
|
uint32 addr = S9xGetWord(DirectIndexedXSlow(READ), (!CheckEmulation() || Registers.DL) ? WRAP_BANK : WRAP_PAGE);
|
|
if (a & READ)
|
|
OpenBus = (uint8) (addr >> 8);
|
|
|
|
return (ICPU.ShiftedDB | addr);
|
|
}
|
|
|
|
static inline uint32 DirectIndexedIndirectE0 (AccessMode a) // (d,X)
|
|
{
|
|
uint32 addr = S9xGetWord(DirectIndexedXE0(READ));
|
|
if (a & READ)
|
|
OpenBus = (uint8) (addr >> 8);
|
|
|
|
return (ICPU.ShiftedDB | addr);
|
|
}
|
|
|
|
static inline uint32 DirectIndexedIndirectE1 (AccessMode a) // (d,X)
|
|
{
|
|
uint32 addr = S9xGetWord(DirectIndexedXE1(READ), Registers.DL ? WRAP_BANK : WRAP_PAGE);
|
|
if (a & READ)
|
|
OpenBus = (uint8) (addr >> 8);
|
|
|
|
return (ICPU.ShiftedDB | addr);
|
|
}
|
|
|
|
static inline uint32 AbsoluteIndexedXSlow (AccessMode a) // a,X
|
|
{
|
|
uint32 addr = AbsoluteSlow(a);
|
|
if (a & WRITE || !CheckIndex() || (addr & 0xff) + Registers.XL >= 0x100)
|
|
AddCycles(ONE_CYCLE);
|
|
|
|
return (addr + Registers.X.W);
|
|
}
|
|
|
|
static inline uint32 AbsoluteIndexedXX0 (AccessMode a) // a,X
|
|
{
|
|
uint32 addr = Absolute(a);
|
|
AddCycles(ONE_CYCLE);
|
|
|
|
return (addr + Registers.X.W);
|
|
}
|
|
|
|
static inline uint32 AbsoluteIndexedXX1 (AccessMode a) // a,X
|
|
{
|
|
uint32 addr = Absolute(a);
|
|
if (a & WRITE || (addr & 0xff) + Registers.XL >= 0x100)
|
|
AddCycles(ONE_CYCLE);
|
|
|
|
return (addr + Registers.X.W);
|
|
}
|
|
|
|
static inline uint32 AbsoluteIndexedYSlow (AccessMode a) // a,Y
|
|
{
|
|
uint32 addr = AbsoluteSlow(a);
|
|
if (a & WRITE || !CheckIndex() || (addr & 0xff) + Registers.YL >= 0x100)
|
|
AddCycles(ONE_CYCLE);
|
|
|
|
return (addr + Registers.Y.W);
|
|
}
|
|
|
|
static inline uint32 AbsoluteIndexedYX0 (AccessMode a) // a,Y
|
|
{
|
|
uint32 addr = Absolute(a);
|
|
AddCycles(ONE_CYCLE);
|
|
|
|
return (addr + Registers.Y.W);
|
|
}
|
|
|
|
static inline uint32 AbsoluteIndexedYX1 (AccessMode a) // a,Y
|
|
{
|
|
uint32 addr = Absolute(a);
|
|
if (a & WRITE || (addr & 0xff) + Registers.YL >= 0x100)
|
|
AddCycles(ONE_CYCLE);
|
|
|
|
return (addr + Registers.Y.W);
|
|
}
|
|
|
|
static inline uint32 AbsoluteLongIndexedXSlow (AccessMode a) // l,X
|
|
{
|
|
return (AbsoluteLongSlow(a) + Registers.X.W);
|
|
}
|
|
|
|
static inline uint32 AbsoluteLongIndexedX (AccessMode a) // l,X
|
|
{
|
|
return (AbsoluteLong(a) + Registers.X.W);
|
|
}
|
|
|
|
static inline uint32 StackRelativeSlow (AccessMode a) // d,S
|
|
{
|
|
uint16 addr = Immediate8Slow(a) + Registers.S.W;
|
|
AddCycles(ONE_CYCLE);
|
|
|
|
return (addr);
|
|
}
|
|
|
|
static inline uint32 StackRelative (AccessMode a) // d,S
|
|
{
|
|
uint16 addr = Immediate8(a) + Registers.S.W;
|
|
AddCycles(ONE_CYCLE);
|
|
|
|
return (addr);
|
|
}
|
|
|
|
static inline uint32 StackRelativeIndirectIndexedSlow (AccessMode a) // (d,S),Y
|
|
{
|
|
uint32 addr = S9xGetWord(StackRelativeSlow(READ));
|
|
if (a & READ)
|
|
OpenBus = (uint8) (addr >> 8);
|
|
addr = (addr + Registers.Y.W + ICPU.ShiftedDB) & 0xffffff;
|
|
AddCycles(ONE_CYCLE);
|
|
|
|
return (addr);
|
|
}
|
|
|
|
static inline uint32 StackRelativeIndirectIndexed (AccessMode a) // (d,S),Y
|
|
{
|
|
uint32 addr = S9xGetWord(StackRelative(READ));
|
|
if (a & READ)
|
|
OpenBus = (uint8) (addr >> 8);
|
|
addr = (addr + Registers.Y.W + ICPU.ShiftedDB) & 0xffffff;
|
|
AddCycles(ONE_CYCLE);
|
|
|
|
return (addr);
|
|
}
|
|
|
|
#endif
|