From 7477c36cb5b8a949ca004e0cc3b9347b6f74dd88 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Sun, 8 May 2016 22:44:56 -0700 Subject: [PATCH] GB Memory: Implement ROM patching --- src/gb/core.c | 25 +++++++++++++++-- src/gb/memory.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 96 insertions(+), 4 deletions(-) diff --git a/src/gb/core.c b/src/gb/core.c index 217114364..0ca70be10 100644 --- a/src/gb/core.c +++ b/src/gb/core.c @@ -321,6 +321,25 @@ static uint32_t _GBCoreRawRead32(struct mCore* core, uint32_t address) { (GBLoad8(cpu, address + 2) << 16) | (GBLoad8(cpu, address + 3) << 24); } +static void _GBCoreRawWrite8(struct mCore* core, uint32_t address, uint8_t value) { + struct LR35902Core* cpu = core->cpu; + GBPatch8(cpu, address, value, NULL); +} + +static void _GBCoreRawWrite16(struct mCore* core, uint32_t address, uint16_t value) { + struct LR35902Core* cpu = core->cpu; + GBPatch8(cpu, address, value, NULL); + GBPatch8(cpu, address + 1, value >> 8, NULL); +} + +static void _GBCoreRawWrite32(struct mCore* core, uint32_t address, uint32_t value) { + struct LR35902Core* cpu = core->cpu; + GBPatch8(cpu, address, value, NULL); + GBPatch8(cpu, address + 1, value >> 8, NULL); + GBPatch8(cpu, address + 2, value >> 16, NULL); + GBPatch8(cpu, address + 3, value >> 24, NULL); +} + static bool _GBCoreSupportsDebuggerType(struct mCore* core, enum mDebuggerType type) { UNUSED(core); switch (type) { @@ -429,9 +448,9 @@ struct mCore* GBCoreCreate(void) { core->rawRead8 = _GBCoreRawRead8; core->rawRead16 = _GBCoreRawRead16; core->rawRead32 = _GBCoreRawRead32; - core->rawWrite8 = NULL; - core->rawWrite16 = NULL; - core->rawWrite32 = NULL; + core->rawWrite8 = _GBCoreRawWrite8; + core->rawWrite16 = _GBCoreRawWrite16; + core->rawWrite32 = _GBCoreRawWrite32; core->supportsDebuggerType = _GBCoreSupportsDebuggerType; core->debuggerPlatform = _GBCoreDebuggerPlatform; core->cliDebuggerSystem = _GBCoreCliDebuggerSystem; diff --git a/src/gb/memory.c b/src/gb/memory.c index 2cac8c8bd..c5271fbb7 100644 --- a/src/gb/memory.c +++ b/src/gb/memory.c @@ -16,6 +16,8 @@ mLOG_DEFINE_CATEGORY(GB_MBC, "GB MBC"); mLOG_DEFINE_CATEGORY(GB_MEM, "GB Memory"); +static void _pristineCow(struct GB* gba); + static void _GBMBCNone(struct GBMemory* memory, uint16_t address, uint8_t value) { UNUSED(memory); UNUSED(address); @@ -467,7 +469,68 @@ void GBDMAStore8(struct LR35902Core* cpu, uint16_t address, int8_t value) { GBStore8(cpu, address, value); } -void GBPatch8(struct LR35902Core* cpu, uint16_t address, int8_t value, int8_t* old); +void GBPatch8(struct LR35902Core* cpu, uint16_t address, int8_t value, int8_t* old) { + struct GB* gb = (struct GB*) cpu->master; + struct GBMemory* memory = &gb->memory; + int8_t oldValue = -1; + + switch (address >> 12) { + case GB_REGION_CART_BANK0: + case GB_REGION_CART_BANK0 + 1: + case GB_REGION_CART_BANK0 + 2: + case GB_REGION_CART_BANK0 + 3: + _pristineCow(gb); + oldValue = memory->rom[address & (GB_SIZE_CART_BANK0 - 1)]; + memory->rom[address & (GB_SIZE_CART_BANK0 - 1)] = value; + break; + case GB_REGION_CART_BANK1: + case GB_REGION_CART_BANK1 + 1: + case GB_REGION_CART_BANK1 + 2: + case GB_REGION_CART_BANK1 + 3: + _pristineCow(gb); + oldValue = memory->romBank[address & (GB_SIZE_CART_BANK0 - 1)]; + memory->romBank[address & (GB_SIZE_CART_BANK0 - 1)] = value; + break; + case GB_REGION_VRAM: + case GB_REGION_VRAM + 1: + oldValue = gb->video.vramBank[address & (GB_SIZE_VRAM_BANK0 - 1)]; + gb->video.vramBank[address & (GB_SIZE_VRAM_BANK0 - 1)] = value; + break; + case GB_REGION_EXTERNAL_RAM: + case GB_REGION_EXTERNAL_RAM + 1: + mLOG(GB_MEM, STUB, "Unimplemented memory Patch8: 0x%08X", address); + return; + case GB_REGION_WORKING_RAM_BANK0: + case GB_REGION_WORKING_RAM_BANK0 + 2: + oldValue = memory->wram[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)]; + memory->wram[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)] = value; + break; + case GB_REGION_WORKING_RAM_BANK1: + oldValue = memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)]; + memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)] = value; + break; + default: + if (address < GB_BASE_OAM) { + oldValue = memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)]; + memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)] = value; + } else if (address < GB_BASE_UNUSABLE) { + oldValue = gb->video.oam.raw[address & 0xFF]; + gb->video.oam.raw[address & 0xFF] = value; + } else if (address < GB_BASE_HRAM) { + mLOG(GB_MEM, STUB, "Unimplemented memory Patch8: 0x%08X", address); + return; + } else if (address < GB_BASE_IE) { + oldValue = memory->hram[address & GB_SIZE_HRAM]; + memory->hram[address & GB_SIZE_HRAM] = value; + } else { + mLOG(GB_MEM, STUB, "Unimplemented memory Patch8: 0x%08X", address); + return; + } + } + if (old) { + *old = oldValue; + } +} static void _switchBank(struct GBMemory* memory, int bank) { size_t bankStart = bank * GB_SIZE_CART_BANK0; @@ -867,3 +930,13 @@ void _GBMBC7Write(struct GBMemory* memory, uint16_t address, uint8_t value) { } } } + +void _pristineCow(struct GB* gb) { + if (gb->memory.rom != gb->pristineRom) { + 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); + _switchBank(&gb->memory, gb->memory.currentBank); +}