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 int i;
179 for (i = 0; i < 4; ++i, ++line) {
180 char digit = *line;
181 value <<= 4;
182 int nybble = _hexDigit(digit);
183 if (nybble < 0) {
184 return 0;
185 }
186 value |= nybble;
187 }
188 *out = value;
189 return line;
190}
191
192static void _registerLine(struct GBACheatSet* cheats, const char* line) {
193 *StringListAppend(&cheats->lines) = strdup(line);
194}
195
196// http://en.wikipedia.org/wiki/Tiny_Encryption_Algorithm
197static void _decryptGameShark(uint32_t* op1, uint32_t* op2, const uint32_t* seeds) {
198 uint32_t sum = 0xC6EF3720;
199 int i;
200 for (i = 0; i < 32; ++i) {
201 *op2 -= ((*op1 << 4) + seeds[2]) ^ (*op1 + sum) ^ ((*op1 >> 5) + seeds[3]);
202 *op1 -= ((*op2 << 4) + seeds[0]) ^ (*op2 + sum) ^ ((*op2 >> 5) + seeds[1]);
203 sum -= 0x9E3779B9;
204 }
205}
206
207static void _reseedGameShark(uint32_t* seeds, uint16_t params, const uint8_t* t1, const uint8_t* t2) {
208 int x, y;
209 int s0 = params >> 8;
210 int s1 = params & 0xFF;
211 for (y = 0; y < 4; ++y) {
212 for (x = 0; x < 4; ++x) {
213 uint8_t z = t1[(s0 + x) & 0xFF] + t2[(s1 + y) & 0xFF];
214 seeds[y] <<= 8;
215 seeds[y] |= z;
216 }
217 }
218}
219
220static void _setGameSharkVersion(struct GBACheatSet* cheats, int version) {
221 cheats->gsaVersion = 1;
222 switch (version) {
223 case 1:
224 memcpy(cheats->gsaSeeds, _gsa1S, 4 * sizeof(uint32_t));
225 break;
226 case 3:
227 memcpy(cheats->gsaSeeds, _par3S, 4 * sizeof(uint32_t));
228 break;
229 }
230}
231
232static bool _addGSA1(struct GBACheatSet* cheats, uint32_t op1, uint32_t op2) {
233 enum GBAGameSharkType type = op1 >> 28;
234 struct GBACheat* cheat = 0;
235
236 if (cheats->incompleteCheat) {
237 if (cheats->remainingAddresses > 0) {
238 cheat = GBACheatListAppend(&cheats->list);
239 cheat->type = CHEAT_ASSIGN;
240 cheat->width = 4;
241 cheat->address = op1;
242 cheat->operand = cheats->incompleteCheat->operand;
243 cheat->repeat = 1;
244 --cheats->remainingAddresses;
245 }
246 if (cheats->remainingAddresses > 0) {
247 cheat = GBACheatListAppend(&cheats->list);
248 cheat->type = CHEAT_ASSIGN;
249 cheat->width = 4;
250 cheat->address = op2;
251 cheat->operand = cheats->incompleteCheat->operand;
252 cheat->repeat = 1;
253 --cheats->remainingAddresses;
254 }
255 if (cheats->remainingAddresses == 0) {
256 cheats->incompleteCheat = 0;
257 }
258 return true;
259 }
260
261 switch (type) {
262 case GSA_ASSIGN_1:
263 cheat = GBACheatListAppend(&cheats->list);
264 cheat->type = CHEAT_ASSIGN;
265 cheat->width = 1;
266 cheat->address = op1 & 0x0FFFFFFF;
267 break;
268 case GSA_ASSIGN_2:
269 cheat = GBACheatListAppend(&cheats->list);
270 cheat->type = CHEAT_ASSIGN;
271 cheat->width = 2;
272 cheat->address = op1 & 0x0FFFFFFF;
273 break;
274 case GSA_ASSIGN_4:
275 cheat = GBACheatListAppend(&cheats->list);
276 cheat->type = CHEAT_ASSIGN;
277 cheat->width = 4;
278 cheat->address = op1 & 0x0FFFFFFF;
279 break;
280 case GSA_ASSIGN_LIST:
281 cheats->remainingAddresses = (op1 & 0xFFFF) - 1;
282 cheat = GBACheatListAppend(&cheats->list);
283 cheat->type = CHEAT_ASSIGN;
284 cheat->width = 4;
285 cheat->address = op2;
286 cheats->incompleteCheat = cheat;
287 break;
288 case GSA_PATCH:
289 cheats->romPatches[0].address = (op1 & 0xFFFFFF) << 1;
290 cheats->romPatches[0].newValue = op2;
291 cheats->romPatches[0].applied = false;
292 cheats->romPatches[0].exists = true;
293 return true;
294 case GSA_BUTTON:
295 // TODO: Implement button
296 return false;
297 case GSA_IF_EQ:
298 if (op1 == 0xDEADFACE) {
299 _reseedGameShark(cheats->gsaSeeds, op2, _gsa1T1, _gsa1T2);
300 return true;
301 }
302 cheat = GBACheatListAppend(&cheats->list);
303 cheat->type = CHEAT_IF_EQ;
304 cheat->width = 2;
305 cheat->address = op1 & 0x0FFFFFFF;
306 break;
307 case GSA_IF_EQ_RANGE:
308 cheat = GBACheatListAppend(&cheats->list);
309 cheat->type = CHEAT_IF_EQ;
310 cheat->width = 2;
311 cheat->address = op2 & 0x0FFFFFFF;
312 cheat->operand = op1 & 0xFFFF;
313 cheat->repeat = (op1 >> 16) & 0xFF;
314 return true;
315 case GSA_HOOK:
316 if (cheats->hook) {
317 return false;
318 }
319 cheats->hook = malloc(sizeof(*cheats->hook));
320 cheats->hook->address = BASE_CART0 | (op1 & (SIZE_CART0 - 1));
321 cheats->hook->mode = MODE_THUMB;
322 cheats->hook->refs = 1;
323 cheats->hook->reentries = 0;
324 return true;
325 default:
326 return false;
327 }
328 cheat->operand = op2;
329 cheat->repeat = 1;
330 return true;
331}
332
333static bool _addGSA3(struct GBACheatSet* cheats, uint32_t op1, uint32_t op2) {
334 // TODO
335 UNUSED(cheats);
336 UNUSED(op1);
337 UNUSED(op2);
338 return false;
339}
340
341static void _addBreakpoint(struct GBACheatDevice* device, struct GBACheatSet* cheats) {
342 if (!device->p || !cheats->hook) {
343 return;
344 }
345 ++cheats->hook->reentries;
346 if (cheats->hook->reentries > 1) {
347 return;
348 }
349 GBASetBreakpoint(device->p, &device->d, cheats->hook->address, cheats->hook->mode, &cheats->hook->patchedOpcode);
350}
351
352static void _removeBreakpoint(struct GBACheatDevice* device, struct GBACheatSet* cheats) {
353 if (!device->p || !cheats->hook) {
354 return;
355 }
356 --cheats->hook->reentries;
357 if (cheats->hook->reentries > 0) {
358 return;
359 }
360 GBAClearBreakpoint(device->p, cheats->hook->address, cheats->hook->mode, cheats->hook->patchedOpcode);
361}
362
363static void _patchROM(struct GBACheatDevice* device, struct GBACheatSet* cheats) {
364 if (!device->p) {
365 return;
366 }
367 int i;
368 for (i = 0; i < MAX_ROM_PATCHES; ++i) {
369 if (!cheats->romPatches[i].exists || cheats->romPatches[i].applied) {
370 continue;
371 }
372 GBAPatch16(device->p->cpu, cheats->romPatches[i].address, cheats->romPatches[i].newValue, &cheats->romPatches[i].oldValue);
373 cheats->romPatches[i].applied = true;
374 }
375}
376
377static void _unpatchROM(struct GBACheatDevice* device, struct GBACheatSet* cheats) {
378 if (!device->p) {
379 return;
380 }
381 int i;
382 for (i = 0; i < MAX_ROM_PATCHES; ++i) {
383 if (!cheats->romPatches[i].exists || !cheats->romPatches[i].applied) {
384 continue;
385 }
386 GBAPatch16(device->p->cpu, cheats->romPatches[i].address, cheats->romPatches[i].oldValue, 0);
387 cheats->romPatches[i].applied = false;
388 }
389}
390
391static void GBACheatDeviceInit(struct ARMCore*, struct ARMComponent*);
392static void GBACheatDeviceDeinit(struct ARMComponent*);
393
394void GBACheatDeviceCreate(struct GBACheatDevice* device) {
395 device->d.id = GBA_CHEAT_DEVICE_ID;
396 device->d.init = GBACheatDeviceInit;
397 device->d.deinit = GBACheatDeviceDeinit;
398 GBACheatSetsInit(&device->cheats, 4);
399}
400
401void GBACheatDeviceDestroy(struct GBACheatDevice* device) {
402 size_t i;
403 for (i = 0; i < GBACheatSetsSize(&device->cheats); ++i) {
404 struct GBACheatSet* set = *GBACheatSetsGetPointer(&device->cheats, i);
405 GBACheatSetDeinit(set);
406 free(set);
407 }
408 GBACheatSetsDeinit(&device->cheats);
409}
410
411void GBACheatSetInit(struct GBACheatSet* set, const char* name) {
412 GBACheatListInit(&set->list, 4);
413 StringListInit(&set->lines, 4);
414 set->incompleteCheat = 0;
415 set->gsaVersion = 0;
416 set->remainingAddresses = 0;
417 set->hook = 0;
418 int i;
419 for (i = 0; i < MAX_ROM_PATCHES; ++i) {
420 set->romPatches[i].exists = false;
421 }
422 if (name) {
423 set->name = strdup(name);
424 } else {
425 set->name = 0;
426 }
427 set->enabled = true;
428}
429
430void GBACheatSetDeinit(struct GBACheatSet* set) {
431 GBACheatListDeinit(&set->list);
432 size_t i;
433 for (i = 0; i < StringListSize(&set->lines); ++i) {
434 free(*StringListGetPointer(&set->lines, i));
435 }
436 if (set->name) {
437 free(set->name);
438 }
439 if (set->hook) {
440 --set->hook->refs;
441 if (set->hook->refs == 0) {
442 free(set->hook);
443 }
444 }
445}
446
447void GBACheatAttachDevice(struct GBA* gba, struct GBACheatDevice* device) {
448 if (gba->cpu->components[GBA_COMPONENT_CHEAT_DEVICE]) {
449 ARMHotplugDetach(gba->cpu, GBA_COMPONENT_CHEAT_DEVICE);
450 }
451 gba->cpu->components[GBA_COMPONENT_CHEAT_DEVICE] = &device->d;
452 ARMHotplugAttach(gba->cpu, GBA_COMPONENT_CHEAT_DEVICE);
453}
454
455void GBACheatAddSet(struct GBACheatDevice* device, struct GBACheatSet* cheats) {
456 *GBACheatSetsAppend(&device->cheats) = cheats;
457 _addBreakpoint(device, cheats);
458 _patchROM(device, cheats);
459}
460
461void GBACheatRemoveSet(struct GBACheatDevice* device, struct GBACheatSet* cheats) {
462 size_t i;
463 for (i = 0; i < GBACheatSetsSize(&device->cheats); ++i) {
464 if (*GBACheatSetsGetPointer(&device->cheats, i) == cheats) {
465 break;
466 }
467 }
468 if (i == GBACheatSetsSize(&device->cheats)) {
469 return;
470 }
471 GBACheatSetsShift(&device->cheats, i, 1);
472 _unpatchROM(device, cheats);
473 _removeBreakpoint(device, cheats);
474}
475
476bool GBACheatAddCodeBreaker(struct GBACheatSet* cheats, uint32_t op1, uint16_t op2) {
477 char line[14] = "XXXXXXXX XXXX";
478 snprintf(line, sizeof(line), "%08X %04X", op1, op2);
479 _registerLine(cheats, line);
480
481 enum GBACodeBreakerType type = op1 >> 28;
482 struct GBACheat* cheat = 0;
483
484 if (cheats->incompleteCheat) {
485 cheats->incompleteCheat->repeat = op1 & 0xFFFF;
486 cheats->incompleteCheat->addressOffset = op2;
487 cheats->incompleteCheat->operandOffset = 0;
488 cheats->incompleteCheat = 0;
489 return true;
490 }
491
492 switch (type) {
493 case CB_GAME_ID:
494 // TODO: Run checksum
495 return true;
496 case CB_HOOK:
497 if (cheats->hook) {
498 return false;
499 }
500 cheats->hook = malloc(sizeof(*cheats->hook));
501 cheats->hook->address = BASE_CART0 | (op1 & (SIZE_CART0 - 1));
502 cheats->hook->mode = MODE_THUMB;
503 cheats->hook->refs = 1;
504 cheats->hook->reentries = 0;
505 return true;
506 case CB_OR_2:
507 cheat = GBACheatListAppend(&cheats->list);
508 cheat->type = CHEAT_OR;
509 cheat->width = 2;
510 break;
511 case CB_ASSIGN_1:
512 cheat = GBACheatListAppend(&cheats->list);
513 cheat->type = CHEAT_ASSIGN;
514 cheat->width = 1;
515 break;
516 case CB_FILL:
517 cheat = GBACheatListAppend(&cheats->list);
518 cheat->type = CHEAT_ASSIGN;
519 cheat->width = 2;
520 cheats->incompleteCheat = cheat;
521 break;
522 case CB_FILL_8:
523 GBALog(0, GBA_LOG_STUB, "[Cheat] CodeBreaker code %08X %04X not supported", op1, op2);
524 return false;
525 case CB_AND_2:
526 cheat = GBACheatListAppend(&cheats->list);
527 cheat->type = CHEAT_AND;
528 cheat->width = 2;
529 break;
530 case CB_IF_EQ:
531 cheat = GBACheatListAppend(&cheats->list);
532 cheat->type = CHEAT_IF_EQ;
533 cheat->width = 2;
534 break;
535 case CB_ASSIGN_2:
536 cheat = GBACheatListAppend(&cheats->list);
537 cheat->type = CHEAT_ASSIGN;
538 cheat->width = 2;
539 break;
540 case CB_ENCRYPT:
541 GBALog(0, GBA_LOG_STUB, "[Cheat] CodeBreaker encryption not supported");
542 return false;
543 case CB_IF_NE:
544 cheat = GBACheatListAppend(&cheats->list);
545 cheat->type = CHEAT_IF_NE;
546 cheat->width = 2;
547 break;
548 case CB_IF_GT:
549 cheat = GBACheatListAppend(&cheats->list);
550 cheat->type = CHEAT_IF_GT;
551 cheat->width = 2;
552 break;
553 case CB_IF_LT:
554 cheat = GBACheatListAppend(&cheats->list);
555 cheat->type = CHEAT_IF_LT;
556 cheat->width = 2;
557 break;
558 case CB_IF_SPECIAL:
559 switch (op1 & 0x0FFFFFFF) {
560 case 0x20:
561 cheat = GBACheatListAppend(&cheats->list);
562 cheat->type = CHEAT_IF_AND;
563 cheat->width = 2;
564 cheat->address = BASE_IO | REG_JOYSTAT;
565 cheat->operand = op2;
566 cheat->repeat = 1;
567 return true;
568 default:
569 GBALog(0, GBA_LOG_STUB, "[Cheat] CodeBreaker code %08X %04X not supported", op1, op2);
570 return false;
571 }
572 case CB_ADD_2:
573 cheat = GBACheatListAppend(&cheats->list);
574 cheat->type = CHEAT_ADD;
575 cheat->width = 2;
576 break;
577 case CB_IF_AND:
578 cheat = GBACheatListAppend(&cheats->list);
579 cheat->type = CHEAT_IF_AND;
580 cheat->width = 2;
581 break;
582 }
583
584 cheat->address = op1 & 0x0FFFFFFF;
585 cheat->operand = op2;
586 cheat->repeat = 1;
587 return true;
588}
589
590bool GBACheatAddCodeBreakerLine(struct GBACheatSet* cheats, const char* line) {
591 uint32_t op1;
592 uint16_t op2;
593 line = _hex32(line, &op1);
594 if (!line) {
595 return false;
596 }
597 while (*line == ' ') {
598 ++line;
599 }
600 line = _hex16(line, &op2);
601 if (!line) {
602 return false;
603 }
604 return GBACheatAddCodeBreaker(cheats, op1, op2);
605}
606
607bool GBACheatAddGameShark(struct GBACheatSet* set, uint32_t op1, uint32_t op2) {
608 uint32_t o1 = op1;
609 uint32_t o2 = op2;
610 char line[18] = "XXXXXXXX XXXXXXXX";
611 snprintf(line, sizeof(line), "%08X %08X", op1, op2);
612 _registerLine(set, line);
613
614 switch (set->gsaVersion) {
615 case 0:
616 _setGameSharkVersion(set, 1);
617 // Fall through
618 case 1:
619 _decryptGameShark(&o1, &o2, set->gsaSeeds);
620 return _addGSA1(set, o1, o2);
621 }
622 return false;
623}
624
625bool GBACheatAddGameSharkLine(struct GBACheatSet* cheats, const char* line) {
626 uint32_t op1;
627 uint32_t op2;
628 line = _hex32(line, &op1);
629 if (!line) {
630 return false;
631 }
632 while (*line == ' ') {
633 ++line;
634 }
635 line = _hex32(line, &op2);
636 if (!line) {
637 return false;
638 }
639 return GBACheatAddGameShark(cheats, op1, op2);
640}
641
642bool GBACheatAddAutodetect(struct GBACheatSet* set, uint32_t op1, uint32_t op2) {
643 uint32_t o1 = op1;
644 uint32_t o2 = op2;
645 char line[18] = "XXXXXXXX XXXXXXXX";
646 snprintf(line, sizeof(line), "%08X %08X", op1, op2);
647 _registerLine(set, line);
648
649 switch (set->gsaVersion) {
650 case 0:
651 // Try to detect GameShark version
652 _decryptGameShark(&o1, &o2, _gsa1S);
653 if ((o1 & 0xF0000000) == 0xF0000000 && !(o2 & 0xFFFFFCFE)) {
654 _setGameSharkVersion(set, 1);
655 return _addGSA1(set, o1, o2);
656 }
657 o1 = op1;
658 o2 = op2;
659 _decryptGameShark(&o1, &o2, _par3S);
660 if ((o1 & 0xFE000000) == 0xC4000000 && !(o2 & 0xFFFF0000)) {
661 _setGameSharkVersion(set, 3);
662 return _addGSA3(set, o1, o2);
663 }
664 break;
665 case 1:
666 _decryptGameShark(&o1, &o2, set->gsaSeeds);
667 return _addGSA1(set, o1, o2);
668 case 3:
669 _decryptGameShark(&o1, &o2, set->gsaSeeds);
670 return _addGSA3(set, o1, o2);
671 }
672 return false;
673}
674
675bool GBACheatAutodetectLine(struct GBACheatSet* cheats, const char* line) {
676 uint32_t op1;
677 uint32_t op2;
678 line = _hex32(line, &op1);
679 if (!line) {
680 return false;
681 }
682 while (*line == ' ') {
683 ++line;
684 }
685 line = _hex32(line, &op2);
686 if (!line) {
687 return false;
688 }
689 return GBACheatAddAutodetect(cheats, op1, op2);
690}
691
692bool GBACheatParseFile(struct GBACheatDevice* device, struct VFile* vf) {
693 char cheat[MAX_LINE_LENGTH];
694 struct GBACheatSet* set = 0;
695 struct GBACheatSet* newSet;
696 int gsaVersion = 0;
697 bool nextDisabled = false;
698 while (true) {
699 size_t i = 0;
700 ssize_t bytesRead = vf->readline(vf, cheat, sizeof(cheat));
701 if (bytesRead == 0) {
702 break;
703 }
704 if (bytesRead < 0) {
705 return false;
706 }
707 while (isspace(cheat[i])) {
708 ++i;
709 }
710 switch (cheat[i]) {
711 case '#':
712 do {
713 ++i;
714 } while (isspace(cheat[i]));
715 newSet = malloc(sizeof(*set));
716 GBACheatSetInit(newSet, &cheat[i]);
717 newSet->enabled = !nextDisabled;
718 nextDisabled = false;
719 if (set) {
720 GBACheatAddSet(device, set);
721 newSet->gsaVersion = set->gsaVersion;
722 memcpy(newSet->gsaSeeds, set->gsaSeeds, sizeof(newSet->gsaSeeds));
723 if (set->hook) {
724 newSet->hook = set->hook;
725 ++newSet->hook->refs;
726 }
727 } else {
728 _setGameSharkVersion(newSet, gsaVersion);
729 }
730 set = newSet;
731 break;
732 case '!':
733 do {
734 ++i;
735 } while (isspace(cheat[i]));
736 if (strncasecmp(&cheat[i], "GSAv", 4) == 0 || strncasecmp(&cheat[i], "PARv", 4) == 0) {
737 i += 4;
738 gsaVersion = atoi(&cheat[i]);
739 break;
740 }
741 if (strcasecmp(&cheat[i], "disabled") == 0) {
742 nextDisabled = true;
743 break;
744 }
745 break;
746 default:
747 if (!set) {
748 set = malloc(sizeof(*set));
749 GBACheatSetInit(set, 0);
750 set->enabled = !nextDisabled;
751 nextDisabled = false;
752 _setGameSharkVersion(set, gsaVersion);
753 }
754 GBACheatAddLine(set, cheat);
755 break;
756 }
757 }
758 if (set) {
759 GBACheatAddSet(device, set);
760 }
761 return true;
762}
763
764bool GBACheatAddLine(struct GBACheatSet* cheats, const char* line) {
765 uint32_t op1;
766 uint16_t op2;
767 uint16_t op3;
768 line = _hex32(line, &op1);
769 if (!line) {
770 return false;
771 }
772 while (isspace(line[0])) {
773 ++line;
774 }
775 line = _hex16(line, &op2);
776 if (!line) {
777 return false;
778 }
779 if (!line[0] || isspace(line[0])) {
780 return GBACheatAddCodeBreaker(cheats, op1, op2);
781 }
782 line = _hex16(line, &op3);
783 if (!line) {
784 return false;
785 }
786 uint32_t realOp2 = op2;
787 realOp2 <<= 16;
788 realOp2 |= op3;
789 return GBACheatAddAutodetect(cheats, op1, realOp2);
790}
791
792void GBACheatRefresh(struct GBACheatDevice* device, struct GBACheatSet* cheats) {
793 if (!cheats->enabled) {
794 return;
795 }
796 bool condition = true;
797 int conditionRemaining = 0;
798 _patchROM(device, cheats);
799
800 size_t nCodes = GBACheatListSize(&cheats->list);
801 size_t i;
802 for (i = 0; i < nCodes; ++i) {
803 if (conditionRemaining > 0) {
804 --conditionRemaining;
805 if (!condition) {
806 continue;
807 }
808 } else {
809 condition = true;
810 }
811 struct GBACheat* cheat = GBACheatListGetPointer(&cheats->list, i);
812 int32_t value = 0;
813 int32_t operand = cheat->operand;
814 uint32_t operationsRemaining = cheat->repeat;
815 uint32_t address = cheat->address;
816 bool performAssignment = false;
817 for (; operationsRemaining; --operationsRemaining) {
818 switch (cheat->type) {
819 case CHEAT_ASSIGN:
820 value = operand;
821 performAssignment = true;
822 break;
823 case CHEAT_AND:
824 value = _readMem(device->p->cpu, address, cheat->width) & operand;
825 performAssignment = true;
826 break;
827 case CHEAT_ADD:
828 value = _readMem(device->p->cpu, address, cheat->width) + operand;
829 performAssignment = true;
830 break;
831 case CHEAT_OR:
832 value = _readMem(device->p->cpu, address, cheat->width) | operand;
833 performAssignment = true;
834 break;
835 case CHEAT_IF_EQ:
836 condition = _readMem(device->p->cpu, address, cheat->width) == operand;
837 conditionRemaining = cheat->repeat;
838 break;
839 case CHEAT_IF_NE:
840 condition = _readMem(device->p->cpu, address, cheat->width) != operand;
841 conditionRemaining = cheat->repeat;
842 break;
843 case CHEAT_IF_LT:
844 condition = _readMem(device->p->cpu, address, cheat->width) < operand;
845 conditionRemaining = cheat->repeat;
846 break;
847 case CHEAT_IF_GT:
848 condition = _readMem(device->p->cpu, address, cheat->width) > operand;
849 conditionRemaining = cheat->repeat;
850 break;
851 case CHEAT_IF_ULT:
852 condition = (uint32_t) _readMem(device->p->cpu, address, cheat->width) < (uint32_t) operand;
853 conditionRemaining = cheat->repeat;
854 break;
855 case CHEAT_IF_UGT:
856 condition = (uint32_t) _readMem(device->p->cpu, address, cheat->width) > (uint32_t) operand;
857 conditionRemaining = cheat->repeat;
858 break;
859 case CHEAT_IF_AND:
860 condition = _readMem(device->p->cpu, address, cheat->width) & operand;
861 conditionRemaining = cheat->repeat;
862 break;
863 case CHEAT_IF_LAND:
864 condition = _readMem(device->p->cpu, address, cheat->width) && operand;
865 conditionRemaining = cheat->repeat;
866 break;
867 }
868
869 if (performAssignment) {
870 _writeMem(device->p->cpu, address, cheat->width, value);
871 }
872
873 address += cheat->addressOffset;
874 operand += cheat->operandOffset;
875 }
876 }
877}
878
879void GBACheatDeviceInit(struct ARMCore* cpu, struct ARMComponent* component) {
880 struct GBACheatDevice* device = (struct GBACheatDevice*) component;
881 device->p = (struct GBA*) cpu->master;
882 size_t i;
883 for (i = 0; i < GBACheatSetsSize(&device->cheats); ++i) {
884 struct GBACheatSet* cheats = *GBACheatSetsGetPointer(&device->cheats, i);
885 _addBreakpoint(device, cheats);
886 _patchROM(device, cheats);
887 }
888}
889
890void GBACheatDeviceDeinit(struct ARMComponent* component) {
891 struct GBACheatDevice* device = (struct GBACheatDevice*) component;
892 size_t i;
893 for (i = GBACheatSetsSize(&device->cheats); i--;) {
894 struct GBACheatSet* cheats = *GBACheatSetsGetPointer(&device->cheats, i);
895 _unpatchROM(device, cheats);
896 _removeBreakpoint(device, cheats);
897 }
898}