src/gba/overrides.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 "overrides.h"
7
8#include "gba/gba.h"
9#include "gba/hardware.h"
10
11#include "util/configuration.h"
12
13static 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 // Dragon Ball Z - The Legacy of Goku
33 { "ALGP", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false },
34
35 // Dragon Ball Z - The Legacy of Goku II
36 { "ALFJ", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false },
37 { "ALFE", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false },
38 { "ALFP", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false },
39
40 // Dragon Ball Z - Taiketsu
41 { "BDBE", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false },
42 { "BDBP", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false },
43
44 // Drill Dozer
45 { "V49J", SAVEDATA_SRAM, HW_RUMBLE, IDLE_LOOP_NONE, false },
46 { "V49E", SAVEDATA_SRAM, HW_RUMBLE, IDLE_LOOP_NONE, false },
47
48 // Final Fantasy Tactics Advance
49 { "AFXE", SAVEDATA_FLASH512, HW_NONE, 0x8000428, false },
50
51 // F-Zero - Climax
52 { "BFTJ", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false },
53
54 // Iridion II
55 { "AI2E", SAVEDATA_FORCE_NONE, HW_NONE, IDLE_LOOP_NONE, false },
56 { "AI2P", SAVEDATA_FORCE_NONE, HW_NONE, IDLE_LOOP_NONE, false },
57
58 // Golden Sun: The Lost Age
59 { "AGFE", SAVEDATA_FLASH512, HW_NONE, 0x801353A, false },
60
61 // Koro Koro Puzzle - Happy Panechu!
62 { "KHPJ", SAVEDATA_EEPROM, HW_TILT, IDLE_LOOP_NONE, false },
63
64 // Mega Man Battle Network
65 { "AREE", SAVEDATA_SRAM, HW_NONE, 0x800032E, false },
66
67 // Mega Man Zero
68 { "AZCE", SAVEDATA_SRAM, HW_NONE, 0x80004E8, false },
69
70 // Metal Slug Advance
71 { "BSME", SAVEDATA_EEPROM, HW_NONE, 0x8000290, false },
72
73 // Pokemon Pinball: Ruby & Sapphire
74 { "BPPJ", SAVEDATA_SRAM, HW_GB_PLAYER_DETECTION, IDLE_LOOP_NONE, false },
75 { "BPPE", SAVEDATA_SRAM, HW_GB_PLAYER_DETECTION, IDLE_LOOP_NONE, false },
76 { "BPPP", SAVEDATA_SRAM, HW_GB_PLAYER_DETECTION, IDLE_LOOP_NONE, false },
77 { "BPPU", SAVEDATA_SRAM, HW_GB_PLAYER_DETECTION, IDLE_LOOP_NONE, false },
78
79 // Pokemon Ruby
80 { "AXVJ", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false },
81 { "AXVE", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false },
82 { "AXVP", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false },
83 { "AXVI", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false },
84 { "AXVS", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false },
85 { "AXVD", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false },
86 { "AXVF", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false },
87
88 // Pokemon Sapphire
89 { "AXPJ", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false },
90 { "AXPE", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false },
91 { "AXPP", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false },
92 { "AXPI", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false },
93 { "AXPS", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false },
94 { "AXPD", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false },
95 { "AXPF", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false },
96
97 // Pokemon Emerald
98 { "BPEJ", SAVEDATA_FLASH1M, HW_RTC, 0x80008C6, false },
99 { "BPEE", SAVEDATA_FLASH1M, HW_RTC, 0x80008C6, false },
100 { "BPEP", SAVEDATA_FLASH1M, HW_RTC, 0x80008C6, false },
101 { "BPEI", SAVEDATA_FLASH1M, HW_RTC, 0x80008C6, false },
102 { "BPES", SAVEDATA_FLASH1M, HW_RTC, 0x80008C6, false },
103 { "BPED", SAVEDATA_FLASH1M, HW_RTC, 0x80008C6, false },
104 { "BPEF", SAVEDATA_FLASH1M, HW_RTC, 0x80008C6, false },
105
106 // Pokemon Mystery Dungeon
107 { "B24J", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false },
108 { "B24E", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false },
109 { "B24P", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false },
110 { "B24U", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false },
111
112 // Pokemon FireRed
113 { "BPRJ", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false },
114 { "BPRE", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false },
115 { "BPRP", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false },
116 { "BPRI", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false },
117 { "BPRS", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false },
118 { "BPRD", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false },
119 { "BPRF", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false },
120
121 // Pokemon LeafGreen
122 { "BPGJ", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false },
123 { "BPGE", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false },
124 { "BPGP", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false },
125 { "BPGI", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false },
126 { "BPGS", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false },
127 { "BPGD", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false },
128 { "BPGF", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false },
129
130 // RockMan EXE 4.5 - Real Operation
131 { "BR4J", SAVEDATA_FLASH512, HW_RTC, IDLE_LOOP_NONE, false },
132
133 // Rocky
134 { "AR8E", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false },
135 { "AROP", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false },
136
137 // Sennen Kazoku
138 { "BKAJ", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false },
139
140 // Shin Bokura no Taiyou: Gyakushuu no Sabata
141 { "U33J", SAVEDATA_EEPROM, HW_RTC | HW_LIGHT_SENSOR, IDLE_LOOP_NONE, false },
142
143 // Super Mario Advance 2
144 { "AA2J", SAVEDATA_EEPROM, HW_NONE, 0x800052E, false },
145 { "AA2E", SAVEDATA_EEPROM, HW_NONE, 0x800052E, false },
146 { "AA2P", SAVEDATA_AUTODETECT, HW_NONE, 0x800052E, false },
147
148 // Super Mario Advance 3
149 { "A3AJ", SAVEDATA_EEPROM, HW_NONE, 0x8002B9C, false },
150 { "A3AE", SAVEDATA_EEPROM, HW_NONE, 0x8002B9C, false },
151 { "A3AP", SAVEDATA_EEPROM, HW_NONE, 0x8002B9C, false },
152
153 // Super Mario Advance 4
154 { "AX4J", SAVEDATA_FLASH1M, HW_NONE, 0x800072A, false },
155 { "AX4E", SAVEDATA_FLASH1M, HW_NONE, 0x800072A, false },
156 { "AX4P", SAVEDATA_FLASH1M, HW_NONE, 0x800072A, false },
157
158 // Super Monkey Ball Jr.
159 { "ALUE", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false },
160 { "ALUP", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false },
161
162 // Top Gun - Combat Zones
163 { "A2YE", SAVEDATA_FORCE_NONE, HW_NONE, IDLE_LOOP_NONE, false },
164
165 // Ueki no Housoku - Jingi Sakuretsu! Nouryokusha Battle
166 { "BUHJ", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false },
167
168 // Wario Ware Twisted
169 { "RZWJ", SAVEDATA_SRAM, HW_RUMBLE | HW_GYRO, IDLE_LOOP_NONE, false },
170 { "RZWE", SAVEDATA_SRAM, HW_RUMBLE | HW_GYRO, IDLE_LOOP_NONE, false },
171 { "RZWP", SAVEDATA_SRAM, HW_RUMBLE | HW_GYRO, IDLE_LOOP_NONE, false },
172
173 // Yoshi's Universal Gravitation
174 { "KYGJ", SAVEDATA_EEPROM, HW_TILT, IDLE_LOOP_NONE, false },
175 { "KYGE", SAVEDATA_EEPROM, HW_TILT, IDLE_LOOP_NONE, false },
176 { "KYGP", SAVEDATA_EEPROM, HW_TILT, IDLE_LOOP_NONE, false },
177
178 { { 0, 0, 0, 0 }, 0, 0, IDLE_LOOP_NONE, false }
179};
180
181bool GBAOverrideFind(const struct Configuration* config, struct GBACartridgeOverride* override) {
182 override->savetype = SAVEDATA_AUTODETECT;
183 override->hardware = HW_NONE;
184 override->idleLoop = IDLE_LOOP_NONE;
185 override->mirroring = false;
186 bool found = false;
187
188 if (override->id[0] == 'F') {
189 // Classic NES Series
190 override->savetype = SAVEDATA_EEPROM;
191 override->mirroring = true;
192 found = true;
193 } else {
194 int i;
195 for (i = 0; _overrides[i].id[0]; ++i) {
196 if (memcmp(override->id, _overrides[i].id, sizeof(override->id)) == 0) {
197 *override = _overrides[i];
198 found = true;
199 break;
200 }
201 }
202 }
203
204 if (config) {
205 char sectionName[16];
206 snprintf(sectionName, sizeof(sectionName), "override.%c%c%c%c", override->id[0], override->id[1], override->id[2], override->id[3]);
207 const char* savetype = ConfigurationGetValue(config, sectionName, "savetype");
208 const char* hardware = ConfigurationGetValue(config, sectionName, "hardware");
209 const char* idleLoop = ConfigurationGetValue(config, sectionName, "idleLoop");
210
211 if (savetype) {
212 if (strcasecmp(savetype, "SRAM") == 0) {
213 found = true;
214 override->savetype = SAVEDATA_SRAM;
215 } else if (strcasecmp(savetype, "EEPROM") == 0) {
216 found = true;
217 override->savetype = SAVEDATA_EEPROM;
218 } else if (strcasecmp(savetype, "FLASH512") == 0) {
219 found = true;
220 override->savetype = SAVEDATA_FLASH512;
221 } else if (strcasecmp(savetype, "FLASH1M") == 0) {
222 found = true;
223 override->savetype = SAVEDATA_FLASH1M;
224 } else if (strcasecmp(savetype, "NONE") == 0) {
225 found = true;
226 override->savetype = SAVEDATA_FORCE_NONE;
227 }
228 }
229
230 if (hardware) {
231 char* end;
232 long type = strtoul(hardware, &end, 0);
233 if (end && !*end) {
234 override->hardware = type;
235 found = true;
236 }
237 }
238
239 if (idleLoop) {
240 char* end;
241 uint32_t address = strtoul(idleLoop, &end, 16);
242 if (end && !*end) {
243 override->idleLoop = address;
244 found = true;
245 }
246 }
247 }
248 return found;
249}
250
251void GBAOverrideSave(struct Configuration* config, const struct GBACartridgeOverride* override) {
252 char sectionName[16];
253 snprintf(sectionName, sizeof(sectionName), "override.%c%c%c%c", override->id[0], override->id[1], override->id[2], override->id[3]);
254 const char* savetype = 0;
255 switch (override->savetype) {
256 case SAVEDATA_SRAM:
257 savetype = "SRAM";
258 break;
259 case SAVEDATA_EEPROM:
260 savetype = "EEPROM";
261 break;
262 case SAVEDATA_FLASH512:
263 savetype = "FLASH512";
264 break;
265 case SAVEDATA_FLASH1M:
266 savetype = "FLASH1M";
267 break;
268 case SAVEDATA_FORCE_NONE:
269 savetype = "NONE";
270 break;
271 case SAVEDATA_AUTODETECT:
272 break;
273 }
274 ConfigurationSetValue(config, sectionName, "savetype", savetype);
275
276 if (override->hardware != HW_NO_OVERRIDE) {
277 ConfigurationSetIntValue(config, sectionName, "hardware", override->hardware);
278 } else {
279 ConfigurationClearValue(config, sectionName, "hardware");
280 }
281
282 if (override->idleLoop != IDLE_LOOP_NONE) {
283 ConfigurationSetUIntValue(config, sectionName, "idleLoop", override->idleLoop);
284 } else {
285 ConfigurationClearValue(config, sectionName, "idleLoop");
286 }
287}
288
289void GBAOverrideApply(struct GBA* gba, const struct GBACartridgeOverride* override) {
290 if (override->savetype != SAVEDATA_AUTODETECT) {
291 GBASavedataForceType(&gba->memory.savedata, override->savetype, gba->realisticTiming);
292 }
293
294 if (override->hardware != HW_NO_OVERRIDE) {
295 GBAHardwareClear(&gba->memory.hw);
296
297 if (override->hardware & HW_RTC) {
298 GBAHardwareInitRTC(&gba->memory.hw);
299 }
300
301 if (override->hardware & HW_GYRO) {
302 GBAHardwareInitGyro(&gba->memory.hw);
303 }
304
305 if (override->hardware & HW_RUMBLE) {
306 GBAHardwareInitRumble(&gba->memory.hw);
307 }
308
309 if (override->hardware & HW_LIGHT_SENSOR) {
310 GBAHardwareInitLight(&gba->memory.hw);
311 }
312
313 if (override->hardware & HW_TILT) {
314 GBAHardwareInitTilt(&gba->memory.hw);
315 }
316
317 if (override->hardware & HW_GB_PLAYER_DETECTION) {
318 gba->memory.hw.devices |= HW_GB_PLAYER_DETECTION;
319 } else {
320 gba->memory.hw.devices &= ~HW_GB_PLAYER_DETECTION;
321 }
322 }
323
324 if (override->idleLoop != IDLE_LOOP_NONE) {
325 gba->idleLoop = override->idleLoop;
326 if (gba->idleOptimization == IDLE_LOOP_DETECT) {
327 gba->idleOptimization = IDLE_LOOP_REMOVE;
328 }
329 }
330
331 if (override->mirroring) {
332 gba->memory.mirroring = true;
333 }
334}
335
336void GBAOverrideApplyDefaults(struct GBA* gba) {
337 struct GBACartridgeOverride override;
338 const struct GBACartridge* cart = (const struct GBACartridge*) gba->memory.rom;
339 memcpy(override.id, &cart->id, sizeof(override.id));
340 if (GBAOverrideFind(0, &override)) {
341 GBAOverrideApply(gba, &override);
342 }
343}