all repos — mgba @ dc5fb14fa18c31812bc2bbab72b718a7846113c2

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