GBA, GB: ROM is now unloaded if a patch is applied

This commit is contained in:
Vicki Pfau 2017-02-01 13:38:11 -08:00
parent af77e5ab62
commit 28a3ac50a6
9 changed files with 108 additions and 84 deletions

View File

@ -63,7 +63,7 @@ struct GB {
uint8_t* keySource; uint8_t* keySource;
void* pristineRom; bool isPristine;
size_t pristineRomSize; size_t pristineRomSize;
size_t yankedRomSize; size_t yankedRomSize;
uint32_t romCrc32; uint32_t romCrc32;

View File

@ -17,7 +17,7 @@ mLOG_DECLARE_CATEGORY(GB_MBC);
struct GB; struct GB;
struct GBMemory; struct GBMemory;
void GBMBCInit(struct GB* gb); 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); void GBMBCSwitchSramBank(struct GB* gb, int bank);
struct GBMBCRTCSaveBuffer { struct GBMBCRTCSaveBuffer {

View File

@ -90,7 +90,7 @@ struct GBA {
struct mRumble* rumble; struct mRumble* rumble;
struct GBARRContext* rr; struct GBARRContext* rr;
void* pristineRom; bool isPristine;
size_t pristineRomSize; size_t pristineRomSize;
size_t yankedRomSize; size_t yankedRomSize;
uint32_t romCrc32; uint32_t romCrc32;

View File

@ -79,7 +79,7 @@ static void GBInit(void* cpu, struct mCPUComponent* component) {
gb->sramVf = NULL; gb->sramVf = NULL;
gb->sramRealVf = NULL; gb->sramRealVf = NULL;
gb->pristineRom = 0; gb->isPristine = false;
gb->pristineRomSize = 0; gb->pristineRomSize = 0;
gb->yankedRomSize = 0; gb->yankedRomSize = 0;
@ -108,24 +108,23 @@ bool GBLoadROM(struct GB* gb, struct VFile* vf) {
gb->romVf = vf; gb->romVf = vf;
gb->pristineRomSize = vf->size(vf); gb->pristineRomSize = vf->size(vf);
vf->seek(vf, 0, SEEK_SET); vf->seek(vf, 0, SEEK_SET);
gb->isPristine = true;
#ifdef _3DS #ifdef _3DS
gb->pristineRom = 0;
if (gb->pristineRomSize <= romBufferSize) { if (gb->pristineRomSize <= romBufferSize) {
gb->pristineRom = romBuffer; gb->memory.rom = romBuffer;
vf->read(vf, romBuffer, gb->pristineRomSize); vf->read(vf, romBuffer, gb->pristineRomSize);
} }
#else #else
gb->pristineRom = vf->map(vf, gb->pristineRomSize, MAP_READ); gb->memory.rom = vf->map(vf, gb->pristineRomSize, MAP_READ);
#endif #endif
if (!gb->pristineRom) { if (!gb->memory.rom) {
return false; return false;
} }
gb->yankedRomSize = 0; gb->yankedRomSize = 0;
gb->memory.rom = gb->pristineRom;
gb->memory.romBase = gb->memory.rom; gb->memory.romBase = gb->memory.rom;
gb->memory.romSize = gb->pristineRomSize; gb->memory.romSize = gb->pristineRomSize;
gb->romCrc32 = doCrc32(gb->memory.rom, gb->memory.romSize); gb->romCrc32 = doCrc32(gb->memory.rom, gb->memory.romSize);
GBMBCSwitchBank(&gb->memory, gb->memory.currentBank); GBMBCSwitchBank(gb, gb->memory.currentBank);
if (gb->cpu) { if (gb->cpu) {
struct LR35902Core* cpu = gb->cpu; struct LR35902Core* cpu = gb->cpu;
@ -263,26 +262,25 @@ void GBSavedataUnmask(struct GB* gb) {
void GBUnloadROM(struct GB* gb) { void GBUnloadROM(struct GB* gb) {
// TODO: Share with GBAUnloadROM // 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); free(gb->memory.romBase);
} }
if (gb->memory.rom && gb->pristineRom != gb->memory.rom) { if (gb->memory.rom && !gb->isPristine) {
if (gb->yankedRomSize) { if (gb->yankedRomSize) {
gb->yankedRomSize = 0; gb->yankedRomSize = 0;
} }
mappedMemoryFree(gb->memory.rom, GB_SIZE_CART_MAX); mappedMemoryFree(gb->memory.rom, GB_SIZE_CART_MAX);
gb->memory.rom = gb->pristineRom;
} }
gb->memory.rom = 0;
if (gb->romVf) { if (gb->romVf) {
#ifndef _3DS #ifndef _3DS
gb->romVf->unmap(gb->romVf, gb->pristineRom, gb->pristineRomSize); gb->romVf->unmap(gb->romVf, gb->memory.rom, gb->pristineRomSize);
#endif #endif
gb->romVf->close(gb->romVf); gb->romVf->close(gb->romVf);
gb->romVf = 0; gb->romVf = NULL;
} }
gb->pristineRom = 0; gb->memory.rom = NULL;
gb->isPristine = false;
GBSavedataUnmask(gb); GBSavedataUnmask(gb);
GBSramDeinit(gb); GBSramDeinit(gb);
@ -317,14 +315,26 @@ void GBApplyPatch(struct GB* gb, struct Patch* patch) {
if (patchedSize > GB_SIZE_CART_MAX) { if (patchedSize > GB_SIZE_CART_MAX) {
patchedSize = GB_SIZE_CART_MAX; patchedSize = GB_SIZE_CART_MAX;
} }
gb->memory.rom = anonymousMemoryMap(GB_SIZE_CART_MAX); void* newRom = anonymousMemoryMap(GB_SIZE_CART_MAX);
if (!patch->applyPatch(patch, gb->pristineRom, gb->pristineRomSize, gb->memory.rom, patchedSize)) { if (!patch->applyPatch(patch, gb->memory.rom, gb->pristineRomSize, newRom, patchedSize)) {
mappedMemoryFree(gb->memory.rom, patchedSize); mappedMemoryFree(newRom, GB_SIZE_CART_MAX);
gb->memory.rom = gb->pristineRom;
return; 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->memory.romSize = patchedSize;
gb->romCrc32 = doCrc32(gb->memory.rom, gb->memory.romSize); gb->romCrc32 = doCrc32(gb->memory.rom, gb->memory.romSize);
gb->cpu->memory.setActiveRegion(gb->cpu, gb->cpu->pc);
} }
void GBDestroy(struct GB* gb) { void GBDestroy(struct GB* gb) {
@ -652,9 +662,6 @@ void GBGetGameTitle(const struct GB* gb, char* out) {
if (gb->memory.rom) { if (gb->memory.rom) {
cart = (const struct GBCartridge*) &gb->memory.rom[0x100]; cart = (const struct GBCartridge*) &gb->memory.rom[0x100];
} }
if (gb->pristineRom) {
cart = (const struct GBCartridge*) &((uint8_t*) gb->pristineRom)[0x100];
}
if (!cart) { if (!cart) {
return; return;
} }
@ -671,9 +678,6 @@ void GBGetGameCode(const struct GB* gb, char* out) {
if (gb->memory.rom) { if (gb->memory.rom) {
cart = (const struct GBCartridge*) &gb->memory.rom[0x100]; cart = (const struct GBCartridge*) &gb->memory.rom[0x100];
} }
if (gb->pristineRom) {
cart = (const struct GBCartridge*) &((uint8_t*) gb->pristineRom)[0x100];
}
if (!cart) { if (!cart) {
return; return;
} }

View File

@ -6,6 +6,7 @@
#include <mgba/internal/gb/mbc.h> #include <mgba/internal/gb/mbc.h>
#include <mgba/core/interface.h> #include <mgba/core/interface.h>
#include <mgba/internal/lr35902/lr35902.h>
#include <mgba/internal/gb/gb.h> #include <mgba/internal/gb/gb.h>
#include <mgba/internal/gb/memory.h> #include <mgba/internal/gb/memory.h>
#include <mgba-util/vfs.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 _GBMBC7(struct GB*, uint16_t address, uint8_t value);
static void _GBHuC3(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; 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); 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; bank = bankStart / GB_SIZE_CART_BANK0;
if (!bank) { if (!bank) {
++bank; ++bank;
} }
} }
memory->romBank = &memory->rom[bankStart]; gb->memory.romBank = &gb->memory.rom[bankStart];
memory->currentBank = bank; 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) { void GBMBCSwitchSramBank(struct GB* gb, int bank) {
@ -249,12 +253,12 @@ void _GBMBC1(struct GB* gb, uint16_t address, uint8_t value) {
if (!bank) { if (!bank) {
++bank; ++bank;
} }
GBMBCSwitchBank(memory, bank | (memory->currentBank & 0x60)); GBMBCSwitchBank(gb, bank | (memory->currentBank & 0x60));
break; break;
case 0x2: case 0x2:
bank &= 3; bank &= 3;
if (!memory->mbcState.mbc1.mode) { if (!memory->mbcState.mbc1.mode) {
GBMBCSwitchBank(memory, (bank << 5) | (memory->currentBank & 0x1F)); GBMBCSwitchBank(gb, (bank << 5) | (memory->currentBank & 0x1F));
} else { } else {
GBMBCSwitchSramBank(gb, bank); GBMBCSwitchSramBank(gb, bank);
} }
@ -262,7 +266,7 @@ void _GBMBC1(struct GB* gb, uint16_t address, uint8_t value) {
case 0x3: case 0x3:
memory->mbcState.mbc1.mode = value & 1; memory->mbcState.mbc1.mode = value & 1;
if (memory->mbcState.mbc1.mode) { if (memory->mbcState.mbc1.mode) {
GBMBCSwitchBank(memory, memory->currentBank & 0x1F); GBMBCSwitchBank(gb, memory->currentBank & 0x1F);
} else { } else {
GBMBCSwitchSramBank(gb, 0); GBMBCSwitchSramBank(gb, 0);
} }
@ -297,7 +301,7 @@ void _GBMBC2(struct GB* gb, uint16_t address, uint8_t value) {
if (!bank) { if (!bank) {
++bank; ++bank;
} }
GBMBCSwitchBank(memory, bank); GBMBCSwitchBank(gb, bank);
break; break;
default: default:
// TODO // TODO
@ -328,7 +332,7 @@ void _GBMBC3(struct GB* gb, uint16_t address, uint8_t value) {
if (!bank) { if (!bank) {
++bank; ++bank;
} }
GBMBCSwitchBank(memory, bank); GBMBCSwitchBank(gb, bank);
break; break;
case 0x2: case 0x2:
if (value < 4) { if (value < 4) {
@ -372,11 +376,11 @@ void _GBMBC5(struct GB* gb, uint16_t address, uint8_t value) {
break; break;
case 0x2: case 0x2:
bank = (memory->currentBank & 0x100) | value; bank = (memory->currentBank & 0x100) | value;
GBMBCSwitchBank(memory, bank); GBMBCSwitchBank(gb, bank);
break; break;
case 0x3: case 0x3:
bank = (memory->currentBank & 0xFF) | ((value & 1) << 8); bank = (memory->currentBank & 0xFF) | ((value & 1) << 8);
GBMBCSwitchBank(memory, bank); GBMBCSwitchBank(gb, bank);
break; break;
case 0x4: case 0x4:
case 0x5: case 0x5:
@ -402,11 +406,10 @@ void _GBMBC6(struct GB* gb, uint16_t address, uint8_t value) {
} }
void _GBMBC7(struct GB* gb, uint16_t address, uint8_t value) { void _GBMBC7(struct GB* gb, uint16_t address, uint8_t value) {
struct GBMemory* memory = &gb->memory;
int bank = value & 0x7F; int bank = value & 0x7F;
switch (address >> 13) { switch (address >> 13) {
case 0x1: case 0x1:
GBMBCSwitchBank(memory, bank); GBMBCSwitchBank(gb, bank);
break; break;
case 0x2: case 0x2:
if (value < 0x10) { if (value < 0x10) {
@ -616,7 +619,7 @@ void _GBHuC3(struct GB* gb, uint16_t address, uint8_t value) {
} }
break; break;
case 0x1: case 0x1:
GBMBCSwitchBank(memory, bank); GBMBCSwitchBank(gb, bank);
break; break;
case 0x2: case 0x2:
GBMBCSwitchSramBank(gb, bank); GBMBCSwitchSramBank(gb, bank);

View File

@ -614,7 +614,7 @@ void GBMemoryDeserialize(struct GB* gb, const struct GBSerializedState* state) {
memory->wramCurrentBank = state->memory.wramCurrentBank; memory->wramCurrentBank = state->memory.wramCurrentBank;
memory->sramCurrentBank = state->memory.sramCurrentBank; memory->sramCurrentBank = state->memory.sramCurrentBank;
GBMBCSwitchBank(memory, memory->currentBank); GBMBCSwitchBank(gb, memory->currentBank);
GBMemorySwitchWramBank(memory, memory->wramCurrentBank); GBMemorySwitchWramBank(memory, memory->wramCurrentBank);
GBMBCSwitchSramBank(gb, memory->sramCurrentBank); GBMBCSwitchSramBank(gb, memory->sramCurrentBank);
@ -651,14 +651,15 @@ void GBMemoryDeserialize(struct GB* gb, const struct GBSerializedState* state) {
} }
void _pristineCow(struct GB* gb) { void _pristineCow(struct GB* gb) {
if (gb->memory.rom != gb->pristineRom) { if (!gb->isPristine) {
return; return;
} }
gb->memory.rom = anonymousMemoryMap(GB_SIZE_CART_MAX); void* newRom = anonymousMemoryMap(GB_SIZE_CART_MAX);
memcpy(gb->memory.rom, gb->pristineRom, gb->memory.romSize); memcpy(newRom, gb->memory.rom, gb->memory.romSize);
memset(((uint8_t*) gb->memory.rom) + gb->memory.romSize, 0xFF, GB_SIZE_CART_MAX - gb->memory.romSize); memset(((uint8_t*) newRom) + gb->memory.romSize, 0xFF, GB_SIZE_CART_MAX - gb->memory.romSize);
if (gb->pristineRom == gb->memory.romBase) { if (gb->memory.rom == gb->memory.romBase) {
gb->memory.romBase = gb->memory.rom; gb->memory.romBase = newRom;
} }
GBMBCSwitchBank(&gb->memory, gb->memory.currentBank); gb->memory.rom = newRom;
GBMBCSwitchBank(gb, gb->memory.currentBank);
} }

View File

@ -323,7 +323,7 @@ static void _GBACoreReset(struct mCore* core) {
#endif #endif
ARMReset(core->cpu); ARMReset(core->cpu);
if (core->opts.skipBios && gba->pristineRom) { if (core->opts.skipBios && gba->isPristine) {
GBASkipBIOS(core->board); GBASkipBIOS(core->board);
} }
} }

View File

@ -104,7 +104,7 @@ static void GBAInit(void* cpu, struct mCPUComponent* component) {
gba->performingDMA = false; gba->performingDMA = false;
gba->pristineRom = 0; gba->isPristine = false;
gba->pristineRomSize = 0; gba->pristineRomSize = 0;
gba->yankedRomSize = 0; gba->yankedRomSize = 0;
@ -112,22 +112,22 @@ static void GBAInit(void* cpu, struct mCPUComponent* component) {
} }
void GBAUnloadROM(struct GBA* gba) { void GBAUnloadROM(struct GBA* gba) {
if (gba->memory.rom && gba->pristineRom != gba->memory.rom) { if (gba->memory.rom && !gba->isPristine) {
if (gba->yankedRomSize) { if (gba->yankedRomSize) {
gba->yankedRomSize = 0; gba->yankedRomSize = 0;
} }
mappedMemoryFree(gba->memory.rom, SIZE_CART0); mappedMemoryFree(gba->memory.rom, SIZE_CART0);
} }
gba->memory.rom = 0;
if (gba->romVf) { if (gba->romVf) {
#ifndef _3DS #ifndef _3DS
gba->romVf->unmap(gba->romVf, gba->pristineRom, gba->pristineRomSize); gba->romVf->unmap(gba->romVf, gba->memory.rom, gba->pristineRomSize);
#endif #endif
gba->romVf->close(gba->romVf); 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); GBASavedataDeinit(&gba->memory.savedata);
if (gba->memory.savedata.realVf) { if (gba->memory.savedata.realVf) {
@ -291,23 +291,23 @@ bool GBALoadMB(struct GBA* gba, struct VFile* vf) {
if (gba->pristineRomSize > SIZE_WORKING_RAM) { if (gba->pristineRomSize > SIZE_WORKING_RAM) {
gba->pristineRomSize = SIZE_WORKING_RAM; gba->pristineRomSize = SIZE_WORKING_RAM;
} }
gba->isPristine = true;
#ifdef _3DS #ifdef _3DS
gba->pristineRom = 0;
if (gba->pristineRomSize <= romBufferSize) { if (gba->pristineRomSize <= romBufferSize) {
gba->pristineRom = romBuffer; gba->memory.wram = romBuffer;
vf->read(vf, romBuffer, gba->pristineRomSize); vf->read(vf, romBuffer, gba->pristineRomSize);
} }
#else #else
gba->pristineRom = vf->map(vf, gba->pristineRomSize, MAP_READ); gba->memory.wram = vf->map(vf, gba->pristineRomSize, MAP_READ);
#endif #endif
if (!gba->pristineRom) { if (!gba->memory.wram) {
mLOG(GBA, WARN, "Couldn't map ROM"); mLOG(GBA, WARN, "Couldn't map ROM");
return false; return false;
} }
gba->yankedRomSize = 0; gba->yankedRomSize = 0;
gba->memory.romSize = 0; gba->memory.romSize = 0;
gba->memory.romMask = 0; gba->memory.romMask = 0;
gba->romCrc32 = doCrc32(gba->pristineRom, gba->pristineRomSize); gba->romCrc32 = doCrc32(gba->memory.wram, gba->pristineRomSize);
return true; return true;
} }
@ -322,21 +322,20 @@ bool GBALoadROM(struct GBA* gba, struct VFile* vf) {
if (gba->pristineRomSize > SIZE_CART0) { if (gba->pristineRomSize > SIZE_CART0) {
gba->pristineRomSize = SIZE_CART0; gba->pristineRomSize = SIZE_CART0;
} }
gba->isPristine = true;
#ifdef _3DS #ifdef _3DS
gba->pristineRom = 0;
if (gba->pristineRomSize <= romBufferSize) { if (gba->pristineRomSize <= romBufferSize) {
gba->pristineRom = romBuffer; gba->memory.rom = romBuffer;
vf->read(vf, romBuffer, gba->pristineRomSize); vf->read(vf, romBuffer, gba->pristineRomSize);
} }
#else #else
gba->pristineRom = vf->map(vf, gba->pristineRomSize, MAP_READ); gba->memory.rom = vf->map(vf, gba->pristineRomSize, MAP_READ);
#endif #endif
if (!gba->pristineRom) { if (!gba->memory.rom) {
mLOG(GBA, WARN, "Couldn't map ROM"); mLOG(GBA, WARN, "Couldn't map ROM");
return false; return false;
} }
gba->yankedRomSize = 0; gba->yankedRomSize = 0;
gba->memory.rom = gba->pristineRom;
gba->memory.romSize = gba->pristineRomSize; gba->memory.romSize = gba->pristineRomSize;
gba->memory.romMask = toPow2(gba->memory.romSize) - 1; gba->memory.romMask = toPow2(gba->memory.romSize) - 1;
gba->memory.mirroring = false; gba->memory.mirroring = false;
@ -389,12 +388,21 @@ void GBAApplyPatch(struct GBA* gba, struct Patch* patch) {
if (!patchedSize || patchedSize > SIZE_CART0) { if (!patchedSize || patchedSize > SIZE_CART0) {
return; return;
} }
gba->memory.rom = anonymousMemoryMap(SIZE_CART0); void* newRom = anonymousMemoryMap(SIZE_CART0);
if (!patch->applyPatch(patch, gba->pristineRom, gba->pristineRomSize, gba->memory.rom, patchedSize)) { if (!patch->applyPatch(patch, gba->memory.rom, gba->pristineRomSize, newRom, patchedSize)) {
mappedMemoryFree(gba->memory.rom, patchedSize); mappedMemoryFree(newRom, SIZE_CART0);
gba->memory.rom = gba->pristineRom;
return; 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.romSize = patchedSize;
gba->memory.romMask = SIZE_CART0 - 1; gba->memory.romMask = SIZE_CART0 - 1;
gba->romCrc32 = doCrc32(gba->memory.rom, gba->memory.romSize); gba->romCrc32 = doCrc32(gba->memory.rom, gba->memory.romSize);
@ -540,8 +548,8 @@ void GBAGetGameTitle(const struct GBA* gba, char* out) {
memcpy(out, &((struct GBACartridge*) gba->memory.rom)->title, 12); memcpy(out, &((struct GBACartridge*) gba->memory.rom)->title, 12);
return; return;
} }
if (gba->pristineRom) { if (gba->isPristine && gba->memory.wram) {
memcpy(out, &((struct GBACartridge*) gba->pristineRom)->title, 12); memcpy(out, &((struct GBACartridge*) gba->memory.wram)->title, 12);
return; return;
} }
strncpy(out, "(BIOS)", 12); strncpy(out, "(BIOS)", 12);

View File

@ -102,13 +102,12 @@ void GBAMemoryDeinit(struct GBA* gba) {
} }
void GBAMemoryReset(struct GBA* gba) { void GBAMemoryReset(struct GBA* gba) {
if (gba->memory.rom || gb->fullBios) {
// Not multiboot
if (gba->memory.wram) { if (gba->memory.wram) {
mappedMemoryFree(gba->memory.wram, SIZE_WORKING_RAM); mappedMemoryFree(gba->memory.wram, SIZE_WORKING_RAM);
} }
gba->memory.wram = anonymousMemoryMap(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.iwram) { if (gba->memory.iwram) {
@ -1541,10 +1540,19 @@ void GBAMemoryDeserialize(struct GBAMemory* memory, const struct GBASerializedSt
} }
void _pristineCow(struct GBA* gba) { void _pristineCow(struct GBA* gba) {
if (gba->memory.rom != gba->pristineRom) { if (!gba->isPristine) {
return; return;
} }
gba->memory.rom = anonymousMemoryMap(SIZE_CART0); void* newRom = anonymousMemoryMap(SIZE_CART0);
memcpy(gba->memory.rom, gba->pristineRom, gba->memory.romSize); memcpy(newRom, gba->memory.rom, gba->memory.romSize);
memset(((uint8_t*) gba->memory.rom) + gba->memory.romSize, 0xFF, SIZE_CART0 - 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];
} }