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}