diff --git a/CHANGES b/CHANGES index 3edb15832..2eebcb87a 100644 --- a/CHANGES +++ b/CHANGES @@ -13,6 +13,7 @@ Bugfixes: - SDL: Fix axes being mapped wrong - Qt: Fix initial state of key mapping - Shaders: Fix AGS-001 shader with some bad drivers + - GBA Memory: Fix mirror on non-overdumped Classic NES games Misc: - GBA: Slightly optimize GBAProcessEvents - Qt: Add preset for DualShock 4 diff --git a/src/gba/context/overrides.c b/src/gba/context/overrides.c index 80128e887..a2f70c7fe 100644 --- a/src/gba/context/overrides.c +++ b/src/gba/context/overrides.c @@ -12,167 +12,169 @@ static const struct GBACartridgeOverride _overrides[] = { // Advance Wars - { "AWRE", SAVEDATA_FLASH512, HW_NONE, 0x8038810 }, - { "AWRP", SAVEDATA_FLASH512, HW_NONE, 0x8038810 }, + { "AWRE", SAVEDATA_FLASH512, HW_NONE, 0x8038810, false }, + { "AWRP", SAVEDATA_FLASH512, HW_NONE, 0x8038810, false }, // Advance Wars 2: Black Hole Rising - { "AW2E", SAVEDATA_FLASH512, HW_NONE, 0x8036E08 }, - { "AW2P", SAVEDATA_FLASH512, HW_NONE, 0x803719C }, + { "AW2E", SAVEDATA_FLASH512, HW_NONE, 0x8036E08, false }, + { "AW2P", SAVEDATA_FLASH512, HW_NONE, 0x803719C, false }, // Boktai: The Sun is in Your Hand - { "U3IJ", SAVEDATA_EEPROM, HW_RTC | HW_LIGHT_SENSOR, IDLE_LOOP_NONE }, - { "U3IE", SAVEDATA_EEPROM, HW_RTC | HW_LIGHT_SENSOR, IDLE_LOOP_NONE }, - { "U3IP", SAVEDATA_EEPROM, HW_RTC | HW_LIGHT_SENSOR, IDLE_LOOP_NONE }, + { "U3IJ", SAVEDATA_EEPROM, HW_RTC | HW_LIGHT_SENSOR, IDLE_LOOP_NONE, false }, + { "U3IE", SAVEDATA_EEPROM, HW_RTC | HW_LIGHT_SENSOR, IDLE_LOOP_NONE, false }, + { "U3IP", SAVEDATA_EEPROM, HW_RTC | HW_LIGHT_SENSOR, IDLE_LOOP_NONE, false }, // Boktai 2: Solar Boy Django - { "U32J", SAVEDATA_EEPROM, HW_RTC | HW_LIGHT_SENSOR, IDLE_LOOP_NONE }, - { "U32E", SAVEDATA_EEPROM, HW_RTC | HW_LIGHT_SENSOR, IDLE_LOOP_NONE }, - { "U32P", SAVEDATA_EEPROM, HW_RTC | HW_LIGHT_SENSOR, IDLE_LOOP_NONE }, + { "U32J", SAVEDATA_EEPROM, HW_RTC | HW_LIGHT_SENSOR, IDLE_LOOP_NONE, false }, + { "U32E", SAVEDATA_EEPROM, HW_RTC | HW_LIGHT_SENSOR, IDLE_LOOP_NONE, false }, + { "U32P", SAVEDATA_EEPROM, HW_RTC | HW_LIGHT_SENSOR, IDLE_LOOP_NONE, false }, // Dragon Ball Z - The Legacy of Goku - { "ALGP", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE }, + { "ALGP", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false }, // Dragon Ball Z - Taiketsu - { "BDBE", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE }, - { "BDBP", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE }, + { "BDBE", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false }, + { "BDBP", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false }, // Drill Dozer - { "V49J", SAVEDATA_SRAM, HW_RUMBLE, IDLE_LOOP_NONE }, - { "V49E", SAVEDATA_SRAM, HW_RUMBLE, IDLE_LOOP_NONE }, + { "V49J", SAVEDATA_SRAM, HW_RUMBLE, IDLE_LOOP_NONE, false }, + { "V49E", SAVEDATA_SRAM, HW_RUMBLE, IDLE_LOOP_NONE, false }, // Final Fantasy Tactics Advance - { "AFXE", SAVEDATA_FLASH512, HW_NONE, 0x8000428 }, + { "AFXE", SAVEDATA_FLASH512, HW_NONE, 0x8000428, false }, // F-Zero - Climax - { "BFTJ", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE }, + { "BFTJ", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false }, // Iridion II - { "AI2E", SAVEDATA_FORCE_NONE, HW_NONE, IDLE_LOOP_NONE }, - { "AI2P", SAVEDATA_FORCE_NONE, HW_NONE, IDLE_LOOP_NONE }, + { "AI2E", SAVEDATA_FORCE_NONE, HW_NONE, IDLE_LOOP_NONE, false }, + { "AI2P", SAVEDATA_FORCE_NONE, HW_NONE, IDLE_LOOP_NONE, false }, // Golden Sun: The Lost Age - { "AGFE", SAVEDATA_FLASH512, HW_NONE, 0x801353A }, + { "AGFE", SAVEDATA_FLASH512, HW_NONE, 0x801353A, false }, // Koro Koro Puzzle - Happy Panechu! - { "KHPJ", SAVEDATA_EEPROM, HW_TILT, IDLE_LOOP_NONE }, + { "KHPJ", SAVEDATA_EEPROM, HW_TILT, IDLE_LOOP_NONE, false }, // Mega Man Battle Network - { "AREE", SAVEDATA_SRAM, HW_NONE, 0x800032E }, + { "AREE", SAVEDATA_SRAM, HW_NONE, 0x800032E, false }, // Mega Man Zero - { "AZCE", SAVEDATA_SRAM, HW_NONE, 0x80004E8 }, + { "AZCE", SAVEDATA_SRAM, HW_NONE, 0x80004E8, false }, // Metal Slug Advance - { "BSME", SAVEDATA_EEPROM, HW_NONE, 0x8000290 }, + { "BSME", SAVEDATA_EEPROM, HW_NONE, 0x8000290, false }, // Pokemon Ruby - { "AXVJ", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE }, - { "AXVE", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE }, - { "AXVP", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE }, - { "AXVI", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE }, - { "AXVS", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE }, - { "AXVD", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE }, - { "AXVF", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE }, + { "AXVJ", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false }, + { "AXVE", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false }, + { "AXVP", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false }, + { "AXVI", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false }, + { "AXVS", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false }, + { "AXVD", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false }, + { "AXVF", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false }, // Pokemon Sapphire - { "AXPJ", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE }, - { "AXPE", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE }, - { "AXPP", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE }, - { "AXPI", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE }, - { "AXPS", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE }, - { "AXPD", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE }, - { "AXPF", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE }, + { "AXPJ", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false }, + { "AXPE", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false }, + { "AXPP", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false }, + { "AXPI", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false }, + { "AXPS", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false }, + { "AXPD", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false }, + { "AXPF", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false }, // Pokemon Emerald - { "BPEJ", SAVEDATA_FLASH1M, HW_RTC, 0x80008C6 }, - { "BPEE", SAVEDATA_FLASH1M, HW_RTC, 0x80008C6 }, - { "BPEP", SAVEDATA_FLASH1M, HW_RTC, 0x80008C6 }, - { "BPEI", SAVEDATA_FLASH1M, HW_RTC, 0x80008C6 }, - { "BPES", SAVEDATA_FLASH1M, HW_RTC, 0x80008C6 }, - { "BPED", SAVEDATA_FLASH1M, HW_RTC, 0x80008C6 }, - { "BPEF", SAVEDATA_FLASH1M, HW_RTC, 0x80008C6 }, + { "BPEJ", SAVEDATA_FLASH1M, HW_RTC, 0x80008C6, false }, + { "BPEE", SAVEDATA_FLASH1M, HW_RTC, 0x80008C6, false }, + { "BPEP", SAVEDATA_FLASH1M, HW_RTC, 0x80008C6, false }, + { "BPEI", SAVEDATA_FLASH1M, HW_RTC, 0x80008C6, false }, + { "BPES", SAVEDATA_FLASH1M, HW_RTC, 0x80008C6, false }, + { "BPED", SAVEDATA_FLASH1M, HW_RTC, 0x80008C6, false }, + { "BPEF", SAVEDATA_FLASH1M, HW_RTC, 0x80008C6, false }, // Pokemon Mystery Dungeon - { "B24J", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE }, - { "B24E", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE }, - { "B24P", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE }, - { "B24U", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE }, + { "B24J", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false }, + { "B24E", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false }, + { "B24P", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false }, + { "B24U", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false }, // Pokemon FireRed - { "BPRJ", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE }, - { "BPRE", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE }, - { "BPRP", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE }, - { "BPRI", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE }, - { "BPRS", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE }, - { "BPRD", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE }, - { "BPRF", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE }, + { "BPRJ", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false }, + { "BPRE", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false }, + { "BPRP", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false }, + { "BPRI", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false }, + { "BPRS", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false }, + { "BPRD", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false }, + { "BPRF", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false }, // Pokemon LeafGreen - { "BPGJ", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE }, - { "BPGE", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE }, - { "BPGP", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE }, - { "BPGI", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE }, - { "BPGS", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE }, - { "BPGD", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE }, - { "BPGF", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE }, + { "BPGJ", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false }, + { "BPGE", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false }, + { "BPGP", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false }, + { "BPGI", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false }, + { "BPGS", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false }, + { "BPGD", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false }, + { "BPGF", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false }, // RockMan EXE 4.5 - Real Operation - { "BR4J", SAVEDATA_FLASH512, HW_RTC, IDLE_LOOP_NONE }, + { "BR4J", SAVEDATA_FLASH512, HW_RTC, IDLE_LOOP_NONE, false }, // Rocky - { "AR8E", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE }, - { "AROP", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE }, + { "AR8E", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false }, + { "AROP", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false }, // Sennen Kazoku - { "BKAJ", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE }, + { "BKAJ", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false }, // Shin Bokura no Taiyou: Gyakushuu no Sabata - { "U33J", SAVEDATA_EEPROM, HW_RTC | HW_LIGHT_SENSOR, IDLE_LOOP_NONE }, + { "U33J", SAVEDATA_EEPROM, HW_RTC | HW_LIGHT_SENSOR, IDLE_LOOP_NONE, false }, // Super Mario Advance 2 - { "AA2J", SAVEDATA_EEPROM, HW_NONE, 0x800052E }, - { "AA2E", SAVEDATA_EEPROM, HW_NONE, 0x800052E }, - { "AA2P", SAVEDATA_AUTODETECT, HW_NONE, 0x800052E }, + { "AA2J", SAVEDATA_EEPROM, HW_NONE, 0x800052E, false }, + { "AA2E", SAVEDATA_EEPROM, HW_NONE, 0x800052E, false }, + { "AA2P", SAVEDATA_AUTODETECT, HW_NONE, 0x800052E, false }, // Super Mario Advance 3 - { "A3AJ", SAVEDATA_EEPROM, HW_NONE, 0x8002B9C }, - { "A3AE", SAVEDATA_EEPROM, HW_NONE, 0x8002B9C }, - { "A3AP", SAVEDATA_EEPROM, HW_NONE, 0x8002B9C }, + { "A3AJ", SAVEDATA_EEPROM, HW_NONE, 0x8002B9C, false }, + { "A3AE", SAVEDATA_EEPROM, HW_NONE, 0x8002B9C, false }, + { "A3AP", SAVEDATA_EEPROM, HW_NONE, 0x8002B9C, false }, // Super Mario Advance 4 - { "AX4J", SAVEDATA_FLASH1M, HW_NONE, 0x800072A }, - { "AX4E", SAVEDATA_FLASH1M, HW_NONE, 0x800072A }, - { "AX4P", SAVEDATA_FLASH1M, HW_NONE, 0x800072A }, + { "AX4J", SAVEDATA_FLASH1M, HW_NONE, 0x800072A, false }, + { "AX4E", SAVEDATA_FLASH1M, HW_NONE, 0x800072A, false }, + { "AX4P", SAVEDATA_FLASH1M, HW_NONE, 0x800072A, false }, // Super Monkey Ball Jr. - { "ALUE", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE }, - { "ALUP", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE }, + { "ALUE", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false }, + { "ALUP", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false }, // Top Gun - Combat Zones - { "A2YE", SAVEDATA_FORCE_NONE, HW_NONE, IDLE_LOOP_NONE }, + { "A2YE", SAVEDATA_FORCE_NONE, HW_NONE, IDLE_LOOP_NONE, false }, // Wario Ware Twisted - { "RZWJ", SAVEDATA_SRAM, HW_RUMBLE | HW_GYRO, IDLE_LOOP_NONE }, - { "RZWE", SAVEDATA_SRAM, HW_RUMBLE | HW_GYRO, IDLE_LOOP_NONE }, - { "RZWP", SAVEDATA_SRAM, HW_RUMBLE | HW_GYRO, IDLE_LOOP_NONE }, + { "RZWJ", SAVEDATA_SRAM, HW_RUMBLE | HW_GYRO, IDLE_LOOP_NONE, false }, + { "RZWE", SAVEDATA_SRAM, HW_RUMBLE | HW_GYRO, IDLE_LOOP_NONE, false }, + { "RZWP", SAVEDATA_SRAM, HW_RUMBLE | HW_GYRO, IDLE_LOOP_NONE, false }, // Yoshi's Universal Gravitation - { "KYGJ", SAVEDATA_EEPROM, HW_TILT, IDLE_LOOP_NONE }, - { "KYGE", SAVEDATA_EEPROM, HW_TILT, IDLE_LOOP_NONE }, - { "KYGP", SAVEDATA_EEPROM, HW_TILT, IDLE_LOOP_NONE }, + { "KYGJ", SAVEDATA_EEPROM, HW_TILT, IDLE_LOOP_NONE, false }, + { "KYGE", SAVEDATA_EEPROM, HW_TILT, IDLE_LOOP_NONE, false }, + { "KYGP", SAVEDATA_EEPROM, HW_TILT, IDLE_LOOP_NONE, false }, - { { 0, 0, 0, 0 }, 0, 0, IDLE_LOOP_NONE } + { { 0, 0, 0, 0 }, 0, 0, IDLE_LOOP_NONE, false } }; bool GBAOverrideFind(const struct Configuration* config, struct GBACartridgeOverride* override) { override->savetype = SAVEDATA_AUTODETECT; override->hardware = HW_NONE; override->idleLoop = IDLE_LOOP_NONE; + override->mirroring = false; bool found = false; if (override->id[0] == 'F') { // Classic NES Series override->savetype = SAVEDATA_EEPROM; + override->mirroring = true; found = true; } else { int i; @@ -311,6 +313,10 @@ void GBAOverrideApply(struct GBA* gba, const struct GBACartridgeOverride* overri gba->idleOptimization = IDLE_LOOP_REMOVE; } } + + if (override->mirroring) { + gba->memory.mirroring = true; + } } void GBAOverrideApplyDefaults(struct GBA* gba) { diff --git a/src/gba/context/overrides.h b/src/gba/context/overrides.h index 9dc7fb67a..58c005588 100644 --- a/src/gba/context/overrides.h +++ b/src/gba/context/overrides.h @@ -17,6 +17,7 @@ struct GBACartridgeOverride { enum SavedataType savetype; int hardware; uint32_t idleLoop; + bool mirroring; }; struct Configuration; diff --git a/src/gba/gba.c b/src/gba/gba.c index 2f4def6cf..b97e4846d 100644 --- a/src/gba/gba.c +++ b/src/gba/gba.c @@ -469,6 +469,7 @@ bool GBALoadROM(struct GBA* gba, struct VFile* vf) { gba->memory.rom = gba->pristineRom; gba->memory.romSize = gba->pristineRomSize; gba->memory.romMask = toPow2(gba->memory.romSize) - 1; + gba->memory.mirroring = false; gba->romCrc32 = doCrc32(gba->memory.rom, gba->memory.romSize); GBAHardwareInit(&gba->memory.hw, &((uint16_t*) gba->memory.rom)[GPIO_REG_DATA >> 1]); // TODO: error check diff --git a/src/gba/memory.c b/src/gba/memory.c index f030246d8..9537f2db7 100644 --- a/src/gba/memory.c +++ b/src/gba/memory.c @@ -82,6 +82,7 @@ void GBAMemoryInit(struct GBA* gba) { cpu->memory.activeNonseqCycles32 = 0; cpu->memory.activeNonseqCycles16 = 0; gba->memory.biosPrefetch = 0; + gba->memory.mirroring = false; } void GBAMemoryDeinit(struct GBA* gba) { @@ -244,8 +245,13 @@ static void GBASetActiveRegion(struct ARMCore* cpu, uint32_t address) { gba->lastJump = address; memory->lastPrefetchedPc = 0; memory->lastPrefetchedLoads = 0; - if (newRegion == memory->activeRegion && (newRegion < REGION_CART0 || (address & (SIZE_CART0 - 1)) < memory->romSize)) { - return; + if (newRegion == memory->activeRegion) { + if (newRegion < REGION_CART0 || (address & (SIZE_CART0 - 1)) < memory->romSize) { + return; + } + if (memory->mirroring && (address & memory->romMask) < memory->romSize) { + return; + } } if (memory->activeRegion == REGION_BIOS) { @@ -372,6 +378,8 @@ static void GBASetActiveRegion(struct ARMCore* cpu, uint32_t address) { wait += waitstatesRegion[address >> BASE_OFFSET]; \ if ((address & (SIZE_CART0 - 1)) < memory->romSize) { \ LOAD_32(value, address & (SIZE_CART0 - 4), memory->rom); \ + } else if (memory->mirroring && (address & memory->romMask) < memory->romSize) { \ + LOAD_32(value, address & memory->romMask, memory->rom); \ } else { \ mLOG(GBA_MEM, GAME_ERROR, "Out of bounds ROM Load32: 0x%08X", address); \ value = ((address & ~3) >> 1) & 0xFFFF; \ @@ -502,6 +510,8 @@ uint32_t GBALoad16(struct ARMCore* cpu, uint32_t address, int* cycleCounter) { wait = memory->waitstatesNonseq16[address >> BASE_OFFSET]; if ((address & (SIZE_CART0 - 1)) < memory->romSize) { LOAD_16(value, address & (SIZE_CART0 - 2), memory->rom); + } else if (memory->mirroring && (address & memory->romMask) < memory->romSize) { + LOAD_16(value, address & memory->romMask, memory->rom); } else { mLOG(GBA_MEM, GAME_ERROR, "Out of bounds ROM Load16: 0x%08X", address); value = (address >> 1) & 0xFFFF; @@ -513,6 +523,8 @@ uint32_t GBALoad16(struct ARMCore* cpu, uint32_t address, int* cycleCounter) { value = GBASavedataReadEEPROM(&memory->savedata); } else if ((address & (SIZE_CART0 - 1)) < memory->romSize) { LOAD_16(value, address & (SIZE_CART0 - 2), memory->rom); + } else if (memory->mirroring && (address & memory->romMask) < memory->romSize) { + LOAD_16(value, address & memory->romMask, memory->rom); } else { mLOG(GBA_MEM, GAME_ERROR, "Out of bounds ROM Load16: 0x%08X", address); value = (address >> 1) & 0xFFFF; @@ -596,6 +608,8 @@ uint32_t GBALoad8(struct ARMCore* cpu, uint32_t address, int* cycleCounter) { wait = memory->waitstatesNonseq16[address >> BASE_OFFSET]; if ((address & (SIZE_CART0 - 1)) < memory->romSize) { value = ((uint8_t*) memory->rom)[address & (SIZE_CART0 - 1)]; + } else if (memory->mirroring && (address & memory->romMask) < memory->romSize) { + value = ((uint8_t*) memory->rom)[address & memory->romMask]; } else { mLOG(GBA_MEM, GAME_ERROR, "Out of bounds ROM Load8: 0x%08X", address); value = (address >> 1) & 0xFF; diff --git a/src/gba/memory.h b/src/gba/memory.h index 8527b1d53..98ea60a34 100644 --- a/src/gba/memory.h +++ b/src/gba/memory.h @@ -142,6 +142,8 @@ struct GBAMemory { int activeDMA; int32_t nextDMA; int32_t eventDiff; + + bool mirroring; }; void GBAMemoryInit(struct GBA* gba);