From 273d2db575de606126b68e52dd04c71d8969dbcf Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Sun, 8 May 2016 23:18:42 -0700 Subject: [PATCH] GB: Add partial Game Genie support --- src/gb/cheats.c | 74 +++++++++++++++++++++++++++++++++++++++++------ src/gb/cheats.h | 6 ++-- src/gba/cheats.h | 1 - src/util/string.c | 47 ++++++++++++++++++++++++++++++ src/util/string.h | 3 ++ 5 files changed, 118 insertions(+), 13 deletions(-) diff --git a/src/gb/cheats.c b/src/gb/cheats.c index 2c50b1256..95489a1c5 100644 --- a/src/gb/cheats.c +++ b/src/gb/cheats.c @@ -5,8 +5,43 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "cheats.h" +#include "core/core.h" +#include "gb/memory.h" #include "util/string.h" +DEFINE_VECTOR(GBCheatPatchList, struct GBCheatPatch); + +static void _patchROM(struct mCheatDevice* device, struct GBCheatSet* cheats) { + if (!device->p) { + return; + } + size_t i; + for (i = 0; i < GBCheatPatchListSize(&cheats->romPatches); ++i) { + struct GBCheatPatch* patch = GBCheatPatchListGetPointer(&cheats->romPatches, i); + if (patch->applied) { + continue; + } + // TODO: Byte check + GBPatch8(device->p->cpu, patch->address, patch->newValue, &patch->oldValue); + patch->applied = true; + } +} + +static void _unpatchROM(struct mCheatDevice* device, struct GBCheatSet* cheats) { + if (!device->p) { + return; + } + size_t i; + for (i = 0; i < GBCheatPatchListSize(&cheats->romPatches); ++i) { + struct GBCheatPatch* patch = GBCheatPatchListGetPointer(&cheats->romPatches, i); + if (!patch->applied) { + continue; + } + GBPatch8(device->p->cpu, patch->address, patch->oldValue, NULL); + patch->applied = false; + } +} + static void GBCheatSetDeinit(struct mCheatSet* set); static void GBCheatAddSet(struct mCheatSet* cheats, struct mCheatDevice* device); static void GBCheatRemoveSet(struct mCheatSet* cheats, struct mCheatDevice* device); @@ -19,6 +54,8 @@ static struct mCheatSet* GBCheatSetCreate(struct mCheatDevice* device, const cha struct GBCheatSet* set = malloc(sizeof(*set)); mCheatSetInit(&set->d, name); + GBCheatPatchListInit(&set->romPatches, 0); + set->d.deinit = GBCheatSetDeinit; set->d.add = GBCheatAddSet; set->d.remove = GBCheatRemoveSet; @@ -39,19 +76,17 @@ struct mCheatDevice* GBCheatDeviceCreate(void) { static void GBCheatSetDeinit(struct mCheatSet* set) { struct GBCheatSet* gbset = (struct GBCheatSet*) set; - UNUSED(gbset); + GBCheatPatchListDeinit(&gbset->romPatches); } static void GBCheatAddSet(struct mCheatSet* cheats, struct mCheatDevice* device) { struct GBCheatSet* gbset = (struct GBCheatSet*) cheats; - UNUSED(gbset); - UNUSED(device); + _patchROM(device, gbset); } static void GBCheatRemoveSet(struct mCheatSet* cheats, struct mCheatDevice* device) { struct GBCheatSet* gbset = (struct GBCheatSet*) cheats; - UNUSED(gbset); - UNUSED(device); + _unpatchROM(device, gbset); } static bool GBCheatAddCodebreaker(struct GBCheatSet* cheats, uint16_t address, uint8_t data) { @@ -77,6 +112,28 @@ static bool GBCheatAddGameSharkLine(struct GBCheatSet* cheats, const char* line) return GBCheatAddGameShark(cheats, op); } +static bool GBCheatAddGameGenieLine(struct GBCheatSet* cheats, const char* line) { + uint16_t op1; + uint16_t op2; + const char* lineNext = hex12(line, &op1); + if (!lineNext || lineNext[0] != '-') { + return false; + } + ++lineNext; + lineNext = hex12(lineNext, &op2); + if (!lineNext) { + return false; + } + uint16_t address = (op1 & 0xF) << 8; + address |= (op2 >> 4) & 0xFF; + address |= ((op2 & 0xF) ^ 0xF) << 12; + struct GBCheatPatch* patch = GBCheatPatchListAppend(&cheats->romPatches); + patch->address = address; + patch->newValue = op1 >> 4; + patch->applied = false; + return true; +} + static bool GBCheatAddVBALine(struct GBCheatSet* cheats, const char* line) { uint16_t address; uint8_t value; @@ -103,7 +160,7 @@ bool GBCheatAddLine(struct mCheatSet* set, const char* line, int type) { case GB_CHEAT_AUTODETECT: break; case GB_CHEAT_GAME_GENIE: - return false; + return GBCheatAddGameGenieLine(cheats, line); case GB_CHEAT_GAMESHARK: return GBCheatAddGameSharkLine(cheats, line); case GB_CHEAT_VBA: @@ -118,7 +175,7 @@ bool GBCheatAddLine(struct mCheatSet* set, const char* line, int type) { bool codebreaker = false; const char* lineNext = hex16(line, &op1); if (!lineNext) { - return false; + return GBCheatAddGameGenieLine(cheats, line); } if (lineNext[0] == ':') { return GBCheatAddVBALine(cheats, line); @@ -148,8 +205,7 @@ bool GBCheatAddLine(struct mCheatSet* set, const char* line, int type) { static void GBCheatRefresh(struct mCheatSet* cheats, struct mCheatDevice* device) { struct GBCheatSet* gbset = (struct GBCheatSet*) cheats; - UNUSED(gbset); - UNUSED(device); + _patchROM(device, gbset); } static void GBCheatSetCopyProperties(struct mCheatSet* set, struct mCheatSet* oldSet) { diff --git a/src/gb/cheats.h b/src/gb/cheats.h index b8093def2..67fcfce12 100644 --- a/src/gb/cheats.h +++ b/src/gb/cheats.h @@ -11,8 +11,6 @@ #include "core/cheats.h" #include "util/vector.h" -#define MAX_ROM_PATCHES 4 - enum GBACheatType { GB_CHEAT_AUTODETECT, GB_CHEAT_GAMESHARK, @@ -25,11 +23,13 @@ struct GBCheatPatch { int8_t newValue; int8_t oldValue; bool applied; - bool exists; }; +DECLARE_VECTOR(GBCheatPatchList, struct GBCheatPatch); + struct GBCheatSet { struct mCheatSet d; + struct GBCheatPatchList romPatches; }; struct mCheatDevice* GBCheatDeviceCreate(void); diff --git a/src/gba/cheats.h b/src/gba/cheats.h index 784124430..138c83880 100644 --- a/src/gba/cheats.h +++ b/src/gba/cheats.h @@ -10,7 +10,6 @@ #include "arm/arm.h" #include "core/cheats.h" -#include "util/vector.h" #define MAX_ROM_PATCHES 4 diff --git a/src/util/string.c b/src/util/string.c index 6649a38ac..a2a23dea0 100644 --- a/src/util/string.c +++ b/src/util/string.c @@ -260,6 +260,22 @@ const char* hex32(const char* line, uint32_t* out) { return line; } +const char* hex24(const char* line, uint32_t* out) { + uint32_t value = 0; + int i; + for (i = 0; i < 6; ++i, ++line) { + char digit = *line; + value <<= 4; + int nybble = hexDigit(digit); + if (nybble < 0) { + return 0; + } + value |= nybble; + } + *out = value; + return line; +} + const char* hex16(const char* line, uint16_t* out) { uint16_t value = 0; *out = 0; @@ -277,6 +293,23 @@ const char* hex16(const char* line, uint16_t* out) { return line; } +const char* hex12(const char* line, uint16_t* out) { + uint16_t value = 0; + *out = 0; + int i; + for (i = 0; i < 3; ++i, ++line) { + char digit = *line; + value <<= 4; + int nybble = hexDigit(digit); + if (nybble < 0) { + return 0; + } + value |= nybble; + } + *out = value; + return line; +} + const char* hex8(const char* line, uint8_t* out) { uint8_t value = 0; *out = 0; @@ -293,3 +326,17 @@ const char* hex8(const char* line, uint8_t* out) { *out = value; return line; } + +const char* hex4(const char* line, uint8_t* out) { + uint8_t value = 0; + *out = 0; + char digit = *line; + value <<= 4; + int nybble = hexDigit(digit); + if (nybble < 0) { + return 0; + } + value |= nybble; + *out = value; + return line; +} diff --git a/src/util/string.h b/src/util/string.h index b209f7d90..9716cfbf6 100644 --- a/src/util/string.h +++ b/src/util/string.h @@ -26,7 +26,10 @@ uint32_t utf16Char(const uint16_t** unicode, size_t* length); int hexDigit(char digit); const char* hex32(const char* line, uint32_t* out); +const char* hex24(const char* line, uint32_t* out); const char* hex16(const char* line, uint16_t* out); +const char* hex12(const char* line, uint16_t* out); const char* hex8(const char* line, uint8_t* out); +const char* hex4(const char* line, uint8_t* out); #endif