all repos — mgba @ 44bbb9d1bba866b7428d78931c2bf66d042d5cfa

mGBA Game Boy Advance Emulator

Core: Refactor out cheats
Jeffrey Pfau jeffrey@endrift.com
Sat, 07 May 2016 22:54:35 -0700
commit

44bbb9d1bba866b7428d78931c2bf66d042d5cfa

parent

4b5885624bc647faf43b5aa83acb04146c41dacd

A src/core/cheats.c

@@ -0,0 +1,360 @@

+/* 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 "core/core.h" +#include "util/string.h" +#include "util/vfs.h" + +#define MAX_LINE_LENGTH 128 + +const uint32_t M_CHEAT_DEVICE_ID = 0xABADC0DE; + +mLOG_DEFINE_CATEGORY(CHEATS, "Cheats"); + +DEFINE_VECTOR(mCheatList, struct mCheat); +DEFINE_VECTOR(mCheatSets, struct mCheatSet*); +DEFINE_VECTOR(StringList, char*); + +static int32_t _readMem(struct mCore* core, uint32_t address, int width) { + switch (width) { + case 1: + return core->busRead8(core, address); + case 2: + return core->busRead16(core, address); + case 4: + return core->busRead32(core, address); + } + return 0; +} + +static void _writeMem(struct mCore* core, uint32_t address, int width, int32_t value) { + switch (width) { + case 1: + core->busWrite8(core, address, value); + break; + case 2: + core->busWrite16(core, address, value); + break; + case 4: + core->busWrite32(core, address, value); + break; + } +} + +static void mCheatDeviceInit(void*, struct mCPUComponent*); +static void mCheatDeviceDeinit(struct mCPUComponent*); + +void mCheatDeviceCreate(struct mCheatDevice* device) { + device->d.id = M_CHEAT_DEVICE_ID; + device->d.init = mCheatDeviceInit; + device->d.deinit = mCheatDeviceDeinit; + mCheatSetsInit(&device->cheats, 4); +} + +void mCheatDeviceDestroy(struct mCheatDevice* device) { + mCheatDeviceClear(device); + mCheatSetsDeinit(&device->cheats); +} + +void mCheatDeviceClear(struct mCheatDevice* device) { + size_t i; + for (i = 0; i < mCheatSetsSize(&device->cheats); ++i) { + struct mCheatSet* set = *mCheatSetsGetPointer(&device->cheats, i); + mCheatSetDeinit(set); + } + mCheatSetsClear(&device->cheats); +} + +void mCheatSetInit(struct mCheatSet* set, const char* name) { + mCheatListInit(&set->list, 4); + StringListInit(&set->lines, 4); + if (name) { + set->name = strdup(name); + } else { + set->name = 0; + } + set->enabled = true; +} + +void mCheatSetDeinit(struct mCheatSet* set) { + mCheatListDeinit(&set->list); + size_t i; + for (i = 0; i < StringListSize(&set->lines); ++i) { + free(*StringListGetPointer(&set->lines, i)); + } + if (set->name) { + free(set->name); + } + set->deinit(set); + free(set); +} + +void mCheatSetRename(struct mCheatSet* set, const char* name) { + if (set->name) { + free(set->name); + set->name = NULL; + } + if (name) { + set->name = strdup(name); + } +} + +bool mCheatAddLine(struct mCheatSet* set, const char* line, int type) { + if (!set->addLine(set, line, type)) { + return false; + } + *StringListAppend(&set->lines) = strdup(line); + return true; +} + +void mCheatAddSet(struct mCheatDevice* device, struct mCheatSet* cheats) { + *mCheatSetsAppend(&device->cheats) = cheats; + cheats->add(cheats, device); +} + +void mCheatRemoveSet(struct mCheatDevice* device, struct mCheatSet* cheats) { + size_t i; + for (i = 0; i < mCheatSetsSize(&device->cheats); ++i) { + if (*mCheatSetsGetPointer(&device->cheats, i) == cheats) { + break; + } + } + if (i == mCheatSetsSize(&device->cheats)) { + return; + } + mCheatSetsShift(&device->cheats, i, 1); + cheats->remove(cheats, device); +} + +bool mCheatParseFile(struct mCheatDevice* device, struct VFile* vf) { +#warning Cheat loading is currently broken + return false; +#if 0 + char cheat[MAX_LINE_LENGTH]; + struct mCheatSet* set = NULL; + struct mCheatSet* newSet; + bool nextDisabled = false; + void* directives = NULL; + while (true) { + size_t i = 0; + ssize_t bytesRead = vf->readline(vf, cheat, sizeof(cheat)); + if (bytesRead == 0) { + break; + } + if (bytesRead < 0) { + return false; + } + while (isspace((int) cheat[i])) { + ++i; + } + switch (cheat[i]) { + case '#': + do { + ++i; + } while (isspace((int) cheat[i])); + cheat[strlen(cheat) - 1] = '\0'; // Remove trailing newline + newSet = device->createSet(device, &cheat[i]); + newSet->enabled = !nextDisabled; + nextDisabled = false; + if (set) { + mCheatAddSet(device, set); + } + if (set) { + newSet->copyProperties(newSet, set); + } + set = newSet; + break; + case '!': + do { + ++i; + } while (isspace((int) cheat[i])); + if (strcasecmp(&cheat[i], "disabled") == 0) { + nextDisabled = true; + break; + } + if (strcasecmp(&cheat[i], "reset") == 0) { + directives = NULL; + break; + } + directives = set->parseDirective(set, &cheat[i], directives); + break; + default: + if (!set) { + set = device->createSet(device, NULL); + set->enabled = !nextDisabled; + nextDisabled = false; + } + mCheatAddLine(set, cheat); + break; + } + } + if (set) { + mCheatAddSet(device, set); + } + return true; +#endif +} + +bool mCheatSaveFile(struct mCheatDevice* device, struct VFile* vf) { +#warning Cheat saving is currently broken + return false; +#if 0 + static const char lineStart[3] = "# "; + static const char lineEnd = '\n'; + void* directives = NULL; + + size_t i; + for (i = 0; i < mCheatSetsSize(&device->cheats); ++i) { + struct mCheatSet* set = *mCheatSetsGetPointer(&device->cheats, i); + void* directives = set->dumpDirectives(set, vf, directives); + if (!set->enabled) { + static const char* disabledDirective = "!disabled\n"; + vf->write(vf, disabledDirective, strlen(disabledDirective)); + } + + vf->write(vf, lineStart, 2); + if (set->name) { + vf->write(vf, set->name, strlen(set->name)); + } + vf->write(vf, &lineEnd, 1); + size_t c; + for (c = 0; c < StringListSize(&set->lines); ++c) { + const char* line = *StringListGetPointer(&set->lines, c); + vf->write(vf, line, strlen(line)); + vf->write(vf, &lineEnd, 1); + } + } + return true; +#endif +} + +void mCheatRefresh(struct mCheatDevice* device, struct mCheatSet* cheats) { + if (!cheats->enabled) { + return; + } + bool condition = true; + int conditionRemaining = 0; + int negativeConditionRemaining = 0; + cheats->refresh(cheats, device); + + size_t nCodes = mCheatListSize(&cheats->list); + size_t i; + for (i = 0; i < nCodes; ++i) { + if (conditionRemaining > 0) { + --conditionRemaining; + if (!condition) { + continue; + } + } else if (negativeConditionRemaining > 0) { + conditionRemaining = negativeConditionRemaining - 1; + negativeConditionRemaining = 0; + condition = !condition; + if (!condition) { + continue; + } + } else { + condition = true; + } + struct mCheat* cheat = mCheatListGetPointer(&cheats->list, i); + int32_t value = 0; + int32_t operand = cheat->operand; + uint32_t operationsRemaining = cheat->repeat; + uint32_t address = cheat->address; + bool performAssignment = false; + for (; operationsRemaining; --operationsRemaining) { + switch (cheat->type) { + case CHEAT_ASSIGN: + value = operand; + performAssignment = true; + break; + case CHEAT_ASSIGN_INDIRECT: + value = operand; + address = _readMem(device->p, address + cheat->addressOffset, 4); + performAssignment = true; + break; + case CHEAT_AND: + value = _readMem(device->p, address, cheat->width) & operand; + performAssignment = true; + break; + case CHEAT_ADD: + value = _readMem(device->p, address, cheat->width) + operand; + performAssignment = true; + break; + case CHEAT_OR: + value = _readMem(device->p, address, cheat->width) | operand; + performAssignment = true; + break; + case CHEAT_IF_EQ: + condition = _readMem(device->p, address, cheat->width) == operand; + conditionRemaining = cheat->repeat; + negativeConditionRemaining = cheat->negativeRepeat; + break; + case CHEAT_IF_NE: + condition = _readMem(device->p, address, cheat->width) != operand; + conditionRemaining = cheat->repeat; + negativeConditionRemaining = cheat->negativeRepeat; + break; + case CHEAT_IF_LT: + condition = _readMem(device->p, address, cheat->width) < operand; + conditionRemaining = cheat->repeat; + negativeConditionRemaining = cheat->negativeRepeat; + break; + case CHEAT_IF_GT: + condition = _readMem(device->p, address, cheat->width) > operand; + conditionRemaining = cheat->repeat; + negativeConditionRemaining = cheat->negativeRepeat; + break; + case CHEAT_IF_ULT: + condition = (uint32_t) _readMem(device->p, address, cheat->width) < (uint32_t) operand; + conditionRemaining = cheat->repeat; + negativeConditionRemaining = cheat->negativeRepeat; + break; + case CHEAT_IF_UGT: + condition = (uint32_t) _readMem(device->p, address, cheat->width) > (uint32_t) operand; + conditionRemaining = cheat->repeat; + negativeConditionRemaining = cheat->negativeRepeat; + break; + case CHEAT_IF_AND: + condition = _readMem(device->p, address, cheat->width) & operand; + conditionRemaining = cheat->repeat; + negativeConditionRemaining = cheat->negativeRepeat; + break; + case CHEAT_IF_LAND: + condition = _readMem(device->p, address, cheat->width) && operand; + conditionRemaining = cheat->repeat; + negativeConditionRemaining = cheat->negativeRepeat; + break; + } + + if (performAssignment) { + _writeMem(device->p, address, cheat->width, value); + } + + address += cheat->addressOffset; + operand += cheat->operandOffset; + } + } +} + +void mCheatDeviceInit(void* cpu, struct mCPUComponent* component) { + UNUSED(cpu); + struct mCheatDevice* device = (struct mCheatDevice*) component; + size_t i; + for (i = 0; i < mCheatSetsSize(&device->cheats); ++i) { + struct mCheatSet* cheats = *mCheatSetsGetPointer(&device->cheats, i); + cheats->add(cheats, device); + } +} + +void mCheatDeviceDeinit(struct mCPUComponent* component) { + struct mCheatDevice* device = (struct mCheatDevice*) component; + size_t i; + for (i = mCheatSetsSize(&device->cheats); i--;) { + struct mCheatSet* cheats = *mCheatSetsGetPointer(&device->cheats, i); + cheats->remove(cheats, device); + } +}
A src/core/cheats.h

@@ -0,0 +1,99 @@

+/* 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 CHEATS_H +#define CHEATS_H + +#include "util/common.h" + +#include "core/cpu.h" +#include "core/log.h" +#include "util/vector.h" + +#define MAX_ROM_PATCHES 4 + +enum mCheatType { + CHEAT_ASSIGN, + CHEAT_ASSIGN_INDIRECT, + CHEAT_AND, + CHEAT_ADD, + CHEAT_OR, + CHEAT_IF_EQ, + CHEAT_IF_NE, + CHEAT_IF_LT, + CHEAT_IF_GT, + CHEAT_IF_ULT, + CHEAT_IF_UGT, + CHEAT_IF_AND, + CHEAT_IF_LAND +}; + +struct mCheat { + enum mCheatType type; + int width; + uint32_t address; + uint32_t operand; + uint32_t repeat; + uint32_t negativeRepeat; + + int32_t addressOffset; + int32_t operandOffset; +}; + +mLOG_DECLARE_CATEGORY(CHEATS); + +DECLARE_VECTOR(mCheatList, struct mCheat); +DECLARE_VECTOR(StringList, char*); + +struct mCheatDevice; +struct mCheatSet { + struct mCheatList list; + + void (*deinit)(struct mCheatSet* set); + void (*add)(struct mCheatSet* set, struct mCheatDevice* device); + void (*remove)(struct mCheatSet* set, struct mCheatDevice* device); + + bool (*addLine)(struct mCheatSet* set, const char* cheat, int type); + void (*copyProperties)(struct mCheatSet* set, struct mCheatSet* oldSet); + + void (*refresh)(struct mCheatSet* set, struct mCheatDevice* device); + + char* name; + bool enabled; + struct StringList lines; +}; + +DECLARE_VECTOR(mCheatSets, struct mCheatSet*); + +struct mCheatDevice { + struct mCPUComponent d; + struct mCore* p; + + struct mCheatSet* (*createSet)(struct mCheatDevice*, const char* name); + + struct mCheatSets cheats; +}; + +struct VFile; + +void mCheatDeviceCreate(struct mCheatDevice*); +void mCheatDeviceDestroy(struct mCheatDevice*); +void mCheatDeviceClear(struct mCheatDevice*); + +void mCheatSetInit(struct mCheatSet*, const char* name); +void mCheatSetDeinit(struct mCheatSet*); +void mCheatSetRename(struct mCheatSet*, const char* name); + +bool mCheatAddLine(struct mCheatSet*, const char* line, int type); + +void mCheatAddSet(struct mCheatDevice*, struct mCheatSet*); +void mCheatRemoveSet(struct mCheatDevice*, struct mCheatSet*); + +bool mCheatParseFile(struct mCheatDevice*, struct VFile*); +bool mCheatSaveFile(struct mCheatDevice*, struct VFile*); + +void mCheatRefresh(struct mCheatDevice*, struct mCheatSet*); + +#endif
M src/core/core.hsrc/core/core.h

@@ -117,6 +117,8 @@ struct mDebuggerPlatform* (*debuggerPlatform)(struct mCore*);

struct CLIDebuggerSystem* (*cliDebuggerSystem)(struct mCore*); void (*attachDebugger)(struct mCore*, struct mDebugger*); void (*detachDebugger)(struct mCore*); + + struct mCheatDevice* (*cheatDevice)(struct mCore*); }; #if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
M src/gba/cheats.csrc/gba/cheats.c

@@ -9,49 +9,10 @@ #include "gba/cheats/gameshark.h"

#include "gba/cheats/parv3.h" #include "gba/gba.h" #include "util/string.h" -#include "util/vfs.h" #define MAX_LINE_LENGTH 128 -const uint32_t GBA_CHEAT_DEVICE_ID = 0xABADC0DE; - -mLOG_DEFINE_CATEGORY(CHEATS, "Cheats"); - -DEFINE_VECTOR(GBACheatList, struct GBACheat); -DEFINE_VECTOR(GBACheatSets, struct GBACheatSet*); -DEFINE_VECTOR(StringList, char*); - -static int32_t _readMem(struct ARMCore* cpu, uint32_t address, int width) { - switch (width) { - case 1: - return cpu->memory.load8(cpu, address, 0); - case 2: - return cpu->memory.load16(cpu, address, 0); - case 4: - return cpu->memory.load32(cpu, address, 0); - } - return 0; -} - -static void _writeMem(struct ARMCore* cpu, uint32_t address, int width, int32_t value) { - switch (width) { - case 1: - cpu->memory.store8(cpu, address, value, 0); - break; - case 2: - cpu->memory.store16(cpu, address, value, 0); - break; - case 4: - cpu->memory.store32(cpu, address, value, 0); - break; - } -} - -void GBACheatRegisterLine(struct GBACheatSet* cheats, const char* line) { - *StringListAppend(&cheats->lines) = strdup(line); -} - -static void _addBreakpoint(struct GBACheatDevice* device, struct GBACheatSet* cheats) { +static void _addBreakpoint(struct mCheatDevice* device, struct GBACheatSet* cheats) { if (!device->p || !cheats->hook) { return; }

@@ -59,10 +20,10 @@ ++cheats->hook->reentries;

if (cheats->hook->reentries > 1) { return; } - GBASetBreakpoint(device->p, &device->d, cheats->hook->address, cheats->hook->mode, &cheats->hook->patchedOpcode); + GBASetBreakpoint(device->p->board, &device->d, cheats->hook->address, cheats->hook->mode, &cheats->hook->patchedOpcode); } -static void _removeBreakpoint(struct GBACheatDevice* device, struct GBACheatSet* cheats) { +static void _removeBreakpoint(struct mCheatDevice* device, struct GBACheatSet* cheats) { if (!device->p || !cheats->hook) { return; }

@@ -70,10 +31,10 @@ --cheats->hook->reentries;

if (cheats->hook->reentries > 0) { return; } - GBAClearBreakpoint(device->p, cheats->hook->address, cheats->hook->mode, cheats->hook->patchedOpcode); + GBAClearBreakpoint(device->p->board, cheats->hook->address, cheats->hook->mode, cheats->hook->patchedOpcode); } -static void _patchROM(struct GBACheatDevice* device, struct GBACheatSet* cheats) { +static void _patchROM(struct mCheatDevice* device, struct GBACheatSet* cheats) { if (!device->p) { return; }

@@ -87,7 +48,7 @@ cheats->romPatches[i].applied = true;

} } -static void _unpatchROM(struct GBACheatDevice* device, struct GBACheatSet* cheats) { +static void _unpatchROM(struct mCheatDevice* device, struct GBACheatSet* cheats) { if (!device->p) { return; }

@@ -101,34 +62,17 @@ cheats->romPatches[i].applied = false;

} } -static void GBACheatDeviceInit(void*, struct mCPUComponent*); -static void GBACheatDeviceDeinit(struct mCPUComponent*); - -void GBACheatDeviceCreate(struct GBACheatDevice* device) { - device->d.id = GBA_CHEAT_DEVICE_ID; - device->d.init = GBACheatDeviceInit; - device->d.deinit = GBACheatDeviceDeinit; - GBACheatSetsInit(&device->cheats, 4); -} - -void GBACheatDeviceDestroy(struct GBACheatDevice* device) { - GBACheatDeviceClear(device); - GBACheatSetsDeinit(&device->cheats); -} - -void GBACheatDeviceClear(struct GBACheatDevice* device) { - size_t i; - for (i = 0; i < GBACheatSetsSize(&device->cheats); ++i) { - struct GBACheatSet* set = *GBACheatSetsGetPointer(&device->cheats, i); - GBACheatSetDeinit(set); - free(set); - } - GBACheatSetsClear(&device->cheats); -} +static void GBACheatSetDeinit(struct mCheatSet* set); +static void GBACheatAddSet(struct mCheatSet* cheats, struct mCheatDevice* device); +static void GBACheatRemoveSet(struct mCheatSet* cheats, struct mCheatDevice* device); +static void GBACheatRefresh(struct mCheatSet* cheats, struct mCheatDevice* device); +static void GBACheatSetCopyProperties(struct mCheatSet* set, struct mCheatSet* oldSet); +static bool GBACheatAddLine(struct mCheatSet*, const char* line, int type); -void GBACheatSetInit(struct GBACheatSet* set, const char* name) { - GBACheatListInit(&set->list, 4); - StringListInit(&set->lines, 4); +static struct mCheatSet* GBACheatSetCreate(struct mCheatDevice* device, const char* name) { + UNUSED(device); + struct GBACheatSet* set = malloc(sizeof(*set)); + mCheatSetInit(&set->d, name); set->incompleteCheat = 0; set->incompletePatch = 0; set->currentBlock = 0;

@@ -136,72 +80,58 @@ set->gsaVersion = 0;

set->cbRngState = 0; set->cbMaster = 0; set->remainingAddresses = 0; - set->hook = 0; + set->hook = NULL; + + set->d.deinit = GBACheatSetDeinit; + set->d.add = GBACheatAddSet; + set->d.remove = GBACheatRemoveSet; + + set->d.addLine = GBACheatAddLine; + set->d.copyProperties = GBACheatSetCopyProperties; + + set->d.refresh = GBACheatRefresh; + int i; for (i = 0; i < MAX_ROM_PATCHES; ++i) { set->romPatches[i].exists = false; } - if (name) { - set->name = strdup(name); - } else { - set->name = 0; - } - set->enabled = true; + return &set->d; } -void GBACheatSetDeinit(struct GBACheatSet* set) { - GBACheatListDeinit(&set->list); - size_t i; - for (i = 0; i < StringListSize(&set->lines); ++i) { - free(*StringListGetPointer(&set->lines, i)); - } - if (set->name) { - free(set->name); - } - if (set->hook) { - --set->hook->refs; - if (set->hook->refs == 0) { - free(set->hook); - } - } +struct mCheatDevice* GBACheatDeviceCreate(void) { + struct mCheatDevice* device = malloc(sizeof(*device)); + mCheatDeviceCreate(device); + device->createSet = GBACheatSetCreate; + return device; } -void GBACheatAttachDevice(struct GBA* gba, struct GBACheatDevice* device) { - // TODO: Remove this function - if (gba->cpu->components[CPU_COMPONENT_CHEAT_DEVICE]) { - ARMHotplugDetach(gba->cpu, CPU_COMPONENT_CHEAT_DEVICE); +static void GBACheatSetDeinit(struct mCheatSet* set) { + struct GBACheatSet* gbaset = (struct GBACheatSet*) set; + if (gbaset->hook) { + --gbaset->hook->refs; + if (gbaset->hook->refs == 0) { + free(gbaset->hook); + } } - gba->cpu->components[CPU_COMPONENT_CHEAT_DEVICE] = &device->d; - ARMHotplugAttach(gba->cpu, CPU_COMPONENT_CHEAT_DEVICE); } -void GBACheatAddSet(struct GBACheatDevice* device, struct GBACheatSet* cheats) { - *GBACheatSetsAppend(&device->cheats) = cheats; - _addBreakpoint(device, cheats); - _patchROM(device, cheats); +static void GBACheatAddSet(struct mCheatSet* cheats, struct mCheatDevice* device) { + struct GBACheatSet* gbaset = (struct GBACheatSet*) cheats; + _addBreakpoint(device, gbaset); + _patchROM(device, gbaset); } -void GBACheatRemoveSet(struct GBACheatDevice* device, struct GBACheatSet* cheats) { - size_t i; - for (i = 0; i < GBACheatSetsSize(&device->cheats); ++i) { - if (*GBACheatSetsGetPointer(&device->cheats, i) == cheats) { - break; - } - } - if (i == GBACheatSetsSize(&device->cheats)) { - return; - } - GBACheatSetsShift(&device->cheats, i, 1); - _unpatchROM(device, cheats); - _removeBreakpoint(device, cheats); +static void GBACheatRemoveSet(struct mCheatSet* cheats, struct mCheatDevice* device) { + struct GBACheatSet* gbaset = (struct GBACheatSet*) cheats; + _unpatchROM(device, gbaset); + _removeBreakpoint(device, gbaset); } -bool GBACheatAddAutodetect(struct GBACheatSet* set, uint32_t op1, uint32_t op2) { +static bool GBACheatAddAutodetect(struct GBACheatSet* set, uint32_t op1, uint32_t op2) { uint32_t o1 = op1; uint32_t o2 = op2; char line[18] = "XXXXXXXX XXXXXXXX"; snprintf(line, sizeof(line), "%08X %08X", op1, op2); - GBACheatRegisterLine(set, line); switch (set->gsaVersion) { case 0:

@@ -229,147 +159,6 @@ }

return false; } -bool GBACheatAutodetectLine(struct GBACheatSet* cheats, const char* line) { - uint32_t op1; - uint32_t op2; - line = hex32(line, &op1); - if (!line) { - return false; - } - while (*line == ' ') { - ++line; - } - line = hex32(line, &op2); - if (!line) { - return false; - } - return GBACheatAddAutodetect(cheats, op1, op2); -} - -bool GBACheatParseFile(struct GBACheatDevice* device, struct VFile* vf) { - char cheat[MAX_LINE_LENGTH]; - struct GBACheatSet* set = 0; - struct GBACheatSet* newSet; - int gsaVersion = 0; - bool nextDisabled = false; - bool reset = false; - while (true) { - size_t i = 0; - ssize_t bytesRead = vf->readline(vf, cheat, sizeof(cheat)); - if (bytesRead == 0) { - break; - } - if (bytesRead < 0) { - return false; - } - while (isspace((int) cheat[i])) { - ++i; - } - switch (cheat[i]) { - case '#': - do { - ++i; - } while (isspace((int) cheat[i])); - cheat[strlen(cheat) - 1] = '\0'; // Remove trailing newline - newSet = malloc(sizeof(*set)); - GBACheatSetInit(newSet, &cheat[i]); - newSet->enabled = !nextDisabled; - nextDisabled = false; - if (set) { - GBACheatAddSet(device, set); - } - if (set && !reset) { - GBACheatSetCopyProperties(newSet, set); - } else { - GBACheatSetGameSharkVersion(newSet, gsaVersion); - } - reset = false; - set = newSet; - break; - case '!': - do { - ++i; - } while (isspace((int) cheat[i])); - if (strncasecmp(&cheat[i], "GSAv", 4) == 0 || strncasecmp(&cheat[i], "PARv", 4) == 0) { - i += 4; - gsaVersion = atoi(&cheat[i]); - break; - } - if (strcasecmp(&cheat[i], "disabled") == 0) { - nextDisabled = true; - break; - } - if (strcasecmp(&cheat[i], "reset") == 0) { - reset = true; - break; - } - break; - default: - if (!set) { - set = malloc(sizeof(*set)); - GBACheatSetInit(set, 0); - set->enabled = !nextDisabled; - nextDisabled = false; - GBACheatSetGameSharkVersion(set, gsaVersion); - } - GBACheatAddLine(set, cheat); - break; - } - } - if (set) { - GBACheatAddSet(device, set); - } - return true; -} - -bool GBACheatSaveFile(struct GBACheatDevice* device, struct VFile* vf) { - static const char lineStart[3] = "# "; - static const char lineEnd = '\n'; - - struct GBACheatHook* lastHook = 0; - - size_t i; - for (i = 0; i < GBACheatSetsSize(&device->cheats); ++i) { - struct GBACheatSet* set = *GBACheatSetsGetPointer(&device->cheats, i); - if (lastHook && set->hook != lastHook) { - static const char* resetDirective = "!reset\n"; - vf->write(vf, resetDirective, strlen(resetDirective)); - } - switch (set->gsaVersion) { - case 1: { - static const char* versionDirective = "!GSAv1\n"; - vf->write(vf, versionDirective, strlen(versionDirective)); - break; - } - case 3: { - static const char* versionDirective = "!PARv3\n"; - vf->write(vf, versionDirective, strlen(versionDirective)); - break; - } - default: - break; - } - lastHook = set->hook; - if (!set->enabled) { - static const char* disabledDirective = "!disabled\n"; - vf->write(vf, disabledDirective, strlen(disabledDirective)); - } - - vf->write(vf, lineStart, 2); - if (set->name) { - vf->write(vf, set->name, strlen(set->name)); - } - vf->write(vf, &lineEnd, 1); - size_t c; - for (c = 0; c < StringListSize(&set->lines); ++c) { - const char* line = *StringListGetPointer(&set->lines, c); - vf->write(vf, line, strlen(line)); - vf->write(vf, &lineEnd, 1); - } - } - return true; -} - bool GBACheatAddVBALine(struct GBACheatSet* cheats, const char* line) { uint32_t address; uint8_t op;

@@ -396,7 +185,7 @@ if (width == 0 || width == 3) {

return false; } - struct GBACheat* cheat = GBACheatListAppend(&cheats->list); + struct mCheat* cheat = mCheatListAppend(&cheats->d.list); cheat->address = address; cheat->operandOffset = 0; cheat->addressOffset = 0;

@@ -404,11 +193,26 @@ cheat->repeat = 1;

cheat->type = CHEAT_ASSIGN; cheat->width = width; cheat->operand = value; - GBACheatRegisterLine(cheats, line); return true; } -bool GBACheatAddLine(struct GBACheatSet* cheats, const char* line) { +bool GBACheatAddLine(struct mCheatSet* set, const char* line, int type) { + struct GBACheatSet* cheats = (struct GBACheatSet*) set; + switch (type) { + case GBA_CHEAT_AUTODETECT: + break; + case GBA_CHEAT_CODEBREAKER: + return GBACheatAddCodeBreakerLine(cheats, line); + case GBA_CHEAT_GAMESHARK: + return GBACheatAddGameSharkLine(cheats, line); + case GBA_CHEAT_PRO_ACTION_REPLAY: + return GBACheatAddProActionReplayLine(cheats, line); + case GBA_CHEAT_VBA: + return GBACheatAddVBALine(cheats, line); + default: + return false; + } + uint32_t op1; uint16_t op2; uint16_t op3;

@@ -439,150 +243,28 @@ realOp2 |= op3;

return GBACheatAddAutodetect(cheats, op1, realOp2); } -void GBACheatRefresh(struct GBACheatDevice* device, struct GBACheatSet* cheats) { - if (!cheats->enabled) { - return; - } - bool condition = true; - int conditionRemaining = 0; - int negativeConditionRemaining = 0; - _patchROM(device, cheats); - - size_t nCodes = GBACheatListSize(&cheats->list); - size_t i; - for (i = 0; i < nCodes; ++i) { - if (conditionRemaining > 0) { - --conditionRemaining; - if (!condition) { - continue; - } - } else if (negativeConditionRemaining > 0) { - conditionRemaining = negativeConditionRemaining - 1; - negativeConditionRemaining = 0; - condition = !condition; - if (!condition) { - continue; - } - } else { - condition = true; - } - struct GBACheat* cheat = GBACheatListGetPointer(&cheats->list, i); - int32_t value = 0; - int32_t operand = cheat->operand; - uint32_t operationsRemaining = cheat->repeat; - uint32_t address = cheat->address; - bool performAssignment = false; - for (; operationsRemaining; --operationsRemaining) { - switch (cheat->type) { - case CHEAT_ASSIGN: - value = operand; - performAssignment = true; - break; - case CHEAT_ASSIGN_INDIRECT: - value = operand; - address = _readMem(device->p->cpu, address + cheat->addressOffset, 4); - performAssignment = true; - break; - case CHEAT_AND: - value = _readMem(device->p->cpu, address, cheat->width) & operand; - performAssignment = true; - break; - case CHEAT_ADD: - value = _readMem(device->p->cpu, address, cheat->width) + operand; - performAssignment = true; - break; - case CHEAT_OR: - value = _readMem(device->p->cpu, address, cheat->width) | operand; - performAssignment = true; - break; - case CHEAT_IF_EQ: - condition = _readMem(device->p->cpu, address, cheat->width) == operand; - conditionRemaining = cheat->repeat; - negativeConditionRemaining = cheat->negativeRepeat; - break; - case CHEAT_IF_NE: - condition = _readMem(device->p->cpu, address, cheat->width) != operand; - conditionRemaining = cheat->repeat; - negativeConditionRemaining = cheat->negativeRepeat; - break; - case CHEAT_IF_LT: - condition = _readMem(device->p->cpu, address, cheat->width) < operand; - conditionRemaining = cheat->repeat; - negativeConditionRemaining = cheat->negativeRepeat; - break; - case CHEAT_IF_GT: - condition = _readMem(device->p->cpu, address, cheat->width) > operand; - conditionRemaining = cheat->repeat; - negativeConditionRemaining = cheat->negativeRepeat; - break; - case CHEAT_IF_ULT: - condition = (uint32_t) _readMem(device->p->cpu, address, cheat->width) < (uint32_t) operand; - conditionRemaining = cheat->repeat; - negativeConditionRemaining = cheat->negativeRepeat; - break; - case CHEAT_IF_UGT: - condition = (uint32_t) _readMem(device->p->cpu, address, cheat->width) > (uint32_t) operand; - conditionRemaining = cheat->repeat; - negativeConditionRemaining = cheat->negativeRepeat; - break; - case CHEAT_IF_AND: - condition = _readMem(device->p->cpu, address, cheat->width) & operand; - conditionRemaining = cheat->repeat; - negativeConditionRemaining = cheat->negativeRepeat; - break; - case CHEAT_IF_LAND: - condition = _readMem(device->p->cpu, address, cheat->width) && operand; - conditionRemaining = cheat->repeat; - negativeConditionRemaining = cheat->negativeRepeat; - break; - } - - if (performAssignment) { - _writeMem(device->p->cpu, address, cheat->width, value); - } - - address += cheat->addressOffset; - operand += cheat->operandOffset; - } - } +static void GBACheatRefresh(struct mCheatSet* cheats, struct mCheatDevice* device) { + struct GBACheatSet* gbaset = (struct GBACheatSet*) cheats; + _patchROM(device, gbaset); } -void GBACheatSetCopyProperties(struct GBACheatSet* newSet, struct GBACheatSet* set) { - newSet->gsaVersion = set->gsaVersion; - memcpy(newSet->gsaSeeds, set->gsaSeeds, sizeof(newSet->gsaSeeds)); - newSet->cbRngState = set->cbRngState; - newSet->cbMaster = set->cbMaster; - memcpy(newSet->cbSeeds, set->cbSeeds, sizeof(newSet->cbSeeds)); - memcpy(newSet->cbTable, set->cbTable, sizeof(newSet->cbTable)); - if (set->hook) { +static void GBACheatSetCopyProperties(struct mCheatSet* set, struct mCheatSet* oldSet) { + struct GBACheatSet* newSet = (struct GBACheatSet*) set; + struct GBACheatSet* gbaset = (struct GBACheatSet*) oldSet; + newSet->gsaVersion = gbaset->gsaVersion; + memcpy(newSet->gsaSeeds, gbaset->gsaSeeds, sizeof(newSet->gsaSeeds)); + newSet->cbRngState = gbaset->cbRngState; + newSet->cbMaster = gbaset->cbMaster; + memcpy(newSet->cbSeeds, gbaset->cbSeeds, sizeof(newSet->cbSeeds)); + memcpy(newSet->cbTable, gbaset->cbTable, sizeof(newSet->cbTable)); + if (gbaset->hook) { if (newSet->hook) { --newSet->hook->refs; if (newSet->hook->refs == 0) { free(newSet->hook); } } - newSet->hook = set->hook; + newSet->hook = gbaset->hook; ++newSet->hook->refs; } } - -void GBACheatDeviceInit(void* cpu, struct mCPUComponent* component) { - struct GBACheatDevice* device = (struct GBACheatDevice*) component; - device->p = (struct GBA*) ((struct ARMCore*) cpu)->master; - size_t i; - for (i = 0; i < GBACheatSetsSize(&device->cheats); ++i) { - struct GBACheatSet* cheats = *GBACheatSetsGetPointer(&device->cheats, i); - _addBreakpoint(device, cheats); - _patchROM(device, cheats); - } -} - -void GBACheatDeviceDeinit(struct mCPUComponent* component) { - struct GBACheatDevice* device = (struct GBACheatDevice*) component; - size_t i; - for (i = GBACheatSetsSize(&device->cheats); i--;) { - struct GBACheatSet* cheats = *GBACheatSetsGetPointer(&device->cheats, i); - _unpatchROM(device, cheats); - _removeBreakpoint(device, cheats); - } -}
M src/gba/cheats.hsrc/gba/cheats.h

@@ -9,25 +9,17 @@

#include "util/common.h" #include "arm/arm.h" -#include "core/log.h" +#include "core/cheats.h" #include "util/vector.h" #define MAX_ROM_PATCHES 4 enum GBACheatType { - CHEAT_ASSIGN, - CHEAT_ASSIGN_INDIRECT, - CHEAT_AND, - CHEAT_ADD, - CHEAT_OR, - CHEAT_IF_EQ, - CHEAT_IF_NE, - CHEAT_IF_LT, - CHEAT_IF_GT, - CHEAT_IF_ULT, - CHEAT_IF_UGT, - CHEAT_IF_AND, - CHEAT_IF_LAND + GBA_CHEAT_AUTODETECT, + GBA_CHEAT_CODEBREAKER, + GBA_CHEAT_GAMESHARK, + GBA_CHEAT_PRO_ACTION_REPLAY, + GBA_CHEAT_VBA }; enum GBACodeBreakerType {

@@ -132,18 +124,6 @@

PAR3_WIDTH_BASE = 25 }; -struct GBACheat { - enum GBACheatType type; - int width; - uint32_t address; - uint32_t operand; - uint32_t repeat; - uint32_t negativeRepeat; - - int32_t addressOffset; - int32_t operandOffset; -}; - struct GBACheatHook { uint32_t address; enum ExecutionMode mode;

@@ -152,14 +132,9 @@ size_t refs;

size_t reentries; }; -mLOG_DECLARE_CATEGORY(CHEATS); - -DECLARE_VECTOR(GBACheatList, struct GBACheat); -DECLARE_VECTOR(StringList, char*); - struct GBACheatSet { + struct mCheatSet d; struct GBACheatHook* hook; - struct GBACheatList list; struct GBACheatPatch { uint32_t address;

@@ -169,9 +144,9 @@ bool applied;

bool exists; } romPatches[MAX_ROM_PATCHES]; - struct GBACheat* incompleteCheat; + struct mCheat* incompleteCheat; struct GBACheatPatch* incompletePatch; - struct GBACheat* currentBlock; + struct mCheat* currentBlock; int gsaVersion; uint32_t gsaSeeds[4];

@@ -180,35 +155,11 @@ uint32_t cbMaster;

uint8_t cbTable[0x30]; uint32_t cbSeeds[4]; int remainingAddresses; - - char* name; - bool enabled; - struct StringList lines; -}; - -DECLARE_VECTOR(GBACheatSets, struct GBACheatSet*); - -struct GBACheatDevice { - struct mCPUComponent d; - struct GBA* p; - - struct GBACheatSets cheats; }; struct VFile; -void GBACheatDeviceCreate(struct GBACheatDevice*); -void GBACheatDeviceDestroy(struct GBACheatDevice*); -void GBACheatDeviceClear(struct GBACheatDevice*); - -void GBACheatSetInit(struct GBACheatSet*, const char* name); -void GBACheatSetDeinit(struct GBACheatSet*); - -void GBACheatAttachDevice(struct GBA* gba, struct GBACheatDevice*); - -void GBACheatAddSet(struct GBACheatDevice*, struct GBACheatSet*); -void GBACheatRemoveSet(struct GBACheatDevice*, struct GBACheatSet*); -void GBACheatSetCopyProperties(struct GBACheatSet* newSet, struct GBACheatSet* set); +struct mCheatDevice* GBACheatDeviceCreate(void); bool GBACheatAddCodeBreaker(struct GBACheatSet*, uint32_t op1, uint16_t op2); bool GBACheatAddCodeBreakerLine(struct GBACheatSet*, const char* line);

@@ -220,14 +171,5 @@ bool GBACheatAddProActionReplay(struct GBACheatSet*, uint32_t op1, uint32_t op2);

bool GBACheatAddProActionReplayLine(struct GBACheatSet*, const char* line); bool GBACheatAddVBALine(struct GBACheatSet*, const char* line); - -bool GBACheatAddAutodetect(struct GBACheatSet*, uint32_t op1, uint32_t op2); - -bool GBACheatParseFile(struct GBACheatDevice*, struct VFile*); -bool GBACheatSaveFile(struct GBACheatDevice*, struct VFile*); - -bool GBACheatAddLine(struct GBACheatSet*, const char* line); - -void GBACheatRefresh(struct GBACheatDevice*, struct GBACheatSet*); #endif
D src/gba/cheats/cheats-private.h

@@ -1,13 +0,0 @@

-/* Copyright (c) 2013-2015 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 GBA_CHEATS_PRIVATE_H -#define GBA_CHEATS_PRIVATE_H - -#include "gba/cheats.h" - -void GBACheatRegisterLine(struct GBACheatSet* set, const char* line); - -#endif
M src/gba/cheats/codebreaker.csrc/gba/cheats/codebreaker.c

@@ -5,7 +5,6 @@ * 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 "gba/cheats.h" -#include "gba/cheats/cheats-private.h" #include "gba/gba.h" #include "gba/io.h" #include "util/string.h"

@@ -190,14 +189,13 @@

bool GBACheatAddCodeBreaker(struct GBACheatSet* cheats, uint32_t op1, uint16_t op2) { char line[14] = "XXXXXXXX XXXX"; snprintf(line, sizeof(line), "%08X %04X", op1, op2); - GBACheatRegisterLine(cheats, line); if (cheats->cbMaster) { _cbDecrypt(cheats, &op1, &op2); } enum GBACodeBreakerType type = op1 >> 28; - struct GBACheat* cheat = 0; + struct mCheat* cheat = NULL; if (cheats->incompleteCheat) { cheats->incompleteCheat->repeat = op1 & 0xFFFF;

@@ -222,17 +220,17 @@ cheats->hook->refs = 1;

cheats->hook->reentries = 0; return true; case CB_OR_2: - cheat = GBACheatListAppend(&cheats->list); + cheat = mCheatListAppend(&cheats->d.list); cheat->type = CHEAT_OR; cheat->width = 2; break; case CB_ASSIGN_1: - cheat = GBACheatListAppend(&cheats->list); + cheat = mCheatListAppend(&cheats->d.list); cheat->type = CHEAT_ASSIGN; cheat->width = 1; break; case CB_FILL: - cheat = GBACheatListAppend(&cheats->list); + cheat = mCheatListAppend(&cheats->d.list); cheat->type = CHEAT_ASSIGN; cheat->width = 2; cheats->incompleteCheat = cheat;

@@ -241,17 +239,17 @@ case CB_FILL_8:

mLOG(CHEATS, STUB, "CodeBreaker code %08X %04X not supported", op1, op2); return false; case CB_AND_2: - cheat = GBACheatListAppend(&cheats->list); + cheat = mCheatListAppend(&cheats->d.list); cheat->type = CHEAT_AND; cheat->width = 2; break; case CB_IF_EQ: - cheat = GBACheatListAppend(&cheats->list); + cheat = mCheatListAppend(&cheats->d.list); cheat->type = CHEAT_IF_EQ; cheat->width = 2; break; case CB_ASSIGN_2: - cheat = GBACheatListAppend(&cheats->list); + cheat = mCheatListAppend(&cheats->d.list); cheat->type = CHEAT_ASSIGN; cheat->width = 2; break;

@@ -259,24 +257,24 @@ case CB_ENCRYPT:

_cbReseed(cheats, op1, op2); return true; case CB_IF_NE: - cheat = GBACheatListAppend(&cheats->list); + cheat = mCheatListAppend(&cheats->d.list); cheat->type = CHEAT_IF_NE; cheat->width = 2; break; case CB_IF_GT: - cheat = GBACheatListAppend(&cheats->list); + cheat = mCheatListAppend(&cheats->d.list); cheat->type = CHEAT_IF_GT; cheat->width = 2; break; case CB_IF_LT: - cheat = GBACheatListAppend(&cheats->list); + cheat = mCheatListAppend(&cheats->d.list); cheat->type = CHEAT_IF_LT; cheat->width = 2; break; case CB_IF_SPECIAL: switch (op1 & 0x0FFFFFFF) { case 0x20: - cheat = GBACheatListAppend(&cheats->list); + cheat = mCheatListAppend(&cheats->d.list); cheat->type = CHEAT_IF_AND; cheat->width = 2; cheat->address = BASE_IO | REG_JOYSTAT;

@@ -288,12 +286,12 @@ mLOG(CHEATS, STUB, "CodeBreaker code %08X %04X not supported", op1, op2);

return false; } case CB_ADD_2: - cheat = GBACheatListAppend(&cheats->list); + cheat = mCheatListAppend(&cheats->d.list); cheat->type = CHEAT_ADD; cheat->width = 2; break; case CB_IF_AND: - cheat = GBACheatListAppend(&cheats->list); + cheat = mCheatListAppend(&cheats->d.list); cheat->type = CHEAT_IF_AND; cheat->width = 2; break;
M src/gba/cheats/gameshark.csrc/gba/cheats/gameshark.c

@@ -5,7 +5,6 @@ * 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 "gameshark.h" -#include "gba/cheats/cheats-private.h" #include "gba/cheats/parv3.h" #include "gba/gba.h" #include "util/string.h"

@@ -90,11 +89,11 @@ }

bool GBACheatAddGameSharkRaw(struct GBACheatSet* cheats, uint32_t op1, uint32_t op2) { enum GBAGameSharkType type = op1 >> 28; - struct GBACheat* cheat = 0; + struct mCheat* cheat = 0; if (cheats->incompleteCheat) { if (cheats->remainingAddresses > 0) { - cheat = GBACheatListAppend(&cheats->list); + cheat = mCheatListAppend(&cheats->d.list); cheat->type = CHEAT_ASSIGN; cheat->width = 4; cheat->address = op1;

@@ -103,7 +102,7 @@ cheat->repeat = 1;

--cheats->remainingAddresses; } if (cheats->remainingAddresses > 0) { - cheat = GBACheatListAppend(&cheats->list); + cheat = mCheatListAppend(&cheats->d.list); cheat->type = CHEAT_ASSIGN; cheat->width = 4; cheat->address = op2;

@@ -119,26 +118,26 @@ }

switch (type) { case GSA_ASSIGN_1: - cheat = GBACheatListAppend(&cheats->list); + cheat = mCheatListAppend(&cheats->d.list); cheat->type = CHEAT_ASSIGN; cheat->width = 1; cheat->address = op1 & 0x0FFFFFFF; break; case GSA_ASSIGN_2: - cheat = GBACheatListAppend(&cheats->list); + cheat = mCheatListAppend(&cheats->d.list); cheat->type = CHEAT_ASSIGN; cheat->width = 2; cheat->address = op1 & 0x0FFFFFFF; break; case GSA_ASSIGN_4: - cheat = GBACheatListAppend(&cheats->list); + cheat = mCheatListAppend(&cheats->d.list); cheat->type = CHEAT_ASSIGN; cheat->width = 4; cheat->address = op1 & 0x0FFFFFFF; break; case GSA_ASSIGN_LIST: cheats->remainingAddresses = (op1 & 0xFFFF) - 1; - cheat = GBACheatListAppend(&cheats->list); + cheat = mCheatListAppend(&cheats->d.list); cheat->type = CHEAT_ASSIGN; cheat->width = 4; cheat->address = op2;

@@ -159,13 +158,13 @@ if (op1 == 0xDEADFACE) {

GBACheatReseedGameShark(cheats->gsaSeeds, op2, _gsa1T1, _gsa1T2); return true; } - cheat = GBACheatListAppend(&cheats->list); + cheat = mCheatListAppend(&cheats->d.list); cheat->type = CHEAT_IF_EQ; cheat->width = 2; cheat->address = op1 & 0x0FFFFFFF; break; case GSA_IF_EQ_RANGE: - cheat = GBACheatListAppend(&cheats->list); + cheat = mCheatListAppend(&cheats->d.list); cheat->type = CHEAT_IF_EQ; cheat->width = 2; cheat->address = op2 & 0x0FFFFFFF;

@@ -195,7 +194,6 @@ uint32_t o1 = op1;

uint32_t o2 = op2; char line[18] = "XXXXXXXX XXXXXXXX"; snprintf(line, sizeof(line), "%08X %08X", op1, op2); - GBACheatRegisterLine(set, line); switch (set->gsaVersion) { case 0:
M src/gba/cheats/parv3.csrc/gba/cheats/parv3.c

@@ -5,7 +5,6 @@ * 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 "parv3.h" -#include "gba/cheats/cheats-private.h" #include "gba/cheats/gameshark.h" #include "gba/gba.h" #include "util/string.h"

@@ -54,7 +53,7 @@ return (x & 0xFFFFF) | ((x << 4) & 0x0F000000);

} static void _parEndBlock(struct GBACheatSet* cheats) { - size_t size = GBACheatListSize(&cheats->list) - GBACheatListIndex(&cheats->list, cheats->currentBlock); + size_t size = mCheatListSize(&cheats->d.list) - mCheatListIndex(&cheats->d.list, cheats->currentBlock); if (cheats->currentBlock->repeat) { cheats->currentBlock->negativeRepeat = size - cheats->currentBlock->repeat; } else {

@@ -64,7 +63,7 @@ cheats->currentBlock = 0;

} static void _parElseBlock(struct GBACheatSet* cheats) { - size_t size = GBACheatListSize(&cheats->list) - GBACheatListIndex(&cheats->list, cheats->currentBlock); + size_t size = mCheatListSize(&cheats->d.list) - mCheatListIndex(&cheats->d.list, cheats->currentBlock); cheats->currentBlock->repeat = size; }

@@ -80,7 +79,7 @@ // TODO: Codes that disable

return false; } - struct GBACheat* cheat = GBACheatListAppend(&cheats->list); + struct mCheat* cheat = mCheatListAppend(&cheats->d.list); cheat->address = _parAddr(op1); cheat->width = width; cheat->operand = op2 & (0xFFFFFFFFU >> ((4 - width) * 8));

@@ -139,7 +138,7 @@ return true;

} static bool _addPAR3Special(struct GBACheatSet* cheats, uint32_t op2) { - struct GBACheat* cheat; + struct mCheat* cheat; switch (op2 & 0xFF000000) { case PAR3_OTHER_SLOWDOWN: // TODO: Slowdown

@@ -188,19 +187,19 @@ return true;

} return false; case PAR3_OTHER_FILL_1: - cheat = GBACheatListAppend(&cheats->list); + cheat = mCheatListAppend(&cheats->d.list); cheat->address = _parAddr(op2); cheat->width = 1; cheats->incompleteCheat = cheat; break; case PAR3_OTHER_FILL_2: - cheat = GBACheatListAppend(&cheats->list); + cheat = mCheatListAppend(&cheats->d.list); cheat->address = _parAddr(op2); cheat->width = 2; cheats->incompleteCheat = cheat; break; case PAR3_OTHER_FILL_4: - cheat = GBACheatListAppend(&cheats->list); + cheat = mCheatListAppend(&cheats->d.list); cheat->address = _parAddr(op2); cheat->width = 3; cheats->incompleteCheat = cheat;

@@ -253,7 +252,7 @@ return _addPAR3Cond(cheats, op1, op2);

} int width = 1 << ((op1 & PAR3_WIDTH) >> PAR3_WIDTH_BASE); - struct GBACheat* cheat = GBACheatListAppend(&cheats->list); + struct mCheat* cheat = mCheatListAppend(&cheats->d.list); cheat->address = _parAddr(op1); cheat->operandOffset = 0; cheat->addressOffset = 0;

@@ -293,7 +292,6 @@ uint32_t o1 = op1;

uint32_t o2 = op2; char line[18] = "XXXXXXXX XXXXXXXX"; snprintf(line, sizeof(line), "%08X %08X", op1, op2); - GBACheatRegisterLine(set, line); switch (set->gsaVersion) { case 0:
M src/gba/core.csrc/gba/core.c

@@ -7,6 +7,7 @@ #include "core.h"

#include "core/core.h" #include "core/log.h" +#include "gba/cheats.h" #include "gba/gba.h" #include "gba/extra/cli.h" #include "gba/overrides.h"

@@ -23,6 +24,7 @@ int keys;

struct mCPUComponent* components[CPU_COMPONENT_MAX]; const struct Configuration* overrides; struct mDebuggerPlatform* debuggerPlatform; + struct mCheatDevice* cheatDevice; }; static bool _GBACoreInit(struct mCore* core) {

@@ -38,8 +40,9 @@ }

core->cpu = cpu; core->board = gba; core->debugger = NULL; + gbacore->overrides = NULL; gbacore->debuggerPlatform = NULL; - gbacore->overrides = 0; + gbacore->cheatDevice = NULL; GBACreate(gba); // TODO: Restore cheats

@@ -68,6 +71,13 @@ mappedMemoryFree(core->board, sizeof(struct GBA));

#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2 mDirectorySetDeinit(&core->dirs); #endif + + struct GBACore* gbacore = (struct GBACore*) core; + free(gbacore->debuggerPlatform); + if (gbacore->cheatDevice) { + mCheatDeviceDestroy(gbacore->cheatDevice); + } + free(gbacore->cheatDevice); free(core); }

@@ -401,6 +411,17 @@ GBADetachDebugger(core->board);

core->debugger = NULL; } +static struct mCheatDevice* _GBACoreCheatDevice(struct mCore* core) { + struct GBACore* gbacore = (struct GBACore*) core; + if (!gbacore->cheatDevice) { + gbacore->cheatDevice = GBACheatDeviceCreate(); + ((struct ARMCore*) core->cpu)->components[CPU_COMPONENT_CHEAT_DEVICE] = &gbacore->cheatDevice->d; + ARMHotplugAttach(core->cpu, CPU_COMPONENT_CHEAT_DEVICE); + gbacore->cheatDevice->p = core; + } + return gbacore->cheatDevice; +} + struct mCore* GBACoreCreate(void) { struct GBACore* gbacore = malloc(sizeof(*gbacore)); struct mCore* core = &gbacore->d;

@@ -460,5 +481,6 @@ core->debuggerPlatform = _GBACoreDebuggerPlatform;

core->cliDebuggerSystem = _GBACoreCliDebuggerSystem; core->attachDebugger = _GBACoreAttachDebugger; core->detachDebugger = _GBACoreDetachDebugger; + core->cheatDevice = _GBACoreCheatDevice; return core; }
M src/gba/gba.csrc/gba/gba.c

@@ -774,13 +774,13 @@ }

break; case CPU_COMPONENT_CHEAT_DEVICE: if (gba->cpu->components[CPU_COMPONENT_CHEAT_DEVICE]) { - struct GBACheatDevice* device = (struct GBACheatDevice*) gba->cpu->components[CPU_COMPONENT_CHEAT_DEVICE]; + struct mCheatDevice* device = (struct mCheatDevice*) gba->cpu->components[CPU_COMPONENT_CHEAT_DEVICE]; struct GBACheatHook* hook = 0; size_t i; - for (i = 0; i < GBACheatSetsSize(&device->cheats); ++i) { - struct GBACheatSet* cheats = *GBACheatSetsGetPointer(&device->cheats, i); + for (i = 0; i < mCheatSetsSize(&device->cheats); ++i) { + struct GBACheatSet* cheats = (struct GBACheatSet*) *mCheatSetsGetPointer(&device->cheats, i); if (cheats->hook && cheats->hook->address == _ARMPCAddress(cpu)) { - GBACheatRefresh(device, cheats); + mCheatRefresh(device, &cheats->d); hook = cheats->hook; } }

@@ -808,12 +808,12 @@ gba->rr->nextFrame(gba->rr);

} if (gba->cpu->components && gba->cpu->components[CPU_COMPONENT_CHEAT_DEVICE]) { - struct GBACheatDevice* device = (struct GBACheatDevice*) gba->cpu->components[CPU_COMPONENT_CHEAT_DEVICE]; + struct mCheatDevice* device = (struct mCheatDevice*) gba->cpu->components[CPU_COMPONENT_CHEAT_DEVICE]; size_t i; - for (i = 0; i < GBACheatSetsSize(&device->cheats); ++i) { - struct GBACheatSet* cheats = *GBACheatSetsGetPointer(&device->cheats, i); + for (i = 0; i < mCheatSetsSize(&device->cheats); ++i) { + struct GBACheatSet* cheats = (struct GBACheatSet*) *mCheatSetsGetPointer(&device->cheats, i); if (!cheats->hook) { - GBACheatRefresh(device, cheats); + mCheatRefresh(device, &cheats->d); } } }
M src/gba/serialize.csrc/gba/serialize.c

@@ -383,10 +383,10 @@ svf->close(svf);

} struct VFile* cheatVf = 0; if (flags & SAVESTATE_CHEATS && gba->cpu->components && gba->cpu->components[CPU_COMPONENT_CHEAT_DEVICE]) { - struct GBACheatDevice* device = (struct GBACheatDevice*) gba->cpu->components[CPU_COMPONENT_CHEAT_DEVICE]; + struct mCheatDevice* device = (struct mCheatDevice*) gba->cpu->components[CPU_COMPONENT_CHEAT_DEVICE]; cheatVf = VFileMemChunk(0, 0); if (cheatVf) { - GBACheatSaveFile(device, cheatVf); + mCheatSaveFile(device, cheatVf); struct GBAExtdataItem item = { .size = cheatVf->size(cheatVf), .data = cheatVf->map(cheatVf, cheatVf->size(cheatVf), MAP_READ),

@@ -479,11 +479,11 @@ }

} if (flags & SAVESTATE_CHEATS && gba->cpu->components && gba->cpu->components[CPU_COMPONENT_CHEAT_DEVICE] && GBAExtdataGet(&extdata, EXTDATA_CHEATS, &item)) { if (item.size) { - struct GBACheatDevice* device = (struct GBACheatDevice*) gba->cpu->components[CPU_COMPONENT_CHEAT_DEVICE]; + struct mCheatDevice* device = (struct mCheatDevice*) gba->cpu->components[CPU_COMPONENT_CHEAT_DEVICE]; struct VFile* svf = VFileFromMemory(item.data, item.size); if (svf) { - GBACheatDeviceClear(device); - GBACheatParseFile(device, svf); + mCheatDeviceClear(device); + mCheatParseFile(device, svf); svf->close(svf); } }
M src/platform/qt/CheatsModel.cppsrc/platform/qt/CheatsModel.cpp

@@ -12,12 +12,12 @@ #include <QFont>

#include <QSet> extern "C" { -#include "gba/cheats.h" +#include "core/cheats.h" } using namespace QGBA; -CheatsModel::CheatsModel(GBACheatDevice* device, QObject* parent) +CheatsModel::CheatsModel(mCheatDevice* device, QObject* parent) : QAbstractItemModel(parent) , m_device(device) {

@@ -30,7 +30,7 @@ }

if (index.parent().isValid()) { int row = index.row(); - GBACheatSet* cheats = static_cast<GBACheatSet*>(index.internalPointer()); + mCheatSet* cheats = static_cast<mCheatSet*>(index.internalPointer()); const char* line = *StringListGetPointer(&cheats->lines, row); switch (role) { case Qt::DisplayRole:

@@ -42,12 +42,12 @@ return QVariant();

} } - if (index.row() >= GBACheatSetsSize(&m_device->cheats)) { + if (index.row() >= mCheatSetsSize(&m_device->cheats)) { return QVariant(); } int row = index.row(); - const GBACheatSet* cheats = *GBACheatSetsGetPointer(&m_device->cheats, index.row()); + const mCheatSet* cheats = *mCheatSetsGetPointer(&m_device->cheats, index.row()); switch (role) { case Qt::DisplayRole: case Qt::EditRole:

@@ -60,20 +60,16 @@ }

} bool CheatsModel::setData(const QModelIndex& index, const QVariant& value, int role) { - if (!index.isValid() || index.parent().isValid() || index.row() > GBACheatSetsSize(&m_device->cheats)) { + if (!index.isValid() || index.parent().isValid() || index.row() > mCheatSetsSize(&m_device->cheats)) { return false; } int row = index.row(); - GBACheatSet* cheats = *GBACheatSetsGetPointer(&m_device->cheats, index.row()); + mCheatSet* cheats = *mCheatSetsGetPointer(&m_device->cheats, index.row()); switch (role) { case Qt::DisplayRole: case Qt::EditRole: - if (cheats->name) { - free(cheats->name); - cheats->name = nullptr; - } - cheats->name = strdup(value.toString().toUtf8().constData()); + mCheatSetRename(cheats, value.toString().toUtf8().constData()); emit dataChanged(index, index); return true; case Qt::CheckStateRole:

@@ -87,7 +83,7 @@ }

QModelIndex CheatsModel::index(int row, int column, const QModelIndex& parent) const { if (parent.isValid()) { - return createIndex(row, column, *GBACheatSetsGetPointer(&m_device->cheats, parent.row())); + return createIndex(row, column, *mCheatSetsGetPointer(&m_device->cheats, parent.row())); } else { return createIndex(row, column, nullptr); }

@@ -97,12 +93,12 @@ QModelIndex CheatsModel::parent(const QModelIndex& index) const {

if (!index.isValid()) { return QModelIndex(); } - const GBACheatSet* cheats = static_cast<const GBACheatSet*>(index.internalPointer()); + const mCheatSet* cheats = static_cast<const mCheatSet*>(index.internalPointer()); if (!cheats) { return QModelIndex(); } - for (size_t i = 0; i < GBACheatSetsSize(&m_device->cheats); ++i) { - if (cheats == *GBACheatSetsGetPointer(&m_device->cheats, i)) { + for (size_t i = 0; i < mCheatSetsSize(&m_device->cheats); ++i) { + if (cheats == *mCheatSetsGetPointer(&m_device->cheats, i)) { return createIndex(i, 0, nullptr); } }

@@ -130,45 +126,44 @@ if (parent.isValid()) {

if (parent.internalPointer()) { return 0; } - const GBACheatSet* set = *GBACheatSetsGetPointer(&m_device->cheats, parent.row()); + const mCheatSet* set = *mCheatSetsGetPointer(&m_device->cheats, parent.row()); return StringListSize(&set->lines); } - return GBACheatSetsSize(&m_device->cheats); + return mCheatSetsSize(&m_device->cheats); } -GBACheatSet* CheatsModel::itemAt(const QModelIndex& index) { +mCheatSet* CheatsModel::itemAt(const QModelIndex& index) { if (!index.isValid()) { return nullptr; } if (index.parent().isValid()) { - return static_cast<GBACheatSet*>(index.internalPointer()); + return static_cast<mCheatSet*>(index.internalPointer()); } - if (index.row() >= GBACheatSetsSize(&m_device->cheats)) { + if (index.row() >= mCheatSetsSize(&m_device->cheats)) { return nullptr; } - return *GBACheatSetsGetPointer(&m_device->cheats, index.row()); + return *mCheatSetsGetPointer(&m_device->cheats, index.row()); } void CheatsModel::removeAt(const QModelIndex& index) { - if (!index.isValid() || index.parent().isValid() || index.row() >= GBACheatSetsSize(&m_device->cheats)) { + if (!index.isValid() || index.parent().isValid() || index.row() >= mCheatSetsSize(&m_device->cheats)) { return; } int row = index.row(); - GBACheatSet* set = *GBACheatSetsGetPointer(&m_device->cheats, index.row()); + mCheatSet* set = *mCheatSetsGetPointer(&m_device->cheats, index.row()); beginRemoveRows(QModelIndex(), row, row); - GBACheatRemoveSet(m_device, set); - GBACheatSetDeinit(set); - delete set; + mCheatRemoveSet(m_device, set); + mCheatSetDeinit(set); endInsertRows(); } QString CheatsModel::toString(const QModelIndexList& indices) const { - QMap<int, GBACheatSet*> setOrder; - QMap<GBACheatSet*, QSet<size_t>> setIndices; + QMap<int, mCheatSet*> setOrder; + QMap<mCheatSet*, QSet<size_t>> setIndices; for (const QModelIndex& index : indices) { - GBACheatSet* set = static_cast<GBACheatSet*>(index.internalPointer()); + mCheatSet* set = static_cast<mCheatSet*>(index.internalPointer()); if (!set) { - set = *GBACheatSetsGetPointer(&m_device->cheats, index.row()); + set = *mCheatSetsGetPointer(&m_device->cheats, index.row()); setOrder[index.row()] = set; QSet<size_t> range; for (size_t i = 0; i < StringListSize(&set->lines); ++i) {

@@ -185,7 +180,7 @@ QStringList strings;

QList<int> order = setOrder.keys(); std::sort(order.begin(), order.end()); for (int i : order) { - GBACheatSet* set = setOrder[i]; + mCheatSet* set = setOrder[i]; QList<size_t> indexOrdex = setIndices[set].toList(); std::sort(indexOrdex.begin(), indexOrdex.end()); for (size_t j : indexOrdex) {

@@ -215,7 +210,7 @@ LOG(QT, WARN) << tr("Failed to open cheats file: %1").arg(path);

return; } beginResetModel(); - GBACheatParseFile(m_device, vf); + mCheatParseFile(m_device, vf); endResetModel(); vf->close(vf); }

@@ -225,17 +220,17 @@ VFile* vf = VFileDevice::open(path, O_TRUNC | O_CREAT | O_WRONLY);

if (!vf) { return; } - GBACheatSaveFile(m_device, vf); + mCheatSaveFile(m_device, vf); vf->close(vf); } -void CheatsModel::addSet(GBACheatSet* set) { - beginInsertRows(QModelIndex(), GBACheatSetsSize(&m_device->cheats), GBACheatSetsSize(&m_device->cheats)); - size_t size = GBACheatSetsSize(&m_device->cheats); +void CheatsModel::addSet(mCheatSet* set) { + beginInsertRows(QModelIndex(), mCheatSetsSize(&m_device->cheats), mCheatSetsSize(&m_device->cheats)); + size_t size = mCheatSetsSize(&m_device->cheats); if (size) { - GBACheatSetCopyProperties(set, *GBACheatSetsGetPointer(&m_device->cheats, size - 1)); + set->copyProperties(set, *mCheatSetsGetPointer(&m_device->cheats, size - 1)); } - GBACheatAddSet(m_device, set); + mCheatAddSet(m_device, set); endInsertRows(); }
M src/platform/qt/CheatsModel.hsrc/platform/qt/CheatsModel.h

@@ -8,8 +8,8 @@ #define QGBA_CHEATS_MODEL

#include <QAbstractItemModel> -struct GBACheatDevice; -struct GBACheatSet; +struct mCheatDevice; +struct mCheatSet; namespace QGBA {

@@ -17,7 +17,7 @@ class CheatsModel : public QAbstractItemModel {

Q_OBJECT public: - CheatsModel(GBACheatDevice* m_device, QObject* parent = nullptr); + CheatsModel(mCheatDevice* m_device, QObject* parent = nullptr); virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; virtual bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override;

@@ -29,7 +29,7 @@ virtual int columnCount(const QModelIndex& parent = QModelIndex()) const override;

virtual int rowCount(const QModelIndex& parent = QModelIndex()) const override; virtual Qt::ItemFlags flags(const QModelIndex& index) const override; - GBACheatSet* itemAt(const QModelIndex& index); + mCheatSet* itemAt(const QModelIndex& index); void removeAt(const QModelIndex& index); QString toString(const QModelIndexList& indices) const;

@@ -39,15 +39,15 @@

void loadFile(const QString& path); void saveFile(const QString& path); - void addSet(GBACheatSet* set); + void addSet(mCheatSet* set); public slots: void invalidated(); private: - GBACheatDevice* m_device; + mCheatDevice* m_device; }; } -#endif+#endif
M src/platform/qt/CheatsView.cppsrc/platform/qt/CheatsView.cpp

@@ -11,7 +11,10 @@

#include <QClipboard> extern "C" { +#include "core/cheats.h" +#ifdef M_CORE_GBA #include "gba/cheats.h" +#endif } using namespace QGBA;

@@ -34,19 +37,19 @@ connect(controller, SIGNAL(gameStopped(mCoreThread*)), &m_model, SLOT(invalidated()));

connect(controller, SIGNAL(stateLoaded(mCoreThread*)), &m_model, SLOT(invalidated())); connect(m_ui.add, &QPushButton::clicked, [this]() { - enterCheat(GBACheatAddLine); + enterCheat(GBA_CHEAT_AUTODETECT); }); connect(m_ui.addGSA, &QPushButton::clicked, [this]() { - enterCheat(GBACheatAddGameSharkLine); + enterCheat(GBA_CHEAT_GAMESHARK); }); connect(m_ui.addPAR, &QPushButton::clicked, [this]() { - enterCheat(GBACheatAddProActionReplayLine); + enterCheat(GBA_CHEAT_PRO_ACTION_REPLAY); }); connect(m_ui.addCB, &QPushButton::clicked, [this]() { - enterCheat(GBACheatAddCodeBreakerLine); + enterCheat(GBA_CHEAT_CODEBREAKER); }); }

@@ -79,9 +82,8 @@ }

} void CheatsView::addSet() { - GBACheatSet* set = new GBACheatSet; - GBACheatSetInit(set, nullptr); m_controller->threadInterrupt(); + mCheatSet* set = m_controller->cheatDevice()->createSet(m_controller->cheatDevice(), nullptr); m_model.addSet(set); m_controller->threadContinue(); }

@@ -99,13 +101,12 @@ }

m_controller->threadContinue(); } -void CheatsView::enterCheat(std::function<bool(GBACheatSet*, const char*)> callback) { - GBACheatSet* set = nullptr; +void CheatsView::enterCheat(int codeType) { + mCheatSet* set = nullptr; QModelIndexList selection = m_ui.cheatList->selectionModel()->selectedIndexes(); QModelIndex index; if (selection.count() == 0) { - set = new GBACheatSet; - GBACheatSetInit(set, nullptr); + set = m_controller->cheatDevice()->createSet(m_controller->cheatDevice(), nullptr); } else if (selection.count() == 1) { index = selection[0]; set = m_model.itemAt(index);

@@ -123,7 +124,7 @@ }

QStringList cheats = m_ui.codeEntry->toPlainText().split('\n', QString::SkipEmptyParts); for (const QString& string : cheats) { m_model.beginAppendRow(index); - callback(set, string.toUtf8().constData()); + mCheatAddLine(set, string.toUtf8().constData(), codeType); m_model.endAppendRow(); } m_controller->threadContinue();
M src/platform/qt/CheatsView.hsrc/platform/qt/CheatsView.h

@@ -14,7 +14,7 @@ #include "CheatsModel.h"

#include "ui_CheatsView.h" -struct GBACheatDevice; +struct mCheatDevice; namespace QGBA {

@@ -35,7 +35,7 @@ void addSet();

void removeSet(); private: - void enterCheat(std::function<bool(GBACheatSet*, const char*)> callback); + void enterCheat(int codeType); Ui::CheatsView m_ui; GameController* m_controller;

@@ -44,4 +44,4 @@ };

} -#endif+#endif
M src/platform/qt/GameController.cppsrc/platform/qt/GameController.cpp

@@ -69,8 +69,6 @@ , m_backupSaveState(nullptr)

, m_saveStateFlags(SAVESTATE_SCREENSHOT | SAVESTATE_SAVEDATA | SAVESTATE_CHEATS) , m_loadStateFlags(SAVESTATE_SCREENSHOT) { - GBACheatDeviceCreate(&m_cheatDevice); - m_lux.p = this; m_lux.sample = [](GBALuminanceSource* context) { GameControllerLux* lux = static_cast<GameControllerLux*>(context);

@@ -235,7 +233,6 @@ m_audioThread->wait();

disconnect(); clearMultiplayerController(); closeGame(); - GBACheatDeviceDestroy(&m_cheatDevice); delete m_backupLoadState; }

@@ -475,13 +472,6 @@ delete[] m_drawContext;

delete[] m_frontBuffer; m_patch = QString(); - - for (size_t i = 0; i < GBACheatSetsSize(&m_cheatDevice.cheats); ++i) { - GBACheatSet* set = *GBACheatSetsGetPointer(&m_cheatDevice.cheats, i); - GBACheatSetDeinit(set); - delete set; - } - GBACheatSetsClear(&m_cheatDevice.cheats); m_threadContext.core->deinit(m_threadContext.core); }
M src/platform/qt/GameController.hsrc/platform/qt/GameController.h

@@ -52,7 +52,7 @@ ~GameController();

const uint32_t* drawContext() const { return m_drawContext; } mCoreThread* thread() { return &m_threadContext; } - GBACheatDevice* cheatDevice() { return &m_cheatDevice; } + mCheatDevice* cheatDevice() { return m_threadContext.core ? m_threadContext.core->cheatDevice(m_threadContext.core) : nullptr; } void threadInterrupt(); void threadContinue();

@@ -174,7 +174,7 @@ uint32_t* m_drawContext;

uint32_t* m_frontBuffer; mCoreThread m_threadContext; const mCoreConfig* m_config; - GBACheatDevice m_cheatDevice; + mCheatDevice* m_cheatDevice; int m_activeKeys; int m_activeButtons; int m_inactiveKeys;