src/gba/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 "gba-overrides.h"
7
8#include "gba.h"
9#include "gba-gpio.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, GPIO_RTC | GPIO_LIGHT_SENSOR, IDLE_LOOP_NONE },
16 { "U3IE", SAVEDATA_EEPROM, GPIO_RTC | GPIO_LIGHT_SENSOR, IDLE_LOOP_NONE },
17 { "U3IP", SAVEDATA_EEPROM, GPIO_RTC | GPIO_LIGHT_SENSOR, IDLE_LOOP_NONE },
18
19 // Boktai 2: Solar Boy Django
20 { "U32J", SAVEDATA_EEPROM, GPIO_RTC | GPIO_LIGHT_SENSOR, IDLE_LOOP_NONE },
21 { "U32E", SAVEDATA_EEPROM, GPIO_RTC | GPIO_LIGHT_SENSOR, IDLE_LOOP_NONE },
22 { "U32P", SAVEDATA_EEPROM, GPIO_RTC | GPIO_LIGHT_SENSOR, IDLE_LOOP_NONE },
23
24 // Drill Dozer
25 { "V49J", SAVEDATA_SRAM, GPIO_RUMBLE, IDLE_LOOP_NONE },
26 { "V49E", SAVEDATA_SRAM, GPIO_RUMBLE, IDLE_LOOP_NONE },
27
28 // Final Fantasy Tactics Advance
29 { "AFXE", SAVEDATA_FLASH512, GPIO_NONE, 0x8000428 },
30
31 // Koro Koro Puzzle - Happy Panechu!
32 { "KHPJ", SAVEDATA_EEPROM, GPIO_TILT, IDLE_LOOP_NONE },
33
34 // Mega Man Battle Network
35 { "AREE", SAVEDATA_SRAM, GPIO_NONE, 0x800032E },
36
37 // Pokemon Ruby
38 { "AXVJ", SAVEDATA_FLASH1M, GPIO_RTC, IDLE_LOOP_NONE },
39 { "AXVE", SAVEDATA_FLASH1M, GPIO_RTC, IDLE_LOOP_NONE },
40 { "AXVP", SAVEDATA_FLASH1M, GPIO_RTC, IDLE_LOOP_NONE },
41 { "AXVI", SAVEDATA_FLASH1M, GPIO_RTC, IDLE_LOOP_NONE },
42 { "AXVS", SAVEDATA_FLASH1M, GPIO_RTC, IDLE_LOOP_NONE },
43 { "AXVD", SAVEDATA_FLASH1M, GPIO_RTC, IDLE_LOOP_NONE },
44 { "AXVF", SAVEDATA_FLASH1M, GPIO_RTC, IDLE_LOOP_NONE },
45
46 // Pokemon Sapphire
47 { "AXPJ", SAVEDATA_FLASH1M, GPIO_RTC, IDLE_LOOP_NONE },
48 { "AXPE", SAVEDATA_FLASH1M, GPIO_RTC, IDLE_LOOP_NONE },
49 { "AXPP", SAVEDATA_FLASH1M, GPIO_RTC, IDLE_LOOP_NONE },
50 { "AXPI", SAVEDATA_FLASH1M, GPIO_RTC, IDLE_LOOP_NONE },
51 { "AXPS", SAVEDATA_FLASH1M, GPIO_RTC, IDLE_LOOP_NONE },
52 { "AXPD", SAVEDATA_FLASH1M, GPIO_RTC, IDLE_LOOP_NONE },
53 { "AXPF", SAVEDATA_FLASH1M, GPIO_RTC, IDLE_LOOP_NONE },
54
55 // Pokemon Emerald
56 { "BPEJ", SAVEDATA_FLASH1M, GPIO_RTC, IDLE_LOOP_NONE },
57 { "BPEE", SAVEDATA_FLASH1M, GPIO_RTC, IDLE_LOOP_NONE },
58 { "BPEP", SAVEDATA_FLASH1M, GPIO_RTC, IDLE_LOOP_NONE },
59 { "BPEI", SAVEDATA_FLASH1M, GPIO_RTC, IDLE_LOOP_NONE },
60 { "BPES", SAVEDATA_FLASH1M, GPIO_RTC, IDLE_LOOP_NONE },
61 { "BPED", SAVEDATA_FLASH1M, GPIO_RTC, IDLE_LOOP_NONE },
62 { "BPEF", SAVEDATA_FLASH1M, GPIO_RTC, IDLE_LOOP_NONE },
63
64 // Pokemon Mystery Dungeon
65 { "B24J", SAVEDATA_FLASH1M, GPIO_NONE, IDLE_LOOP_NONE },
66 { "B24E", SAVEDATA_FLASH1M, GPIO_NONE, IDLE_LOOP_NONE },
67 { "B24P", SAVEDATA_FLASH1M, GPIO_NONE, IDLE_LOOP_NONE },
68 { "B24U", SAVEDATA_FLASH1M, GPIO_NONE, IDLE_LOOP_NONE },
69
70 // Pokemon FireRed
71 { "BPRJ", SAVEDATA_FLASH1M, GPIO_NONE, IDLE_LOOP_NONE },
72 { "BPRE", SAVEDATA_FLASH1M, GPIO_NONE, IDLE_LOOP_NONE },
73 { "BPRP", SAVEDATA_FLASH1M, GPIO_NONE, IDLE_LOOP_NONE },
74
75 // Pokemon LeafGreen
76 { "BPGJ", SAVEDATA_FLASH1M, GPIO_NONE, IDLE_LOOP_NONE },
77 { "BPGE", SAVEDATA_FLASH1M, GPIO_NONE, IDLE_LOOP_NONE },
78 { "BPGP", SAVEDATA_FLASH1M, GPIO_NONE, IDLE_LOOP_NONE },
79
80 // RockMan EXE 4.5 - Real Operation
81 { "BR4J", SAVEDATA_FLASH512, GPIO_RTC, IDLE_LOOP_NONE },
82
83 // Shin Bokura no Taiyou: Gyakushuu no Sabata
84 { "U33J", SAVEDATA_EEPROM, GPIO_RTC | GPIO_LIGHT_SENSOR, IDLE_LOOP_NONE },
85
86 // Super Mario Advance 4
87 { "AX4J", SAVEDATA_FLASH1M, GPIO_NONE, IDLE_LOOP_NONE },
88 { "AX4E", SAVEDATA_FLASH1M, GPIO_NONE, IDLE_LOOP_NONE },
89 { "AX4P", SAVEDATA_FLASH1M, GPIO_NONE, IDLE_LOOP_NONE },
90
91 // Top Gun - Combat Zones
92 { "A2YE", SAVEDATA_FORCE_NONE, GPIO_NONE, IDLE_LOOP_NONE },
93
94 // Wario Ware Twisted
95 { "RZWJ", SAVEDATA_SRAM, GPIO_RUMBLE | GPIO_GYRO, IDLE_LOOP_NONE },
96 { "RZWE", SAVEDATA_SRAM, GPIO_RUMBLE | GPIO_GYRO, IDLE_LOOP_NONE },
97 { "RZWP", SAVEDATA_SRAM, GPIO_RUMBLE | GPIO_GYRO, IDLE_LOOP_NONE },
98
99 // Yoshi's Universal Gravitation
100 { "KYGJ", SAVEDATA_EEPROM, GPIO_TILT, IDLE_LOOP_NONE },
101 { "KYGE", SAVEDATA_EEPROM, GPIO_TILT, IDLE_LOOP_NONE },
102 { "KYGP", SAVEDATA_EEPROM, GPIO_TILT, IDLE_LOOP_NONE },
103
104 { { 0, 0, 0, 0 }, 0, 0, IDLE_LOOP_NONE }
105};
106
107bool GBAOverrideFind(const struct Configuration* config, struct GBACartridgeOverride* override) {
108 override->savetype = SAVEDATA_AUTODETECT;
109 override->hardware = GPIO_NONE;
110 override->idleLoop = IDLE_LOOP_NONE;
111 bool found;
112
113 if (override->id[0] == 'F') {
114 // Classic NES Series
115 override->savetype = SAVEDATA_EEPROM;
116 found = true;
117 } else {
118 int i;
119 for (i = 0; _overrides[i].id[0]; ++i) {
120 if (memcmp(override->id, _overrides[i].id, sizeof(override->id)) == 0) {
121 *override = _overrides[i];
122 found = true;
123 break;
124 }
125 }
126 }
127
128 if (config) {
129 char sectionName[16];
130 snprintf(sectionName, sizeof(sectionName), "override.%c%c%c%c", override->id[0], override->id[1], override->id[2], override->id[3]);
131 const char* savetype = ConfigurationGetValue(config, sectionName, "savetype");
132 const char* hardware = ConfigurationGetValue(config, sectionName, "hardware");
133 const char* idleLoop = ConfigurationGetValue(config, sectionName, "idleLoop");
134
135 if (savetype) {
136 if (strcasecmp(savetype, "SRAM") == 0) {
137 found = true;
138 override->savetype = SAVEDATA_SRAM;
139 } else if (strcasecmp(savetype, "EEPROM") == 0) {
140 found = true;
141 override->savetype = SAVEDATA_EEPROM;
142 } else if (strcasecmp(savetype, "FLASH512") == 0) {
143 found = true;
144 override->savetype = SAVEDATA_FLASH512;
145 } else if (strcasecmp(savetype, "FLASH1M") == 0) {
146 found = true;
147 override->savetype = SAVEDATA_FLASH1M;
148 } else if (strcasecmp(savetype, "NONE") == 0) {
149 found = true;
150 override->savetype = SAVEDATA_FORCE_NONE;
151 }
152 }
153
154 if (hardware) {
155 char* end;
156 long type = strtoul(hardware, &end, 0);
157 if (end && !*end) {
158 override->hardware = type;
159 found = true;
160 }
161 }
162
163 if (idleLoop) {
164 char* end;
165 uint32_t address = strtoul(idleLoop, &end, 16);
166 if (end && !*end) {
167 override->idleLoop = address;
168 found = true;
169 }
170 }
171 }
172 return found;
173}
174
175void GBAOverrideSave(struct Configuration* config, const struct GBACartridgeOverride* override) {
176 char sectionName[16];
177 snprintf(sectionName, sizeof(sectionName), "override.%c%c%c%c", override->id[0], override->id[1], override->id[2], override->id[3]);
178 const char* savetype = 0;
179 switch (override->savetype) {
180 case SAVEDATA_SRAM:
181 savetype = "SRAM";
182 break;
183 case SAVEDATA_EEPROM:
184 savetype = "EEPROM";
185 break;
186 case SAVEDATA_FLASH512:
187 savetype = "FLASH512";
188 break;
189 case SAVEDATA_FLASH1M:
190 savetype = "FLASH1M";
191 break;
192 case SAVEDATA_FORCE_NONE:
193 savetype = "NONE";
194 break;
195 case SAVEDATA_AUTODETECT:
196 break;
197 }
198 ConfigurationSetValue(config, sectionName, "savetype", savetype);
199
200 if (override->hardware != GPIO_NO_OVERRIDE) {
201 ConfigurationSetIntValue(config, sectionName, "hardware", override->hardware);
202 } else {
203 ConfigurationClearValue(config, sectionName, "hardware");
204 }
205
206 if (override->idleLoop != IDLE_LOOP_NONE) {
207 ConfigurationSetUIntValue(config, sectionName, "idleLoop", override->idleLoop);
208 } else {
209 ConfigurationClearValue(config, sectionName, "idleLoop");
210 }
211}
212
213void GBAOverrideApply(struct GBA* gba, const struct GBACartridgeOverride* override) {
214 if (override->savetype != SAVEDATA_AUTODETECT) {
215 GBASavedataForceType(&gba->memory.savedata, override->savetype);
216 }
217
218 if (override->hardware != GPIO_NO_OVERRIDE) {
219 GBAGPIOClear(&gba->memory.gpio);
220
221 if (override->hardware & GPIO_RTC) {
222 GBAGPIOInitRTC(&gba->memory.gpio);
223 }
224
225 if (override->hardware & GPIO_GYRO) {
226 GBAGPIOInitGyro(&gba->memory.gpio);
227 }
228
229 if (override->hardware & GPIO_RUMBLE) {
230 GBAGPIOInitRumble(&gba->memory.gpio);
231 }
232
233 if (override->hardware & GPIO_LIGHT_SENSOR) {
234 GBAGPIOInitLightSensor(&gba->memory.gpio);
235 }
236
237 if (override->hardware & GPIO_TILT) {
238 GBAGPIOInitTilt(&gba->memory.gpio);
239 }
240 }
241
242 if (override->idleLoop != IDLE_LOOP_NONE) {
243 gba->idleLoop = override->idleLoop;
244 if (gba->idleOptimization == IDLE_LOOP_DETECT) {
245 gba->idleOptimization = IDLE_LOOP_REMOVE;
246 }
247 }
248}