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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
#include "cheats.h"
|
#include "cheats.h"
|
||||||
|
|
||||||
|
#include "core/core.h"
|
||||||
|
#include "gb/memory.h"
|
||||||
#include "util/string.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 GBCheatSetDeinit(struct mCheatSet* set);
|
||||||
static void GBCheatAddSet(struct mCheatSet* cheats, struct mCheatDevice* device);
|
static void GBCheatAddSet(struct mCheatSet* cheats, struct mCheatDevice* device);
|
||||||
static void GBCheatRemoveSet(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));
|
struct GBCheatSet* set = malloc(sizeof(*set));
|
||||||
mCheatSetInit(&set->d, name);
|
mCheatSetInit(&set->d, name);
|
||||||
|
|
||||||
|
GBCheatPatchListInit(&set->romPatches, 0);
|
||||||
|
|
||||||
set->d.deinit = GBCheatSetDeinit;
|
set->d.deinit = GBCheatSetDeinit;
|
||||||
set->d.add = GBCheatAddSet;
|
set->d.add = GBCheatAddSet;
|
||||||
set->d.remove = GBCheatRemoveSet;
|
set->d.remove = GBCheatRemoveSet;
|
||||||
|
@ -39,19 +76,17 @@ struct mCheatDevice* GBCheatDeviceCreate(void) {
|
||||||
|
|
||||||
static void GBCheatSetDeinit(struct mCheatSet* set) {
|
static void GBCheatSetDeinit(struct mCheatSet* set) {
|
||||||
struct GBCheatSet* gbset = (struct GBCheatSet*) set;
|
struct GBCheatSet* gbset = (struct GBCheatSet*) set;
|
||||||
UNUSED(gbset);
|
GBCheatPatchListDeinit(&gbset->romPatches);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void GBCheatAddSet(struct mCheatSet* cheats, struct mCheatDevice* device) {
|
static void GBCheatAddSet(struct mCheatSet* cheats, struct mCheatDevice* device) {
|
||||||
struct GBCheatSet* gbset = (struct GBCheatSet*) cheats;
|
struct GBCheatSet* gbset = (struct GBCheatSet*) cheats;
|
||||||
UNUSED(gbset);
|
_patchROM(device, gbset);
|
||||||
UNUSED(device);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void GBCheatRemoveSet(struct mCheatSet* cheats, struct mCheatDevice* device) {
|
static void GBCheatRemoveSet(struct mCheatSet* cheats, struct mCheatDevice* device) {
|
||||||
struct GBCheatSet* gbset = (struct GBCheatSet*) cheats;
|
struct GBCheatSet* gbset = (struct GBCheatSet*) cheats;
|
||||||
UNUSED(gbset);
|
_unpatchROM(device, gbset);
|
||||||
UNUSED(device);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool GBCheatAddCodebreaker(struct GBCheatSet* cheats, uint16_t address, uint8_t data) {
|
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);
|
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) {
|
static bool GBCheatAddVBALine(struct GBCheatSet* cheats, const char* line) {
|
||||||
uint16_t address;
|
uint16_t address;
|
||||||
uint8_t value;
|
uint8_t value;
|
||||||
|
@ -103,7 +160,7 @@ bool GBCheatAddLine(struct mCheatSet* set, const char* line, int type) {
|
||||||
case GB_CHEAT_AUTODETECT:
|
case GB_CHEAT_AUTODETECT:
|
||||||
break;
|
break;
|
||||||
case GB_CHEAT_GAME_GENIE:
|
case GB_CHEAT_GAME_GENIE:
|
||||||
return false;
|
return GBCheatAddGameGenieLine(cheats, line);
|
||||||
case GB_CHEAT_GAMESHARK:
|
case GB_CHEAT_GAMESHARK:
|
||||||
return GBCheatAddGameSharkLine(cheats, line);
|
return GBCheatAddGameSharkLine(cheats, line);
|
||||||
case GB_CHEAT_VBA:
|
case GB_CHEAT_VBA:
|
||||||
|
@ -118,7 +175,7 @@ bool GBCheatAddLine(struct mCheatSet* set, const char* line, int type) {
|
||||||
bool codebreaker = false;
|
bool codebreaker = false;
|
||||||
const char* lineNext = hex16(line, &op1);
|
const char* lineNext = hex16(line, &op1);
|
||||||
if (!lineNext) {
|
if (!lineNext) {
|
||||||
return false;
|
return GBCheatAddGameGenieLine(cheats, line);
|
||||||
}
|
}
|
||||||
if (lineNext[0] == ':') {
|
if (lineNext[0] == ':') {
|
||||||
return GBCheatAddVBALine(cheats, line);
|
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) {
|
static void GBCheatRefresh(struct mCheatSet* cheats, struct mCheatDevice* device) {
|
||||||
struct GBCheatSet* gbset = (struct GBCheatSet*) cheats;
|
struct GBCheatSet* gbset = (struct GBCheatSet*) cheats;
|
||||||
UNUSED(gbset);
|
_patchROM(device, gbset);
|
||||||
UNUSED(device);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void GBCheatSetCopyProperties(struct mCheatSet* set, struct mCheatSet* oldSet) {
|
static void GBCheatSetCopyProperties(struct mCheatSet* set, struct mCheatSet* oldSet) {
|
||||||
|
|
|
@ -11,8 +11,6 @@
|
||||||
#include "core/cheats.h"
|
#include "core/cheats.h"
|
||||||
#include "util/vector.h"
|
#include "util/vector.h"
|
||||||
|
|
||||||
#define MAX_ROM_PATCHES 4
|
|
||||||
|
|
||||||
enum GBACheatType {
|
enum GBACheatType {
|
||||||
GB_CHEAT_AUTODETECT,
|
GB_CHEAT_AUTODETECT,
|
||||||
GB_CHEAT_GAMESHARK,
|
GB_CHEAT_GAMESHARK,
|
||||||
|
@ -25,11 +23,13 @@ struct GBCheatPatch {
|
||||||
int8_t newValue;
|
int8_t newValue;
|
||||||
int8_t oldValue;
|
int8_t oldValue;
|
||||||
bool applied;
|
bool applied;
|
||||||
bool exists;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
DECLARE_VECTOR(GBCheatPatchList, struct GBCheatPatch);
|
||||||
|
|
||||||
struct GBCheatSet {
|
struct GBCheatSet {
|
||||||
struct mCheatSet d;
|
struct mCheatSet d;
|
||||||
|
struct GBCheatPatchList romPatches;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mCheatDevice* GBCheatDeviceCreate(void);
|
struct mCheatDevice* GBCheatDeviceCreate(void);
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
|
|
||||||
#include "arm/arm.h"
|
#include "arm/arm.h"
|
||||||
#include "core/cheats.h"
|
#include "core/cheats.h"
|
||||||
#include "util/vector.h"
|
|
||||||
|
|
||||||
#define MAX_ROM_PATCHES 4
|
#define MAX_ROM_PATCHES 4
|
||||||
|
|
||||||
|
|
|
@ -260,6 +260,22 @@ const char* hex32(const char* line, uint32_t* out) {
|
||||||
return line;
|
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) {
|
const char* hex16(const char* line, uint16_t* out) {
|
||||||
uint16_t value = 0;
|
uint16_t value = 0;
|
||||||
*out = 0;
|
*out = 0;
|
||||||
|
@ -277,6 +293,23 @@ const char* hex16(const char* line, uint16_t* out) {
|
||||||
return line;
|
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) {
|
const char* hex8(const char* line, uint8_t* out) {
|
||||||
uint8_t value = 0;
|
uint8_t value = 0;
|
||||||
*out = 0;
|
*out = 0;
|
||||||
|
@ -293,3 +326,17 @@ const char* hex8(const char* line, uint8_t* out) {
|
||||||
*out = value;
|
*out = value;
|
||||||
return line;
|
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);
|
int hexDigit(char digit);
|
||||||
const char* hex32(const char* line, uint32_t* out);
|
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* 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* hex8(const char* line, uint8_t* out);
|
||||||
|
const char* hex4(const char* line, uint8_t* out);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue