/*****************************************************************************\ 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. \*****************************************************************************/ #pragma once enum AccessMode { NONE = 0, READ = 1, WRITE = 2, MODIFY = 3, JUMP = 5, JSR = 8 }; inline uint8_t Immediate8Slow(AccessMode a) { uint8_t val = S9xGetByte(Registers.PC.xPBPC); if (a & READ) OpenBus = val; ++Registers.PC.W.xPC; return val; } inline uint8_t Immediate8(AccessMode a) { uint8_t val = CPU.PCBase[Registers.PC.W.xPC]; if (a & READ) OpenBus = val; AddCycles(CPU.MemSpeed); ++Registers.PC.W.xPC; return val; } inline uint16_t Immediate16Slow(AccessMode a) { uint16_t val = S9xGetWord(Registers.PC.xPBPC, WRAP_BANK); if (a & READ) OpenBus = static_cast(val >> 8); Registers.PC.W.xPC += 2; return val; } inline uint16_t Immediate16(AccessMode a) { uint16_t val = READ_WORD(CPU.PCBase + Registers.PC.W.xPC); if (a & READ) OpenBus = static_cast(val >> 8); AddCycles(CPU.MemSpeedx2); Registers.PC.W.xPC += 2; return val; } inline uint32_t RelativeSlow(AccessMode a) // branch $xx { int8_t offset = Immediate8Slow(a); return (static_cast(Registers.PC.W.xPC) + offset) & 0xffff; } inline uint32_t Relative(AccessMode a) // branch $xx { int8_t offset = Immediate8(a); return (static_cast(Registers.PC.W.xPC) + offset) & 0xffff; } inline uint32_t RelativeLongSlow(AccessMode a) // BRL $xxxx { int16_t offset = Immediate16Slow(a); return (static_cast(Registers.PC.W.xPC) + offset) & 0xffff; } inline uint32_t RelativeLong(AccessMode a) // BRL $xxxx { int16_t offset = Immediate16(a); return (static_cast(Registers.PC.W.xPC) + offset) & 0xffff; } inline uint32_t AbsoluteIndexedIndirectSlow(AccessMode a) // (a,X) { uint16_t 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.PC.B.xPCl; addr |= Immediate8Slow(READ) << 8; } else addr = Immediate16Slow(READ); AddCycles(ONE_CYCLE); addr += Registers.X.W; // Address load wraps within the bank uint16_t addr2 = S9xGetWord(ICPU.ShiftedPB | addr, WRAP_BANK); OpenBus = addr2 >> 8; return addr2; } inline uint32_t AbsoluteIndexedIndirect(AccessMode) // (a,X) { uint16_t addr = Immediate16Slow(READ); AddCycles(ONE_CYCLE); addr += Registers.X.W; // Address load wraps within the bank uint16_t addr2 = S9xGetWord(ICPU.ShiftedPB | addr, WRAP_BANK); OpenBus = addr2 >> 8; return addr2; } template inline uint32_t AbsoluteIndirectLongWrapper(F f, AccessMode) { uint16_t addr = f(READ); // No info on wrapping, but it doesn't matter anyway due to mirroring uint32_t addr2 = S9xGetWord(addr); OpenBus = addr2 >> 8; addr2 |= (OpenBus = S9xGetByte(addr + 2)) << 16; return addr2; } inline uint32_t AbsoluteIndirectLongSlow(AccessMode a) // [a] { return AbsoluteIndirectLongWrapper(Immediate16Slow, a); } inline uint32_t AbsoluteIndirectLong(AccessMode a) // [a] { return AbsoluteIndirectLongWrapper(Immediate16, a); } template inline uint32_t AbsoluteIndirectWrapper(F f, AccessMode) { // No info on wrapping, but it doesn't matter anyway due to mirroring uint16_t addr2 = S9xGetWord(f(READ)); OpenBus = addr2 >> 8; return addr2; } inline uint32_t AbsoluteIndirectSlow(AccessMode a) // (a) { return AbsoluteIndirectWrapper(Immediate16Slow, a); } inline uint32_t AbsoluteIndirect(AccessMode a) // (a) { return AbsoluteIndirectWrapper(Immediate16, a); } template inline uint32_t AbsoluteWrapper(F f, AccessMode a) { return ICPU.ShiftedDB | f(a); } inline uint32_t AbsoluteSlow(AccessMode a) // a { return AbsoluteWrapper(Immediate16Slow, a); } inline uint32_t Absolute(AccessMode a) // a { return AbsoluteWrapper(Immediate16, a); } inline uint32_t AbsoluteLongSlow(AccessMode a) // l { uint32_t 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.PC.B.xPB; addr |= Immediate8Slow(a) << 16; return addr; } inline uint32_t AbsoluteLong(AccessMode a) // l { uint32_t addr = READ_3WORD(CPU.PCBase + Registers.PC.W.xPC); AddCycles(CPU.MemSpeedx2 + CPU.MemSpeed); if (a & READ) OpenBus = addr >> 16; Registers.PC.W.xPC += 3; return addr; } template inline uint32_t DirectWrapper(F f, AccessMode a) { uint16_t addr = f(a) + Registers.D.W; if (Registers.D.B.l) AddCycles(ONE_CYCLE); return addr; } inline uint32_t DirectSlow(AccessMode a) // d { return DirectWrapper(Immediate8Slow, a); } inline uint32_t Direct(AccessMode a) // d { return DirectWrapper(Immediate8, a); } inline uint32_t DirectIndirectSlow(AccessMode a) // (d) { uint32_t addr = S9xGetWord(DirectSlow(READ), !CheckEmulation() || Registers.D.B.l ? WRAP_BANK : WRAP_PAGE); if (a & READ) OpenBus = static_cast(addr >> 8); addr |= ICPU.ShiftedDB; return addr; } inline uint32_t DirectIndirectE0(AccessMode a) // (d) { uint32_t addr = S9xGetWord(Direct(READ)); if (a & READ) OpenBus = static_cast(addr >> 8); addr |= ICPU.ShiftedDB; return addr; } inline uint32_t DirectIndirectE1(AccessMode a) // (d) { uint32_t addr = S9xGetWord(DirectSlow(READ), Registers.D.B.l ? WRAP_BANK : WRAP_PAGE); if (a & READ) OpenBus = static_cast(addr >> 8); addr |= ICPU.ShiftedDB; return addr; } inline uint32_t DirectIndirectIndexedSlow(AccessMode a) // (d),Y { uint32_t addr = DirectIndirectSlow(a); if ((a & WRITE) || !CheckIndex() || (addr & 0xff) + Registers.Y.B.l >= 0x100) AddCycles(ONE_CYCLE); return addr + Registers.Y.W; } inline uint32_t DirectIndirectIndexedE0X0(AccessMode a) // (d),Y { uint32_t addr = DirectIndirectE0(a); AddCycles(ONE_CYCLE); return addr + Registers.Y.W; } inline uint32_t DirectIndirectIndexedE0X1(AccessMode a) // (d),Y { uint32_t addr = DirectIndirectE0(a); if ((a & WRITE) || (addr & 0xff) + Registers.Y.B.l >= 0x100) AddCycles(ONE_CYCLE); return addr + Registers.Y.W; } inline uint32_t DirectIndirectIndexedE1(AccessMode a) // (d),Y { uint32_t addr = DirectIndirectE1(a); if ((a & WRITE) || (addr & 0xff) + Registers.Y.B.l >= 0x100) AddCycles(ONE_CYCLE); return addr + Registers.Y.W; } template inline uint32_t DirectIndirectLongWrapper(F f, AccessMode) { uint16_t addr = f(READ); uint32_t addr2 = S9xGetWord(addr); OpenBus = addr2 >> 8; addr2 |= (OpenBus = S9xGetByte(addr + 2)) << 16; return addr2; } inline uint32_t DirectIndirectLongSlow(AccessMode a) // [d] { return DirectIndirectLongWrapper(DirectSlow, a); } inline uint32_t DirectIndirectLong(AccessMode a) // [d] { return DirectIndirectLongWrapper(Direct, a); } template inline uint32_t DirectIndirectIndexedLongWrapper(F f, AccessMode a) { return f(a) + Registers.Y.W; } inline uint32_t DirectIndirectIndexedLongSlow(AccessMode a) // [d],Y { return DirectIndirectIndexedLongWrapper(DirectIndirectLongSlow, a); } inline uint32_t DirectIndirectIndexedLong(AccessMode a) // [d],Y { return DirectIndirectIndexedLongWrapper(DirectIndirectLong, a); } inline uint32_t DirectIndexedXSlow(AccessMode a) // d,X { pair addr; addr.W = DirectSlow(a); if (!CheckEmulation() || Registers.D.B.l) addr.W += Registers.X.W; else addr.B.l += Registers.X.B.l; AddCycles(ONE_CYCLE); return addr.W; } inline uint32_t DirectIndexedXE0(AccessMode a) // d,X { uint16_t addr = Direct(a) + Registers.X.W; AddCycles(ONE_CYCLE); return addr; } inline uint32_t DirectIndexedXE1(AccessMode a) // d,X { if (Registers.D.B.l) return DirectIndexedXE0(a); else { pair addr; addr.W = Direct(a); addr.B.l += Registers.X.B.l; AddCycles(ONE_CYCLE); return addr.W; } } inline uint32_t DirectIndexedYSlow(AccessMode a) // d,Y { pair addr; addr.W = DirectSlow(a); if (!CheckEmulation() || Registers.D.B.l) addr.W += Registers.Y.W; else addr.B.l += Registers.Y.B.l; AddCycles(ONE_CYCLE); return addr.W; } inline uint32_t DirectIndexedYE0(AccessMode a) // d,Y { uint16_t addr = Direct(a) + Registers.Y.W; AddCycles(ONE_CYCLE); return addr; } inline uint32_t DirectIndexedYE1(AccessMode a) // d,Y { if (Registers.D.B.l) return DirectIndexedYE0(a); else { pair addr; addr.W = Direct(a); addr.B.l += Registers.Y.B.l; AddCycles(ONE_CYCLE); return addr.W; } } inline uint32_t DirectIndexedIndirectSlow(AccessMode a) // (d,X) { uint32_t addr = S9xGetWord(DirectIndexedXSlow(READ), !CheckEmulation() || Registers.D.B.l ? WRAP_BANK : WRAP_PAGE); if (a & READ) OpenBus = static_cast(addr >> 8); return ICPU.ShiftedDB | addr; } inline uint32_t DirectIndexedIndirectE0(AccessMode a) // (d,X) { uint32_t addr = S9xGetWord(DirectIndexedXE0(READ)); if (a & READ) OpenBus = static_cast(addr >> 8); return ICPU.ShiftedDB | addr; } inline uint32_t DirectIndexedIndirectE1(AccessMode a) // (d,X) { uint32_t addr = S9xGetWord(DirectIndexedXE1(READ), Registers.D.B.l ? WRAP_BANK : WRAP_PAGE); if (a & READ) OpenBus = static_cast(addr >> 8); return ICPU.ShiftedDB | addr; } inline uint32_t AbsoluteIndexedXSlow(AccessMode a) // a,X { uint32_t addr = AbsoluteSlow(a); if ((a & WRITE) || !CheckIndex() || (addr & 0xff) + Registers.X.B.l >= 0x100) AddCycles(ONE_CYCLE); return addr + Registers.X.W; } inline uint32_t AbsoluteIndexedXX0(AccessMode a) // a,X { uint32_t addr = Absolute(a); AddCycles(ONE_CYCLE); return addr + Registers.X.W; } inline uint32_t AbsoluteIndexedXX1(AccessMode a) // a,X { uint32_t addr = Absolute(a); if ((a & WRITE) || (addr & 0xff) + Registers.X.B.l >= 0x100) AddCycles(ONE_CYCLE); return addr + Registers.X.W; } inline uint32_t AbsoluteIndexedYSlow(AccessMode a) // a,Y { uint32_t addr = AbsoluteSlow(a); if ((a & WRITE) || !CheckIndex() || (addr & 0xff) + Registers.Y.B.l >= 0x100) AddCycles(ONE_CYCLE); return addr + Registers.Y.W; } inline uint32_t AbsoluteIndexedYX0(AccessMode a) // a,Y { uint32_t addr = Absolute(a); AddCycles(ONE_CYCLE); return addr + Registers.Y.W; } inline uint32_t AbsoluteIndexedYX1(AccessMode a) // a,Y { uint32_t addr = Absolute(a); if ((a & WRITE) || (addr & 0xff) + Registers.Y.B.l >= 0x100) AddCycles(ONE_CYCLE); return addr + Registers.Y.W; } template inline uint32_t AbsoluteLongIndexedXWrapper(F f, AccessMode a) { return f(a) + Registers.X.W; } inline uint32_t AbsoluteLongIndexedXSlow(AccessMode a) // l,X { return AbsoluteLongIndexedXWrapper(AbsoluteLongSlow, a); } inline uint32_t AbsoluteLongIndexedX(AccessMode a) // l,X { return AbsoluteLongIndexedXWrapper(AbsoluteLong, a); } template inline uint32_t StackRelativeWrapper(F f, AccessMode a) { uint16_t addr = f(a) + Registers.S.W; AddCycles(ONE_CYCLE); return addr; } inline uint32_t StackRelativeSlow(AccessMode a) // d,S { return StackRelativeWrapper(Immediate8Slow, a); } inline uint32_t StackRelative(AccessMode a) // d,S { return StackRelativeWrapper(Immediate8, a); } template inline uint32_t StackRelativeIndirectIndexedWrapper(F f, AccessMode a) { uint32_t addr = S9xGetWord(f(READ)); if (a & READ) OpenBus = static_cast(addr >> 8); addr = (addr + Registers.Y.W + ICPU.ShiftedDB) & 0xffffff; AddCycles(ONE_CYCLE); return addr; } inline uint32_t StackRelativeIndirectIndexedSlow(AccessMode a) // (d,S),Y { return StackRelativeIndirectIndexedWrapper(StackRelativeSlow, a); } inline uint32_t StackRelativeIndirectIndexed(AccessMode a) // (d,S),Y { return StackRelativeIndirectIndexedWrapper(StackRelative, a); }