all repos — mgba @ d05f513a17098d4128caa6581aff9af49aaf0d05

mGBA Game Boy Advance Emulator

src/gb/cheats.c (view raw)

  1/* Copyright (c) 2013-2016 Jeffrey Pfau
  2 *
  3 * This Source Code Form is subject to the terms of the Mozilla Public
  4 * License, v. 2.0. If a copy of the MPL was not distributed with this
  5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  6#include "cheats.h"
  7
  8#include "core/core.h"
  9#include "gb/memory.h"
 10#include "util/string.h"
 11
 12DEFINE_VECTOR(GBCheatPatchList, struct GBCheatPatch);
 13
 14static void _patchROM(struct mCheatDevice* device, struct GBCheatSet* cheats) {
 15	if (!device->p) {
 16		return;
 17	}
 18	size_t i;
 19	for (i = 0; i < GBCheatPatchListSize(&cheats->romPatches); ++i) {
 20		struct GBCheatPatch* patch = GBCheatPatchListGetPointer(&cheats->romPatches, i);
 21		if (patch->applied) {
 22			continue;
 23		}
 24		// TODO: Byte check
 25		GBPatch8(device->p->cpu, patch->address, patch->newValue, &patch->oldValue);
 26		patch->applied = true;
 27	}
 28}
 29
 30static void _unpatchROM(struct mCheatDevice* device, struct GBCheatSet* cheats) {
 31	if (!device->p) {
 32		return;
 33	}
 34	size_t i;
 35	for (i = 0; i < GBCheatPatchListSize(&cheats->romPatches); ++i) {
 36		struct GBCheatPatch* patch = GBCheatPatchListGetPointer(&cheats->romPatches, i);
 37		if (!patch->applied) {
 38			continue;
 39		}
 40		GBPatch8(device->p->cpu, patch->address, patch->oldValue, NULL);
 41		patch->applied = false;
 42	}
 43}
 44
 45static void GBCheatSetDeinit(struct mCheatSet* set);
 46static void GBCheatAddSet(struct mCheatSet* cheats, struct mCheatDevice* device);
 47static void GBCheatRemoveSet(struct mCheatSet* cheats, struct mCheatDevice* device);
 48static void GBCheatRefresh(struct mCheatSet* cheats, struct mCheatDevice* device);
 49static void GBCheatSetCopyProperties(struct mCheatSet* set, struct mCheatSet* oldSet);
 50static void GBCheatParseDirectives(struct mCheatSet* set, const struct StringList* directives);
 51static void GBCheatDumpDirectives(struct mCheatSet* set, struct StringList* directives);
 52static bool GBCheatAddLine(struct mCheatSet*, const char* line, int type);
 53
 54static struct mCheatSet* GBCheatSetCreate(struct mCheatDevice* device, const char* name) {
 55	UNUSED(device);
 56	struct GBCheatSet* set = malloc(sizeof(*set));
 57	mCheatSetInit(&set->d, name);
 58
 59	GBCheatPatchListInit(&set->romPatches, 0);
 60
 61	set->d.deinit = GBCheatSetDeinit;
 62	set->d.add = GBCheatAddSet;
 63	set->d.remove = GBCheatRemoveSet;
 64
 65	set->d.addLine = GBCheatAddLine;
 66	set->d.copyProperties = GBCheatSetCopyProperties;
 67
 68	set->d.parseDirectives = GBCheatParseDirectives;
 69	set->d.dumpDirectives = GBCheatDumpDirectives;
 70
 71	set->d.refresh = GBCheatRefresh;
 72	return &set->d;
 73}
 74
 75struct mCheatDevice* GBCheatDeviceCreate(void) {
 76	struct mCheatDevice* device = malloc(sizeof(*device));
 77	mCheatDeviceCreate(device);
 78	device->createSet = GBCheatSetCreate;
 79	return device;
 80}
 81
 82static void GBCheatSetDeinit(struct mCheatSet* set) {
 83	struct GBCheatSet* gbset = (struct GBCheatSet*) set;
 84	GBCheatPatchListDeinit(&gbset->romPatches);
 85}
 86
 87static void GBCheatAddSet(struct mCheatSet* cheats, struct mCheatDevice* device) {
 88	struct GBCheatSet* gbset = (struct GBCheatSet*) cheats;
 89	_patchROM(device, gbset);
 90}
 91
 92static void GBCheatRemoveSet(struct mCheatSet* cheats, struct mCheatDevice* device) {
 93	struct GBCheatSet* gbset = (struct GBCheatSet*) cheats;
 94	_unpatchROM(device, gbset);
 95}
 96
 97static bool GBCheatAddCodebreaker(struct GBCheatSet* cheats, uint16_t address, uint8_t data) {
 98	struct mCheat* cheat = mCheatListAppend(&cheats->d.list);
 99	cheat->type = CHEAT_ASSIGN;
100	cheat->width = 1;
101	cheat->address = address;
102	cheat->operand = data;
103	cheat->repeat = 1;
104	cheat->negativeRepeat = 0;
105	return true;
106}
107
108static bool GBCheatAddGameShark(struct GBCheatSet* cheats, uint32_t op) {
109	return GBCheatAddCodebreaker(cheats, ((op & 0xFF) << 8) | ((op >> 8) & 0xFF), (op >> 16) & 0xFF);
110}
111
112static bool GBCheatAddGameSharkLine(struct GBCheatSet* cheats, const char* line) {
113	uint32_t op;
114	if (!hex32(line, &op)) {
115		return false;
116	}
117	return GBCheatAddGameShark(cheats, op);
118}
119
120static bool GBCheatAddGameGenieLine(struct GBCheatSet* cheats, const char* line) {
121	uint16_t op1;
122	uint16_t op2;
123	const char* lineNext = hex12(line, &op1);
124	if (!lineNext || lineNext[0] != '-') {
125		return false;
126	}
127	++lineNext;
128	lineNext = hex12(lineNext, &op2);
129	if (!lineNext) {
130		return false;
131	}
132	uint16_t address = (op1 & 0xF) << 8;
133	address |= (op2 >> 4) & 0xFF;
134	address |= ((op2 & 0xF) ^ 0xF) << 12;
135	struct GBCheatPatch* patch = GBCheatPatchListAppend(&cheats->romPatches);
136	patch->address = address;
137	patch->newValue = op1 >> 4;
138	patch->applied = false;
139	return true;
140}
141
142static bool GBCheatAddVBALine(struct GBCheatSet* cheats, const char* line) {
143	uint16_t address;
144	uint8_t value;
145	const char* lineNext = hex16(line, &address);
146	if (!lineNext && lineNext[0] != ':') {
147		return false;
148	}
149	if (!hex8(line, &value)) {
150		return false;
151	}
152	struct mCheat* cheat = mCheatListAppend(&cheats->d.list);
153	cheat->type = CHEAT_ASSIGN;
154	cheat->width = 1;
155	cheat->address = address;
156	cheat->operand = value;
157	cheat->repeat = 1;
158	cheat->negativeRepeat = 0;
159	return true;
160}
161
162bool GBCheatAddLine(struct mCheatSet* set, const char* line, int type) {
163	struct GBCheatSet* cheats = (struct GBCheatSet*) set;
164	switch (type) {
165	case GB_CHEAT_AUTODETECT:
166		break;
167	case GB_CHEAT_GAME_GENIE:
168		return GBCheatAddGameGenieLine(cheats, line);
169	case GB_CHEAT_GAMESHARK:
170		return GBCheatAddGameSharkLine(cheats, line);
171	case GB_CHEAT_VBA:
172		return GBCheatAddVBALine(cheats, line);
173	default:
174		return false;
175	}
176
177	uint16_t op1;
178	uint8_t op2;
179	uint8_t op3;
180	bool codebreaker = false;
181	const char* lineNext = hex16(line, &op1);
182	if (!lineNext) {
183		return GBCheatAddGameGenieLine(cheats, line);
184	}
185	if (lineNext[0] == ':') {
186		return GBCheatAddVBALine(cheats, line);
187	}
188	lineNext = hex8(lineNext, &op2);
189	if (!lineNext) {
190		return false;
191	}
192	if (lineNext[0] == '-') {
193		codebreaker = true;
194		++lineNext;
195	}
196	lineNext = hex8(lineNext, &op3);
197	if (!lineNext) {
198		return false;
199	}
200	if (codebreaker) {
201		uint16_t address = (op1 << 8) | op2;
202		return GBCheatAddCodebreaker(cheats, address, op3);
203	} else {
204		uint32_t realOp = op1 << 16;
205		realOp |= op2 << 8;
206		realOp |= op3;
207		return GBCheatAddGameShark(cheats, realOp);
208	}
209}
210
211static void GBCheatRefresh(struct mCheatSet* cheats, struct mCheatDevice* device) {
212	struct GBCheatSet* gbset = (struct GBCheatSet*) cheats;
213	_patchROM(device, gbset);
214}
215
216static void GBCheatSetCopyProperties(struct mCheatSet* set, struct mCheatSet* oldSet) {
217	UNUSED(set);
218	UNUSED(oldSet);
219}
220
221static void GBCheatParseDirectives(struct mCheatSet* set, const struct StringList* directives) {
222	UNUSED(set);
223	UNUSED(directives);
224}
225
226static void GBCheatDumpDirectives(struct mCheatSet* set, struct StringList* directives) {
227	UNUSED(set);
228	UNUSED(directives);
229}