/*****************************************************************************\ 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 #include "cpuexec.h" inline void addCyclesInMemoryAccess(int32_t speed) { if (!CPU.InDMAorHDMA) { CPU.Cycles += speed; while (CPU.Cycles >= CPU.NextEvent) S9xDoHEventProcessing(); } } inline void addCyclesInMemoryAccess_x2(int32_t speed) { if (!CPU.InDMAorHDMA) { CPU.Cycles += speed << 1; while (CPU.Cycles >= CPU.NextEvent) S9xDoHEventProcessing(); } } extern uint8_t OpenBus; inline int32_t memory_speed(uint32_t address) { if (address & 0x408000) { if (address & 0x800000) return CPU.FastROMSpeed; return SLOW_ONE_CYCLE; } if ((address + 0x6000) & 0x4000) return SLOW_ONE_CYCLE; if ((address - 0x4000) & 0x7e00) return ONE_CYCLE; return TWO_CYCLES; } inline uint8_t S9xGetByte(uint32_t Address) { int block = (Address & 0xffffff) >> MEMMAP_SHIFT; uint8_t *GetAddress = Memory.Map[block]; int32_t speed = memory_speed(Address); uint8_t byte; if (GetAddress >= reinterpret_cast(CMemory::MAP_LAST)) { byte = GetAddress[Address & 0xffff]; addCyclesInMemoryAccess(speed); return byte; } switch (reinterpret_cast(GetAddress)) { case CMemory::MAP_CPU: byte = S9xGetCPU(Address & 0xffff); addCyclesInMemoryAccess(speed); return byte; case CMemory::MAP_PPU: if (CPU.InDMAorHDMA && (Address & 0xff00) == 0x2100) return OpenBus; byte = S9xGetPPU(Address & 0xffff); addCyclesInMemoryAccess(speed); return byte; case CMemory::MAP_LOROM_SRAM: case CMemory::MAP_SA1RAM: // Address & 0x7fff : offset into bank // Address & 0xff0000 : bank // bank >> 1 | offset : SRAM address, unbound // unbound & SRAMMask : SRAM offset byte = Memory.SRAM[(((Address & 0xff0000) >> 1) | (Address & 0x7fff)) & Memory.SRAMMask]; addCyclesInMemoryAccess(speed); return byte; case CMemory::MAP_HIROM_SRAM: case CMemory::MAP_RONLY_SRAM: byte = Memory.SRAM[((Address & 0x7fff) - 0x6000 + ((Address & 0xf0000) >> 3)) & Memory.SRAMMask]; addCyclesInMemoryAccess(speed); return byte; default: byte = OpenBus; addCyclesInMemoryAccess(speed); return byte; } } inline uint16_t S9xGetWord(uint32_t Address, s9xwrap_t w = WRAP_NONE) { uint16_t word; uint32_t mask = MEMMAP_MASK & (w == WRAP_PAGE ? 0xff : (w == WRAP_BANK ? 0xffff : 0xffffff)); if ((Address & mask) == mask) { PC_t a; word = OpenBus = S9xGetByte(Address); switch (w) { case WRAP_PAGE: a.xPBPC = Address; ++a.B.xPCl; return word | (S9xGetByte(a.xPBPC) << 8); case WRAP_BANK: a.xPBPC = Address; ++a.W.xPC; return word | (S9xGetByte(a.xPBPC) << 8); default: return word | (S9xGetByte(Address + 1) << 8); } } int block = (Address & 0xffffff) >> MEMMAP_SHIFT; uint8_t *GetAddress = Memory.Map[block]; int32_t speed = memory_speed(Address); if (GetAddress >= reinterpret_cast(CMemory::MAP_LAST)) { word = READ_WORD(&GetAddress[Address & 0xffff]); addCyclesInMemoryAccess_x2(speed); return word; } switch (reinterpret_cast(GetAddress)) { case CMemory::MAP_CPU: word = S9xGetCPU(Address & 0xffff); addCyclesInMemoryAccess(speed); word |= S9xGetCPU((Address + 1) & 0xffff) << 8; addCyclesInMemoryAccess(speed); return word; case CMemory::MAP_PPU: if (CPU.InDMAorHDMA) { word = OpenBus = S9xGetByte(Address); return word | (S9xGetByte(Address + 1) << 8); } word = S9xGetPPU(Address & 0xffff); addCyclesInMemoryAccess(speed); word |= S9xGetPPU((Address + 1) & 0xffff) << 8; addCyclesInMemoryAccess(speed); return word; case CMemory::MAP_LOROM_SRAM: case CMemory::MAP_SA1RAM: if (Memory.SRAMMask >= MEMMAP_MASK) word = READ_WORD(&Memory.SRAM[(((Address & 0xff0000) >> 1) | (Address & 0x7fff)) & Memory.SRAMMask]); else word = Memory.SRAM[(((Address & 0xff0000) >> 1) | (Address & 0x7fff)) & Memory.SRAMMask] | (Memory.SRAM[((((Address + 1) & 0xff0000) >> 1) | ((Address + 1) & 0x7fff)) & Memory.SRAMMask] << 8); addCyclesInMemoryAccess_x2(speed); return word; case CMemory::MAP_HIROM_SRAM: case CMemory::MAP_RONLY_SRAM: if (Memory.SRAMMask >= MEMMAP_MASK) word = READ_WORD(&Memory.SRAM[((Address & 0x7fff) - 0x6000 + ((Address & 0xf0000) >> 3)) & Memory.SRAMMask]); else word = Memory.SRAM[((Address & 0x7fff) - 0x6000 + ((Address & 0xf0000) >> 3)) & Memory.SRAMMask] | (Memory.SRAM[(((Address + 1) & 0x7fff) - 0x6000 + (((Address + 1) & 0xf0000) >> 3)) & Memory.SRAMMask] << 8); addCyclesInMemoryAccess_x2(speed); return word; default: word = OpenBus | (OpenBus << 8); addCyclesInMemoryAccess_x2(speed); return word; } } inline void S9xSetByte(uint8_t Byt, uint32_t Address) { int block = (Address & 0xffffff) >> MEMMAP_SHIFT; uint8_t *SetAddress = Memory.WriteMap[block]; int32_t speed = memory_speed(Address); if (SetAddress >= reinterpret_cast(CMemory::MAP_LAST)) { SetAddress[Address & 0xffff] = Byt; addCyclesInMemoryAccess(speed); return; } switch (reinterpret_cast(SetAddress)) { case CMemory::MAP_CPU: S9xSetCPU(Byt, Address & 0xffff); addCyclesInMemoryAccess(speed); break; case CMemory::MAP_PPU: if (CPU.InDMAorHDMA && (Address & 0xff00) == 0x2100) return; S9xSetPPU(Byt, Address & 0xffff); addCyclesInMemoryAccess(speed); break; case CMemory::MAP_LOROM_SRAM: if (Memory.SRAMMask) Memory.SRAM[(((Address & 0xff0000) >> 1) | (Address & 0x7fff)) & Memory.SRAMMask] = Byt; addCyclesInMemoryAccess(speed); break; case CMemory::MAP_HIROM_SRAM: if (Memory.SRAMMask) Memory.SRAM[((Address & 0x7fff) - 0x6000 + ((Address & 0xf0000) >> 3)) & Memory.SRAMMask] = Byt; addCyclesInMemoryAccess(speed); break; case CMemory::MAP_SA1RAM: Memory.SRAM[Address & 0xffff] = Byt; addCyclesInMemoryAccess(speed); break; default: addCyclesInMemoryAccess(speed); } } inline void S9xSetWord(uint16_t Word, uint32_t Address, s9xwrap_t w = WRAP_NONE, s9xwriteorder_t o = WRITE_01) { uint32_t mask = MEMMAP_MASK & (w == WRAP_PAGE ? 0xff : (w == WRAP_BANK ? 0xffff : 0xffffff)); if ((Address & mask) == mask) { PC_t a; if (!o) S9xSetByte(static_cast(Word), Address); switch (w) { case WRAP_PAGE: a.xPBPC = Address; ++a.B.xPCl; S9xSetByte(Word >> 8, a.xPBPC); break; case WRAP_BANK: a.xPBPC = Address; ++a.W.xPC; S9xSetByte(Word >> 8, a.xPBPC); break; default: S9xSetByte(Word >> 8, Address + 1); } if (o) S9xSetByte(static_cast(Word), Address); return; } int block = (Address & 0xffffff) >> MEMMAP_SHIFT; uint8_t *SetAddress = Memory.WriteMap[block]; int32_t speed = memory_speed(Address); if (SetAddress >= reinterpret_cast(CMemory::MAP_LAST)) { WRITE_WORD(&SetAddress[Address & 0xffff], Word); addCyclesInMemoryAccess_x2(speed); return; } switch (reinterpret_cast(SetAddress)) { case CMemory::MAP_CPU: if (o) { S9xSetCPU(Word >> 8, (Address + 1) & 0xffff); addCyclesInMemoryAccess(speed); S9xSetCPU(static_cast(Word), Address & 0xffff); addCyclesInMemoryAccess(speed); } else { S9xSetCPU(static_cast(Word), Address & 0xffff); addCyclesInMemoryAccess(speed); S9xSetCPU(Word >> 8, (Address + 1) & 0xffff); addCyclesInMemoryAccess(speed); } break; case CMemory::MAP_PPU: if (CPU.InDMAorHDMA) { if ((Address & 0xff00) != 0x2100) S9xSetPPU(static_cast(Word), Address & 0xffff); if (((Address + 1) & 0xff00) != 0x2100) S9xSetPPU(Word >> 8, (Address + 1) & 0xffff); break; } if (o) { S9xSetPPU(Word >> 8, (Address + 1) & 0xffff); addCyclesInMemoryAccess(speed); S9xSetPPU(static_cast(Word), Address & 0xffff); addCyclesInMemoryAccess(speed); } else { S9xSetPPU(static_cast(Word), Address & 0xffff); addCyclesInMemoryAccess(speed); S9xSetPPU(Word >> 8, (Address + 1) & 0xffff); addCyclesInMemoryAccess(speed); } break; case CMemory::MAP_LOROM_SRAM: if (Memory.SRAMMask) { if (Memory.SRAMMask >= MEMMAP_MASK) WRITE_WORD(&Memory.SRAM[(((Address & 0xff0000) >> 1) | (Address & 0x7fff)) & Memory.SRAMMask], Word); else { Memory.SRAM[(((Address & 0xff0000) >> 1) | (Address & 0x7fff)) & Memory.SRAMMask] = static_cast(Word); Memory.SRAM[((((Address + 1) & 0xff0000) >> 1) | ((Address + 1) & 0x7fff)) & Memory.SRAMMask] = Word >> 8; } } addCyclesInMemoryAccess_x2(speed); break; case CMemory::MAP_HIROM_SRAM: if (Memory.SRAMMask) { if (Memory.SRAMMask >= MEMMAP_MASK) WRITE_WORD(&Memory.SRAM[((Address & 0x7fff) - 0x6000 + ((Address & 0xf0000) >> 3)) & Memory.SRAMMask], Word); else { Memory.SRAM[((Address & 0x7fff) - 0x6000 + ((Address & 0xf0000) >> 3)) & Memory.SRAMMask] = static_cast(Word); Memory.SRAM[(((Address + 1) & 0x7fff) - 0x6000 + (((Address + 1) & 0xf0000) >> 3)) & Memory.SRAMMask] = Word >> 8; } } addCyclesInMemoryAccess_x2(speed); break; case CMemory::MAP_SA1RAM: WRITE_WORD(&Memory.SRAM[Address & 0xffff], Word); addCyclesInMemoryAccess_x2(speed); break; default: addCyclesInMemoryAccess_x2(speed); } } inline void S9xSetPCBase(uint32_t Address) { Registers.PC.xPBPC = Address & 0xffffff; ICPU.ShiftedPB = Address & 0xff0000; uint8_t *GetAddress = Memory.Map[static_cast((Address & 0xffffff) >> MEMMAP_SHIFT)]; CPU.MemSpeed = memory_speed(Address); CPU.MemSpeedx2 = CPU.MemSpeed << 1; if (GetAddress >= reinterpret_cast(CMemory::MAP_LAST)) { CPU.PCBase = GetAddress; return; } switch (reinterpret_cast(GetAddress)) { case CMemory::MAP_LOROM_SRAM: if ((Memory.SRAMMask & MEMMAP_MASK) != MEMMAP_MASK) CPU.PCBase = nullptr; else CPU.PCBase = &Memory.SRAM[((((Address & 0xff0000) >> 1) | (Address & 0x7fff)) & Memory.SRAMMask) - (Address & 0xffff)]; break; case CMemory::MAP_HIROM_SRAM: if ((Memory.SRAMMask & MEMMAP_MASK) != MEMMAP_MASK) CPU.PCBase = nullptr; else CPU.PCBase = &Memory.SRAM[(((Address & 0x7fff) - 0x6000 + ((Address & 0xf0000) >> 3)) & Memory.SRAMMask) - (Address & 0xffff)]; break; case CMemory::MAP_SA1RAM: CPU.PCBase = &Memory.SRAM[0]; break; default: CPU.PCBase = nullptr; } } inline uint8_t *S9xGetBasePointer(uint32_t Address) { uint8_t *GetAddress = Memory.Map[(Address & 0xffffff) >> MEMMAP_SHIFT]; if (GetAddress >= reinterpret_cast(CMemory::MAP_LAST)) return GetAddress; switch (reinterpret_cast(GetAddress)) { case CMemory::MAP_LOROM_SRAM: if ((Memory.SRAMMask & MEMMAP_MASK) != MEMMAP_MASK) return nullptr; return &Memory.SRAM[((((Address & 0xff0000) >> 1) | (Address & 0x7fff)) & Memory.SRAMMask) - (Address & 0xffff)]; case CMemory::MAP_HIROM_SRAM: if ((Memory.SRAMMask & MEMMAP_MASK) != MEMMAP_MASK) return nullptr; return &Memory.SRAM[(((Address & 0x7fff) - 0x6000 + ((Address & 0xf0000) >> 3)) & Memory.SRAMMask) - (Address & 0xffff)]; case CMemory::MAP_SA1RAM: return &Memory.SRAM[0]; default: return nullptr; } } inline uint8_t *S9xGetMemPointer(uint32_t Address) { uint8_t *GetAddress = Memory.Map[(Address & 0xffffff) >> MEMMAP_SHIFT]; if (GetAddress >= reinterpret_cast(CMemory::MAP_LAST)) return &GetAddress[Address & 0xffff]; switch (reinterpret_cast(GetAddress)) { case CMemory::MAP_LOROM_SRAM: if ((Memory.SRAMMask & MEMMAP_MASK) != MEMMAP_MASK) return nullptr; return &Memory.SRAM[(((Address & 0xff0000) >> 1) | (Address & 0x7fff)) & Memory.SRAMMask]; case CMemory::MAP_HIROM_SRAM: if ((Memory.SRAMMask & MEMMAP_MASK) != MEMMAP_MASK) return nullptr; return &Memory.SRAM[((Address & 0x7fff) - 0x6000 + ((Address & 0xf0000) >> 3)) & Memory.SRAMMask]; case CMemory::MAP_SA1RAM: return &Memory.SRAM[Address & 0xffff]; default: return nullptr; } }