all repos — mgba @ 44d3718eb06629a71d76e8b8e709915f29e97610

mGBA Game Boy Advance Emulator

src/gba/cheats.c (view raw)

  1/* Copyright (c) 2013-2015 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 "gba/gba.h"
  9#include "gba/io.h"
 10#include "util/vfs.h"
 11
 12#define MAX_LINE_LENGTH 128
 13
 14const uint32_t GBA_CHEAT_DEVICE_ID = 0xABADC0DE;
 15
 16DEFINE_VECTOR(GBACheatList, struct GBACheat);
 17DEFINE_VECTOR(GBACheatSets, struct GBACheatSet*);
 18DEFINE_VECTOR(StringList, char*);
 19
 20static const uint32_t _gsa1S[4] = { 0x09F4FBBD, 0x9681884A, 0x352027E9, 0xF3DEE5A7 };
 21static const uint32_t _par3S[4] = { 0x7AA9648F, 0x7FAE6994, 0xC0EFAAD5, 0x42712C57 };
 22
 23static const uint8_t _gsa1T1[256] = {
 24	0x31, 0x1C, 0x23, 0xE5, 0x89, 0x8E, 0xA1, 0x37, 0x74, 0x6D, 0x67, 0xFC, 0x1F, 0xC0, 0xB1, 0x94,
 25	0x3B, 0x05, 0x56, 0x86, 0x00, 0x24, 0xF0, 0x17, 0x72, 0xA2, 0x3D, 0x1B, 0xE3, 0x17, 0xC5, 0x0B,
 26	0xB9, 0xE2, 0xBD, 0x58, 0x71, 0x1B, 0x2C, 0xFF, 0xE4, 0xC9, 0x4C, 0x5E, 0xC9, 0x55, 0x33, 0x45,
 27	0x7C, 0x3F, 0xB2, 0x51, 0xFE, 0x10, 0x7E, 0x75, 0x3C, 0x90, 0x8D, 0xDA, 0x94, 0x38, 0xC3, 0xE9,
 28	0x95, 0xEA, 0xCE, 0xA6, 0x06, 0xE0, 0x4F, 0x3F, 0x2A, 0xE3, 0x3A, 0xE4, 0x43, 0xBD, 0x7F, 0xDA,
 29	0x55, 0xF0, 0xEA, 0xCB, 0x2C, 0xA8, 0x47, 0x61, 0xA0, 0xEF, 0xCB, 0x13, 0x18, 0x20, 0xAF, 0x3E,
 30	0x4D, 0x9E, 0x1E, 0x77, 0x51, 0xC5, 0x51, 0x20, 0xCF, 0x21, 0xF9, 0x39, 0x94, 0xDE, 0xDD, 0x79,
 31	0x4E, 0x80, 0xC4, 0x9D, 0x94, 0xD5, 0x95, 0x01, 0x27, 0x27, 0xBD, 0x6D, 0x78, 0xB5, 0xD1, 0x31,
 32	0x6A, 0x65, 0x74, 0x74, 0x58, 0xB3, 0x7C, 0xC9, 0x5A, 0xED, 0x50, 0x03, 0xC4, 0xA2, 0x94, 0x4B,
 33	0xF0, 0x58, 0x09, 0x6F, 0x3E, 0x7D, 0xAE, 0x7D, 0x58, 0xA0, 0x2C, 0x91, 0xBB, 0xE1, 0x70, 0xEB,
 34	0x73, 0xA6, 0x9A, 0x44, 0x25, 0x90, 0x16, 0x62, 0x53, 0xAE, 0x08, 0xEB, 0xDC, 0xF0, 0xEE, 0x77,
 35	0xC2, 0xDE, 0x81, 0xE8, 0x30, 0x89, 0xDB, 0xFE, 0xBC, 0xC2, 0xDF, 0x26, 0xE9, 0x8B, 0xD6, 0x93,
 36	0xF0, 0xCB, 0x56, 0x90, 0xC0, 0x46, 0x68, 0x15, 0x43, 0xCB, 0xE9, 0x98, 0xE3, 0xAF, 0x31, 0x25,
 37	0x4D, 0x7B, 0xF3, 0xB1, 0x74, 0xE2, 0x64, 0xAC, 0xD9, 0xF6, 0xA0, 0xD5, 0x0B, 0x9B, 0x49, 0x52,
 38	0x69, 0x3B, 0x71, 0x00, 0x2F, 0xBB, 0xBA, 0x08, 0xB1, 0xAE, 0xBB, 0xB3, 0xE1, 0xC9, 0xA6, 0x7F,
 39	0x17, 0x97, 0x28, 0x72, 0x12, 0x6E, 0x91, 0xAE, 0x3A, 0xA2, 0x35, 0x46, 0x27, 0xF8, 0x12, 0x50
 40};
 41
 42static const uint8_t _gsa1T2[256] = {
 43	0xD8, 0x65, 0x04, 0xC2, 0x65, 0xD5, 0xB0, 0x0C, 0xDF, 0x9D, 0xF0, 0xC3, 0x9A, 0x17, 0xC9, 0xA6,
 44	0xE1, 0xAC, 0x0D, 0x14, 0x2F, 0x3C, 0x2C, 0x87, 0xA2, 0xBF, 0x4D, 0x5F, 0xAC, 0x2D, 0x9D, 0xE1,
 45	0x0C, 0x9C, 0xE7, 0x7F, 0xFC, 0xA8, 0x66, 0x59, 0xAC, 0x18, 0xD7, 0x05, 0xF0, 0xBF, 0xD1, 0x8B,
 46	0x35, 0x9F, 0x59, 0xB4, 0xBA, 0x55, 0xB2, 0x85, 0xFD, 0xB1, 0x72, 0x06, 0x73, 0xA4, 0xDB, 0x48,
 47	0x7B, 0x5F, 0x67, 0xA5, 0x95, 0xB9, 0xA5, 0x4A, 0xCF, 0xD1, 0x44, 0xF3, 0x81, 0xF5, 0x6D, 0xF6,
 48	0x3A, 0xC3, 0x57, 0x83, 0xFA, 0x8E, 0x15, 0x2A, 0xA2, 0x04, 0xB2, 0x9D, 0xA8, 0x0D, 0x7F, 0xB8,
 49	0x0F, 0xF6, 0xAC, 0xBE, 0x97, 0xCE, 0x16, 0xE6, 0x31, 0x10, 0x60, 0x16, 0xB5, 0x83, 0x45, 0xEE,
 50	0xD7, 0x5F, 0x2C, 0x08, 0x58, 0xB1, 0xFD, 0x7E, 0x79, 0x00, 0x34, 0xAD, 0xB5, 0x31, 0x34, 0x39,
 51	0xAF, 0xA8, 0xDD, 0x52, 0x6A, 0xB0, 0x60, 0x35, 0xB8, 0x1D, 0x52, 0xF5, 0xF5, 0x30, 0x00, 0x7B,
 52	0xF4, 0xBA, 0x03, 0xCB, 0x3A, 0x84, 0x14, 0x8A, 0x6A, 0xEF, 0x21, 0xBD, 0x01, 0xD8, 0xA0, 0xD4,
 53	0x43, 0xBE, 0x23, 0xE7, 0x76, 0x27, 0x2C, 0x3F, 0x4D, 0x3F, 0x43, 0x18, 0xA7, 0xC3, 0x47, 0xA5,
 54	0x7A, 0x1D, 0x02, 0x55, 0x09, 0xD1, 0xFF, 0x55, 0x5E, 0x17, 0xA0, 0x56, 0xF4, 0xC9, 0x6B, 0x90,
 55	0xB4, 0x80, 0xA5, 0x07, 0x22, 0xFB, 0x22, 0x0D, 0xD9, 0xC0, 0x5B, 0x08, 0x35, 0x05, 0xC1, 0x75,
 56	0x4F, 0xD0, 0x51, 0x2D, 0x2E, 0x5E, 0x69, 0xE7, 0x3B, 0xC2, 0xDA, 0xFF, 0xF6, 0xCE, 0x3E, 0x76,
 57	0xE8, 0x36, 0x8C, 0x39, 0xD8, 0xF3, 0xE9, 0xA6, 0x42, 0xE6, 0xC1, 0x4C, 0x05, 0xBE, 0x17, 0xF2,
 58	0x5C, 0x1B, 0x19, 0xDB, 0x0F, 0xF3, 0xF8, 0x49, 0xEB, 0x36, 0xF6, 0x40, 0x6F, 0xAD, 0xC1, 0x8C
 59};
 60
 61static const uint8_t _par3T1[256] = {
 62	0xD0, 0xFF, 0xBA, 0xE5, 0xC1, 0xC7, 0xDB, 0x5B, 0x16, 0xE3, 0x6E, 0x26, 0x62, 0x31, 0x2E, 0x2A,
 63	0xD1, 0xBB, 0x4A, 0xE6, 0xAE, 0x2F, 0x0A, 0x90, 0x29, 0x90, 0xB6, 0x67, 0x58, 0x2A, 0xB4, 0x45,
 64	0x7B, 0xCB, 0xF0, 0x73, 0x84, 0x30, 0x81, 0xC2, 0xD7, 0xBE, 0x89, 0xD7, 0x4E, 0x73, 0x5C, 0xC7,
 65	0x80, 0x1B, 0xE5, 0xE4, 0x43, 0xC7, 0x46, 0xD6, 0x6F, 0x7B, 0xBF, 0xED, 0xE5, 0x27, 0xD1, 0xB5,
 66	0xD0, 0xD8, 0xA3, 0xCB, 0x2B, 0x30, 0xA4, 0xF0, 0x84, 0x14, 0x72, 0x5C, 0xFF, 0xA4, 0xFB, 0x54,
 67	0x9D, 0x70, 0xE2, 0xFF, 0xBE, 0xE8, 0x24, 0x76, 0xE5, 0x15, 0xFB, 0x1A, 0xBC, 0x87, 0x02, 0x2A,
 68	0x58, 0x8F, 0x9A, 0x95, 0xBD, 0xAE, 0x8D, 0x0C, 0xA5, 0x4C, 0xF2, 0x5C, 0x7D, 0xAD, 0x51, 0xFB,
 69	0xB1, 0x22, 0x07, 0xE0, 0x29, 0x7C, 0xEB, 0x98, 0x14, 0xC6, 0x31, 0x97, 0xE4, 0x34, 0x8F, 0xCC,
 70	0x99, 0x56, 0x9F, 0x78, 0x43, 0x91, 0x85, 0x3F, 0xC2, 0xD0, 0xD1, 0x80, 0xD1, 0x77, 0xA7, 0xE2,
 71	0x43, 0x99, 0x1D, 0x2F, 0x8B, 0x6A, 0xE4, 0x66, 0x82, 0xF7, 0x2B, 0x0B, 0x65, 0x14, 0xC0, 0xC2,
 72	0x1D, 0x96, 0x78, 0x1C, 0xC4, 0xC3, 0xD2, 0xB1, 0x64, 0x07, 0xD7, 0x6F, 0x02, 0xE9, 0x44, 0x31,
 73	0xDB, 0x3C, 0xEB, 0x93, 0xED, 0x9A, 0x57, 0x05, 0xB9, 0x0E, 0xAF, 0x1F, 0x48, 0x11, 0xDC, 0x35,
 74	0x6C, 0xB8, 0xEE, 0x2A, 0x48, 0x2B, 0xBC, 0x89, 0x12, 0x59, 0xCB, 0xD1, 0x18, 0xEA, 0x72, 0x11,
 75	0x01, 0x75, 0x3B, 0xB5, 0x56, 0xF4, 0x8B, 0xA0, 0x41, 0x75, 0x86, 0x7B, 0x94, 0x12, 0x2D, 0x4C,
 76	0x0C, 0x22, 0xC9, 0x4A, 0xD8, 0xB1, 0x8D, 0xF0, 0x55, 0x2E, 0x77, 0x50, 0x1C, 0x64, 0x77, 0xAA,
 77	0x3E, 0xAC, 0xD3, 0x3D, 0xCE, 0x60, 0xCA, 0x5D, 0xA0, 0x92, 0x78, 0xC6, 0x51, 0xFE, 0xF9, 0x30
 78};
 79
 80static const uint8_t _par3T2[256] = {
 81	0xAA, 0xAF, 0xF0, 0x72, 0x90, 0xF7, 0x71, 0x27, 0x06, 0x11, 0xEB, 0x9C, 0x37, 0x12, 0x72, 0xAA,
 82	0x65, 0xBC, 0x0D, 0x4A, 0x76, 0xF6, 0x5C, 0xAA, 0xB0, 0x7A, 0x7D, 0x81, 0xC1, 0xCE, 0x2F, 0x9F,
 83	0x02, 0x75, 0x38, 0xC8, 0xFC, 0x66, 0x05, 0xC2, 0x2C, 0xBD, 0x91, 0xAD, 0x03, 0xB1, 0x88, 0x93,
 84	0x31, 0xC6, 0xAB, 0x40, 0x23, 0x43, 0x76, 0x54, 0xCA, 0xE7, 0x00, 0x96, 0x9F, 0xD8, 0x24, 0x8B,
 85	0xE4, 0xDC, 0xDE, 0x48, 0x2C, 0xCB, 0xF7, 0x84, 0x1D, 0x45, 0xE5, 0xF1, 0x75, 0xA0, 0xED, 0xCD,
 86	0x4B, 0x24, 0x8A, 0xB3, 0x98, 0x7B, 0x12, 0xB8, 0xF5, 0x63, 0x97, 0xB3, 0xA6, 0xA6, 0x0B, 0xDC,
 87	0xD8, 0x4C, 0xA8, 0x99, 0x27, 0x0F, 0x8F, 0x94, 0x63, 0x0F, 0xB0, 0x11, 0x94, 0xC7, 0xE9, 0x7F,
 88	0x3B, 0x40, 0x72, 0x4C, 0xDB, 0x84, 0x78, 0xFE, 0xB8, 0x56, 0x08, 0x80, 0xDF, 0x20, 0x2F, 0xB9,
 89	0x66, 0x2D, 0x60, 0x63, 0xF5, 0x18, 0x15, 0x1B, 0x86, 0x85, 0xB9, 0xB4, 0x68, 0x0E, 0xC6, 0xD1,
 90	0x8A, 0x81, 0x2B, 0xB3, 0xF6, 0x48, 0xF0, 0x4F, 0x9C, 0x28, 0x1C, 0xA4, 0x51, 0x2F, 0xD7, 0x4B,
 91	0x17, 0xE7, 0xCC, 0x50, 0x9F, 0xD0, 0xD1, 0x40, 0x0C, 0x0D, 0xCA, 0x83, 0xFA, 0x5E, 0xCA, 0xEC,
 92	0xBF, 0x4E, 0x7C, 0x8F, 0xF0, 0xAE, 0xC2, 0xD3, 0x28, 0x41, 0x9B, 0xC8, 0x04, 0xB9, 0x4A, 0xBA,
 93	0x72, 0xE2, 0xB5, 0x06, 0x2C, 0x1E, 0x0B, 0x2C, 0x7F, 0x11, 0xA9, 0x26, 0x51, 0x9D, 0x3F, 0xF8,
 94	0x62, 0x11, 0x2E, 0x89, 0xD2, 0x9D, 0x35, 0xB1, 0xE4, 0x0A, 0x4D, 0x93, 0x01, 0xA7, 0xD1, 0x2D,
 95	0x00, 0x87, 0xE2, 0x2D, 0xA4, 0xE9, 0x0A, 0x06, 0x66, 0xF8, 0x1F, 0x44, 0x75, 0xB5, 0x6B, 0x1C,
 96	0xFC, 0x31, 0x09, 0x48, 0xA3, 0xFF, 0x92, 0x12, 0x58, 0xE9, 0xFA, 0xAE, 0x4F, 0xE2, 0xB4, 0xCC
 97};
 98
 99static int32_t _readMem(struct ARMCore* cpu, uint32_t address, int width) {
100	switch (width) {
101	case 1:
102		return cpu->memory.load8(cpu, address, 0);
103	case 2:
104		return cpu->memory.load16(cpu, address, 0);
105	case 4:
106		return cpu->memory.load32(cpu, address, 0);
107	}
108	return 0;
109}
110
111static void _writeMem(struct ARMCore* cpu, uint32_t address, int width, int32_t value) {
112	switch (width) {
113	case 1:
114		cpu->memory.store8(cpu, address, value, 0);
115		break;
116	case 2:
117		cpu->memory.store16(cpu, address, value, 0);
118		break;
119	case 4:
120		cpu->memory.store32(cpu, address, value, 0);
121		break;
122	}
123}
124
125static int _hexDigit(char digit) {
126	switch (digit) {
127	case '0':
128	case '1':
129	case '2':
130	case '3':
131	case '4':
132	case '5':
133	case '6':
134	case '7':
135	case '8':
136	case '9':
137		return digit - '0';
138
139	case 'a':
140	case 'b':
141	case 'c':
142	case 'd':
143	case 'e':
144	case 'f':
145		return digit - 'a' + 10;
146
147	case 'A':
148	case 'B':
149	case 'C':
150	case 'D':
151	case 'E':
152	case 'F':
153		return digit - 'A' + 10;
154
155	default:
156		return -1;
157	}
158}
159
160static const char* _hex32(const char* line, uint32_t* out) {
161	uint32_t value = 0;
162	int i;
163	for (i = 0; i < 8; ++i, ++line) {
164		char digit = *line;
165		value <<= 4;
166		int nybble = _hexDigit(digit);
167		if (nybble < 0) {
168			return 0;
169		}
170		value |= nybble;
171	}
172	*out = value;
173	return line;
174}
175
176static const char* _hex16(const char* line, uint16_t* out) {
177	uint16_t value = 0;
178	*out = 0;
179	int i;
180	for (i = 0; i < 4; ++i, ++line) {
181		char digit = *line;
182		value <<= 4;
183		int nybble = _hexDigit(digit);
184		if (nybble < 0) {
185			return 0;
186		}
187		value |= nybble;
188	}
189	*out = value;
190	return line;
191}
192
193static void _registerLine(struct GBACheatSet* cheats, const char* line) {
194	*StringListAppend(&cheats->lines) = strdup(line);
195}
196
197// http://en.wikipedia.org/wiki/Tiny_Encryption_Algorithm
198static void _decryptGameShark(uint32_t* op1, uint32_t* op2, const uint32_t* seeds) {
199	uint32_t sum = 0xC6EF3720;
200	int i;
201	for (i = 0; i < 32; ++i) {
202		*op2 -= ((*op1 << 4) + seeds[2]) ^ (*op1 + sum) ^ ((*op1 >> 5) + seeds[3]);
203		*op1 -= ((*op2 << 4) + seeds[0]) ^ (*op2 + sum) ^ ((*op2 >> 5) + seeds[1]);
204		sum -= 0x9E3779B9;
205	}
206}
207
208static void _reseedGameShark(uint32_t* seeds, uint16_t params, const uint8_t* t1, const uint8_t* t2) {
209	int x, y;
210	int s0 = params >> 8;
211	int s1 = params & 0xFF;
212	for (y = 0; y < 4; ++y) {
213		for (x = 0; x < 4; ++x) {
214			uint8_t z = t1[(s0 + x) & 0xFF] + t2[(s1 + y) & 0xFF];
215			seeds[y] <<= 8;
216			seeds[y] |= z;
217		}
218	}
219}
220
221static void _setGameSharkVersion(struct GBACheatSet* cheats, int version) {
222	cheats->gsaVersion = 1;
223	switch (version) {
224	case 1:
225		memcpy(cheats->gsaSeeds, _gsa1S, 4 * sizeof(uint32_t));
226		break;
227	case 3:
228		memcpy(cheats->gsaSeeds, _par3S, 4 * sizeof(uint32_t));
229		break;
230	}
231}
232
233static bool _addGSA1(struct GBACheatSet* cheats, uint32_t op1, uint32_t op2) {
234	enum GBAGameSharkType type = op1 >> 28;
235	struct GBACheat* cheat = 0;
236
237	if (cheats->incompleteCheat) {
238		if (cheats->remainingAddresses > 0) {
239			cheat = GBACheatListAppend(&cheats->list);
240			cheat->type = CHEAT_ASSIGN;
241			cheat->width = 4;
242			cheat->address = op1;
243			cheat->operand = cheats->incompleteCheat->operand;
244			cheat->repeat = 1;
245			--cheats->remainingAddresses;
246		}
247		if (cheats->remainingAddresses > 0) {
248			cheat = GBACheatListAppend(&cheats->list);
249			cheat->type = CHEAT_ASSIGN;
250			cheat->width = 4;
251			cheat->address = op2;
252			cheat->operand = cheats->incompleteCheat->operand;
253			cheat->repeat = 1;
254			--cheats->remainingAddresses;
255		}
256		if (cheats->remainingAddresses == 0) {
257			cheats->incompleteCheat = 0;
258		}
259		return true;
260	}
261
262	switch (type) {
263	case GSA_ASSIGN_1:
264		cheat = GBACheatListAppend(&cheats->list);
265		cheat->type = CHEAT_ASSIGN;
266		cheat->width = 1;
267		cheat->address = op1 & 0x0FFFFFFF;
268		break;
269	case GSA_ASSIGN_2:
270		cheat = GBACheatListAppend(&cheats->list);
271		cheat->type = CHEAT_ASSIGN;
272		cheat->width = 2;
273		cheat->address = op1 & 0x0FFFFFFF;
274		break;
275	case GSA_ASSIGN_4:
276		cheat = GBACheatListAppend(&cheats->list);
277		cheat->type = CHEAT_ASSIGN;
278		cheat->width = 4;
279		cheat->address = op1 & 0x0FFFFFFF;
280		break;
281	case GSA_ASSIGN_LIST:
282		cheats->remainingAddresses = (op1 & 0xFFFF) - 1;
283		cheat = GBACheatListAppend(&cheats->list);
284		cheat->type = CHEAT_ASSIGN;
285		cheat->width = 4;
286		cheat->address = op2;
287		cheats->incompleteCheat = cheat;
288		break;
289	case GSA_PATCH:
290		cheats->romPatches[0].address = (op1 & 0xFFFFFF) << 1;
291		cheats->romPatches[0].newValue = op2;
292		cheats->romPatches[0].applied = false;
293		cheats->romPatches[0].exists = true;
294		return true;
295	case GSA_BUTTON:
296		// TODO: Implement button
297		return false;
298	case GSA_IF_EQ:
299		if (op1 == 0xDEADFACE) {
300			_reseedGameShark(cheats->gsaSeeds, op2, _gsa1T1, _gsa1T2);
301			return true;
302		}
303		cheat = GBACheatListAppend(&cheats->list);
304		cheat->type = CHEAT_IF_EQ;
305		cheat->width = 2;
306		cheat->address = op1 & 0x0FFFFFFF;
307		break;
308	case GSA_IF_EQ_RANGE:
309		cheat = GBACheatListAppend(&cheats->list);
310		cheat->type = CHEAT_IF_EQ;
311		cheat->width = 2;
312		cheat->address = op2 & 0x0FFFFFFF;
313		cheat->operand = op1 & 0xFFFF;
314		cheat->repeat = (op1 >> 16) & 0xFF;
315		return true;
316	case GSA_HOOK:
317		if (cheats->hook) {
318			return false;
319		}
320		cheats->hook = malloc(sizeof(*cheats->hook));
321		cheats->hook->address = BASE_CART0 | (op1 & (SIZE_CART0 - 1));
322		cheats->hook->mode = MODE_THUMB;
323		cheats->hook->refs = 1;
324		cheats->hook->reentries = 0;
325		return true;
326	default:
327		return false;
328	}
329	cheat->operand = op2;
330	cheat->repeat = 1;
331	return true;
332}
333
334static bool _addPAR3(struct GBACheatSet* cheats, uint32_t op1, uint32_t op2) {
335	// TODO
336	UNUSED(cheats);
337	UNUSED(op1);
338	UNUSED(op2);
339	UNUSED(_par3T1);
340	UNUSED(_par3T2);
341	return false;
342}
343
344static void _addBreakpoint(struct GBACheatDevice* device, struct GBACheatSet* cheats) {
345	if (!device->p || !cheats->hook) {
346		return;
347	}
348	++cheats->hook->reentries;
349	if (cheats->hook->reentries > 1) {
350		return;
351	}
352	GBASetBreakpoint(device->p, &device->d, cheats->hook->address, cheats->hook->mode, &cheats->hook->patchedOpcode);
353}
354
355static void _removeBreakpoint(struct GBACheatDevice* device, struct GBACheatSet* cheats) {
356	if (!device->p || !cheats->hook) {
357		return;
358	}
359	--cheats->hook->reentries;
360	if (cheats->hook->reentries > 0) {
361		return;
362	}
363	GBAClearBreakpoint(device->p, cheats->hook->address, cheats->hook->mode, cheats->hook->patchedOpcode);
364}
365
366static void _patchROM(struct GBACheatDevice* device, struct GBACheatSet* cheats) {
367	if (!device->p) {
368		return;
369	}
370	int i;
371	for (i = 0; i < MAX_ROM_PATCHES; ++i) {
372		if (!cheats->romPatches[i].exists || cheats->romPatches[i].applied) {
373			continue;
374		}
375		GBAPatch16(device->p->cpu, cheats->romPatches[i].address, cheats->romPatches[i].newValue, &cheats->romPatches[i].oldValue);
376		cheats->romPatches[i].applied = true;
377	}
378}
379
380static void _unpatchROM(struct GBACheatDevice* device, struct GBACheatSet* cheats) {
381	if (!device->p) {
382		return;
383	}
384	int i;
385	for (i = 0; i < MAX_ROM_PATCHES; ++i) {
386		if (!cheats->romPatches[i].exists || !cheats->romPatches[i].applied) {
387			continue;
388		}
389		GBAPatch16(device->p->cpu, cheats->romPatches[i].address, cheats->romPatches[i].oldValue, 0);
390		cheats->romPatches[i].applied = false;
391	}
392}
393
394static void GBACheatDeviceInit(struct ARMCore*, struct ARMComponent*);
395static void GBACheatDeviceDeinit(struct ARMComponent*);
396
397void GBACheatDeviceCreate(struct GBACheatDevice* device) {
398	device->d.id = GBA_CHEAT_DEVICE_ID;
399	device->d.init = GBACheatDeviceInit;
400	device->d.deinit = GBACheatDeviceDeinit;
401	GBACheatSetsInit(&device->cheats, 4);
402}
403
404void GBACheatDeviceDestroy(struct GBACheatDevice* device) {
405	size_t i;
406	for (i = 0; i < GBACheatSetsSize(&device->cheats); ++i) {
407		struct GBACheatSet* set = *GBACheatSetsGetPointer(&device->cheats, i);
408		GBACheatSetDeinit(set);
409		free(set);
410	}
411	GBACheatSetsDeinit(&device->cheats);
412}
413
414void GBACheatSetInit(struct GBACheatSet* set, const char* name) {
415	GBACheatListInit(&set->list, 4);
416	StringListInit(&set->lines, 4);
417	set->incompleteCheat = 0;
418	set->gsaVersion = 0;
419	set->remainingAddresses = 0;
420	set->hook = 0;
421	int i;
422	for (i = 0; i < MAX_ROM_PATCHES; ++i) {
423		set->romPatches[i].exists = false;
424	}
425	if (name) {
426		set->name = strdup(name);
427	} else {
428		set->name = 0;
429	}
430	set->enabled = true;
431}
432
433void GBACheatSetDeinit(struct GBACheatSet* set) {
434	GBACheatListDeinit(&set->list);
435	size_t i;
436	for (i = 0; i < StringListSize(&set->lines); ++i) {
437		free(*StringListGetPointer(&set->lines, i));
438	}
439	if (set->name) {
440		free(set->name);
441	}
442	if (set->hook) {
443		--set->hook->refs;
444		if (set->hook->refs == 0) {
445			free(set->hook);
446		}
447	}
448}
449
450void GBACheatAttachDevice(struct GBA* gba, struct GBACheatDevice* device) {
451	if (gba->cpu->components[GBA_COMPONENT_CHEAT_DEVICE]) {
452		ARMHotplugDetach(gba->cpu, GBA_COMPONENT_CHEAT_DEVICE);
453	}
454	gba->cpu->components[GBA_COMPONENT_CHEAT_DEVICE] = &device->d;
455	ARMHotplugAttach(gba->cpu, GBA_COMPONENT_CHEAT_DEVICE);
456}
457
458void GBACheatAddSet(struct GBACheatDevice* device, struct GBACheatSet* cheats) {
459	*GBACheatSetsAppend(&device->cheats) = cheats;
460	_addBreakpoint(device, cheats);
461	_patchROM(device, cheats);
462}
463
464void GBACheatRemoveSet(struct GBACheatDevice* device, struct GBACheatSet* cheats) {
465	size_t i;
466	for (i = 0; i < GBACheatSetsSize(&device->cheats); ++i) {
467		if (*GBACheatSetsGetPointer(&device->cheats, i) == cheats) {
468			break;
469		}
470	}
471	if (i == GBACheatSetsSize(&device->cheats)) {
472		return;
473	}
474	GBACheatSetsShift(&device->cheats, i, 1);
475	_unpatchROM(device, cheats);
476	_removeBreakpoint(device, cheats);
477}
478
479bool GBACheatAddCodeBreaker(struct GBACheatSet* cheats, uint32_t op1, uint16_t op2) {
480	char line[14] = "XXXXXXXX XXXX";
481	snprintf(line, sizeof(line), "%08X %04X", op1, op2);
482	_registerLine(cheats, line);
483
484	enum GBACodeBreakerType type = op1 >> 28;
485	struct GBACheat* cheat = 0;
486
487	if (cheats->incompleteCheat) {
488		cheats->incompleteCheat->repeat = op1 & 0xFFFF;
489		cheats->incompleteCheat->addressOffset = op2;
490		cheats->incompleteCheat->operandOffset = 0;
491		cheats->incompleteCheat = 0;
492		return true;
493	}
494
495	switch (type) {
496	case CB_GAME_ID:
497		// TODO: Run checksum
498		return true;
499	case CB_HOOK:
500		if (cheats->hook) {
501			return false;
502		}
503		cheats->hook = malloc(sizeof(*cheats->hook));
504		cheats->hook->address = BASE_CART0 | (op1 & (SIZE_CART0 - 1));
505		cheats->hook->mode = MODE_THUMB;
506		cheats->hook->refs = 1;
507		cheats->hook->reentries = 0;
508		return true;
509	case CB_OR_2:
510		cheat = GBACheatListAppend(&cheats->list);
511		cheat->type = CHEAT_OR;
512		cheat->width = 2;
513		break;
514	case CB_ASSIGN_1:
515		cheat = GBACheatListAppend(&cheats->list);
516		cheat->type = CHEAT_ASSIGN;
517		cheat->width = 1;
518		break;
519	case CB_FILL:
520		cheat = GBACheatListAppend(&cheats->list);
521		cheat->type = CHEAT_ASSIGN;
522		cheat->width = 2;
523		cheats->incompleteCheat = cheat;
524		break;
525	case CB_FILL_8:
526		GBALog(0, GBA_LOG_STUB, "[Cheat] CodeBreaker code %08X %04X not supported", op1, op2);
527		return false;
528	case CB_AND_2:
529		cheat = GBACheatListAppend(&cheats->list);
530		cheat->type = CHEAT_AND;
531		cheat->width = 2;
532		break;
533	case CB_IF_EQ:
534		cheat = GBACheatListAppend(&cheats->list);
535		cheat->type = CHEAT_IF_EQ;
536		cheat->width = 2;
537		break;
538	case CB_ASSIGN_2:
539		cheat = GBACheatListAppend(&cheats->list);
540		cheat->type = CHEAT_ASSIGN;
541		cheat->width = 2;
542		break;
543	case CB_ENCRYPT:
544		GBALog(0, GBA_LOG_STUB, "[Cheat] CodeBreaker encryption not supported");
545		return false;
546	case CB_IF_NE:
547		cheat = GBACheatListAppend(&cheats->list);
548		cheat->type = CHEAT_IF_NE;
549		cheat->width = 2;
550		break;
551	case CB_IF_GT:
552		cheat = GBACheatListAppend(&cheats->list);
553		cheat->type = CHEAT_IF_GT;
554		cheat->width = 2;
555		break;
556	case CB_IF_LT:
557		cheat = GBACheatListAppend(&cheats->list);
558		cheat->type = CHEAT_IF_LT;
559		cheat->width = 2;
560		break;
561	case CB_IF_SPECIAL:
562		switch (op1 & 0x0FFFFFFF) {
563		case 0x20:
564			cheat = GBACheatListAppend(&cheats->list);
565			cheat->type = CHEAT_IF_AND;
566			cheat->width = 2;
567			cheat->address = BASE_IO | REG_JOYSTAT;
568			cheat->operand = op2;
569			cheat->repeat = 1;
570			return true;
571		default:
572			GBALog(0, GBA_LOG_STUB, "[Cheat] CodeBreaker code %08X %04X not supported", op1, op2);
573			return false;
574		}
575	case CB_ADD_2:
576		cheat = GBACheatListAppend(&cheats->list);
577		cheat->type = CHEAT_ADD;
578		cheat->width = 2;
579		break;
580	case CB_IF_AND:
581		cheat = GBACheatListAppend(&cheats->list);
582		cheat->type = CHEAT_IF_AND;
583		cheat->width = 2;
584		break;
585	}
586
587	cheat->address = op1 & 0x0FFFFFFF;
588	cheat->operand = op2;
589	cheat->repeat = 1;
590	return true;
591}
592
593bool GBACheatAddCodeBreakerLine(struct GBACheatSet* cheats, const char* line) {
594	uint32_t op1;
595	uint16_t op2;
596	line = _hex32(line, &op1);
597	if (!line) {
598		return false;
599	}
600	while (*line == ' ') {
601		++line;
602	}
603	line = _hex16(line, &op2);
604	if (!line) {
605		return false;
606	}
607	return GBACheatAddCodeBreaker(cheats, op1, op2);
608}
609
610bool GBACheatAddGameShark(struct GBACheatSet* set, uint32_t op1, uint32_t op2) {
611	uint32_t o1 = op1;
612	uint32_t o2 = op2;
613	char line[18] = "XXXXXXXX XXXXXXXX";
614	snprintf(line, sizeof(line), "%08X %08X", op1, op2);
615	_registerLine(set, line);
616
617	switch (set->gsaVersion) {
618	case 0:
619		_setGameSharkVersion(set, 1);
620		// Fall through
621	case 1:
622		_decryptGameShark(&o1, &o2, set->gsaSeeds);
623		return _addGSA1(set, o1, o2);
624	}
625	return false;
626}
627
628bool GBACheatAddGameSharkLine(struct GBACheatSet* cheats, const char* line) {
629	uint32_t op1;
630	uint32_t op2;
631	line = _hex32(line, &op1);
632	if (!line) {
633		return false;
634	}
635	while (*line == ' ') {
636		++line;
637	}
638	line = _hex32(line, &op2);
639	if (!line) {
640		return false;
641	}
642	return GBACheatAddGameShark(cheats, op1, op2);
643}
644
645bool GBACheatAddAutodetect(struct GBACheatSet* set, uint32_t op1, uint32_t op2) {
646	uint32_t o1 = op1;
647	uint32_t o2 = op2;
648	char line[18] = "XXXXXXXX XXXXXXXX";
649	snprintf(line, sizeof(line), "%08X %08X", op1, op2);
650	_registerLine(set, line);
651
652	switch (set->gsaVersion) {
653	case 0:
654		// Try to detect GameShark version
655		_decryptGameShark(&o1, &o2, _gsa1S);
656		if ((o1 & 0xF0000000) == 0xF0000000 && !(o2 & 0xFFFFFCFE)) {
657			_setGameSharkVersion(set, 1);
658			return _addGSA1(set, o1, o2);
659		}
660		o1 = op1;
661		o2 = op2;
662		_decryptGameShark(&o1, &o2, _par3S);
663		if ((o1 & 0xFE000000) == 0xC4000000 && !(o2 & 0xFFFF0000)) {
664			_setGameSharkVersion(set, 3);
665			return _addPAR3(set, o1, o2);
666		}
667		break;
668	case 1:
669		_decryptGameShark(&o1, &o2, set->gsaSeeds);
670		return _addGSA1(set, o1, o2);
671	case 3:
672		_decryptGameShark(&o1, &o2, set->gsaSeeds);
673		return _addPAR3(set, o1, o2);
674	}
675	return false;
676}
677
678bool GBACheatAutodetectLine(struct GBACheatSet* cheats, const char* line) {
679	uint32_t op1;
680	uint32_t op2;
681	line = _hex32(line, &op1);
682	if (!line) {
683		return false;
684	}
685	while (*line == ' ') {
686		++line;
687	}
688	line = _hex32(line, &op2);
689	if (!line) {
690		return false;
691	}
692	return GBACheatAddAutodetect(cheats, op1, op2);
693}
694
695bool GBACheatParseFile(struct GBACheatDevice* device, struct VFile* vf) {
696	char cheat[MAX_LINE_LENGTH];
697	struct GBACheatSet* set = 0;
698	struct GBACheatSet* newSet;
699	int gsaVersion = 0;
700	bool nextDisabled = false;
701	bool reset = false;
702	while (true) {
703		size_t i = 0;
704		ssize_t bytesRead = vf->readline(vf, cheat, sizeof(cheat));
705		if (bytesRead == 0) {
706			break;
707		}
708		if (bytesRead < 0) {
709			return false;
710		}
711		while (isspace(cheat[i])) {
712			++i;
713		}
714		switch (cheat[i]) {
715		case '#':
716			do {
717				++i;
718			} while (isspace(cheat[i]));
719			newSet = malloc(sizeof(*set));
720			GBACheatSetInit(newSet, &cheat[i]);
721			newSet->enabled = !nextDisabled;
722			nextDisabled = false;
723			if (set) {
724				GBACheatAddSet(device, set);
725			}
726			if (set && !reset) {
727				GBACheatSetCopyProperties(newSet, set);
728			} else {
729				_setGameSharkVersion(newSet, gsaVersion);
730			}
731			reset = false;
732			set = newSet;
733			break;
734		case '!':
735			do {
736				++i;
737			} while (isspace(cheat[i]));
738			if (strncasecmp(&cheat[i], "GSAv", 4) == 0 || strncasecmp(&cheat[i], "PARv", 4) == 0) {
739				i += 4;
740				gsaVersion = atoi(&cheat[i]);
741				break;
742			}
743			if (strcasecmp(&cheat[i], "disabled") == 0) {
744				nextDisabled = true;
745				break;
746			}
747			if (strcasecmp(&cheat[i], "reset") == 0) {
748				reset = true;
749				break;
750			}
751			break;
752		default:
753			if (!set) {
754				set = malloc(sizeof(*set));
755				GBACheatSetInit(set, 0);
756				set->enabled = !nextDisabled;
757				nextDisabled = false;
758				_setGameSharkVersion(set, gsaVersion);
759			}
760			GBACheatAddLine(set, cheat);
761			break;
762		}
763	}
764	if (set) {
765		GBACheatAddSet(device, set);
766	}
767	return true;
768}
769
770bool GBACheatSaveFile(struct GBACheatDevice* device, struct VFile* vf) {
771	static const char lineStart[3] = "# ";
772	static const char lineEnd = '\n';
773
774	struct GBACheatHook* lastHook = 0;
775
776	size_t i;
777	for (i = 0; i < GBACheatSetsSize(&device->cheats); ++i) {
778		struct GBACheatSet* set = *GBACheatSetsGetPointer(&device->cheats, i);
779		if (lastHook && set->hook != lastHook) {
780			static const char* resetDirective = "!reset\n";
781			vf->write(vf, resetDirective, strlen(resetDirective));
782		}
783		switch (set->gsaVersion) {
784		case 1: {
785			static const char* versionDirective = "!GSAv1\n";
786			vf->write(vf, versionDirective, strlen(versionDirective));
787			break;
788		}
789		case 3: {
790			static const char* versionDirective = "!PARv3\n";
791			vf->write(vf, versionDirective, strlen(versionDirective));
792			break;
793		}
794		default:
795			break;
796		}
797		lastHook = set->hook;
798		if (!set->enabled) {
799			static const char* disabledDirective = "!disabled\n";
800			vf->write(vf, disabledDirective, strlen(disabledDirective));
801		}
802
803		vf->write(vf, lineStart, 2);
804		if (set->name) {
805			vf->write(vf, set->name, strlen(set->name));
806		}
807		vf->write(vf, &lineEnd, 1);
808		size_t c;
809		for (c = 0; c < StringListSize(&set->lines); ++c) {
810			const char* line = *StringListGetPointer(&set->lines, c);
811			vf->write(vf, line, strlen(line));
812			vf->write(vf, &lineEnd, 1);
813		}
814	}
815	return true;
816}
817
818bool GBACheatAddLine(struct GBACheatSet* cheats, const char* line) {
819	uint32_t op1;
820	uint16_t op2;
821	uint16_t op3;
822	line = _hex32(line, &op1);
823	if (!line) {
824		return false;
825	}
826	while (isspace(line[0])) {
827		++line;
828	}
829	line = _hex16(line, &op2);
830	if (!line) {
831		return false;
832	}
833	if (!line[0] || isspace(line[0])) {
834		return GBACheatAddCodeBreaker(cheats, op1, op2);
835	}
836	line = _hex16(line, &op3);
837	if (!line) {
838		return false;
839	}
840	uint32_t realOp2 = op2;
841	realOp2 <<= 16;
842	realOp2 |= op3;
843	return GBACheatAddAutodetect(cheats, op1, realOp2);
844}
845
846void GBACheatRefresh(struct GBACheatDevice* device, struct GBACheatSet* cheats) {
847	if (!cheats->enabled) {
848		return;
849	}
850	bool condition = true;
851	int conditionRemaining = 0;
852	_patchROM(device, cheats);
853
854	size_t nCodes = GBACheatListSize(&cheats->list);
855	size_t i;
856	for (i = 0; i < nCodes; ++i) {
857		if (conditionRemaining > 0) {
858			--conditionRemaining;
859			if (!condition) {
860				continue;
861			}
862		} else {
863			condition = true;
864		}
865		struct GBACheat* cheat = GBACheatListGetPointer(&cheats->list, i);
866		int32_t value = 0;
867		int32_t operand = cheat->operand;
868		uint32_t operationsRemaining = cheat->repeat;
869		uint32_t address = cheat->address;
870		bool performAssignment = false;
871		for (; operationsRemaining; --operationsRemaining) {
872			switch (cheat->type) {
873			case CHEAT_ASSIGN:
874				value = operand;
875				performAssignment = true;
876				break;
877			case CHEAT_AND:
878				value = _readMem(device->p->cpu, address, cheat->width) & operand;
879				performAssignment = true;
880				break;
881			case CHEAT_ADD:
882				value = _readMem(device->p->cpu, address, cheat->width) + operand;
883				performAssignment = true;
884				break;
885			case CHEAT_OR:
886				value = _readMem(device->p->cpu, address, cheat->width) | operand;
887				performAssignment = true;
888				break;
889			case CHEAT_IF_EQ:
890				condition = _readMem(device->p->cpu, address, cheat->width) == operand;
891				conditionRemaining = cheat->repeat;
892				break;
893			case CHEAT_IF_NE:
894				condition = _readMem(device->p->cpu, address, cheat->width) != operand;
895				conditionRemaining = cheat->repeat;
896				break;
897			case CHEAT_IF_LT:
898				condition = _readMem(device->p->cpu, address, cheat->width) < operand;
899				conditionRemaining = cheat->repeat;
900				break;
901			case CHEAT_IF_GT:
902				condition = _readMem(device->p->cpu, address, cheat->width) > operand;
903				conditionRemaining = cheat->repeat;
904				break;
905			case CHEAT_IF_ULT:
906				condition = (uint32_t) _readMem(device->p->cpu, address, cheat->width) < (uint32_t) operand;
907				conditionRemaining = cheat->repeat;
908				break;
909			case CHEAT_IF_UGT:
910				condition = (uint32_t) _readMem(device->p->cpu, address, cheat->width) > (uint32_t) operand;
911				conditionRemaining = cheat->repeat;
912				break;
913			case CHEAT_IF_AND:
914				condition = _readMem(device->p->cpu, address, cheat->width) & operand;
915				conditionRemaining = cheat->repeat;
916				break;
917			case CHEAT_IF_LAND:
918				condition = _readMem(device->p->cpu, address, cheat->width) && operand;
919				conditionRemaining = cheat->repeat;
920				break;
921			}
922
923			if (performAssignment) {
924				_writeMem(device->p->cpu, address, cheat->width, value);
925			}
926
927			address += cheat->addressOffset;
928			operand += cheat->operandOffset;
929		}
930	}
931}
932
933void GBACheatSetCopyProperties(struct GBACheatSet* newSet, struct GBACheatSet* set) {
934	newSet->gsaVersion = set->gsaVersion;
935	memcpy(newSet->gsaSeeds, set->gsaSeeds, sizeof(newSet->gsaSeeds));
936	if (set->hook) {
937		if (newSet->hook) {
938			--newSet->hook->refs;
939			if (newSet->hook->refs == 0) {
940				free(newSet->hook);
941			}
942		}
943		newSet->hook = set->hook;
944		++newSet->hook->refs;
945	}
946}
947
948void GBACheatDeviceInit(struct ARMCore* cpu, struct ARMComponent* component) {
949	struct GBACheatDevice* device = (struct GBACheatDevice*) component;
950	device->p = (struct GBA*) cpu->master;
951	size_t i;
952	for (i = 0; i < GBACheatSetsSize(&device->cheats); ++i) {
953		struct GBACheatSet* cheats = *GBACheatSetsGetPointer(&device->cheats, i);
954		_addBreakpoint(device, cheats);
955		_patchROM(device, cheats);
956	}
957}
958
959void GBACheatDeviceDeinit(struct ARMComponent* component) {
960	struct GBACheatDevice* device = (struct GBACheatDevice*) component;
961	size_t i;
962	for (i = GBACheatSetsSize(&device->cheats); i--;) {
963		struct GBACheatSet* cheats = *GBACheatSetsGetPointer(&device->cheats, i);
964		_unpatchROM(device, cheats);
965		_removeBreakpoint(device, cheats);
966	}
967}