GBA, GB: ROM is now unloaded if a patch is applied
@@ -63,7 +63,7 @@ struct mTiming timing;
uint8_t* keySource; - void* pristineRom; + bool isPristine; size_t pristineRomSize; size_t yankedRomSize; uint32_t romCrc32;
@@ -17,7 +17,7 @@
struct GB; struct GBMemory; void GBMBCInit(struct GB* gb); -void GBMBCSwitchBank(struct GBMemory* memory, int bank); +void GBMBCSwitchBank(struct GB* gb, int bank); void GBMBCSwitchSramBank(struct GB* gb, int bank); struct GBMBCRTCSaveBuffer {
@@ -90,7 +90,7 @@ struct mRTCSource* rtcSource;
struct mRumble* rumble; struct GBARRContext* rr; - void* pristineRom; + bool isPristine; size_t pristineRomSize; size_t yankedRomSize; uint32_t romCrc32;
@@ -79,7 +79,7 @@ gb->romVf = NULL;
gb->sramVf = NULL; gb->sramRealVf = NULL; - gb->pristineRom = 0; + gb->isPristine = false; gb->pristineRomSize = 0; gb->yankedRomSize = 0;@@ -108,24 +108,23 @@ GBUnloadROM(gb);
gb->romVf = vf; gb->pristineRomSize = vf->size(vf); vf->seek(vf, 0, SEEK_SET); + gb->isPristine = true; #ifdef _3DS - gb->pristineRom = 0; if (gb->pristineRomSize <= romBufferSize) { - gb->pristineRom = romBuffer; + gb->memory.rom = romBuffer; vf->read(vf, romBuffer, gb->pristineRomSize); } #else - gb->pristineRom = vf->map(vf, gb->pristineRomSize, MAP_READ); + gb->memory.rom = vf->map(vf, gb->pristineRomSize, MAP_READ); #endif - if (!gb->pristineRom) { + if (!gb->memory.rom) { return false; } gb->yankedRomSize = 0; - gb->memory.rom = gb->pristineRom; gb->memory.romBase = gb->memory.rom; gb->memory.romSize = gb->pristineRomSize; gb->romCrc32 = doCrc32(gb->memory.rom, gb->memory.romSize); - GBMBCSwitchBank(&gb->memory, gb->memory.currentBank); + GBMBCSwitchBank(gb, gb->memory.currentBank); if (gb->cpu) { struct LR35902Core* cpu = gb->cpu;@@ -263,26 +262,25 @@ }
void GBUnloadROM(struct GB* gb) { // TODO: Share with GBAUnloadROM - if (gb->memory.rom && gb->memory.romBase != gb->memory.rom && gb->memory.romBase != gb->pristineRom) { + if (gb->memory.rom && gb->memory.romBase != gb->memory.rom && !gb->isPristine) { free(gb->memory.romBase); } - if (gb->memory.rom && gb->pristineRom != gb->memory.rom) { + if (gb->memory.rom && !gb->isPristine) { if (gb->yankedRomSize) { gb->yankedRomSize = 0; } mappedMemoryFree(gb->memory.rom, GB_SIZE_CART_MAX); - gb->memory.rom = gb->pristineRom; } - gb->memory.rom = 0; if (gb->romVf) { #ifndef _3DS - gb->romVf->unmap(gb->romVf, gb->pristineRom, gb->pristineRomSize); + gb->romVf->unmap(gb->romVf, gb->memory.rom, gb->pristineRomSize); #endif gb->romVf->close(gb->romVf); - gb->romVf = 0; + gb->romVf = NULL; } - gb->pristineRom = 0; + gb->memory.rom = NULL; + gb->isPristine = false; GBSavedataUnmask(gb); GBSramDeinit(gb);@@ -317,14 +315,26 @@ }
if (patchedSize > GB_SIZE_CART_MAX) { patchedSize = GB_SIZE_CART_MAX; } - gb->memory.rom = anonymousMemoryMap(GB_SIZE_CART_MAX); - if (!patch->applyPatch(patch, gb->pristineRom, gb->pristineRomSize, gb->memory.rom, patchedSize)) { - mappedMemoryFree(gb->memory.rom, patchedSize); - gb->memory.rom = gb->pristineRom; + void* newRom = anonymousMemoryMap(GB_SIZE_CART_MAX); + if (!patch->applyPatch(patch, gb->memory.rom, gb->pristineRomSize, newRom, patchedSize)) { + mappedMemoryFree(newRom, GB_SIZE_CART_MAX); return; } + if (gb->romVf) { +#ifndef _3DS + gb->romVf->unmap(gb->romVf, gb->memory.rom, gb->pristineRomSize); +#endif + gb->romVf->close(gb->romVf); + gb->romVf = NULL; + } + gb->isPristine = false; + if (gb->memory.romBase == gb->memory.rom) { + gb->memory.romBase = newRom; + } + gb->memory.rom = newRom; gb->memory.romSize = patchedSize; gb->romCrc32 = doCrc32(gb->memory.rom, gb->memory.romSize); + gb->cpu->memory.setActiveRegion(gb->cpu, gb->cpu->pc); } void GBDestroy(struct GB* gb) {@@ -652,9 +662,6 @@ const struct GBCartridge* cart = NULL;
if (gb->memory.rom) { cart = (const struct GBCartridge*) &gb->memory.rom[0x100]; } - if (gb->pristineRom) { - cart = (const struct GBCartridge*) &((uint8_t*) gb->pristineRom)[0x100]; - } if (!cart) { return; }@@ -670,9 +677,6 @@ memset(out, 0, 8);
const struct GBCartridge* cart = NULL; if (gb->memory.rom) { cart = (const struct GBCartridge*) &gb->memory.rom[0x100]; - } - if (gb->pristineRom) { - cart = (const struct GBCartridge*) &((uint8_t*) gb->pristineRom)[0x100]; } if (!cart) { return;
@@ -6,6 +6,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <mgba/internal/gb/mbc.h> #include <mgba/core/interface.h> +#include <mgba/internal/lr35902/lr35902.h> #include <mgba/internal/gb/gb.h> #include <mgba/internal/gb/memory.h> #include <mgba-util/vfs.h>@@ -28,18 +29,21 @@ static void _GBMBC6(struct GB*, uint16_t address, uint8_t value);
static void _GBMBC7(struct GB*, uint16_t address, uint8_t value); static void _GBHuC3(struct GB*, uint16_t address, uint8_t value); -void GBMBCSwitchBank(struct GBMemory* memory, int bank) { +void GBMBCSwitchBank(struct GB* gb, int bank) { size_t bankStart = bank * GB_SIZE_CART_BANK0; - if (bankStart + GB_SIZE_CART_BANK0 > memory->romSize) { + if (bankStart + GB_SIZE_CART_BANK0 > gb->memory.romSize) { mLOG(GB_MBC, GAME_ERROR, "Attempting to switch to an invalid ROM bank: %0X", bank); - bankStart &= (memory->romSize - 1); + bankStart &= (gb->memory.romSize - 1); bank = bankStart / GB_SIZE_CART_BANK0; if (!bank) { ++bank; } } - memory->romBank = &memory->rom[bankStart]; - memory->currentBank = bank; + gb->memory.romBank = &gb->memory.rom[bankStart]; + gb->memory.currentBank = bank; + if (gb->cpu->pc < GB_BASE_VRAM) { + gb->cpu->memory.setActiveRegion(gb->cpu, gb->cpu->pc); + } } void GBMBCSwitchSramBank(struct GB* gb, int bank) {@@ -249,12 +253,12 @@ case 0x1:
if (!bank) { ++bank; } - GBMBCSwitchBank(memory, bank | (memory->currentBank & 0x60)); + GBMBCSwitchBank(gb, bank | (memory->currentBank & 0x60)); break; case 0x2: bank &= 3; if (!memory->mbcState.mbc1.mode) { - GBMBCSwitchBank(memory, (bank << 5) | (memory->currentBank & 0x1F)); + GBMBCSwitchBank(gb, (bank << 5) | (memory->currentBank & 0x1F)); } else { GBMBCSwitchSramBank(gb, bank); }@@ -262,7 +266,7 @@ break;
case 0x3: memory->mbcState.mbc1.mode = value & 1; if (memory->mbcState.mbc1.mode) { - GBMBCSwitchBank(memory, memory->currentBank & 0x1F); + GBMBCSwitchBank(gb, memory->currentBank & 0x1F); } else { GBMBCSwitchSramBank(gb, 0); }@@ -297,7 +301,7 @@ case 0x1:
if (!bank) { ++bank; } - GBMBCSwitchBank(memory, bank); + GBMBCSwitchBank(gb, bank); break; default: // TODO@@ -328,7 +332,7 @@ case 0x1:
if (!bank) { ++bank; } - GBMBCSwitchBank(memory, bank); + GBMBCSwitchBank(gb, bank); break; case 0x2: if (value < 4) {@@ -372,11 +376,11 @@ }
break; case 0x2: bank = (memory->currentBank & 0x100) | value; - GBMBCSwitchBank(memory, bank); + GBMBCSwitchBank(gb, bank); break; case 0x3: bank = (memory->currentBank & 0xFF) | ((value & 1) << 8); - GBMBCSwitchBank(memory, bank); + GBMBCSwitchBank(gb, bank); break; case 0x4: case 0x5:@@ -402,11 +406,10 @@ UNUSED(value);
} void _GBMBC7(struct GB* gb, uint16_t address, uint8_t value) { - struct GBMemory* memory = &gb->memory; int bank = value & 0x7F; switch (address >> 13) { case 0x1: - GBMBCSwitchBank(memory, bank); + GBMBCSwitchBank(gb, bank); break; case 0x2: if (value < 0x10) {@@ -616,7 +619,7 @@ break;
} break; case 0x1: - GBMBCSwitchBank(memory, bank); + GBMBCSwitchBank(gb, bank); break; case 0x2: GBMBCSwitchSramBank(gb, bank);
@@ -614,7 +614,7 @@ LOAD_16LE(memory->currentBank, 0, &state->memory.currentBank);
memory->wramCurrentBank = state->memory.wramCurrentBank; memory->sramCurrentBank = state->memory.sramCurrentBank; - GBMBCSwitchBank(memory, memory->currentBank); + GBMBCSwitchBank(gb, memory->currentBank); GBMemorySwitchWramBank(memory, memory->wramCurrentBank); GBMBCSwitchSramBank(gb, memory->sramCurrentBank);@@ -651,14 +651,15 @@ memory->activeRtcReg = GBSerializedMemoryFlagsGetActiveRtcReg(flags);
} void _pristineCow(struct GB* gb) { - if (gb->memory.rom != gb->pristineRom) { + if (!gb->isPristine) { return; } - gb->memory.rom = anonymousMemoryMap(GB_SIZE_CART_MAX); - memcpy(gb->memory.rom, gb->pristineRom, gb->memory.romSize); - memset(((uint8_t*) gb->memory.rom) + gb->memory.romSize, 0xFF, GB_SIZE_CART_MAX - gb->memory.romSize); - if (gb->pristineRom == gb->memory.romBase) { - gb->memory.romBase = gb->memory.rom; + void* newRom = anonymousMemoryMap(GB_SIZE_CART_MAX); + memcpy(newRom, gb->memory.rom, gb->memory.romSize); + memset(((uint8_t*) newRom) + gb->memory.romSize, 0xFF, GB_SIZE_CART_MAX - gb->memory.romSize); + if (gb->memory.rom == gb->memory.romBase) { + gb->memory.romBase = newRom; } - GBMBCSwitchBank(&gb->memory, gb->memory.currentBank); + gb->memory.rom = newRom; + GBMBCSwitchBank(gb, gb->memory.currentBank); }
@@ -323,7 +323,7 @@ }
#endif ARMReset(core->cpu); - if (core->opts.skipBios && gba->pristineRom) { + if (core->opts.skipBios && gba->isPristine) { GBASkipBIOS(core->board); } }
@@ -104,7 +104,7 @@ gba->allowOpposingDirections = true;
gba->performingDMA = false; - gba->pristineRom = 0; + gba->isPristine = false; gba->pristineRomSize = 0; gba->yankedRomSize = 0;@@ -112,22 +112,22 @@ mTimingInit(&gba->timing, &gba->cpu->cycles, &gba->cpu->nextEvent);
} void GBAUnloadROM(struct GBA* gba) { - if (gba->memory.rom && gba->pristineRom != gba->memory.rom) { + if (gba->memory.rom && !gba->isPristine) { if (gba->yankedRomSize) { gba->yankedRomSize = 0; } mappedMemoryFree(gba->memory.rom, SIZE_CART0); } - gba->memory.rom = 0; if (gba->romVf) { #ifndef _3DS - gba->romVf->unmap(gba->romVf, gba->pristineRom, gba->pristineRomSize); + gba->romVf->unmap(gba->romVf, gba->memory.rom, gba->pristineRomSize); #endif gba->romVf->close(gba->romVf); - gba->romVf = 0; + gba->romVf = NULL; } - gba->pristineRom = 0; + gba->memory.rom = NULL; + gba->isPristine = false; GBASavedataDeinit(&gba->memory.savedata); if (gba->memory.savedata.realVf) {@@ -291,23 +291,23 @@ vf->seek(vf, 0, SEEK_SET);
if (gba->pristineRomSize > SIZE_WORKING_RAM) { gba->pristineRomSize = SIZE_WORKING_RAM; } + gba->isPristine = true; #ifdef _3DS - gba->pristineRom = 0; if (gba->pristineRomSize <= romBufferSize) { - gba->pristineRom = romBuffer; + gba->memory.wram = romBuffer; vf->read(vf, romBuffer, gba->pristineRomSize); } #else - gba->pristineRom = vf->map(vf, gba->pristineRomSize, MAP_READ); + gba->memory.wram = vf->map(vf, gba->pristineRomSize, MAP_READ); #endif - if (!gba->pristineRom) { + if (!gba->memory.wram) { mLOG(GBA, WARN, "Couldn't map ROM"); return false; } gba->yankedRomSize = 0; gba->memory.romSize = 0; gba->memory.romMask = 0; - gba->romCrc32 = doCrc32(gba->pristineRom, gba->pristineRomSize); + gba->romCrc32 = doCrc32(gba->memory.wram, gba->pristineRomSize); return true; }@@ -322,21 +322,20 @@ vf->seek(vf, 0, SEEK_SET);
if (gba->pristineRomSize > SIZE_CART0) { gba->pristineRomSize = SIZE_CART0; } + gba->isPristine = true; #ifdef _3DS - gba->pristineRom = 0; if (gba->pristineRomSize <= romBufferSize) { - gba->pristineRom = romBuffer; + gba->memory.rom = romBuffer; vf->read(vf, romBuffer, gba->pristineRomSize); } #else - gba->pristineRom = vf->map(vf, gba->pristineRomSize, MAP_READ); + gba->memory.rom = vf->map(vf, gba->pristineRomSize, MAP_READ); #endif - if (!gba->pristineRom) { + if (!gba->memory.rom) { mLOG(GBA, WARN, "Couldn't map ROM"); return false; } gba->yankedRomSize = 0; - gba->memory.rom = gba->pristineRom; gba->memory.romSize = gba->pristineRomSize; gba->memory.romMask = toPow2(gba->memory.romSize) - 1; gba->memory.mirroring = false;@@ -389,12 +388,21 @@ size_t patchedSize = patch->outputSize(patch, gba->memory.romSize);
if (!patchedSize || patchedSize > SIZE_CART0) { return; } - gba->memory.rom = anonymousMemoryMap(SIZE_CART0); - if (!patch->applyPatch(patch, gba->pristineRom, gba->pristineRomSize, gba->memory.rom, patchedSize)) { - mappedMemoryFree(gba->memory.rom, patchedSize); - gba->memory.rom = gba->pristineRom; + void* newRom = anonymousMemoryMap(SIZE_CART0); + if (!patch->applyPatch(patch, gba->memory.rom, gba->pristineRomSize, newRom, patchedSize)) { + mappedMemoryFree(newRom, SIZE_CART0); return; } + if (gba->romVf) { +#ifndef _3DS + gba->romVf->unmap(gba->romVf, gba->memory.rom, gba->pristineRomSize); +#endif + gba->romVf->close(gba->romVf); + gba->romVf = NULL; + } + gba->isPristine = false; + gba->memory.rom = newRom; + gba->memory.hw.gpioBase = &((uint16_t*) gba->memory.rom)[GPIO_REG_DATA >> 1]; gba->memory.romSize = patchedSize; gba->memory.romMask = SIZE_CART0 - 1; gba->romCrc32 = doCrc32(gba->memory.rom, gba->memory.romSize);@@ -540,8 +548,8 @@ if (gba->memory.rom) {
memcpy(out, &((struct GBACartridge*) gba->memory.rom)->title, 12); return; } - if (gba->pristineRom) { - memcpy(out, &((struct GBACartridge*) gba->pristineRom)->title, 12); + if (gba->isPristine && gba->memory.wram) { + memcpy(out, &((struct GBACartridge*) gba->memory.wram)->title, 12); return; } strncpy(out, "(BIOS)", 12);
@@ -102,13 +102,12 @@ }
} void GBAMemoryReset(struct GBA* gba) { - if (gba->memory.wram) { - mappedMemoryFree(gba->memory.wram, SIZE_WORKING_RAM); - } - gba->memory.wram = anonymousMemoryMap(SIZE_WORKING_RAM); - if (gba->pristineRom && !gba->memory.rom) { - // Multiboot - memcpy(gba->memory.wram, gba->pristineRom, gba->pristineRomSize); + if (gba->memory.rom || gb->fullBios) { + // Not multiboot + if (gba->memory.wram) { + mappedMemoryFree(gba->memory.wram, SIZE_WORKING_RAM); + } + gba->memory.wram = anonymousMemoryMap(SIZE_WORKING_RAM); } if (gba->memory.iwram) {@@ -1541,10 +1540,19 @@ memcpy(memory->iwram, state->iwram, SIZE_WORKING_IRAM);
} void _pristineCow(struct GBA* gba) { - if (gba->memory.rom != gba->pristineRom) { + if (!gba->isPristine) { return; } - gba->memory.rom = anonymousMemoryMap(SIZE_CART0); - memcpy(gba->memory.rom, gba->pristineRom, gba->memory.romSize); - memset(((uint8_t*) gba->memory.rom) + gba->memory.romSize, 0xFF, SIZE_CART0 - gba->memory.romSize); + void* newRom = anonymousMemoryMap(SIZE_CART0); + memcpy(newRom, gba->memory.rom, gba->memory.romSize); + memset(((uint8_t*) newRom) + gba->memory.romSize, 0xFF, SIZE_CART0 - gba->memory.romSize); + if (gba->romVf) { +#ifndef _3DS + gba->romVf->unmap(gba->romVf, gba->memory.rom, gba->memory.romSize); +#endif + gba->romVf->close(gba->romVf); + gba->romVf = NULL; + } + gba->memory.rom = newRom; + gba->memory.hw.gpioBase = &((uint16_t*) gba->memory.rom)[GPIO_REG_DATA >> 1]; }