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 <mgba/internal/gb/cheats.h>
7 
8 #include <mgba/core/core.h>
9 #include <mgba/internal/gb/gb.h>
10 #include <mgba/internal/gb/memory.h>
11 #include <mgba-util/string.h>
12 
13 static void GBCheatSetCopyProperties(struct mCheatSet* set, struct mCheatSet* oldSet);
14 static void GBCheatParseDirectives(struct mCheatSet* set, const struct StringList* directives);
15 static void GBCheatDumpDirectives(struct mCheatSet* set, struct StringList* directives);
16 static bool GBCheatAddLine(struct mCheatSet*, const char* line, int type);
17 
GBCheatSetCreate(struct mCheatDevice * device,const char * name)18 static struct mCheatSet* GBCheatSetCreate(struct mCheatDevice* device, const char* name) {
19 	UNUSED(device);
20 	struct mCheatSet* set = malloc(sizeof(*set));
21 	mCheatSetInit(set, name);
22 
23 	set->deinit = NULL;
24 	set->add = NULL;
25 	set->remove = NULL;
26 
27 	set->addLine = GBCheatAddLine;
28 	set->copyProperties = GBCheatSetCopyProperties;
29 
30 	set->parseDirectives = GBCheatParseDirectives;
31 	set->dumpDirectives = GBCheatDumpDirectives;
32 
33 	set->refresh = NULL;
34 	return set;
35 }
36 
GBCheatDeviceCreate(void)37 struct mCheatDevice* GBCheatDeviceCreate(void) {
38 	struct mCheatDevice* device = malloc(sizeof(*device));
39 	mCheatDeviceCreate(device);
40 	device->createSet = GBCheatSetCreate;
41 	return device;
42 }
43 
GBCheatAddCodebreaker(struct mCheatSet * cheats,uint16_t address,uint8_t data)44 static bool GBCheatAddCodebreaker(struct mCheatSet* cheats, uint16_t address, uint8_t data) {
45 	struct mCheat* cheat = mCheatListAppend(&cheats->list);
46 	cheat->type = CHEAT_ASSIGN;
47 	cheat->width = 1;
48 	cheat->address = address;
49 	cheat->operand = data;
50 	cheat->repeat = 1;
51 	cheat->negativeRepeat = 0;
52 	return true;
53 }
54 
GBCheatAddGameShark(struct mCheatSet * cheats,uint32_t op)55 static bool GBCheatAddGameShark(struct mCheatSet* cheats, uint32_t op) {
56 	return GBCheatAddCodebreaker(cheats, ((op & 0xFF) << 8) | ((op >> 8) & 0xFF), (op >> 16) & 0xFF);
57 }
58 
GBCheatAddGameSharkLine(struct mCheatSet * cheats,const char * line)59 static bool GBCheatAddGameSharkLine(struct mCheatSet* cheats, const char* line) {
60 	uint32_t op;
61 	if (!hex32(line, &op)) {
62 		return false;
63 	}
64 	return GBCheatAddGameShark(cheats, op);
65 }
66 
GBCheatAddGameGenieLine(struct mCheatSet * cheats,const char * line)67 static bool GBCheatAddGameGenieLine(struct mCheatSet* cheats, const char* line) {
68 	uint16_t op1;
69 	uint16_t op2;
70 	uint16_t op3 = 0x1000;
71 	const char* lineNext = hex12(line, &op1);
72 	if (!lineNext || lineNext[0] != '-') {
73 		return false;
74 	}
75 	++lineNext;
76 	lineNext = hex12(lineNext, &op2);
77 	if (!lineNext) {
78 		return false;
79 	}
80 	if (lineNext[0] == '-') {
81 		++lineNext;
82 		lineNext = hex12(lineNext, &op3);
83 	}
84 	if (!lineNext || lineNext[0]) {
85 		return false;
86 	}
87 	uint16_t address = (op1 & 0xF) << 8;
88 	address |= (op2 >> 4) & 0xFF;
89 	address |= ((op2 & 0xF) ^ 0xF) << 12;
90 	struct mCheatPatch* patch = mCheatPatchListAppend(&cheats->romPatches);
91 	patch->address = address;
92 	patch->value = op1 >> 4;
93 	patch->applied = false;
94 	patch->width = 1;
95 	patch->segment = -1;
96 	if (op3 < 0x1000) {
97 		uint32_t value = ((op3 & 0xF00) << 20) | (op3 & 0xF);
98 		value = ROR(value, 2);
99 		value |= value >> 24;
100 		value ^= 0xBA;
101 		patch->checkValue = value & 0xFF;
102 		patch->check = true;
103 	} else {
104 		patch->check = false;
105 	}
106 	return true;
107 }
108 
GBCheatAddVBALine(struct mCheatSet * cheats,const char * line)109 static bool GBCheatAddVBALine(struct mCheatSet* cheats, const char* line) {
110 	uint16_t address;
111 	uint8_t value;
112 	const char* lineNext = hex16(line, &address);
113 	if (!lineNext || lineNext[0] != ':') {
114 		return false;
115 	}
116 	if (!hex8(line, &value)) {
117 		return false;
118 	}
119 	struct mCheat* cheat = mCheatListAppend(&cheats->list);
120 	cheat->type = CHEAT_ASSIGN;
121 	cheat->width = 1;
122 	cheat->address = address;
123 	cheat->operand = value;
124 	cheat->repeat = 1;
125 	cheat->negativeRepeat = 0;
126 	return true;
127 }
128 
GBCheatAddLine(struct mCheatSet * cheats,const char * line,int type)129 bool GBCheatAddLine(struct mCheatSet* cheats, const char* line, int type) {
130 	switch (type) {
131 	case GB_CHEAT_AUTODETECT:
132 		break;
133 	case GB_CHEAT_GAME_GENIE:
134 		return GBCheatAddGameGenieLine(cheats, line);
135 	case GB_CHEAT_GAMESHARK:
136 		return GBCheatAddGameSharkLine(cheats, line);
137 	case GB_CHEAT_VBA:
138 		return GBCheatAddVBALine(cheats, line);
139 	default:
140 		return false;
141 	}
142 
143 	uint16_t op1;
144 	uint8_t op2;
145 	uint8_t op3;
146 	bool codebreaker = false;
147 	const char* lineNext = hex16(line, &op1);
148 	if (!lineNext) {
149 		return GBCheatAddGameGenieLine(cheats, line);
150 	}
151 	if (lineNext[0] == ':') {
152 		return GBCheatAddVBALine(cheats, line);
153 	}
154 	lineNext = hex8(lineNext, &op2);
155 	if (!lineNext) {
156 		return false;
157 	}
158 	if (lineNext[0] == '-') {
159 		codebreaker = true;
160 		++lineNext;
161 	}
162 	lineNext = hex8(lineNext, &op3);
163 	if (!lineNext) {
164 		return false;
165 	}
166 	if (codebreaker) {
167 		uint16_t address = (op1 << 8) | op2;
168 		return GBCheatAddCodebreaker(cheats, address, op3);
169 	} else {
170 		uint32_t realOp = op1 << 16;
171 		realOp |= op2 << 8;
172 		realOp |= op3;
173 		return GBCheatAddGameShark(cheats, realOp);
174 	}
175 }
176 
GBCheatSetCopyProperties(struct mCheatSet * set,struct mCheatSet * oldSet)177 static void GBCheatSetCopyProperties(struct mCheatSet* set, struct mCheatSet* oldSet) {
178 	UNUSED(set);
179 	UNUSED(oldSet);
180 }
181 
GBCheatParseDirectives(struct mCheatSet * set,const struct StringList * directives)182 static void GBCheatParseDirectives(struct mCheatSet* set, const struct StringList* directives) {
183 	UNUSED(set);
184 	UNUSED(directives);
185 }
186 
GBCheatDumpDirectives(struct mCheatSet * set,struct StringList * directives)187 static void GBCheatDumpDirectives(struct mCheatSet* set, struct StringList* directives) {
188 	UNUSED(set);
189 	UNUSED(directives);
190 }
191