src/gba/supervisor/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 // Boktai: The Sun is in Your Hand
15 { "U3IJ", SAVEDATA_EEPROM, HW_RTC | HW_LIGHT_SENSOR, IDLE_LOOP_NONE },
16 { "U3IE", SAVEDATA_EEPROM, HW_RTC | HW_LIGHT_SENSOR, IDLE_LOOP_NONE },
17 { "U3IP", SAVEDATA_EEPROM, HW_RTC | HW_LIGHT_SENSOR, IDLE_LOOP_NONE },
18
19 // Boktai 2: Solar Boy Django
20 { "U32J", SAVEDATA_EEPROM, HW_RTC | HW_LIGHT_SENSOR, IDLE_LOOP_NONE },
21 { "U32E", SAVEDATA_EEPROM, HW_RTC | HW_LIGHT_SENSOR, IDLE_LOOP_NONE },
22 { "U32P", SAVEDATA_EEPROM, HW_RTC | HW_LIGHT_SENSOR, IDLE_LOOP_NONE },
23
24 // Dragon Ball Z - The Legacy of Goku
25 { "ALGP", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE },
26
27 // Dragon Ball Z - Taiketsu
28 { "BDBE", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE },
29 { "BDBP", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE },
30
31 // Drill Dozer
32 { "V49J", SAVEDATA_SRAM, HW_RUMBLE, IDLE_LOOP_NONE },
33 { "V49E", SAVEDATA_SRAM, HW_RUMBLE, IDLE_LOOP_NONE },
34
35 // Final Fantasy Tactics Advance
36 { "AFXE", SAVEDATA_FLASH512, HW_NONE, 0x8000428 },
37
38 // F-Zero - Climax
39 { "BFTJ", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE },
40
41 // Golden Sun: The Lost Age
42 { "AGFE", SAVEDATA_FLASH512, HW_NONE, 0x801353A },
43
44 // Koro Koro Puzzle - Happy Panechu!
45 { "KHPJ", SAVEDATA_EEPROM, HW_TILT, IDLE_LOOP_NONE },
46
47 // Mega Man Battle Network
48 { "AREE", SAVEDATA_SRAM, HW_NONE, 0x800032E },
49
50 // Metal Slug Advance
51 { "BSME", SAVEDATA_EEPROM, HW_NONE, 0x8000290 },
52
53 // Pokemon Ruby
54 { "AXVJ", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE },
55 { "AXVE", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE },
56 { "AXVP", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE },
57 { "AXVI", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE },
58 { "AXVS", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE },
59 { "AXVD", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE },
60 { "AXVF", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE },
61
62 // Pokemon Sapphire
63 { "AXPJ", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE },
64 { "AXPE", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE },
65 { "AXPP", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE },
66 { "AXPI", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE },
67 { "AXPS", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE },
68 { "AXPD", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE },
69 { "AXPF", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE },
70
71 // Pokemon Emerald
72 { "BPEJ", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE },
73 { "BPEE", SAVEDATA_FLASH1M, HW_RTC, 0x80008C6 },
74 { "BPEP", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE },
75 { "BPEI", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE },
76 { "BPES", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE },
77 { "BPED", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE },
78 { "BPEF", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE },
79
80 // Pokemon Mystery Dungeon
81 { "B24J", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE },
82 { "B24E", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE },
83 { "B24P", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE },
84 { "B24U", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE },
85
86 // Pokemon FireRed
87 { "BPRJ", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE },
88 { "BPRE", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE },
89 { "BPRP", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE },
90 { "BPRI", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE },
91 { "BPRS", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE },
92 { "BPRD", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE },
93 { "BPRF", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE },
94
95 // Pokemon LeafGreen
96 { "BPGJ", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE },
97 { "BPGE", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE },
98 { "BPGP", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE },
99 { "BPGI", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE },
100 { "BPGS", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE },
101 { "BPGD", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE },
102 { "BPGF", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE },
103
104 // RockMan EXE 4.5 - Real Operation
105 { "BR4J", SAVEDATA_FLASH512, HW_RTC, IDLE_LOOP_NONE },
106
107 // Rocky
108 { "AR8E", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE },
109 { "AROP", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE },
110
111 // Sennen Kazoku
112 { "BKAJ", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE },
113
114 // Shin Bokura no Taiyou: Gyakushuu no Sabata
115 { "U33J", SAVEDATA_EEPROM, HW_RTC | HW_LIGHT_SENSOR, IDLE_LOOP_NONE },
116
117 // Super Mario Advance 2
118 { "AA2E", SAVEDATA_EEPROM, HW_NONE, 0x800052E },
119
120 // Super Mario Advance 3
121 { "A3AE", SAVEDATA_EEPROM, HW_NONE, 0x8002B9C },
122
123 // Super Mario Advance 4
124 { "AX4J", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE },
125 { "AX4E", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE },
126 { "AX4P", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE },
127
128 // Top Gun - Combat Zones
129 { "A2YE", SAVEDATA_FORCE_NONE, HW_NONE, IDLE_LOOP_NONE },
130
131 // Wario Ware Twisted
132 { "RZWJ", SAVEDATA_SRAM, HW_RUMBLE | HW_GYRO, IDLE_LOOP_NONE },
133 { "RZWE", SAVEDATA_SRAM, HW_RUMBLE | HW_GYRO, IDLE_LOOP_NONE },
134 { "RZWP", SAVEDATA_SRAM, HW_RUMBLE | HW_GYRO, IDLE_LOOP_NONE },
135
136 // Yoshi's Universal Gravitation
137 { "KYGJ", SAVEDATA_EEPROM, HW_TILT, IDLE_LOOP_NONE },
138 { "KYGE", SAVEDATA_EEPROM, HW_TILT, IDLE_LOOP_NONE },
139 { "KYGP", SAVEDATA_EEPROM, HW_TILT, IDLE_LOOP_NONE },
140
141 { { 0, 0, 0, 0 }, 0, 0, IDLE_LOOP_NONE }
142};
143
144bool GBAOverrideFind(const struct Configuration* config, struct GBACartridgeOverride* override) {
145 override->savetype = SAVEDATA_AUTODETECT;
146 override->hardware = HW_NONE;
147 override->idleLoop = IDLE_LOOP_NONE;
148 bool found;
149
150 if (override->id[0] == 'F') {
151 // Classic NES Series
152 override->savetype = SAVEDATA_EEPROM;
153 found = true;
154 } else {
155 int i;
156 for (i = 0; _overrides[i].id[0]; ++i) {
157 if (memcmp(override->id, _overrides[i].id, sizeof(override->id)) == 0) {
158 *override = _overrides[i];
159 found = true;
160 break;
161 }
162 }
163 }
164
165 if (config) {
166 char sectionName[16];
167 snprintf(sectionName, sizeof(sectionName), "override.%c%c%c%c", override->id[0], override->id[1], override->id[2], override->id[3]);
168 const char* savetype = ConfigurationGetValue(config, sectionName, "savetype");
169 const char* hardware = ConfigurationGetValue(config, sectionName, "hardware");
170 const char* idleLoop = ConfigurationGetValue(config, sectionName, "idleLoop");
171
172 if (savetype) {
173 if (strcasecmp(savetype, "SRAM") == 0) {
174 found = true;
175 override->savetype = SAVEDATA_SRAM;
176 } else if (strcasecmp(savetype, "EEPROM") == 0) {
177 found = true;
178 override->savetype = SAVEDATA_EEPROM;
179 } else if (strcasecmp(savetype, "FLASH512") == 0) {
180 found = true;
181 override->savetype = SAVEDATA_FLASH512;
182 } else if (strcasecmp(savetype, "FLASH1M") == 0) {
183 found = true;
184 override->savetype = SAVEDATA_FLASH1M;
185 } else if (strcasecmp(savetype, "NONE") == 0) {
186 found = true;
187 override->savetype = SAVEDATA_FORCE_NONE;
188 }
189 }
190
191 if (hardware) {
192 char* end;
193 long type = strtoul(hardware, &end, 0);
194 if (end && !*end) {
195 override->hardware = type;
196 found = true;
197 }
198 }
199
200 if (idleLoop) {
201 char* end;
202 uint32_t address = strtoul(idleLoop, &end, 16);
203 if (end && !*end) {
204 override->idleLoop = address;
205 found = true;
206 }
207 }
208 }
209 return found;
210}
211
212void GBAOverrideSave(struct Configuration* config, const struct GBACartridgeOverride* override) {
213 char sectionName[16];
214 snprintf(sectionName, sizeof(sectionName), "override.%c%c%c%c", override->id[0], override->id[1], override->id[2], override->id[3]);
215 const char* savetype = 0;
216 switch (override->savetype) {
217 case SAVEDATA_SRAM:
218 savetype = "SRAM";
219 break;
220 case SAVEDATA_EEPROM:
221 savetype = "EEPROM";
222 break;
223 case SAVEDATA_FLASH512:
224 savetype = "FLASH512";
225 break;
226 case SAVEDATA_FLASH1M:
227 savetype = "FLASH1M";
228 break;
229 case SAVEDATA_FORCE_NONE:
230 savetype = "NONE";
231 break;
232 case SAVEDATA_AUTODETECT:
233 break;
234 }
235 ConfigurationSetValue(config, sectionName, "savetype", savetype);
236
237 if (override->hardware != HW_NO_OVERRIDE) {
238 ConfigurationSetIntValue(config, sectionName, "hardware", override->hardware);
239 } else {
240 ConfigurationClearValue(config, sectionName, "hardware");
241 }
242
243 if (override->idleLoop != IDLE_LOOP_NONE) {
244 ConfigurationSetUIntValue(config, sectionName, "idleLoop", override->idleLoop);
245 } else {
246 ConfigurationClearValue(config, sectionName, "idleLoop");
247 }
248}
249
250void GBAOverrideApply(struct GBA* gba, const struct GBACartridgeOverride* override) {
251 if (override->savetype != SAVEDATA_AUTODETECT) {
252 GBASavedataForceType(&gba->memory.savedata, override->savetype);
253 }
254
255 if (override->hardware != HW_NO_OVERRIDE) {
256 GBAHardwareClear(&gba->memory.hw);
257
258 if (override->hardware & HW_RTC) {
259 GBAHardwareInitRTC(&gba->memory.hw);
260 }
261
262 if (override->hardware & HW_GYRO) {
263 GBAHardwareInitGyro(&gba->memory.hw);
264 }
265
266 if (override->hardware & HW_RUMBLE) {
267 GBAHardwareInitRumble(&gba->memory.hw);
268 }
269
270 if (override->hardware & HW_LIGHT_SENSOR) {
271 GBAHardwareInitLight(&gba->memory.hw);
272 }
273
274 if (override->hardware & HW_TILT) {
275 GBAHardwareInitTilt(&gba->memory.hw);
276 }
277 }
278
279 if (override->idleLoop != IDLE_LOOP_NONE) {
280 gba->idleLoop = override->idleLoop;
281 if (gba->idleOptimization == IDLE_LOOP_DETECT) {
282 gba->idleOptimization = IDLE_LOOP_REMOVE;
283 }
284 }
285}