mirror of https://github.com/mgba-emu/mgba.git
GB: Preliminary cheat support
This commit is contained in:
parent
0fa6da495d
commit
890b063ea5
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
|
12
src/gb/gb.c
12
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue