#pragma once #include "../common/Port.h" #include "Sound.h" extern const uint32_t objTilesAddress[3]; extern bool stopState; extern bool holdState; extern int cpuNextEvent; extern bool cpuDmaHack; extern uint32_t cpuDmaLast; extern bool timer0On; extern int timer0Ticks; extern int timer0ClockReload; extern bool timer1On; extern int timer1Ticks; extern int timer1ClockReload; extern bool timer2On; extern int timer2Ticks; extern int timer2ClockReload; extern bool timer3On; extern int timer3Ticks; extern int timer3ClockReload; extern int cpuTotalTicks; inline uint8_t CPUReadByteQuick(uint32_t addr) { return map[addr >> 24].address[addr & map[addr >> 24].mask]; } inline uint16_t CPUReadHalfWordQuick(uint32_t addr) { return READ16LE(&map[addr >> 24].address[addr & map[addr >> 24].mask]); } inline uint32_t CPUReadMemoryQuick(uint32_t addr) { return READ32LE(&map[addr >> 24].address[addr & map[addr >> 24].mask]); } inline uint32_t CPUReadMemory(uint32_t address) { uint32_t value; uint32_t oldAddress = address; if (address & 3) address &= ~0x03; switch (address >> 24) { case 0: if (reg[15].I >> 24) { if (address < 0x4000) value = READ32LE(&biosProtected[0]); else goto unreadable; } else value = READ32LE(&bios[address & 0x3FFC]); break; case 2: value = READ32LE(&workRAM[address & 0x3FFFC]); break; case 3: value = READ32LE(&internalRAM[address & 0x7ffC]); break; case 4: if (address < 0x4000400 && ioReadable[address & 0x3fc]) { if (ioReadable[(address & 0x3fc) + 2]) value = READ32LE(&ioMem[address & 0x3fC]); else value = READ16LE(&ioMem[address & 0x3fc]); } else goto unreadable; break; case 5: value = READ32LE(&paletteRAM[address & 0x3fC]); break; case 6: address &= 0x1fffc; if ((DISPCNT & 7) > 2 && (address & 0x1C000) == 0x18000) { value = 0; break; } if ((address & 0x18000) == 0x18000) address &= 0x17fff; value = READ32LE(&vram[address]); break; case 7: value = READ32LE(&oam[address & 0x3FC]); break; case 8: case 9: case 10: case 11: case 12: value = READ32LE(&rom[address & 0x1FFFFFC]); break; case 13: case 14: case 15: value = 0; break; // default default: unreadable: if (cpuDmaHack) value = cpuDmaLast; else { if (armState) return CPUReadMemoryQuick(reg[15].I); else return CPUReadHalfWordQuick(reg[15].I) | CPUReadHalfWordQuick(reg[15].I) << 16; } } if (oldAddress & 3) { int shift = (oldAddress & 3) << 3; value = (value >> shift) | (value << (32 - shift)); } return value; } inline uint32_t CPUReadHalfWord(uint32_t address) { uint32_t value; uint32_t oldAddress = address; if (address & 1) address &= ~0x01; switch (address >> 24) { case 0: if (reg[15].I >> 24) { if (address < 0x4000) value = READ16LE(&biosProtected[address & 2]); else goto unreadable; } else value = READ16LE(&bios[address & 0x3FFE]); break; case 2: value = READ16LE(&workRAM[address & 0x3FFFE]); break; case 3: value = READ16LE(&internalRAM[address & 0x7ffe]); break; case 4: if (address < 0x4000400 && ioReadable[address & 0x3fe]) { value = READ16LE(&ioMem[address & 0x3fe]); if ((address & 0x3fe) > 0xFF && (address & 0x3fe) < 0x10E) { if ((address & 0x3fe) == 0x100 && timer0On) value = 0xFFFF - ((timer0Ticks - cpuTotalTicks) >> timer0ClockReload); else if ((address & 0x3fe) == 0x104 && timer1On && !(TM1CNT & 4)) value = 0xFFFF - ((timer1Ticks - cpuTotalTicks) >> timer1ClockReload); else if ((address & 0x3fe) == 0x108 && timer2On && !(TM2CNT & 4)) value = 0xFFFF - ((timer2Ticks - cpuTotalTicks) >> timer2ClockReload); else if ((address & 0x3fe) == 0x10C && timer3On && !(TM3CNT & 4)) value = 0xFFFF - ((timer3Ticks - cpuTotalTicks) >> timer3ClockReload); } } else if (address < 0x4000400 && ioReadable[address & 0x3fc]) value = 0; else goto unreadable; break; case 5: value = READ16LE(&paletteRAM[address & 0x3fe]); break; case 6: address &= 0x1fffe; if ((DISPCNT & 7) > 2 && (address & 0x1C000) == 0x18000) { value = 0; break; } if ((address & 0x18000) == 0x18000) address &= 0x17fff; value = READ16LE(&vram[address]); break; case 7: value = READ16LE(&oam[address & 0x3fe]); break; case 8: case 9: case 10: case 11: case 12: if (address == 0x80000c4 || address == 0x80000c6 || address == 0x80000c8) value = 0; else value = READ16LE(&rom[address & 0x1FFFFFE]); break; case 13: case 14: case 15: value = 0; break; // default default: unreadable: if (cpuDmaHack) value = cpuDmaLast & 0xFFFF; else { if (armState) value = CPUReadHalfWordQuick(reg[15].I + (address & 2)); else value = CPUReadHalfWordQuick(reg[15].I); } return value; } if (oldAddress & 1) value = (value >> 8) | (value << 24); return value; } inline int16_t CPUReadHalfWordSigned(uint32_t address) { return static_cast(CPUReadHalfWord(address)); } inline uint8_t CPUReadByte(uint32_t address) { switch (address >> 24) { case 0: if (reg[15].I >> 24) { if (address < 0x4000) return biosProtected[address & 3]; else break; } return bios[address & 0x3FFF]; case 2: return workRAM[address & 0x3FFFF]; case 3: return internalRAM[address & 0x7fff]; case 4: if (address < 0x4000400 && ioReadable[address & 0x3ff]) return ioMem[address & 0x3ff]; else break; case 5: return paletteRAM[address & 0x3ff]; case 6: address &= 0x1ffff; if ((DISPCNT & 7) > 2 && (address & 0x1C000) == 0x18000) return 0; if ((address & 0x18000) == 0x18000) address &= 0x17fff; return vram[address]; case 7: return oam[address & 0x3ff]; case 8: case 9: case 10: case 11: case 12: return rom[address & 0x1FFFFFF]; case 13: case 14: case 15: return 0; } if (cpuDmaHack) return cpuDmaLast & 0xFF; else { if (armState) return CPUReadByteQuick(reg[15].I + (address & 3)); else return CPUReadByteQuick(reg[15].I + (address & 1)); } } inline void CPUWriteMemory(uint32_t address, uint32_t value) { address &= 0xFFFFFFFC; switch (address >> 24) { case 0x02: WRITE32LE(&workRAM[address & 0x3FFFC], value); break; case 0x03: WRITE32LE(&internalRAM[address & 0x7ffC], value); break; case 0x04: if (address < 0x4000400) { CPUUpdateRegister(address & 0x3FC, value & 0xFFFF); CPUUpdateRegister((address & 0x3FC) + 2, value >> 16); } break; case 0x05: WRITE32LE(&paletteRAM[address & 0x3FC], value); break; case 0x06: address &= 0x1fffc; if ((DISPCNT & 7) > 2 && (address & 0x1C000) == 0x18000) return; if ((address & 0x18000) == 0x18000) address &= 0x17fff; WRITE32LE(&vram[address], value); break; case 0x07: WRITE32LE(&oam[address & 0x3fc], value); } } inline void CPUWriteHalfWord(uint32_t address, uint16_t value) { address &= 0xFFFFFFFE; switch (address >> 24) { case 2: WRITE16LE(&workRAM[address & 0x3FFFE], value); break; case 3: WRITE16LE(&internalRAM[address & 0x7ffe], value); break; case 4: if (address < 0x4000400) CPUUpdateRegister(address & 0x3fe, value); break; case 5: WRITE16LE(&paletteRAM[address & 0x3fe], value); break; case 6: address &= 0x1fffe; if ((DISPCNT & 7) > 2 && (address & 0x1C000) == 0x18000) return; if ((address & 0x18000) == 0x18000) address &= 0x17fff; WRITE16LE(&vram[address], value); break; case 7: WRITE16LE(&oam[address & 0x3fe], value); } } inline void CPUWriteByte(uint32_t address, uint8_t b) { switch (address >> 24) { case 2: workRAM[address & 0x3FFFF] = b; break; case 3: internalRAM[address & 0x7fff] = b; break; case 4: if (address < 0x4000400) { switch (address & 0x3FF) { case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x68: case 0x69: case 0x6c: case 0x6d: case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x78: case 0x79: case 0x7c: case 0x7d: case 0x80: case 0x81: case 0x84: case 0x85: case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97: case 0x98: case 0x99: case 0x9a: case 0x9b: case 0x9c: case 0x9d: case 0x9e: case 0x9f: soundEvent(address & 0xFF, b); break; case 0x301: // HALTCNT, undocumented if (b == 0x80) stopState = true; holdState = true; cpuNextEvent = cpuTotalTicks; break; default: // every other register uint32_t lowerBits = address & 0x3fe; if (address & 1) CPUUpdateRegister(lowerBits, (READ16LE(&ioMem[lowerBits]) & 0x00FF) | (b << 8)); else CPUUpdateRegister(lowerBits, (READ16LE(&ioMem[lowerBits]) & 0xFF00) | b); } } break; case 5: // no need to switch *reinterpret_cast(&paletteRAM[address & 0x3FE]) = (b << 8) | b; break; case 6: address &= 0x1fffe; if ((DISPCNT & 7) > 2 && (address & 0x1C000) == 0x18000) return; if ((address & 0x18000) == 0x18000) address &= 0x17fff; // no need to switch // byte writes to OBJ VRAM are ignored if (address < objTilesAddress[((DISPCNT & 7) + 1) >> 2]) *reinterpret_cast(&vram[address]) = (b << 8) | b; break; case 7: // no need to switch // byte writes to OAM are ignored //*reinterpret_cast(&oam[address & 0x3FE]) = (b << 8) | b; break; } }