diff --git a/src/gb/cheats.c b/src/gb/cheats.c new file mode 100644 index 000000000..e657e539b --- /dev/null +++ b/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); +} diff --git a/src/gb/cheats.h b/src/gb/cheats.h new file mode 100644 index 000000000..b8093def2 --- /dev/null +++ b/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 diff --git a/src/gb/core.c b/src/gb/core.c index 26f30eb7e..217114364 100644 --- a/src/gb/core.c +++ b/src/gb/core.c @@ -6,6 +6,7 @@ #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 GBCore { 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 @@ static bool _GBCoreInit(struct mCore* core) { 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 @@ static void _GBCoreDeinit(struct mCore* core) { #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 @@ static void _GBCoreDetachDebugger(struct mCore* core) { 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 @@ struct mCore* GBCoreCreate(void) { core->cliDebuggerSystem = _GBCoreCliDebuggerSystem; core->attachDebugger = _GBCoreAttachDebugger; core->detachDebugger = _GBCoreDetachDebugger; + core->cheatDevice = _GBCoreCheatDevice; return core; } diff --git a/src/gb/gb.c b/src/gb/gb.c index 17d1f867e..abd3f7e84 100644 --- a/src/gb/gb.c +++ b/src/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 @@ void GBGetGameCode(struct GB* gb, char* out) { 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); + } + } +} diff --git a/src/gb/video.c b/src/gb/video.c index 1aadb9b70..9aae94110 100644 --- a/src/gb/video.c +++ b/src/gb/video.c @@ -116,6 +116,7 @@ int32_t GBVideoProcessEvents(struct GBVideo* video, int32_t cycles) { mCoreSyncPostFrame(video->p->sync); video->frameskipCounter = video->frameskip; } + GBFrameEnded(video->p); ++video->frameCounter; struct mCoreThread* thread = mCoreThreadGet(); diff --git a/src/platform/qt/Window.cpp b/src/platform/qt/Window.cpp index a07399e10..93a23b6ea 100644 --- a/src/platform/qt/Window.cpp +++ b/src/platform/qt/Window.cpp @@ -1235,7 +1235,7 @@ void Window::setupMenu(QMenuBar* menubar) { 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