all repos — mgba @ 890b063ea5e3f7e4a6e742a57619c7ef959d8a0e

mGBA Game Boy Advance Emulator

GB: Preliminary cheat support
Jeffrey Pfau jeffrey@endrift.com
Sun, 08 May 2016 01:34:51 -0700
commit

890b063ea5e3f7e4a6e742a57619c7ef959d8a0e

parent

0fa6da495d80052b4231e84fd843e5010cf5c2c5

6 files changed, 220 insertions(+), 1 deletions(-)

jump to
A src/gb/cheats.c

@@ -0,0 +1,147 @@

+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * 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 "util/string.h" + +static void GBCheatSetDeinit(struct mCheatSet* set); +static void GBCheatAddSet(struct mCheatSet* cheats, struct mCheatDevice* device); +static void GBCheatRemoveSet(struct mCheatSet* cheats, struct mCheatDevice* device); +static void GBCheatRefresh(struct mCheatSet* cheats, struct mCheatDevice* device); +static void GBCheatSetCopyProperties(struct mCheatSet* set, struct mCheatSet* oldSet); +static bool GBCheatAddLine(struct mCheatSet*, const char* line, int type); + +static struct mCheatSet* GBCheatSetCreate(struct mCheatDevice* device, const char* name) { + UNUSED(device); + struct GBCheatSet* set = malloc(sizeof(*set)); + mCheatSetInit(&set->d, name); + + set->d.deinit = GBCheatSetDeinit; + set->d.add = GBCheatAddSet; + set->d.remove = GBCheatRemoveSet; + + set->d.addLine = GBCheatAddLine; + set->d.copyProperties = GBCheatSetCopyProperties; + + set->d.refresh = GBCheatRefresh; + return &set->d; +} + +struct mCheatDevice* GBCheatDeviceCreate(void) { + struct mCheatDevice* device = malloc(sizeof(*device)); + mCheatDeviceCreate(device); + device->createSet = GBCheatSetCreate; + return device; +} + +static void GBCheatSetDeinit(struct mCheatSet* set) { + struct GBCheatSet* gbset = (struct GBCheatSet*) set; + UNUSED(gbset); +} + +static void GBCheatAddSet(struct mCheatSet* cheats, struct mCheatDevice* device) { + struct GBCheatSet* gbset = (struct GBCheatSet*) cheats; + UNUSED(gbset); + UNUSED(device); +} + +static void GBCheatRemoveSet(struct mCheatSet* cheats, struct mCheatDevice* device) { + struct GBCheatSet* gbset = (struct GBCheatSet*) cheats; + UNUSED(gbset); + UNUSED(device); +} + +static bool GBCheatAddGameShark(struct GBCheatSet* cheats, uint32_t op) { + struct mCheat* cheat = mCheatListAppend(&cheats->d.list); + cheat->type = CHEAT_ASSIGN; + cheat->width = 1; + cheat->address = ((op & 0xFF) << 8) | ((op >> 8) & 0xFF); + cheat->operand = (op >> 16) & 0xFF; + cheat->repeat = 1; + cheat->negativeRepeat = 0; + return true; +} + +static bool GBCheatAddGameSharkLine(struct GBCheatSet* cheats, const char* line) { + uint32_t op; + if (!hex32(line, &op)) { + return false; + } + return GBCheatAddGameShark(cheats, op); +} + +static bool GBCheatAddVBALine(struct GBCheatSet* cheats, const char* line) { + uint16_t address; + uint8_t value; + const char* lineNext = hex16(line, &address); + if (!lineNext && lineNext[0] != ':') { + return false; + } + if (!hex8(line, &value)) { + return false; + } + struct mCheat* cheat = mCheatListAppend(&cheats->d.list); + cheat->type = CHEAT_ASSIGN; + cheat->width = 1; + cheat->address = address; + cheat->operand = value; + cheat->repeat = 1; + cheat->negativeRepeat = 0; + return true; +} + +bool GBCheatAddLine(struct mCheatSet* set, const char* line, int type) { + struct GBCheatSet* cheats = (struct GBCheatSet*) set; + switch (type) { + case GB_CHEAT_AUTODETECT: + break; + case GB_CHEAT_GAME_GENIE: + return false; + case GB_CHEAT_GAMESHARK: + return GBCheatAddGameSharkLine(cheats, line); + case GB_CHEAT_VBA: + return GBCheatAddVBALine(cheats, line); + default: + return false; + } + + uint16_t op1; + uint8_t op2; + uint8_t op3; + const char* lineNext = hex16(line, &op1); + if (!lineNext) { + return false; + } + if (lineNext[0] == ':') { + return GBCheatAddVBALine(cheats, line); + } + lineNext = hex8(lineNext, &op2); + if (!lineNext) { + return false; + } + if (lineNext[0] == '-') { + return false; + } + lineNext = hex8(lineNext, &op3); + if (!lineNext) { + return false; + } + uint32_t realOp = op1 << 16; + realOp |= op2 << 8; + realOp |= op3; + return GBCheatAddGameShark(cheats, realOp); +} + +static void GBCheatRefresh(struct mCheatSet* cheats, struct mCheatDevice* device) { + struct GBCheatSet* gbset = (struct GBCheatSet*) cheats; + UNUSED(gbset); + UNUSED(device); +} + +static void GBCheatSetCopyProperties(struct mCheatSet* set, struct mCheatSet* oldSet) { + UNUSED(set); + UNUSED(oldSet); +}
A src/gb/cheats.h

