mirror of https://github.com/mgba-emu/mgba.git
GB: Add partial Game Genie support
This commit is contained in:
parent
7477c36cb5
commit
273d2db575
|
@ -5,8 +5,43 @@
|
|||
* 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);
|
||||
|
@ -19,6 +54,8 @@ static struct mCheatSet* GBCheatSetCreate(struct mCheatDevice* device, const cha
|
|||
struct GBCheatSet* set = malloc(sizeof(*set));
|
||||
mCheatSetInit(&set->d, name);
|
||||
|
||||
GBCheatPatchListInit(&set->romPatches, 0);
|
||||
|
||||
set->d.deinit = GBCheatSetDeinit;
|
||||
set->d.add = GBCheatAddSet;
|
||||
set->d.remove = GBCheatRemoveSet;
|
||||
|
@ -39,19 +76,17 @@ struct mCheatDevice* GBCheatDeviceCreate(void) {
|
|||
|
||||
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 @@ static bool GBCheatAddGameSharkLine(struct GBCheatSet* cheats, const char* line)
|
|||
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 @@ bool GBCheatAddLine(struct mCheatSet* set, const char* line, int 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 @@ bool GBCheatAddLine(struct mCheatSet* set, const char* line, int type) {
|
|||
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 @@ bool GBCheatAddLine(struct mCheatSet* set, const char* line, int type) {
|
|||
|
||||
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) {
|
||||
|
|
|
@ -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 @@ struct GBCheatPatch {
|
|||
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);
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
|
||||
#include "arm/arm.h"
|
||||
#include "core/cheats.h"
|
||||
#include "util/vector.h"
|
||||
|
||||
#define MAX_ROM_PATCHES 4
|
||||
|
||||
|
|
|
@ -260,6 +260,22 @@ const char* hex32(const char* line, uint32_t* out) {
|
|||
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 @@ const char* hex16(const char* line, uint16_t* out) {
|
|||
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 @@ const char* hex8(const char* line, uint8_t* out) {
|
|||
*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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue