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 GBALog(0, GBA_LOG_STUB, "GameShark button unimplemented");
298 return false;
299 case GSA_IF_EQ:
300 if (op1 == 0xDEADFACE) {
301 _reseedGameShark(cheats->gsaSeeds, op2, _gsa1T1, _gsa1T2);
302 return true;
303 }
304 cheat = GBACheatListAppend(&cheats->list);
305 cheat->type = CHEAT_IF_EQ;
306 cheat->width = 2;
307 cheat->address = op1 & 0x0FFFFFFF;
308 break;
309 case GSA_IF_EQ_RANGE:
310 cheat = GBACheatListAppend(&cheats->list);
311 cheat->type = CHEAT_IF_EQ;
312 cheat->width = 2;
313 cheat->address = op2 & 0x0FFFFFFF;
314 cheat->operand = op1 & 0xFFFF;
315 cheat->repeat = (op1 >> 16) & 0xFF;
316 return true;
317 case GSA_HOOK:
318 if (cheats->hook) {
319 return false;
320 }
321 cheats->hook = malloc(sizeof(*cheats->hook));
322 cheats->hook->address = BASE_CART0 | (op1 & (SIZE_CART0 - 1));
323 cheats->hook->mode = MODE_THUMB;
324 cheats->hook->refs = 1;
325 cheats->hook->reentries = 0;
326 return true;
327 default:
328 return false;
329 }
330 cheat->operand = op2;
331 cheat->repeat = 1;
332 return true;
333}
334
335static uint32_t _parAddr(uint32_t x) {
336 return (x & 0xFFFFF) | ((x << 4) & 0x0F000000);
337}
338
339static void _parEndBlock(struct GBACheatSet* cheats) {
340 size_t size = GBACheatListSize(&cheats->list) - GBACheatListIndex(&cheats->list, cheats->currentBlock);
341 if (cheats->currentBlock->repeat) {
342 cheats->currentBlock->negativeRepeat = size - cheats->currentBlock->repeat;
343 } else {
344 cheats->currentBlock->repeat = size;
345 }
346 cheats->currentBlock = 0;
347}
348
349static void _parElseBlock(struct GBACheatSet* cheats) {
350 size_t size = GBACheatListSize(&cheats->list) - GBACheatListIndex(&cheats->list, cheats->currentBlock);
351 cheats->currentBlock->repeat = size;
352}
353
354static bool _addPAR3Cond(struct GBACheatSet* cheats, uint32_t op1, uint32_t op2) {
355 enum GBAActionReplay3Condition condition = op1 & PAR3_COND;
356 int width = 1 << ((op1 & PAR3_WIDTH) >> PAR3_WIDTH_BASE);
357 if (width > 4) {
358 // TODO: Always false conditions
359 return false;
360 }
361 if ((op1 & PAR3_ACTION) == PAR3_ACTION_DISABLE) {
362 // TODO: Codes that disable
363 return false;
364 }
365
366 struct GBACheat* cheat = GBACheatListAppend(&cheats->list);
367 cheat->address = _parAddr(op1);
368 cheat->width = width;
369 cheat->operand = op2 & (0xFFFFFFFFU >> ((4 - width) * 8));
370 cheat->addressOffset = 0;
371 cheat->operandOffset = 0;
372
373 switch (op1 & PAR3_ACTION) {
374 case PAR3_ACTION_NEXT:
375 cheat->repeat = 1;
376 cheat->negativeRepeat = 0;
377 break;
378 case PAR3_ACTION_NEXT_TWO:
379 cheat->repeat = 2;
380 cheat->negativeRepeat = 0;
381 break;
382 case PAR3_ACTION_BLOCK:
383 cheat->repeat = 0;
384 cheat->negativeRepeat = 0;
385 if (cheats->currentBlock) {
386 _parEndBlock(cheats);
387 }
388 cheats->currentBlock = cheat;
389 break;
390 }
391
392 switch (condition) {
393 case PAR3_COND_OTHER:
394 // We shouldn't be able to get here
395 GBALog(0, GBA_LOG_ERROR, "Unexpectedly created 'other' PARv3 code");
396 cheat->type = CHEAT_IF_LAND;
397 cheat->operand = 0;
398 break;
399 case PAR3_COND_EQ:
400 cheat->type = CHEAT_IF_EQ;
401 break;
402 case PAR3_COND_NE:
403 cheat->type = CHEAT_IF_NE;
404 break;
405 case PAR3_COND_LT:
406 cheat->type = CHEAT_IF_LT;
407 break;
408 case PAR3_COND_GT:
409 cheat->type = CHEAT_IF_GT;
410 break;
411 case PAR3_COND_ULT:
412 cheat->type = CHEAT_IF_ULT;
413 break;
414 case PAR3_COND_UGT:
415 cheat->type = CHEAT_IF_UGT;
416 break;
417 case PAR3_COND_LAND:
418 cheat->type = CHEAT_IF_LAND;
419 break;
420 }
421 return true;
422}
423
424static bool _addPAR3Special(struct GBACheatSet* cheats, uint32_t op2) {
425 struct GBACheat* cheat;
426 switch (op2 & 0xFF000000) {
427 case PAR3_OTHER_SLOWDOWN:
428 // TODO: Slowdown
429 return false;
430 case PAR3_OTHER_BUTTON_1:
431 case PAR3_OTHER_BUTTON_2:
432 case PAR3_OTHER_BUTTON_4:
433 // TODO: Button
434 GBALog(0, GBA_LOG_STUB, "GameShark button unimplemented");
435 return false;
436 // TODO: Fix overriding existing patches
437 case PAR3_OTHER_PATCH_1:
438 cheats->romPatches[0].address = (op2 & 0xFFFFFF) << 1;
439 cheats->romPatches[0].applied = false;
440 cheats->romPatches[0].exists = true;
441 cheats->incompletePatch = &cheats->romPatches[0];
442 break;
443 case PAR3_OTHER_PATCH_2:
444 cheats->romPatches[1].address = (op2 & 0xFFFFFF) << 1;
445 cheats->romPatches[1].applied = false;
446 cheats->romPatches[1].exists = true;
447 cheats->incompletePatch = &cheats->romPatches[1];
448 break;
449 case PAR3_OTHER_PATCH_3:
450 cheats->romPatches[2].address = (op2 & 0xFFFFFF) << 1;
451 cheats->romPatches[2].applied = false;
452 cheats->romPatches[2].exists = true;
453 cheats->incompletePatch = &cheats->romPatches[2];
454 break;
455 case PAR3_OTHER_PATCH_4:
456 cheats->romPatches[3].address = (op2 & 0xFFFFFF) << 1;
457 cheats->romPatches[3].applied = false;
458 cheats->romPatches[3].exists = true;
459 cheats->incompletePatch = &cheats->romPatches[3];
460 break;
461 case PAR3_OTHER_ENDIF:
462 if (cheats->currentBlock) {
463 _parEndBlock(cheats);
464 return true;
465 }
466 return false;
467 case PAR3_OTHER_ELSE:
468 if (cheats->currentBlock) {
469 _parElseBlock(cheats);
470 return true;
471 }
472 return false;
473 case PAR3_OTHER_FILL_1:
474 cheat = GBACheatListAppend(&cheats->list);
475 cheat->address = _parAddr(op2);
476 cheat->width = 1;
477 cheats->incompleteCheat = cheat;
478 break;
479 case PAR3_OTHER_FILL_2:
480 cheat = GBACheatListAppend(&cheats->list);
481 cheat->address = _parAddr(op2);
482 cheat->width = 2;
483 cheats->incompleteCheat = cheat;
484 break;
485 case PAR3_OTHER_FILL_4:
486 cheat = GBACheatListAppend(&cheats->list);
487 cheat->address = _parAddr(op2);
488 cheat->width = 3;
489 cheats->incompleteCheat = cheat;
490 break;
491 }
492 return true;
493}
494
495static bool _addPAR3(struct GBACheatSet* cheats, uint32_t op1, uint32_t op2) {
496 if (cheats->incompletePatch) {
497 cheats->incompletePatch->newValue = op1;
498 cheats->incompletePatch = 0;
499 return true;
500 }
501 if (cheats->incompleteCheat) {
502 cheats->incompleteCheat->operand = op1 & (0xFFFFFFFFU >> ((4 - cheats->incompleteCheat->width) * 8));
503 cheats->incompleteCheat->addressOffset = op2 >> 24;
504 cheats->incompleteCheat->repeat = (op2 >> 16) & 0xFF;
505 cheats->incompleteCheat->addressOffset = (op2 & 0xFFFF) * cheats->incompleteCheat->width;
506 cheats->incompleteCheat = 0;
507 return true;
508 }
509
510 if (op2 == 0x001DC0DE) {
511 return true;
512 }
513
514 switch (op1) {
515 case 0x00000000:
516 return _addPAR3Special(cheats, op2);
517 case 0xDEADFACE:
518 _reseedGameShark(cheats->gsaSeeds, op2, _par3T1, _par3T2);
519 return true;
520 }
521
522 if (op1 >> 24 == 0xC4) {
523 if (cheats->hook) {
524 return false;
525 }
526 cheats->hook = malloc(sizeof(*cheats->hook));
527 cheats->hook->address = BASE_CART0 | (op1 & (SIZE_CART0 - 1));
528 cheats->hook->mode = MODE_THUMB;
529 cheats->hook->refs = 1;
530 cheats->hook->reentries = 0;
531 return true;
532 }
533
534 if (op1 & PAR3_COND) {
535 return _addPAR3Cond(cheats, op1, op2);
536 }
537
538 int width = 1 << ((op1 & PAR3_WIDTH) >> PAR3_WIDTH_BASE);
539 struct GBACheat* cheat = GBACheatListAppend(&cheats->list);
540 cheat->address = _parAddr(op1);
541 cheat->operandOffset = 0;
542 cheat->addressOffset = 0;
543 cheat->repeat = 1;
544
545 switch (op1 & PAR3_BASE) {
546 case PAR3_BASE_ASSIGN:
547 cheat->type = CHEAT_ASSIGN;
548 cheat->addressOffset = width;
549 if (width < 4) {
550 cheat->repeat = (op2 >> (width * 8)) + 1;
551 }
552 break;
553 case PAR3_BASE_INDIRECT:
554 cheat->type = CHEAT_ASSIGN_INDIRECT;
555 if (width < 4) {
556 cheat->addressOffset = (op2 >> (width * 8)) * width;
557 }
558 break;
559 case PAR3_BASE_ADD:
560 cheat->type = CHEAT_ADD;
561 break;
562 case PAR3_BASE_OTHER:
563 width = ((op1 >> 24) & 1) + 1;
564 cheat->type = CHEAT_ASSIGN;
565 cheat->address = BASE_IO | (op1 & OFFSET_MASK);
566 break;
567 }
568
569 cheat->width = width;
570 cheat->operand = op2 & (0xFFFFFFFFU >> ((4 - width) * 8));
571 return true;
572}
573
574static void _addBreakpoint(struct GBACheatDevice* device, struct GBACheatSet* cheats) {
575 if (!device->p || !cheats->hook) {
576 return;
577 }
578 ++cheats->hook->reentries;
579 if (cheats->hook->reentries > 1) {
580 return;
581 }
582 GBASetBreakpoint(device->p, &device->d, cheats->hook->address, cheats->hook->mode, &cheats->hook->patchedOpcode);
583}
584
585static void _removeBreakpoint(struct GBACheatDevice* device, struct GBACheatSet* cheats) {
586 if (!device->p || !cheats->hook) {
587 return;
588 }
589 --cheats->hook->reentries;
590 if (cheats->hook->reentries > 0) {
591 return;
592 }
593 GBAClearBreakpoint(device->p, cheats->hook->address, cheats->hook->mode, cheats->hook->patchedOpcode);
594}
595
596static void _patchROM(struct GBACheatDevice* device, struct GBACheatSet* cheats) {
597 if (!device->p) {
598 return;
599 }
600 int i;
601 for (i = 0; i < MAX_ROM_PATCHES; ++i) {
602 if (!cheats->romPatches[i].exists || cheats->romPatches[i].applied) {
603 continue;
604 }
605 GBAPatch16(device->p->cpu, cheats->romPatches[i].address, cheats->romPatches[i].newValue, &cheats->romPatches[i].oldValue);
606 cheats->romPatches[i].applied = true;
607 }
608}
609
610static void _unpatchROM(struct GBACheatDevice* device, struct GBACheatSet* cheats) {
611 if (!device->p) {
612 return;
613 }
614 int i;
615 for (i = 0; i < MAX_ROM_PATCHES; ++i) {
616 if (!cheats->romPatches[i].exists || !cheats->romPatches[i].applied) {
617 continue;
618 }
619 GBAPatch16(device->p->cpu, cheats->romPatches[i].address, cheats->romPatches[i].oldValue, 0);
620 cheats->romPatches[i].applied = false;
621 }
622}
623
624static void GBACheatDeviceInit(struct ARMCore*, struct ARMComponent*);
625static void GBACheatDeviceDeinit(struct ARMComponent*);
626
627void GBACheatDeviceCreate(struct GBACheatDevice* device) {
628 device->d.id = GBA_CHEAT_DEVICE_ID;
629 device->d.init = GBACheatDeviceInit;
630 device->d.deinit = GBACheatDeviceDeinit;
631 GBACheatSetsInit(&device->cheats, 4);
632}
633
634void GBACheatDeviceDestroy(struct GBACheatDevice* device) {
635 size_t i;
636 for (i = 0; i < GBACheatSetsSize(&device->cheats); ++i) {
637 struct GBACheatSet* set = *GBACheatSetsGetPointer(&device->cheats, i);
638 GBACheatSetDeinit(set);
639 free(set);
640 }
641 GBACheatSetsDeinit(&device->cheats);
642}
643
644void GBACheatSetInit(struct GBACheatSet* set, const char* name) {
645 GBACheatListInit(&set->list, 4);
646 StringListInit(&set->lines, 4);
647 set->incompleteCheat = 0;
648 set->incompletePatch = 0;
649 set->currentBlock = 0;
650 set->gsaVersion = 0;
651 set->remainingAddresses = 0;
652 set->hook = 0;
653 int i;
654 for (i = 0; i < MAX_ROM_PATCHES; ++i) {
655 set->romPatches[i].exists = false;
656 }
657 if (name) {
658 set->name = strdup(name);
659 } else {
660 set->name = 0;
661 }
662 set->enabled = true;
663}
664
665void GBACheatSetDeinit(struct GBACheatSet* set) {
666 GBACheatListDeinit(&set->list);
667 size_t i;
668 for (i = 0; i < StringListSize(&set->lines); ++i) {
669 free(*StringListGetPointer(&set->lines, i));
670 }
671 if (set->name) {
672 free(set->name);
673 }
674 if (set->hook) {
675 --set->hook->refs;
676 if (set->hook->refs == 0) {
677 free(set->hook);
678 }
679 }
680}
681
682void GBACheatAttachDevice(struct GBA* gba, struct GBACheatDevice* device) {
683 if (gba->cpu->components[GBA_COMPONENT_CHEAT_DEVICE]) {
684 ARMHotplugDetach(gba->cpu, GBA_COMPONENT_CHEAT_DEVICE);
685 }
686 gba->cpu->components[GBA_COMPONENT_CHEAT_DEVICE] = &device->d;
687 ARMHotplugAttach(gba->cpu, GBA_COMPONENT_CHEAT_DEVICE);
688}
689
690void GBACheatAddSet(struct GBACheatDevice* device, struct GBACheatSet* cheats) {
691 *GBACheatSetsAppend(&device->cheats) = cheats;
692 _addBreakpoint(device, cheats);
693 _patchROM(device, cheats);
694}
695
696void GBACheatRemoveSet(struct GBACheatDevice* device, struct GBACheatSet* cheats) {
697 size_t i;
698 for (i = 0; i < GBACheatSetsSize(&device->cheats); ++i) {
699 if (*GBACheatSetsGetPointer(&device->cheats, i) == cheats) {
700 break;
701 }
702 }
703 if (i == GBACheatSetsSize(&device->cheats)) {
704 return;
705 }
706 GBACheatSetsShift(&device->cheats, i, 1);
707 _unpatchROM(device, cheats);
708 _removeBreakpoint(device, cheats);
709}
710
711bool GBACheatAddCodeBreaker(struct GBACheatSet* cheats, uint32_t op1, uint16_t op2) {
712 char line[14] = "XXXXXXXX XXXX";
713 snprintf(line, sizeof(line), "%08X %04X", op1, op2);
714 _registerLine(cheats, line);
715
716 enum GBACodeBreakerType type = op1 >> 28;
717 struct GBACheat* cheat = 0;
718
719 if (cheats->incompleteCheat) {
720 cheats->incompleteCheat->repeat = op1 & 0xFFFF;
721 cheats->incompleteCheat->addressOffset = op2;
722 cheats->incompleteCheat->operandOffset = 0;
723 cheats->incompleteCheat = 0;
724 return true;
725 }
726
727 switch (type) {
728 case CB_GAME_ID:
729 // TODO: Run checksum
730 return true;
731 case CB_HOOK:
732 if (cheats->hook) {
733 return false;
734 }
735 cheats->hook = malloc(sizeof(*cheats->hook));
736 cheats->hook->address = BASE_CART0 | (op1 & (SIZE_CART0 - 1));
737 cheats->hook->mode = MODE_THUMB;
738 cheats->hook->refs = 1;
739 cheats->hook->reentries = 0;
740 return true;
741 case CB_OR_2:
742 cheat = GBACheatListAppend(&cheats->list);
743 cheat->type = CHEAT_OR;
744 cheat->width = 2;
745 break;
746 case CB_ASSIGN_1:
747 cheat = GBACheatListAppend(&cheats->list);
748 cheat->type = CHEAT_ASSIGN;
749 cheat->width = 1;
750 break;
751 case CB_FILL:
752 cheat = GBACheatListAppend(&cheats->list);
753 cheat->type = CHEAT_ASSIGN;
754 cheat->width = 2;
755 cheats->incompleteCheat = cheat;
756 break;
757 case CB_FILL_8:
758 GBALog(0, GBA_LOG_STUB, "[Cheat] CodeBreaker code %08X %04X not supported", op1, op2);
759 return false;
760 case CB_AND_2:
761 cheat = GBACheatListAppend(&cheats->list);
762 cheat->type = CHEAT_AND;
763 cheat->width = 2;
764 break;
765 case CB_IF_EQ:
766 cheat = GBACheatListAppend(&cheats->list);
767 cheat->type = CHEAT_IF_EQ;
768 cheat->width = 2;
769 break;
770 case CB_ASSIGN_2:
771 cheat = GBACheatListAppend(&cheats->list);
772 cheat->type = CHEAT_ASSIGN;
773 cheat->width = 2;
774 break;
775 case CB_ENCRYPT:
776 GBALog(0, GBA_LOG_STUB, "[Cheat] CodeBreaker encryption not supported");
777 return false;
778 case CB_IF_NE:
779 cheat = GBACheatListAppend(&cheats->list);
780 cheat->type = CHEAT_IF_NE;
781 cheat->width = 2;
782 break;
783 case CB_IF_GT:
784 cheat = GBACheatListAppend(&cheats->list);
785 cheat->type = CHEAT_IF_GT;
786 cheat->width = 2;
787 break;
788 case CB_IF_LT:
789 cheat = GBACheatListAppend(&cheats->list);
790 cheat->type = CHEAT_IF_LT;
791 cheat->width = 2;
792 break;
793 case CB_IF_SPECIAL:
794 switch (op1 & 0x0FFFFFFF) {
795 case 0x20:
796 cheat = GBACheatListAppend(&cheats->list);
797 cheat->type = CHEAT_IF_AND;
798 cheat->width = 2;
799 cheat->address = BASE_IO | REG_JOYSTAT;
800 cheat->operand = op2;
801 cheat->repeat = 1;
802 return true;
803 default:
804 GBALog(0, GBA_LOG_STUB, "[Cheat] CodeBreaker code %08X %04X not supported", op1, op2);
805 return false;
806 }
807 case CB_ADD_2:
808 cheat = GBACheatListAppend(&cheats->list);
809 cheat->type = CHEAT_ADD;
810 cheat->width = 2;
811 break;
812 case CB_IF_AND:
813 cheat = GBACheatListAppend(&cheats->list);
814 cheat->type = CHEAT_IF_AND;
815 cheat->width = 2;
816 break;
817 }
818
819 cheat->address = op1 & 0x0FFFFFFF;
820 cheat->operand = op2;
821 cheat->repeat = 1;
822 cheat->negativeRepeat = 0;
823 return true;
824}
825
826bool GBACheatAddCodeBreakerLine(struct GBACheatSet* cheats, const char* line) {
827 uint32_t op1;
828 uint16_t op2;
829 line = _hex32(line, &op1);
830 if (!line) {
831 return false;
832 }
833 while (*line == ' ') {
834 ++line;
835 }
836 line = _hex16(line, &op2);
837 if (!line) {
838 return false;
839 }
840 return GBACheatAddCodeBreaker(cheats, op1, op2);
841}
842
843bool GBACheatAddGameShark(struct GBACheatSet* set, uint32_t op1, uint32_t op2) {
844 uint32_t o1 = op1;
845 uint32_t o2 = op2;
846 char line[18] = "XXXXXXXX XXXXXXXX";
847 snprintf(line, sizeof(line), "%08X %08X", op1, op2);
848 _registerLine(set, line);
849
850 switch (set->gsaVersion) {
851 case 0:
852 _setGameSharkVersion(set, 1);
853 // Fall through
854 case 1:
855 _decryptGameShark(&o1, &o2, set->gsaSeeds);
856 return _addGSA1(set, o1, o2);
857 }
858 return false;
859}
860
861bool GBACheatAddGameSharkLine(struct GBACheatSet* cheats, const char* line) {
862 uint32_t op1;
863 uint32_t op2;
864 line = _hex32(line, &op1);
865 if (!line) {
866 return false;
867 }
868 while (*line == ' ') {
869 ++line;
870 }
871 line = _hex32(line, &op2);
872 if (!line) {
873 return false;
874 }
875 return GBACheatAddGameShark(cheats, op1, op2);
876}
877
878bool GBACheatAddProActionReplay(struct GBACheatSet* set, uint32_t op1, uint32_t op2) {
879 uint32_t o1 = op1;
880 uint32_t o2 = op2;
881 char line[18] = "XXXXXXXX XXXXXXXX";
882 snprintf(line, sizeof(line), "%08X %08X", op1, op2);
883 _registerLine(set, line);
884
885 switch (set->gsaVersion) {
886 case 0:
887 _setGameSharkVersion(set, 3);
888 // Fall through
889 case 1:
890 _decryptGameShark(&o1, &o2, set->gsaSeeds);
891 return _addPAR3(set, o1, o2);
892 }
893 return false;
894}
895
896bool GBACheatAddProActionReplayLine(struct GBACheatSet* cheats, const char* line) {
897 uint32_t op1;
898 uint32_t op2;
899 line = _hex32(line, &op1);
900 if (!line) {
901 return false;
902 }
903 while (*line == ' ') {
904 ++line;
905 }
906 line = _hex32(line, &op2);
907 if (!line) {
908 return false;
909 }
910 return GBACheatAddProActionReplay(cheats, op1, op2);
911}
912
913bool GBACheatAddAutodetect(struct GBACheatSet* set, uint32_t op1, uint32_t op2) {
914 uint32_t o1 = op1;
915 uint32_t o2 = op2;
916 char line[18] = "XXXXXXXX XXXXXXXX";
917 snprintf(line, sizeof(line), "%08X %08X", op1, op2);
918 _registerLine(set, line);
919
920 switch (set->gsaVersion) {
921 case 0:
922 // Try to detect GameShark version
923 _decryptGameShark(&o1, &o2, _gsa1S);
924 if ((o1 & 0xF0000000) == 0xF0000000 && !(o2 & 0xFFFFFCFE)) {
925 _setGameSharkVersion(set, 1);
926 return _addGSA1(set, o1, o2);
927 }
928 o1 = op1;
929 o2 = op2;
930 _decryptGameShark(&o1, &o2, _par3S);
931 if ((o1 & 0xFE000000) == 0xC4000000 && !(o2 & 0xFFFF0000)) {
932 _setGameSharkVersion(set, 3);
933 return _addPAR3(set, o1, o2);
934 }
935 break;
936 case 1:
937 _decryptGameShark(&o1, &o2, set->gsaSeeds);
938 return _addGSA1(set, o1, o2);
939 case 3:
940 _decryptGameShark(&o1, &o2, set->gsaSeeds);
941 return _addPAR3(set, o1, o2);
942 }
943 return false;
944}
945
946bool GBACheatAutodetectLine(struct GBACheatSet* cheats, const char* line) {
947 uint32_t op1;
948 uint32_t op2;
949 line = _hex32(line, &op1);
950 if (!line) {
951 return false;
952 }
953 while (*line == ' ') {
954 ++line;
955 }
956 line = _hex32(line, &op2);
957 if (!line) {
958 return false;
959 }
960 return GBACheatAddAutodetect(cheats, op1, op2);
961}
962
963bool GBACheatParseFile(struct GBACheatDevice* device, struct VFile* vf) {
964 char cheat[MAX_LINE_LENGTH];
965 struct GBACheatSet* set = 0;
966 struct GBACheatSet* newSet;
967 int gsaVersion = 0;
968 bool nextDisabled = false;
969 bool reset = false;
970 while (true) {
971 size_t i = 0;
972 ssize_t bytesRead = vf->readline(vf, cheat, sizeof(cheat));
973 if (bytesRead == 0) {
974 break;
975 }
976 if (bytesRead < 0) {
977 return false;
978 }
979 while (isspace(cheat[i])) {
980 ++i;
981 }
982 switch (cheat[i]) {
983 case '#':
984 do {
985 ++i;
986 } while (isspace(cheat[i]));
987 newSet = malloc(sizeof(*set));
988 GBACheatSetInit(newSet, &cheat[i]);
989 newSet->enabled = !nextDisabled;
990 nextDisabled = false;
991 if (set) {
992 GBACheatAddSet(device, set);
993 }
994 if (set && !reset) {
995 GBACheatSetCopyProperties(newSet, set);
996 } else {
997 _setGameSharkVersion(newSet, gsaVersion);
998 }
999 reset = false;
1000 set = newSet;
1001 break;
1002 case '!':
1003 do {
1004 ++i;
1005 } while (isspace(cheat[i]));
1006 if (strncasecmp(&cheat[i], "GSAv", 4) == 0 || strncasecmp(&cheat[i], "PARv", 4) == 0) {
1007 i += 4;
1008 gsaVersion = atoi(&cheat[i]);
1009 break;
1010 }
1011 if (strcasecmp(&cheat[i], "disabled") == 0) {
1012 nextDisabled = true;
1013 break;
1014 }
1015 if (strcasecmp(&cheat[i], "reset") == 0) {
1016 reset = true;
1017 break;
1018 }
1019 break;
1020 default:
1021 if (!set) {
1022 set = malloc(sizeof(*set));
1023 GBACheatSetInit(set, 0);
1024 set->enabled = !nextDisabled;
1025 nextDisabled = false;
1026 _setGameSharkVersion(set, gsaVersion);
1027 }
1028 GBACheatAddLine(set, cheat);
1029 break;
1030 }
1031 }
1032 if (set) {
1033 GBACheatAddSet(device, set);
1034 }
1035 return true;
1036}
1037
1038bool GBACheatSaveFile(struct GBACheatDevice* device, struct VFile* vf) {
1039 static const char lineStart[3] = "# ";
1040 static const char lineEnd = '\n';
1041
1042 struct GBACheatHook* lastHook = 0;
1043
1044 size_t i;
1045 for (i = 0; i < GBACheatSetsSize(&device->cheats); ++i) {
1046 struct GBACheatSet* set = *GBACheatSetsGetPointer(&device->cheats, i);
1047 if (lastHook && set->hook != lastHook) {
1048 static const char* resetDirective = "!reset\n";
1049 vf->write(vf, resetDirective, strlen(resetDirective));
1050 }
1051 switch (set->gsaVersion) {
1052 case 1: {
1053 static const char* versionDirective = "!GSAv1\n";
1054 vf->write(vf, versionDirective, strlen(versionDirective));
1055 break;
1056 }
1057 case 3: {
1058 static const char* versionDirective = "!PARv3\n";
1059 vf->write(vf, versionDirective, strlen(versionDirective));
1060 break;
1061 }
1062 default:
1063 break;
1064 }
1065 lastHook = set->hook;
1066 if (!set->enabled) {
1067 static const char* disabledDirective = "!disabled\n";
1068 vf->write(vf, disabledDirective, strlen(disabledDirective));
1069 }
1070
1071 vf->write(vf, lineStart, 2);
1072 if (set->name) {
1073 vf->write(vf, set->name, strlen(set->name));
1074 }
1075 vf->write(vf, &lineEnd, 1);
1076 size_t c;
1077 for (c = 0; c < StringListSize(&set->lines); ++c) {
1078 const char* line = *StringListGetPointer(&set->lines, c);
1079 vf->write(vf, line, strlen(line));
1080 vf->write(vf, &lineEnd, 1);
1081 }
1082 }
1083 return true;
1084}
1085
1086bool GBACheatAddLine(struct GBACheatSet* cheats, const char* line) {
1087 uint32_t op1;
1088 uint16_t op2;
1089 uint16_t op3;
1090 line = _hex32(line, &op1);
1091 if (!line) {
1092 return false;
1093 }
1094 while (isspace(line[0])) {
1095 ++line;
1096 }
1097 line = _hex16(line, &op2);
1098 if (!line) {
1099 return false;
1100 }
1101 if (!line[0] || isspace(line[0])) {
1102 return GBACheatAddCodeBreaker(cheats, op1, op2);
1103 }
1104 line = _hex16(line, &op3);
1105 if (!line) {
1106 return false;
1107 }
1108 uint32_t realOp2 = op2;
1109 realOp2 <<= 16;
1110 realOp2 |= op3;
1111 return GBACheatAddAutodetect(cheats, op1, realOp2);
1112}
1113
1114void GBACheatRefresh(struct GBACheatDevice* device, struct GBACheatSet* cheats) {
1115 if (!cheats->enabled) {
1116 return;
1117 }
1118 bool condition = true;
1119 int conditionRemaining = 0;
1120 int negativeConditionRemaining = 0;
1121 _patchROM(device, cheats);
1122
1123 size_t nCodes = GBACheatListSize(&cheats->list);
1124 size_t i;
1125 for (i = 0; i < nCodes; ++i) {
1126 if (conditionRemaining > 0) {
1127 --conditionRemaining;
1128 if (!condition) {
1129 continue;
1130 }
1131 } else if (negativeConditionRemaining > 0) {
1132 conditionRemaining = negativeConditionRemaining - 1;
1133 negativeConditionRemaining = 0;
1134 condition = !condition;
1135 if (!condition) {
1136 continue;
1137 }
1138 } else {
1139 condition = true;
1140 }
1141 struct GBACheat* cheat = GBACheatListGetPointer(&cheats->list, i);
1142 int32_t value = 0;
1143 int32_t operand = cheat->operand;
1144 uint32_t operationsRemaining = cheat->repeat;
1145 uint32_t address = cheat->address;
1146 bool performAssignment = false;
1147 for (; operationsRemaining; --operationsRemaining) {
1148 switch (cheat->type) {
1149 case CHEAT_ASSIGN:
1150 value = operand;
1151 performAssignment = true;
1152 break;
1153 case CHEAT_ASSIGN_INDIRECT:
1154 value = operand;
1155 address = _readMem(device->p->cpu, address + cheat->addressOffset, 4);
1156 performAssignment = true;
1157 break;
1158 case CHEAT_AND:
1159 value = _readMem(device->p->cpu, address, cheat->width) & operand;
1160 performAssignment = true;
1161 break;
1162 case CHEAT_ADD:
1163 value = _readMem(device->p->cpu, address, cheat->width) + operand;
1164 performAssignment = true;
1165 break;
1166 case CHEAT_OR:
1167 value = _readMem(device->p->cpu, address, cheat->width) | operand;
1168 performAssignment = true;
1169 break;
1170 case CHEAT_IF_EQ:
1171 condition = _readMem(device->p->cpu, address, cheat->width) == operand;
1172 conditionRemaining = cheat->repeat;
1173 negativeConditionRemaining = cheat->negativeRepeat;
1174 break;
1175 case CHEAT_IF_NE:
1176 condition = _readMem(device->p->cpu, address, cheat->width) != operand;
1177 conditionRemaining = cheat->repeat;
1178 negativeConditionRemaining = cheat->negativeRepeat;
1179 break;
1180 case CHEAT_IF_LT:
1181 condition = _readMem(device->p->cpu, address, cheat->width) < operand;
1182 conditionRemaining = cheat->repeat;
1183 negativeConditionRemaining = cheat->negativeRepeat;
1184 break;
1185 case CHEAT_IF_GT:
1186 condition = _readMem(device->p->cpu, address, cheat->width) > operand;
1187 conditionRemaining = cheat->repeat;
1188 negativeConditionRemaining = cheat->negativeRepeat;
1189 break;
1190 case CHEAT_IF_ULT:
1191 condition = (uint32_t) _readMem(device->p->cpu, address, cheat->width) < (uint32_t) operand;
1192 conditionRemaining = cheat->repeat;
1193 negativeConditionRemaining = cheat->negativeRepeat;
1194 break;
1195 case CHEAT_IF_UGT:
1196 condition = (uint32_t) _readMem(device->p->cpu, address, cheat->width) > (uint32_t) operand;
1197 conditionRemaining = cheat->repeat;
1198 negativeConditionRemaining = cheat->negativeRepeat;
1199 break;
1200 case CHEAT_IF_AND:
1201 condition = _readMem(device->p->cpu, address, cheat->width) & operand;
1202 conditionRemaining = cheat->repeat;
1203 negativeConditionRemaining = cheat->negativeRepeat;
1204 break;
1205 case CHEAT_IF_LAND:
1206 condition = _readMem(device->p->cpu, address, cheat->width) && operand;
1207 conditionRemaining = cheat->repeat;
1208 negativeConditionRemaining = cheat->negativeRepeat;
1209 break;
1210 }
1211
1212 if (performAssignment) {
1213 _writeMem(device->p->cpu, address, cheat->width, value);
1214 }
1215
1216 address += cheat->addressOffset;
1217 operand += cheat->operandOffset;
1218 }
1219 }
1220}
1221
1222void GBACheatSetCopyProperties(struct GBACheatSet* newSet, struct GBACheatSet* set) {
1223 newSet->gsaVersion = set->gsaVersion;
1224 memcpy(newSet->gsaSeeds, set->gsaSeeds, sizeof(newSet->gsaSeeds));
1225 if (set->hook) {
1226 if (newSet->hook) {
1227 --newSet->hook->refs;
1228 if (newSet->hook->refs == 0) {
1229 free(newSet->hook);
1230 }
1231 }
1232 newSet->hook = set->hook;
1233 ++newSet->hook->refs;
1234 }
1235}
1236
1237void GBACheatDeviceInit(struct ARMCore* cpu, struct ARMComponent* component) {
1238 struct GBACheatDevice* device = (struct GBACheatDevice*) component;
1239 device->p = (struct GBA*) cpu->master;
1240 size_t i;
1241 for (i = 0; i < GBACheatSetsSize(&device->cheats); ++i) {
1242 struct GBACheatSet* cheats = *GBACheatSetsGetPointer(&device->cheats, i);
1243 _addBreakpoint(device, cheats);
1244 _patchROM(device, cheats);
1245 }
1246}
1247
1248void GBACheatDeviceDeinit(struct ARMComponent* component) {
1249 struct GBACheatDevice* device = (struct GBACheatDevice*) component;
1250 size_t i;
1251 for (i = GBACheatSetsSize(&device->cheats); i--;) {
1252 struct GBACheatSet* cheats = *GBACheatSetsGetPointer(&device->cheats, i);
1253 _unpatchROM(device, cheats);
1254 _removeBreakpoint(device, cheats);
1255 }
1256}