GBA Memory: Add GBAPatch functions for force-writing and patching memory addresses

This commit is contained in:
Jeffrey Pfau 2015-02-03 23:49:34 -08:00
parent 56291e63e5
commit 15b3a3281f
3 changed files with 153 additions and 49 deletions

View File

@ -712,66 +712,31 @@ void GBAFrameEnded(struct GBA* gba) {
}
static bool _setSoftwareBreakpoint(struct ARMDebugger* debugger, uint32_t address, enum ExecutionMode mode, uint32_t* opcode) {
struct GBA* gba = (struct GBA*) debugger->cpu->master;
int immediate = GBA_COMPONENT_DEBUGGER;
uint32_t value;
if (mode == MODE_ARM) {
int32_t value;
int32_t old;
value = 0xE1200070;
value |= immediate & 0xF;
value |= (immediate & 0xFFF0) << 4;
GBAPatch32(debugger->cpu, address, value, &old);
*opcode = old;
} else {
int16_t value;
int16_t old;
value = 0xBE00;
value |= immediate & 0xFF;
GBAPatch16(debugger->cpu, address, value, &old);
*opcode = old;
}
uint32_t old;
switch (address >> BASE_OFFSET) {
case REGION_CART0:
case REGION_CART0_EX:
case REGION_CART1:
case REGION_CART1_EX:
case REGION_CART2:
case REGION_CART2_EX:
if ((address & (SIZE_CART0 - 1)) < gba->memory.romSize) {
if (mode == MODE_ARM) {
LOAD_32(old, address & (SIZE_CART0 - 1), gba->memory.rom);
STORE_32(value, address & (SIZE_CART0 - 1), gba->memory.rom);
} else {
LOAD_16(old, address & (SIZE_CART0 - 1), gba->memory.rom);
STORE_16(value, address & (SIZE_CART0 - 1), gba->memory.rom);
}
*opcode = old;
return true;
}
break;
default:
break;
}
return false;
return true;
}
static bool _clearSoftwareBreakpoint(struct ARMDebugger* debugger, uint32_t address, enum ExecutionMode mode, uint32_t opcode) {
struct GBA* gba = (struct GBA*) debugger->cpu->master;
switch (address >> BASE_OFFSET) {
case REGION_CART0:
case REGION_CART0_EX:
case REGION_CART1:
case REGION_CART1_EX:
case REGION_CART2:
case REGION_CART2_EX:
if ((address & (SIZE_CART0 - 1)) < gba->memory.romSize) {
if (mode == MODE_ARM) {
STORE_32(opcode, address & (SIZE_CART0 - 1), gba->memory.rom);
} else {
STORE_16(opcode, address & (SIZE_CART0 - 1), gba->memory.rom);
}
return true;
}
break;
default:
break;
if (mode == MODE_ARM) {
GBAPatch32(debugger->cpu, address, opcode, 0);
} else {
GBAPatch16(debugger->cpu, address, opcode, 0);
}
return false;
return true;
}

View File

@ -804,6 +804,142 @@ void GBAStore8(struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCo
}
}
void GBAPatch32(struct ARMCore* cpu, uint32_t address, int32_t value, int32_t* old) {
struct GBA* gba = (struct GBA*) cpu->master;
struct GBAMemory* memory = &gba->memory;
int32_t oldValue = -1;
switch (address >> BASE_OFFSET) {
case REGION_WORKING_RAM:
LOAD_32(oldValue, address & (SIZE_WORKING_RAM - 1), memory->wram);
STORE_32(value, address & (SIZE_WORKING_RAM - 1), memory->wram);
break;
case REGION_WORKING_IRAM:
LOAD_32(oldValue, address & (SIZE_WORKING_IRAM - 1), memory->iwram);
STORE_32(value, address & (SIZE_WORKING_IRAM - 1), memory->iwram);
break;
case REGION_IO:
GBALog(gba, GBA_LOG_STUB, "Unimplemented memory Patch32: 0x%08X", address);
break;
case REGION_PALETTE_RAM:
LOAD_32(oldValue, address & (SIZE_PALETTE_RAM - 1), gba->video.palette);
STORE_32(value, address & (SIZE_PALETTE_RAM - 1), gba->video.palette);
gba->video.renderer->writePalette(gba->video.renderer, address & (SIZE_PALETTE_RAM - 1), value);
gba->video.renderer->writePalette(gba->video.renderer, (address & (SIZE_PALETTE_RAM - 1)) + 2, value >> 16);
break;
case REGION_VRAM:
if ((address & 0x0001FFFF) < SIZE_VRAM) {
LOAD_32(oldValue, address & 0x0001FFFF, gba->video.renderer->vram);
STORE_32(value, address & 0x0001FFFF, gba->video.renderer->vram);
} else {
LOAD_32(oldValue, address & 0x00017FFF, gba->video.renderer->vram);
STORE_32(value, address & 0x00017FFF, gba->video.renderer->vram);
}
break;
case REGION_OAM:
LOAD_32(oldValue, address & (SIZE_OAM - 1), gba->video.oam.raw);
STORE_32(value, address & (SIZE_OAM - 1), gba->video.oam.raw);
gba->video.renderer->writeOAM(gba->video.renderer, (address & (SIZE_OAM - 1)) >> 1);
gba->video.renderer->writeOAM(gba->video.renderer, ((address & (SIZE_OAM - 1)) + 2) >> 1);
break;
case REGION_CART0:
case REGION_CART0_EX:
case REGION_CART1:
case REGION_CART1_EX:
case REGION_CART2:
case REGION_CART2_EX:
if ((address & (SIZE_CART0 - 1)) < gba->memory.romSize) {
LOAD_32(oldValue, address & (SIZE_CART0 - 1), gba->memory.rom);
STORE_32(value, address & (SIZE_CART0 - 1), gba->memory.rom);
} else {
GBALog(gba, GBA_LOG_WARN, "Bad memory Patch32: 0x%08X", address);
}
break;
case REGION_CART_SRAM:
case REGION_CART_SRAM_MIRROR:
if (memory->savedata.type == SAVEDATA_SRAM) {
LOAD_32(oldValue, address & (SIZE_CART_SRAM - 1), memory->savedata.data);
STORE_32(value, address & (SIZE_CART_SRAM - 1), memory->savedata.data);
} else {
GBALog(gba, GBA_LOG_GAME_ERROR, "Writing to non-existent SRAM: 0x%08X", address);
}
break;
default:
GBALog(gba, GBA_LOG_WARN, "Bad memory Patch16: 0x%08X", address);
break;
}
if (old) {
*old = oldValue;
}
}
void GBAPatch16(struct ARMCore* cpu, uint32_t address, int16_t value, int16_t* old) {
struct GBA* gba = (struct GBA*) cpu->master;
struct GBAMemory* memory = &gba->memory;
int16_t oldValue = -1;
switch (address >> BASE_OFFSET) {
case REGION_WORKING_RAM:
LOAD_16(oldValue, address & (SIZE_WORKING_RAM - 1), memory->wram);
STORE_16(value, address & (SIZE_WORKING_RAM - 1), memory->wram);
break;
case REGION_WORKING_IRAM:
LOAD_16(oldValue, address & (SIZE_WORKING_IRAM - 1), memory->iwram);
STORE_16(value, address & (SIZE_WORKING_IRAM - 1), memory->iwram);
break;
case REGION_IO:
GBALog(gba, GBA_LOG_STUB, "Unimplemented memory Patch16: 0x%08X", address);
break;
case REGION_PALETTE_RAM:
LOAD_16(oldValue, address & (SIZE_PALETTE_RAM - 1), gba->video.palette);
STORE_16(value, address & (SIZE_PALETTE_RAM - 1), gba->video.palette);
gba->video.renderer->writePalette(gba->video.renderer, address & (SIZE_PALETTE_RAM - 1), value);
break;
case REGION_VRAM:
if ((address & 0x0001FFFF) < SIZE_VRAM) {
LOAD_16(oldValue, address & 0x0001FFFF, gba->video.renderer->vram);
STORE_16(value, address & 0x0001FFFF, gba->video.renderer->vram);
} else {
LOAD_16(oldValue, address & 0x00017FFF, gba->video.renderer->vram);
STORE_16(value, address & 0x00017FFF, gba->video.renderer->vram);
}
break;
case REGION_OAM:
LOAD_16(oldValue, address & (SIZE_OAM - 1), gba->video.oam.raw);
STORE_16(value, address & (SIZE_OAM - 1), gba->video.oam.raw);
gba->video.renderer->writeOAM(gba->video.renderer, (address & (SIZE_OAM - 1)) >> 1);
break;
case REGION_CART0:
case REGION_CART0_EX:
case REGION_CART1:
case REGION_CART1_EX:
case REGION_CART2:
case REGION_CART2_EX:
if ((address & (SIZE_CART0 - 1)) < gba->memory.romSize) {
LOAD_16(oldValue, address & (SIZE_CART0 - 1), gba->memory.rom);
STORE_16(value, address & (SIZE_CART0 - 1), gba->memory.rom);
} else {
GBALog(gba, GBA_LOG_WARN, "Bad memory Patch16: 0x%08X", address);
}
break;
case REGION_CART_SRAM:
case REGION_CART_SRAM_MIRROR:
if (memory->savedata.type == SAVEDATA_SRAM) {
LOAD_16(oldValue, address & (SIZE_CART_SRAM - 1), memory->savedata.data);
STORE_16(value, address & (SIZE_CART_SRAM - 1), memory->savedata.data);
} else {
GBALog(gba, GBA_LOG_GAME_ERROR, "Writing to non-existent SRAM: 0x%08X", address);
}
break;
default:
GBALog(gba, GBA_LOG_WARN, "Bad memory Patch16: 0x%08X", address);
break;
}
if (old) {
*old = oldValue;
}
}
#define LDM_LOOP(LDM) \
for (i = 0; i < 16; i += 4) { \
if (UNLIKELY(mask & (1 << i))) { \

View File

@ -152,6 +152,9 @@ void GBAStore32(struct ARMCore* cpu, uint32_t address, int32_t value, int* cycle
void GBAStore16(struct ARMCore* cpu, uint32_t address, int16_t value, int* cycleCounter);
void GBAStore8(struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCounter);
void GBAPatch32(struct ARMCore* cpu, uint32_t address, int32_t value, int32_t* old);
void GBAPatch16(struct ARMCore* cpu, uint32_t address, int16_t value, int16_t* old);
uint32_t GBALoadMultiple(struct ARMCore*, uint32_t baseAddress, int mask, enum LSMDirection direction, int* cycleCounter);
uint32_t GBAStoreMultiple(struct ARMCore*, uint32_t baseAddress, int mask, enum LSMDirection direction, int* cycleCounter);