all repos — mgba @ 273d2db575de606126b68e52dd04c71d8969dbcf

mGBA Game Boy Advance Emulator

GB: Add partial Game Genie support
Jeffrey Pfau jeffrey@endrift.com
Sun, 08 May 2016 23:18:42 -0700
commit

273d2db575de606126b68e52dd04c71d8969dbcf

parent

7477c36cb5b8a949ca004e0cc3b9347b6f74dd88

5 files changed, 118 insertions(+), 13 deletions(-)

jump to
M src/gb/cheats.csrc/gb/cheats.c

@@ -5,8 +5,43 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this

* 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);

@@ -18,6 +53,8 @@ static struct mCheatSet* GBCheatSetCreate(struct mCheatDevice* device, const char* name) {

UNUSED(device); struct GBCheatSet* set = malloc(sizeof(*set)); mCheatSetInit(&set->d, name); + + GBCheatPatchListInit(&set->romPatches, 0); set->d.deinit = GBCheatSetDeinit; set->d.add = GBCheatAddSet;

@@ -39,19 +76,17 @@ }

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 @@ }

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 @@ switch (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 @@ uint8_t op3;

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 @@ }

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) {
M src/gb/cheats.hsrc/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 @@ uint16_t address;

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);
M src/gba/cheats.hsrc/gba/cheats.h

@@ -10,7 +10,6 @@ #include "util/common.h"

#include "arm/arm.h" #include "core/cheats.h" -#include "util/vector.h" #define MAX_ROM_PATCHES 4
M src/util/string.csrc/util/string.c

@@ -260,6 +260,22 @@ *out = value;

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 @@ *out = value;

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 @@ }

*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; +}
M src/util/string.hsrc/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