GB: Preliminary cheat support

This commit is contained in:
Jeffrey Pfau 2016-05-08 01:34:51 -07:00
parent 0fa6da495d
commit 890b063ea5
6 changed files with 220 additions and 1 deletions

147
src/gb/cheats.c Normal file
View File

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

37
src/gb/cheats.h Normal file
View File

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

View File

@ -6,6 +6,7 @@
#include "core.h" #include "core.h"
#include "core/core.h" #include "core/core.h"
#include "gb/cheats.h"
#include "gb/cli.h" #include "gb/cli.h"
#include "gb/gb.h" #include "gb/gb.h"
#include "gb/renderers/software.h" #include "gb/renderers/software.h"
@ -19,6 +20,7 @@ struct GBCore {
uint8_t keys; uint8_t keys;
struct mCPUComponent* components[CPU_COMPONENT_MAX]; struct mCPUComponent* components[CPU_COMPONENT_MAX];
struct mDebuggerPlatform* debuggerPlatform; struct mDebuggerPlatform* debuggerPlatform;
struct mCheatDevice* cheatDevice;
}; };
static bool _GBCoreInit(struct mCore* core) { static bool _GBCoreInit(struct mCore* core) {
@ -34,6 +36,7 @@ static bool _GBCoreInit(struct mCore* core) {
core->cpu = cpu; core->cpu = cpu;
core->board = gb; core->board = gb;
gbcore->debuggerPlatform = NULL; gbcore->debuggerPlatform = NULL;
gbcore->cheatDevice = NULL;
GBCreate(gb); GBCreate(gb);
memset(gbcore->components, 0, sizeof(gbcore->components)); memset(gbcore->components, 0, sizeof(gbcore->components));
@ -60,6 +63,13 @@ static void _GBCoreDeinit(struct mCore* core) {
#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2 #if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
mDirectorySetDeinit(&core->dirs); mDirectorySetDeinit(&core->dirs);
#endif #endif
struct GBCore* gbcore = (struct GBCore*) core;
free(gbcore->debuggerPlatform);
if (gbcore->cheatDevice) {
mCheatDeviceDestroy(gbcore->cheatDevice);
}
free(gbcore->cheatDevice);
free(core); free(core);
} }
@ -357,6 +367,17 @@ static void _GBCoreDetachDebugger(struct mCore* core) {
core->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 mCore* GBCoreCreate(void) {
struct GBCore* gbcore = malloc(sizeof(*gbcore)); struct GBCore* gbcore = malloc(sizeof(*gbcore));
struct mCore* core = &gbcore->d; struct mCore* core = &gbcore->d;
@ -416,5 +437,6 @@ struct mCore* GBCoreCreate(void) {
core->cliDebuggerSystem = _GBCoreCliDebuggerSystem; core->cliDebuggerSystem = _GBCoreCliDebuggerSystem;
core->attachDebugger = _GBCoreAttachDebugger; core->attachDebugger = _GBCoreAttachDebugger;
core->detachDebugger = _GBCoreDetachDebugger; core->detachDebugger = _GBCoreDetachDebugger;
core->cheatDevice = _GBCoreCheatDevice;
return core; return core;
} }

View File

@ -8,6 +8,7 @@
#include "gb/io.h" #include "gb/io.h"
#include "core/core.h" #include "core/core.h"
#include "core/cheats.h"
#include "util/crc32.h" #include "util/crc32.h"
#include "util/memory.h" #include "util/memory.h"
#include "util/math.h" #include "util/math.h"
@ -383,3 +384,14 @@ void GBGetGameCode(struct GB* gb, char* out) {
memcpy(&out[4], cart->maker, 4); 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);
}
}
}

View File

@ -116,6 +116,7 @@ int32_t GBVideoProcessEvents(struct GBVideo* video, int32_t cycles) {
mCoreSyncPostFrame(video->p->sync); mCoreSyncPostFrame(video->p->sync);
video->frameskipCounter = video->frameskip; video->frameskipCounter = video->frameskip;
} }
GBFrameEnded(video->p);
++video->frameCounter; ++video->frameCounter;
struct mCoreThread* thread = mCoreThreadGet(); struct mCoreThread* thread = mCoreThreadGet();

View File

@ -1235,7 +1235,7 @@ void Window::setupMenu(QMenuBar* menubar) {
QAction* cheats = new QAction(tr("&Cheats..."), toolsMenu); QAction* cheats = new QAction(tr("&Cheats..."), toolsMenu);
connect(cheats, SIGNAL(triggered()), this, SLOT(openCheatsWindow())); connect(cheats, SIGNAL(triggered()), this, SLOT(openCheatsWindow()));
m_gbaActions.append(cheats); m_gameActions.append(cheats);
addControlledAction(toolsMenu, cheats, "cheatsWindow"); addControlledAction(toolsMenu, cheats, "cheatsWindow");
#ifdef USE_GDB_STUB #ifdef USE_GDB_STUB