@@ -0,0 +1,37 @@

+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * 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/. */ +#ifndef GB_CHEATS_H +#define GB_CHEATS_H + +#include "util/common.h" + +#include "core/cheats.h" +#include "util/vector.h" + +#define MAX_ROM_PATCHES 4 + +enum GBACheatType { + GB_CHEAT_AUTODETECT, + GB_CHEAT_GAMESHARK, + GB_CHEAT_GAME_GENIE, + GB_CHEAT_VBA +}; + +struct GBCheatPatch { + uint16_t address; + int8_t newValue; + int8_t oldValue; + bool applied; + bool exists; +}; + +struct GBCheatSet { + struct mCheatSet d; +}; + +struct mCheatDevice* GBCheatDeviceCreate(void); + +#endif
M src/gb/core.csrc/gb/core.c

@@ -6,6 +6,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "core.h" #include "core/core.h" +#include "gb/cheats.h" #include "gb/cli.h" #include "gb/gb.h" #include "gb/renderers/software.h"

@@ -19,6 +20,7 @@ struct GBVideoSoftwareRenderer renderer;

uint8_t keys; struct mCPUComponent* components[CPU_COMPONENT_MAX]; struct mDebuggerPlatform* debuggerPlatform; + struct mCheatDevice* cheatDevice; }; static bool _GBCoreInit(struct mCore* core) {

@@ -34,6 +36,7 @@ }

core->cpu = cpu; core->board = gb; gbcore->debuggerPlatform = NULL; + gbcore->cheatDevice = NULL; GBCreate(gb); memset(gbcore->components, 0, sizeof(gbcore->components));

@@ -60,6 +63,13 @@ mappedMemoryFree(core->board, sizeof(struct GB));

#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2 mDirectorySetDeinit(&core->dirs); #endif + + struct GBCore* gbcore = (struct GBCore*) core; + free(gbcore->debuggerPlatform); + if (gbcore->cheatDevice) { + mCheatDeviceDestroy(gbcore->cheatDevice); + } + free(gbcore->cheatDevice); free(core); }

@@ -357,6 +367,17 @@ cpu->components[CPU_COMPONENT_DEBUGGER] = NULL;

core->debugger = NULL; } +static struct mCheatDevice* _GBCoreCheatDevice(struct mCore* core) { + struct GBCore* gbcore = (struct GBCore*) core; + if (!gbcore->cheatDevice) { + gbcore->cheatDevice = GBCheatDeviceCreate(); + ((struct LR35902Core*) core->cpu)->components[CPU_COMPONENT_CHEAT_DEVICE] = &gbcore->cheatDevice->d; + LR35902HotplugAttach(core->cpu, CPU_COMPONENT_CHEAT_DEVICE); + gbcore->cheatDevice->p = core; + } + return gbcore->cheatDevice; +} + struct mCore* GBCoreCreate(void) { struct GBCore* gbcore = malloc(sizeof(*gbcore)); struct mCore* core = &gbcore->d;

@@ -416,5 +437,6 @@ core->debuggerPlatform = _GBCoreDebuggerPlatform;

core->cliDebuggerSystem = _GBCoreCliDebuggerSystem; core->attachDebugger = _GBCoreAttachDebugger; core->detachDebugger = _GBCoreDetachDebugger; + core->cheatDevice = _GBCoreCheatDevice; return core; }
M src/gb/gb.csrc/gb/gb.c

@@ -8,6 +8,7 @@

#include "gb/io.h" #include "core/core.h" +#include "core/cheats.h" #include "util/crc32.h" #include "util/memory.h" #include "util/math.h"

@@ -383,3 +384,14 @@ if (cart->oldLicensee == 0x33) {

memcpy(&out[4], cart->maker, 4); } } + +void GBFrameEnded(struct GB* gb) { + if (gb->cpu->components && gb->cpu->components[CPU_COMPONENT_CHEAT_DEVICE]) { + struct mCheatDevice* device = (struct mCheatDevice*) gb->cpu->components[CPU_COMPONENT_CHEAT_DEVICE]; + size_t i; + for (i = 0; i < mCheatSetsSize(&device->cheats); ++i) { + struct mCheatSet* cheats = *mCheatSetsGetPointer(&device->cheats, i); + mCheatRefresh(device, cheats); + } + } +}
M src/gb/video.csrc/gb/video.c

@@ -116,6 +116,7 @@ video->renderer->finishFrame(video->renderer);

mCoreSyncPostFrame(video->p->sync); video->frameskipCounter = video->frameskip; } + GBFrameEnded(video->p); ++video->frameCounter; struct mCoreThread* thread = mCoreThreadGet();
M src/platform/qt/Window.cppsrc/platform/qt/Window.cpp

@@ -1235,7 +1235,7 @@ addControlledAction(toolsMenu, sensors, "sensorWindow");

QAction* cheats = new QAction(tr("&Cheats..."), toolsMenu); connect(cheats, SIGNAL(triggered()), this, SLOT(openCheatsWindow())); - m_gbaActions.append(cheats); + m_gameActions.append(cheats); addControlledAction(toolsMenu, cheats, "cheatsWindow"); #ifdef USE_GDB_STUB