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 <mgba/internal/gba/overrides.h>
7
8 #include <mgba/internal/gba/gba.h>
9 #include <mgba/internal/gba/hardware.h>
10
11 #include <mgba-util/configuration.h>
12
13 static const struct GBACartridgeOverride _overrides[] = {
14 // Advance Wars
15 { "AWRE", SAVEDATA_FLASH512, HW_NONE, 0x8038810, false },
16 { "AWRP", SAVEDATA_FLASH512, HW_NONE, 0x8038810, false },
17
18 // Advance Wars 2: Black Hole Rising
19 { "AW2E", SAVEDATA_FLASH512, HW_NONE, 0x8036E08, false },
20 { "AW2P", SAVEDATA_FLASH512, HW_NONE, 0x803719C, false },
21
22 // Boktai: The Sun is in Your Hand
23 { "U3IJ", SAVEDATA_EEPROM, HW_RTC | HW_LIGHT_SENSOR, IDLE_LOOP_NONE, false },
24 { "U3IE", SAVEDATA_EEPROM, HW_RTC | HW_LIGHT_SENSOR, IDLE_LOOP_NONE, false },
25 { "U3IP", SAVEDATA_EEPROM, HW_RTC | HW_LIGHT_SENSOR, IDLE_LOOP_NONE, false },
26
27 // Boktai 2: Solar Boy Django
28 { "U32J", SAVEDATA_EEPROM, HW_RTC | HW_LIGHT_SENSOR, IDLE_LOOP_NONE, false },
29 { "U32E", SAVEDATA_EEPROM, HW_RTC | HW_LIGHT_SENSOR, IDLE_LOOP_NONE, false },
30 { "U32P", SAVEDATA_EEPROM, HW_RTC | HW_LIGHT_SENSOR, IDLE_LOOP_NONE, false },
31
32 // Crash Bandicoot 2 - N-Tranced
33 { "AC8J", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false },
34 { "AC8E", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false },
35 { "AC8P", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false },
36
37 // DigiCommunication Nyo - Datou! Black Gemagema Dan
38 { "BDKJ", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false },
39
40 // Dragon Ball Z - The Legacy of Goku
41 { "ALGP", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false },
42
43 // Dragon Ball Z - The Legacy of Goku II
44 { "ALFJ", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false },
45 { "ALFE", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false },
46 { "ALFP", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false },
47
48 // Dragon Ball Z - Taiketsu
49 { "BDBE", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false },
50 { "BDBP", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false },
51
52 // Drill Dozer
53 { "V49J", SAVEDATA_SRAM, HW_RUMBLE, IDLE_LOOP_NONE, false },
54 { "V49E", SAVEDATA_SRAM, HW_RUMBLE, IDLE_LOOP_NONE, false },
55 { "V49P", SAVEDATA_SRAM, HW_RUMBLE, IDLE_LOOP_NONE, false },
56
57 // e-Reader
58 { "PEAJ", SAVEDATA_FLASH1M, HW_EREADER, IDLE_LOOP_NONE },
59 { "PSAJ", SAVEDATA_FLASH1M, HW_EREADER, IDLE_LOOP_NONE },
60 { "PSAE", SAVEDATA_FLASH1M, HW_EREADER, IDLE_LOOP_NONE },
61
62 // Final Fantasy Tactics Advance
63 { "AFXE", SAVEDATA_FLASH512, HW_NONE, 0x8000428, false },
64
65 // F-Zero - Climax
66 { "BFTJ", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false },
67
68 // Iridion II
69 { "AI2E", SAVEDATA_FORCE_NONE, HW_NONE, IDLE_LOOP_NONE, false },
70 { "AI2P", SAVEDATA_FORCE_NONE, HW_NONE, IDLE_LOOP_NONE, false },
71
72 // Golden Sun: The Lost Age
73 { "AGFE", SAVEDATA_FLASH512, HW_NONE, 0x801353A, false },
74
75 // Koro Koro Puzzle - Happy Panechu!
76 { "KHPJ", SAVEDATA_EEPROM, HW_TILT, IDLE_LOOP_NONE, false },
77
78 // Legendz - Yomigaeru Shiren no Shima
79 { "BLJJ", SAVEDATA_FLASH512, HW_RTC, IDLE_LOOP_NONE, false },
80 { "BLJK", SAVEDATA_FLASH512, HW_RTC, IDLE_LOOP_NONE, false },
81
82 // Legendz - Sign of Nekuromu
83 { "BLVJ", SAVEDATA_FLASH512, HW_RTC, IDLE_LOOP_NONE, false },
84
85 // Mega Man Battle Network
86 { "AREE", SAVEDATA_SRAM, HW_NONE, 0x800032E, false },
87
88 // Mega Man Zero
89 { "AZCE", SAVEDATA_SRAM, HW_NONE, 0x80004E8, false },
90
91 // Metal Slug Advance
92 { "BSME", SAVEDATA_EEPROM, HW_NONE, 0x8000290, false },
93
94 // Pokemon Ruby
95 { "AXVJ", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false },
96 { "AXVE", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false },
97 { "AXVP", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false },
98 { "AXVI", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false },
99 { "AXVS", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false },
100 { "AXVD", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false },
101 { "AXVF", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false },
102
103 // Pokemon Sapphire
104 { "AXPJ", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false },
105 { "AXPE", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false },
106 { "AXPP", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false },
107 { "AXPI", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false },
108 { "AXPS", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false },
109 { "AXPD", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false },
110 { "AXPF", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false },
111
112 // Pokemon Emerald
113 { "BPEJ", SAVEDATA_FLASH1M, HW_RTC, 0x80008C6, false },
114 { "BPEE", SAVEDATA_FLASH1M, HW_RTC, 0x80008C6, false },
115 { "BPEP", SAVEDATA_FLASH1M, HW_RTC, 0x80008C6, false },
116 { "BPEI", SAVEDATA_FLASH1M, HW_RTC, 0x80008C6, false },
117 { "BPES", SAVEDATA_FLASH1M, HW_RTC, 0x80008C6, false },
118 { "BPED", SAVEDATA_FLASH1M, HW_RTC, 0x80008C6, false },
119 { "BPEF", SAVEDATA_FLASH1M, HW_RTC, 0x80008C6, false },
120
121 // Pokemon Mystery Dungeon
122 { "B24J", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false },
123 { "B24E", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false },
124 { "B24P", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false },
125 { "B24U", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false },
126
127 // Pokemon FireRed
128 { "BPRJ", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false },
129 { "BPRE", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false },
130 { "BPRP", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false },
131 { "BPRI", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false },
132 { "BPRS", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false },
133 { "BPRD", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false },
134 { "BPRF", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false },
135
136 // Pokemon LeafGreen
137 { "BPGJ", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false },
138 { "BPGE", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false },
139 { "BPGP", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false },
140 { "BPGI", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false },
141 { "BPGS", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false },
142 { "BPGD", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false },
143 { "BPGF", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false },
144
145 // RockMan EXE 4.5 - Real Operation
146 { "BR4J", SAVEDATA_FLASH512, HW_RTC, IDLE_LOOP_NONE, false },
147
148 // Rocky
149 { "AR8E", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false },
150 { "AROP", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false },
151
152 // Sennen Kazoku
153 { "BKAJ", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false },
154
155 // Shin Bokura no Taiyou: Gyakushuu no Sabata
156 { "U33J", SAVEDATA_EEPROM, HW_RTC | HW_LIGHT_SENSOR, IDLE_LOOP_NONE, false },
157
158 // Super Mario Advance 2
159 { "AA2J", SAVEDATA_EEPROM, HW_NONE, 0x800052E, false },
160 { "AA2E", SAVEDATA_EEPROM, HW_NONE, 0x800052E, false },
161 { "AA2P", SAVEDATA_AUTODETECT, HW_NONE, 0x800052E, false },
162
163 // Super Mario Advance 3
164 { "A3AJ", SAVEDATA_EEPROM, HW_NONE, 0x8002B9C, false },
165 { "A3AE", SAVEDATA_EEPROM, HW_NONE, 0x8002B9C, false },
166 { "A3AP", SAVEDATA_EEPROM, HW_NONE, 0x8002B9C, false },
167
168 // Super Mario Advance 4
169 { "AX4J", SAVEDATA_FLASH1M, HW_NONE, 0x800072A, false },
170 { "AX4E", SAVEDATA_FLASH1M, HW_NONE, 0x800072A, false },
171 { "AX4P", SAVEDATA_FLASH1M, HW_NONE, 0x800072A, false },
172
173 // Super Monkey Ball Jr.
174 { "ALUE", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false },
175 { "ALUP", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false },
176
177 // Top Gun - Combat Zones
178 { "A2YE", SAVEDATA_FORCE_NONE, HW_NONE, IDLE_LOOP_NONE, false },
179
180 // Ueki no Housoku - Jingi Sakuretsu! Nouryokusha Battle
181 { "BUHJ", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false },
182
183 // Wario Ware Twisted
184 { "RZWJ", SAVEDATA_SRAM, HW_RUMBLE | HW_GYRO, IDLE_LOOP_NONE, false },
185 { "RZWE", SAVEDATA_SRAM, HW_RUMBLE | HW_GYRO, IDLE_LOOP_NONE, false },
186 { "RZWP", SAVEDATA_SRAM, HW_RUMBLE | HW_GYRO, IDLE_LOOP_NONE, false },
187
188 // Yoshi's Universal Gravitation
189 { "KYGJ", SAVEDATA_EEPROM, HW_TILT, IDLE_LOOP_NONE, false },
190 { "KYGE", SAVEDATA_EEPROM, HW_TILT, IDLE_LOOP_NONE, false },
191 { "KYGP", SAVEDATA_EEPROM, HW_TILT, IDLE_LOOP_NONE, false },
192
193 // Aging cartridge
194 { "TCHK", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false },
195
196 // Famicom Mini series 3 (FDS), some aren't mirrored (22 - 28)
197 // See https://forum.no-intro.org/viewtopic.php?f=2&t=4221 for discussion
198 { "FNMJ", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false },
199 { "FMRJ", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false },
200 { "FPTJ", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false },
201 { "FLBJ", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false },
202 { "FFMJ", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false },
203 { "FTKJ", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false },
204 { "FTUJ", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false },
205
206 { { 0, 0, 0, 0 }, 0, 0, IDLE_LOOP_NONE, false }
207 };
208
GBAOverrideFind(const struct Configuration * config,struct GBACartridgeOverride * override)209 bool GBAOverrideFind(const struct Configuration* config, struct GBACartridgeOverride* override) {
210 override->savetype = SAVEDATA_AUTODETECT;
211 override->hardware = HW_NONE;
212 override->idleLoop = IDLE_LOOP_NONE;
213 override->mirroring = false;
214 override->vbaBugCompat = false;
215 bool found = false;
216
217 int i;
218 for (i = 0; _overrides[i].id[0]; ++i) {
219 if (memcmp(override->id, _overrides[i].id, sizeof(override->id)) == 0) {
220 *override = _overrides[i];
221 found = true;
222 break;
223 }
224 }
225 if (!found && override->id[0] == 'F') {
226 // Classic NES Series
227 override->savetype = SAVEDATA_EEPROM;
228 override->mirroring = true;
229 found = true;
230 }
231
232 if (config) {
233 char sectionName[16];
234 snprintf(sectionName, sizeof(sectionName), "override.%c%c%c%c", override->id[0], override->id[1], override->id[2], override->id[3]);
235 const char* savetype = ConfigurationGetValue(config, sectionName, "savetype");
236 const char* hardware = ConfigurationGetValue(config, sectionName, "hardware");
237 const char* idleLoop = ConfigurationGetValue(config, sectionName, "idleLoop");
238
239 if (savetype) {
240 if (strcasecmp(savetype, "SRAM") == 0) {
241 found = true;
242 override->savetype = SAVEDATA_SRAM;
243 } else if (strcasecmp(savetype, "EEPROM") == 0) {
244 found = true;
245 override->savetype = SAVEDATA_EEPROM;
246 } else if (strcasecmp(savetype, "EEPROM512") == 0) {
247 found = true;
248 override->savetype = SAVEDATA_EEPROM512;
249 } else if (strcasecmp(savetype, "FLASH512") == 0) {
250 found = true;
251 override->savetype = SAVEDATA_FLASH512;
252 } else if (strcasecmp(savetype, "FLASH1M") == 0) {
253 found = true;
254 override->savetype = SAVEDATA_FLASH1M;
255 } else if (strcasecmp(savetype, "NONE") == 0) {
256 found = true;
257 override->savetype = SAVEDATA_FORCE_NONE;
258 }
259 }
260
261 if (hardware) {
262 char* end;
263 long type = strtoul(hardware, &end, 0);
264 if (end && !*end) {
265 override->hardware = type;
266 found = true;
267 }
268 }
269
270 if (idleLoop) {
271 char* end;
272 uint32_t address = strtoul(idleLoop, &end, 16);
273 if (end && !*end) {
274 override->idleLoop = address;
275 found = true;
276 }
277 }
278 }
279 return found;
280 }
281
GBAOverrideSave(struct Configuration * config,const struct GBACartridgeOverride * override)282 void GBAOverrideSave(struct Configuration* config, const struct GBACartridgeOverride* override) {
283 char sectionName[16];
284 snprintf(sectionName, sizeof(sectionName), "override.%c%c%c%c", override->id[0], override->id[1], override->id[2], override->id[3]);
285 const char* savetype = 0;
286 switch (override->savetype) {
287 case SAVEDATA_SRAM:
288 savetype = "SRAM";
289 break;
290 case SAVEDATA_EEPROM:
291 savetype = "EEPROM";
292 break;
293 case SAVEDATA_EEPROM512:
294 savetype = "EEPROM512";
295 break;
296 case SAVEDATA_FLASH512:
297 savetype = "FLASH512";
298 break;
299 case SAVEDATA_FLASH1M:
300 savetype = "FLASH1M";
301 break;
302 case SAVEDATA_FORCE_NONE:
303 savetype = "NONE";
304 break;
305 case SAVEDATA_AUTODETECT:
306 break;
307 }
308 ConfigurationSetValue(config, sectionName, "savetype", savetype);
309
310 if (override->hardware != HW_NO_OVERRIDE) {
311 ConfigurationSetIntValue(config, sectionName, "hardware", override->hardware);
312 } else {
313 ConfigurationClearValue(config, sectionName, "hardware");
314 }
315
316 if (override->idleLoop != IDLE_LOOP_NONE) {
317 ConfigurationSetUIntValue(config, sectionName, "idleLoop", override->idleLoop);
318 } else {
319 ConfigurationClearValue(config, sectionName, "idleLoop");
320 }
321 }
322
GBAOverrideApply(struct GBA * gba,const struct GBACartridgeOverride * override)323 void GBAOverrideApply(struct GBA* gba, const struct GBACartridgeOverride* override) {
324 if (override->savetype != SAVEDATA_AUTODETECT) {
325 GBASavedataForceType(&gba->memory.savedata, override->savetype);
326 }
327
328 gba->vbaBugCompat = override->vbaBugCompat;
329
330 if (override->hardware != HW_NO_OVERRIDE) {
331 GBAHardwareClear(&gba->memory.hw);
332
333 if (override->hardware & HW_RTC) {
334 GBAHardwareInitRTC(&gba->memory.hw);
335 }
336
337 if (override->hardware & HW_GYRO) {
338 GBAHardwareInitGyro(&gba->memory.hw);
339 }
340
341 if (override->hardware & HW_RUMBLE) {
342 GBAHardwareInitRumble(&gba->memory.hw);
343 }
344
345 if (override->hardware & HW_LIGHT_SENSOR) {
346 GBAHardwareInitLight(&gba->memory.hw);
347 }
348
349 if (override->hardware & HW_TILT) {
350 GBAHardwareInitTilt(&gba->memory.hw);
351 }
352
353 if (override->hardware & HW_EREADER) {
354 GBAHardwareInitEReader(&gba->memory.hw);
355 }
356
357 if (override->hardware & HW_GB_PLAYER_DETECTION) {
358 gba->memory.hw.devices |= HW_GB_PLAYER_DETECTION;
359 } else {
360 gba->memory.hw.devices &= ~HW_GB_PLAYER_DETECTION;
361 }
362 }
363
364 if (override->idleLoop != IDLE_LOOP_NONE) {
365 gba->idleLoop = override->idleLoop;
366 if (gba->idleOptimization == IDLE_LOOP_DETECT) {
367 gba->idleOptimization = IDLE_LOOP_REMOVE;
368 }
369 }
370
371 if (override->mirroring) {
372 gba->memory.mirroring = true;
373 }
374 }
375
GBAOverrideApplyDefaults(struct GBA * gba,const struct Configuration * overrides)376 void GBAOverrideApplyDefaults(struct GBA* gba, const struct Configuration* overrides) {
377 struct GBACartridgeOverride override = { .idleLoop = IDLE_LOOP_NONE };
378 const struct GBACartridge* cart = (const struct GBACartridge*) gba->memory.rom;
379 if (cart) {
380 memcpy(override.id, &cart->id, sizeof(override.id));
381
382 static const uint32_t pokemonTable[] = {
383 // Emerald
384 0x4881F3F8, // BPEJ
385 0x8C4D3108, // BPES
386 0x1F1C08FB, // BPEE
387 0x34C9DF89, // BPED
388 0xA3FDCCB1, // BPEF
389 0xA0AEC80A, // BPEI
390
391 // FireRed
392 0x1A81EEDF, // BPRD
393 0x3B2056E9, // BPRJ
394 0x5DC668F6, // BPRF
395 0x73A72167, // BPRI
396 0x84EE4776, // BPRE rev 1
397 0x9F08064E, // BPRS
398 0xBB640DF7, // BPRJ rev 1
399 0xDD88761C, // BPRE
400
401 // Ruby
402 0x61641576, // AXVE rev 1
403 0xAEAC73E6, // AXVE rev 2
404 0xF0815EE7, // AXVE
405 };
406
407 bool isPokemon = false;
408 isPokemon = isPokemon || !strncmp("pokemon red version", &((const char*) gba->memory.rom)[0x108], 20);
409 isPokemon = isPokemon || !strncmp("pokemon emerald version", &((const char*) gba->memory.rom)[0x108], 24);
410 isPokemon = isPokemon || !strncmp("AXVE", &((const char*) gba->memory.rom)[0xAC], 4);
411 bool isKnownPokemon = false;
412 if (isPokemon) {
413 size_t i;
414 for (i = 0; !isKnownPokemon && i < sizeof(pokemonTable) / sizeof(*pokemonTable); ++i) {
415 isKnownPokemon = gba->romCrc32 == pokemonTable[i];
416 }
417 }
418
419 if (isPokemon && !isKnownPokemon) {
420 // Enable FLASH1M and RTC on Pokémon ROM hacks
421 override.savetype = SAVEDATA_FLASH1M;
422 override.hardware = HW_RTC;
423 override.vbaBugCompat = true;
424 GBAOverrideApply(gba, &override);
425 } else if (GBAOverrideFind(overrides, &override)) {
426 GBAOverrideApply(gba, &override);
427 }
428 }
429 }
430