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;
void* pristineRom;
bool isPristine;
size_t pristineRomSize;
size_t yankedRomSize;
uint32_t romCrc32;

View File

@ -17,7 +17,7 @@ mLOG_DECLARE_CATEGORY(GB_MBC);
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 {

View File

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

View File

@ -79,7 +79,7 @@ static void GBInit(void* cpu, struct mCPUComponent* component) {
gb->sramVf = NULL;
gb->sramRealVf = NULL;
gb->pristineRom = 0;
gb->isPristine = false;
gb->pristineRomSize = 0;
gb->yankedRomSize = 0;
@ -108,24 +108,23 @@ bool GBLoadROM(struct GB* gb, struct VFile* vf) {
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 GBSavedataUnmask(struct GB* gb) {
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 @@ void GBApplyPatch(struct GB* gb, struct Patch* patch) {
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 @@ void GBGetGameTitle(const struct GB* gb, char* out) {
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;
}
@ -671,9 +678,6 @@ void GBGetGameCode(const struct GB* gb, char* out) {
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;
}

View File

@ -6,6 +6,7 @@
#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 @@ void _GBMBC1(struct GB* gb, uint16_t address, uint8_t value) {
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 @@ void _GBMBC1(struct GB* gb, uint16_t address, uint8_t value) {
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 @@ void _GBMBC2(struct GB* gb, uint16_t address, uint8_t value) {
if (!bank) {
++bank;
}
GBMBCSwitchBank(memory, bank);
GBMBCSwitchBank(gb, bank);
break;
default:
// TODO
@ -328,7 +332,7 @@ void _GBMBC3(struct GB* gb, uint16_t address, uint8_t value) {
if (!bank) {
++bank;
}
GBMBCSwitchBank(memory, bank);
GBMBCSwitchBank(gb, bank);
break;
case 0x2:
if (value < 4) {
@ -372,11 +376,11 @@ void _GBMBC5(struct GB* gb, uint16_t address, uint8_t value) {
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 @@ void _GBMBC6(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;
switch (address >> 13) {
case 0x1:
GBMBCSwitchBank(memory, bank);
GBMBCSwitchBank(gb, bank);
break;
case 0x2:
if (value < 0x10) {
@ -616,7 +619,7 @@ void _GBHuC3(struct GB* gb, uint16_t address, uint8_t value) {
}
break;
case 0x1:
GBMBCSwitchBank(memory, bank);
GBMBCSwitchBank(gb, bank);
break;
case 0x2:
GBMBCSwitchSramBank(gb, bank);

View File

@ -614,7 +614,7 @@ void GBMemoryDeserialize(struct GB* gb, const struct GBSerializedState* state) {
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 @@ void GBMemoryDeserialize(struct GB* gb, const struct GBSerializedState* state) {
}
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);
}

View File

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

View File

@ -104,7 +104,7 @@ static void GBAInit(void* cpu, struct mCPUComponent* component) {
gba->performingDMA = false;
gba->pristineRom = 0;
gba->isPristine = false;
gba->pristineRomSize = 0;
gba->yankedRomSize = 0;
@ -112,22 +112,22 @@ static void GBAInit(void* cpu, struct mCPUComponent* component) {
}
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 @@ bool GBALoadMB(struct GBA* gba, struct VFile* vf) {
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 @@ bool GBALoadROM(struct GBA* gba, struct VFile* vf) {
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 @@ void GBAApplyPatch(struct GBA* gba, struct Patch* patch) {
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 @@ void GBAGetGameTitle(const struct GBA* gba, char* out) {
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);

View File

@ -102,13 +102,12 @@ void GBAMemoryDeinit(struct GBA* gba) {
}
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 @@ void GBAMemoryDeserialize(struct GBAMemory* memory, const struct GBASerializedSt
}
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];
}