mirror of https://github.com/mgba-emu/mgba.git
GBA: Configurable game overrides
This commit is contained in:
parent
eced06bc2a
commit
466916729e
1
CHANGES
1
CHANGES
|
@ -18,6 +18,7 @@ Features:
|
||||||
- Support IPv6
|
- Support IPv6
|
||||||
- Save directory of last loaded file
|
- Save directory of last loaded file
|
||||||
- Support BPS patches
|
- Support BPS patches
|
||||||
|
- Configurable game overrides
|
||||||
Bugfixes:
|
Bugfixes:
|
||||||
- Qt: Fix issue with set frame sizes being the wrong height
|
- Qt: Fix issue with set frame sizes being the wrong height
|
||||||
- Qt: Fix emulator crashing when full screen if a game is not running
|
- Qt: Fix emulator crashing when full screen if a game is not running
|
||||||
|
|
|
@ -0,0 +1,199 @@
|
||||||
|
/* Copyright (c) 2013-2015 Jeffrey Pfau
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
#include "gba-overrides.h"
|
||||||
|
|
||||||
|
#include "gba.h"
|
||||||
|
#include "gba-gpio.h"
|
||||||
|
|
||||||
|
#include "util/configuration.h"
|
||||||
|
|
||||||
|
static const struct GBACartridgeOverride _overrides[] = {
|
||||||
|
// Boktai: The Sun is in Your Hand
|
||||||
|
{ "U3IJ", SAVEDATA_EEPROM, GPIO_RTC | GPIO_LIGHT_SENSOR, -1 },
|
||||||
|
{ "U3IE", SAVEDATA_EEPROM, GPIO_RTC | GPIO_LIGHT_SENSOR, -1 },
|
||||||
|
{ "U3IP", SAVEDATA_EEPROM, GPIO_RTC | GPIO_LIGHT_SENSOR, -1 },
|
||||||
|
|
||||||
|
// Boktai 2: Solar Boy Django
|
||||||
|
{ "U32J", SAVEDATA_EEPROM, GPIO_RTC | GPIO_LIGHT_SENSOR, -1 },
|
||||||
|
{ "U32E", SAVEDATA_EEPROM, GPIO_RTC | GPIO_LIGHT_SENSOR, -1 },
|
||||||
|
{ "U32P", SAVEDATA_EEPROM, GPIO_RTC | GPIO_LIGHT_SENSOR, -1 },
|
||||||
|
|
||||||
|
// Drill Dozer
|
||||||
|
{ "V49J", SAVEDATA_SRAM, GPIO_RUMBLE, -1 },
|
||||||
|
{ "V49E", SAVEDATA_SRAM, GPIO_RUMBLE, -1 },
|
||||||
|
|
||||||
|
// Final Fantasy Tactics Advance
|
||||||
|
{ "AFXE", SAVEDATA_FLASH512, GPIO_NONE, 0x8000418 },
|
||||||
|
|
||||||
|
// Koro Koro Puzzle - Happy Panechu!
|
||||||
|
{ "KHPJ", SAVEDATA_EEPROM, GPIO_TILT, -1 },
|
||||||
|
|
||||||
|
// Mega Man Battle Network
|
||||||
|
{ "AREE", SAVEDATA_SRAM, GPIO_NONE, 0x800032E },
|
||||||
|
|
||||||
|
// Pokemon Ruby
|
||||||
|
{ "AXVJ", SAVEDATA_FLASH1M, GPIO_RTC, -1 },
|
||||||
|
{ "AXVE", SAVEDATA_FLASH1M, GPIO_RTC, -1 },
|
||||||
|
{ "AXVP", SAVEDATA_FLASH1M, GPIO_RTC, -1 },
|
||||||
|
{ "AXVI", SAVEDATA_FLASH1M, GPIO_RTC, -1 },
|
||||||
|
{ "AXVS", SAVEDATA_FLASH1M, GPIO_RTC, -1 },
|
||||||
|
{ "AXVD", SAVEDATA_FLASH1M, GPIO_RTC, -1 },
|
||||||
|
{ "AXVF", SAVEDATA_FLASH1M, GPIO_RTC, -1 },
|
||||||
|
|
||||||
|
// Pokemon Sapphire
|
||||||
|
{ "AXPJ", SAVEDATA_FLASH1M, GPIO_RTC, -1 },
|
||||||
|
{ "AXPE", SAVEDATA_FLASH1M, GPIO_RTC, -1 },
|
||||||
|
{ "AXPP", SAVEDATA_FLASH1M, GPIO_RTC, -1 },
|
||||||
|
{ "AXPI", SAVEDATA_FLASH1M, GPIO_RTC, -1 },
|
||||||
|
{ "AXPS", SAVEDATA_FLASH1M, GPIO_RTC, -1 },
|
||||||
|
{ "AXPD", SAVEDATA_FLASH1M, GPIO_RTC, -1 },
|
||||||
|
{ "AXPF", SAVEDATA_FLASH1M, GPIO_RTC, -1 },
|
||||||
|
|
||||||
|
// Pokemon Emerald
|
||||||
|
{ "BPEJ", SAVEDATA_FLASH1M, GPIO_RTC, -1 },
|
||||||
|
{ "BPEE", SAVEDATA_FLASH1M, GPIO_RTC, -1 },
|
||||||
|
{ "BPEP", SAVEDATA_FLASH1M, GPIO_RTC, -1 },
|
||||||
|
{ "BPEI", SAVEDATA_FLASH1M, GPIO_RTC, -1 },
|
||||||
|
{ "BPES", SAVEDATA_FLASH1M, GPIO_RTC, -1 },
|
||||||
|
{ "BPED", SAVEDATA_FLASH1M, GPIO_RTC, -1 },
|
||||||
|
{ "BPEF", SAVEDATA_FLASH1M, GPIO_RTC, -1 },
|
||||||
|
|
||||||
|
// Pokemon Mystery Dungeon
|
||||||
|
{ "B24J", SAVEDATA_FLASH1M, GPIO_NONE, -1 },
|
||||||
|
{ "B24E", SAVEDATA_FLASH1M, GPIO_NONE, -1 },
|
||||||
|
{ "B24P", SAVEDATA_FLASH1M, GPIO_NONE, -1 },
|
||||||
|
{ "B24U", SAVEDATA_FLASH1M, GPIO_NONE, -1 },
|
||||||
|
|
||||||
|
// Pokemon FireRed
|
||||||
|
{ "BPRJ", SAVEDATA_FLASH1M, GPIO_NONE, -1 },
|
||||||
|
{ "BPRE", SAVEDATA_FLASH1M, GPIO_NONE, -1 },
|
||||||
|
{ "BPRP", SAVEDATA_FLASH1M, GPIO_NONE, -1 },
|
||||||
|
|
||||||
|
// Pokemon LeafGreen
|
||||||
|
{ "BPGJ", SAVEDATA_FLASH1M, GPIO_NONE, -1 },
|
||||||
|
{ "BPGE", SAVEDATA_FLASH1M, GPIO_NONE, -1 },
|
||||||
|
{ "BPGP", SAVEDATA_FLASH1M, GPIO_NONE, -1 },
|
||||||
|
|
||||||
|
// RockMan EXE 4.5 - Real Operation
|
||||||
|
{ "BR4J", SAVEDATA_FLASH512, GPIO_RTC, -1 },
|
||||||
|
|
||||||
|
// Shin Bokura no Taiyou: Gyakushuu no Sabata
|
||||||
|
{ "U33J", SAVEDATA_EEPROM, GPIO_RTC | GPIO_LIGHT_SENSOR, -1 },
|
||||||
|
|
||||||
|
// Super Mario Advance 4
|
||||||
|
{ "AX4J", SAVEDATA_FLASH1M, GPIO_NONE, -1 },
|
||||||
|
{ "AX4E", SAVEDATA_FLASH1M, GPIO_NONE, -1 },
|
||||||
|
{ "AX4P", SAVEDATA_FLASH1M, GPIO_NONE, -1 },
|
||||||
|
|
||||||
|
// Top Gun - Combat Zones
|
||||||
|
{ "A2YE", SAVEDATA_FORCE_NONE, GPIO_NONE, -1 },
|
||||||
|
|
||||||
|
// Wario Ware Twisted
|
||||||
|
{ "RZWJ", SAVEDATA_SRAM, GPIO_RUMBLE | GPIO_GYRO, -1 },
|
||||||
|
{ "RZWE", SAVEDATA_SRAM, GPIO_RUMBLE | GPIO_GYRO, -1 },
|
||||||
|
{ "RZWP", SAVEDATA_SRAM, GPIO_RUMBLE | GPIO_GYRO, -1 },
|
||||||
|
|
||||||
|
// Yoshi's Universal Gravitation
|
||||||
|
{ "KYGJ", SAVEDATA_EEPROM, GPIO_TILT, -1 },
|
||||||
|
{ "KYGE", SAVEDATA_EEPROM, GPIO_TILT, -1 },
|
||||||
|
{ "KYGP", SAVEDATA_EEPROM, GPIO_TILT, -1 },
|
||||||
|
|
||||||
|
{ { 0, 0, 0, 0 }, 0, 0, -1 }
|
||||||
|
};
|
||||||
|
|
||||||
|
bool GBAOverrideFind(const struct Configuration* config, struct GBACartridgeOverride* override) {
|
||||||
|
override->savetype = SAVEDATA_AUTODETECT;
|
||||||
|
override->hardware = GPIO_NONE;
|
||||||
|
override->idleLoop = -1;
|
||||||
|
bool found;
|
||||||
|
|
||||||
|
if (override->id[0] == 'F') {
|
||||||
|
// Classic NES Series
|
||||||
|
override->savetype = SAVEDATA_EEPROM;
|
||||||
|
found = true;
|
||||||
|
} else {
|
||||||
|
int i;
|
||||||
|
for (i = 0; _overrides[i].id[0]; ++i) {
|
||||||
|
if (memcmp(override->id, _overrides[i].id, sizeof(override->id)) == 0) {
|
||||||
|
*override = _overrides[i];
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config) {
|
||||||
|
char sectionName[16];
|
||||||
|
snprintf(sectionName, sizeof(sectionName), "override.%c%c%c%c", override->id[0], override->id[1], override->id[2], override->id[3]);
|
||||||
|
const char* savetype = ConfigurationGetValue(config, sectionName, "savetype");
|
||||||
|
const char* hardware = ConfigurationGetValue(config, sectionName, "hardware");
|
||||||
|
const char* idleLoop = ConfigurationGetValue(config, sectionName, "idleLoop");
|
||||||
|
|
||||||
|
if (savetype) {
|
||||||
|
if (strcasecmp(savetype, "SRAM") == 0) {
|
||||||
|
found = true;
|
||||||
|
override->savetype = SAVEDATA_SRAM;
|
||||||
|
} else if (strcasecmp(savetype, "EEPROM") == 0) {
|
||||||
|
found = true;
|
||||||
|
override->savetype = SAVEDATA_EEPROM;
|
||||||
|
} else if (strcasecmp(savetype, "FLASH512") == 0) {
|
||||||
|
found = true;
|
||||||
|
override->savetype = SAVEDATA_FLASH512;
|
||||||
|
} else if (strcasecmp(savetype, "FLASH1M") == 0) {
|
||||||
|
found = true;
|
||||||
|
override->savetype = SAVEDATA_FLASH1M;
|
||||||
|
} else if (strcasecmp(savetype, "NONE") == 0) {
|
||||||
|
found = true;
|
||||||
|
override->savetype = SAVEDATA_FORCE_NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hardware) {
|
||||||
|
char* end;
|
||||||
|
long type = strtoul(hardware, &end, 0);
|
||||||
|
if (end && !*end) {
|
||||||
|
override->hardware = type;
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (idleLoop) {
|
||||||
|
char* end;
|
||||||
|
uint32_t address = strtoul(idleLoop, &end, 16);
|
||||||
|
if (end && !*end) {
|
||||||
|
override->idleLoop = address;
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GBAOverrideApply(struct GBA* gba, const struct GBACartridgeOverride* override) {
|
||||||
|
GBASavedataForceType(&gba->memory.savedata, override->savetype);
|
||||||
|
|
||||||
|
if (override->hardware & GPIO_RTC) {
|
||||||
|
GBAGPIOInitRTC(&gba->memory.gpio);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (override->hardware & GPIO_GYRO) {
|
||||||
|
GBAGPIOInitGyro(&gba->memory.gpio);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (override->hardware & GPIO_RUMBLE) {
|
||||||
|
GBAGPIOInitRumble(&gba->memory.gpio);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (override->hardware & GPIO_LIGHT_SENSOR) {
|
||||||
|
GBAGPIOInitLightSensor(&gba->memory.gpio);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (override->hardware & GPIO_TILT) {
|
||||||
|
GBAGPIOInitTilt(&gba->memory.gpio);
|
||||||
|
}
|
||||||
|
|
||||||
|
gba->busyLoop = override->idleLoop;
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
/* Copyright (c) 2013-2015 Jeffrey Pfau
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
#ifndef GBA_OVERRIDES_H
|
||||||
|
#define GBA_OVERRIDES_H
|
||||||
|
|
||||||
|
#include "util/common.h"
|
||||||
|
|
||||||
|
#include "gba-savedata.h"
|
||||||
|
|
||||||
|
struct GBACartridgeOverride {
|
||||||
|
char id[4];
|
||||||
|
enum SavedataType savetype;
|
||||||
|
int hardware;
|
||||||
|
uint32_t idleLoop;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Configuration;
|
||||||
|
bool GBAOverrideFind(const struct Configuration*, struct GBACartridgeOverride* override);
|
||||||
|
bool GBAOverrideSave(struct Configuration*, const struct GBACartridgeOverride* override);
|
||||||
|
|
||||||
|
struct GBA;
|
||||||
|
void GBAOverrideApply(struct GBA*, const struct GBACartridgeOverride*);
|
||||||
|
|
||||||
|
#endif
|
|
@ -8,6 +8,7 @@
|
||||||
#include "arm.h"
|
#include "arm.h"
|
||||||
#include "gba.h"
|
#include "gba.h"
|
||||||
#include "gba-config.h"
|
#include "gba-config.h"
|
||||||
|
#include "gba-overrides.h"
|
||||||
#include "gba-serialize.h"
|
#include "gba-serialize.h"
|
||||||
|
|
||||||
#include "debugger/debugger.h"
|
#include "debugger/debugger.h"
|
||||||
|
@ -141,6 +142,14 @@ static THREAD_ENTRY _GBAThreadRun(void* context) {
|
||||||
|
|
||||||
if (threadContext->rom) {
|
if (threadContext->rom) {
|
||||||
GBALoadROM(&gba, threadContext->rom, threadContext->save, threadContext->fname);
|
GBALoadROM(&gba, threadContext->rom, threadContext->save, threadContext->fname);
|
||||||
|
|
||||||
|
struct GBACartridgeOverride override;
|
||||||
|
const struct GBACartridge* cart = (const struct GBACartridge*) gba.memory.rom;
|
||||||
|
memcpy(override.id, &cart->id, sizeof(override.id));
|
||||||
|
if (GBAOverrideFind(threadContext->overrides, &override)) {
|
||||||
|
GBAOverrideApply(&gba, &override);
|
||||||
|
}
|
||||||
|
|
||||||
if (threadContext->bios && GBAIsBIOS(threadContext->bios)) {
|
if (threadContext->bios && GBAIsBIOS(threadContext->bios)) {
|
||||||
GBALoadBIOS(&gba, threadContext->bios);
|
GBALoadBIOS(&gba, threadContext->bios);
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,6 +70,7 @@ struct GBAThread {
|
||||||
const char* fname;
|
const char* fname;
|
||||||
int activeKeys;
|
int activeKeys;
|
||||||
struct GBAAVStream* stream;
|
struct GBAAVStream* stream;
|
||||||
|
struct Configuration* overrides;
|
||||||
|
|
||||||
// Run-time options
|
// Run-time options
|
||||||
int frameskip;
|
int frameskip;
|
||||||
|
|
144
src/gba/gba.c
144
src/gba/gba.c
|
@ -24,107 +24,6 @@ const uint32_t GBA_COMPONENT_MAGIC = 0x1000000;
|
||||||
static const size_t GBA_ROM_MAGIC_OFFSET = 2;
|
static const size_t GBA_ROM_MAGIC_OFFSET = 2;
|
||||||
static const uint8_t GBA_ROM_MAGIC[] = { 0x00, 0xEA };
|
static const uint8_t GBA_ROM_MAGIC[] = { 0x00, 0xEA };
|
||||||
|
|
||||||
struct GBACartridgeOverride {
|
|
||||||
const char id[4];
|
|
||||||
enum SavedataType type;
|
|
||||||
int gpio;
|
|
||||||
uint32_t busyLoop;
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct GBACartridgeOverride _overrides[] = {
|
|
||||||
// Boktai: The Sun is in Your Hand
|
|
||||||
{ "U3IJ", SAVEDATA_EEPROM, GPIO_RTC | GPIO_LIGHT_SENSOR, -1 },
|
|
||||||
{ "U3IE", SAVEDATA_EEPROM, GPIO_RTC | GPIO_LIGHT_SENSOR, -1 },
|
|
||||||
{ "U3IP", SAVEDATA_EEPROM, GPIO_RTC | GPIO_LIGHT_SENSOR, -1 },
|
|
||||||
|
|
||||||
// Boktai 2: Solar Boy Django
|
|
||||||
{ "U32J", SAVEDATA_EEPROM, GPIO_RTC | GPIO_LIGHT_SENSOR, -1 },
|
|
||||||
{ "U32E", SAVEDATA_EEPROM, GPIO_RTC | GPIO_LIGHT_SENSOR, -1 },
|
|
||||||
{ "U32P", SAVEDATA_EEPROM, GPIO_RTC | GPIO_LIGHT_SENSOR, -1 },
|
|
||||||
|
|
||||||
// Drill Dozer
|
|
||||||
{ "V49J", SAVEDATA_SRAM, GPIO_RUMBLE, -1 },
|
|
||||||
{ "V49E", SAVEDATA_SRAM, GPIO_RUMBLE, -1 },
|
|
||||||
|
|
||||||
// Final Fantasy Tactics Advance
|
|
||||||
{ "AFXE", SAVEDATA_FLASH512, GPIO_NONE, 0x8000418 },
|
|
||||||
|
|
||||||
// Koro Koro Puzzle - Happy Panechu!
|
|
||||||
{ "KHPJ", SAVEDATA_EEPROM, GPIO_TILT, -1 },
|
|
||||||
|
|
||||||
// Mega Man Battle Network
|
|
||||||
{ "AREE", SAVEDATA_SRAM, GPIO_NONE, 0x800032E },
|
|
||||||
|
|
||||||
// Pokemon Ruby
|
|
||||||
{ "AXVJ", SAVEDATA_FLASH1M, GPIO_RTC, -1 },
|
|
||||||
{ "AXVE", SAVEDATA_FLASH1M, GPIO_RTC, -1 },
|
|
||||||
{ "AXVP", SAVEDATA_FLASH1M, GPIO_RTC, -1 },
|
|
||||||
{ "AXVI", SAVEDATA_FLASH1M, GPIO_RTC, -1 },
|
|
||||||
{ "AXVS", SAVEDATA_FLASH1M, GPIO_RTC, -1 },
|
|
||||||
{ "AXVD", SAVEDATA_FLASH1M, GPIO_RTC, -1 },
|
|
||||||
{ "AXVF", SAVEDATA_FLASH1M, GPIO_RTC, -1 },
|
|
||||||
|
|
||||||
// Pokemon Sapphire
|
|
||||||
{ "AXPJ", SAVEDATA_FLASH1M, GPIO_RTC, -1 },
|
|
||||||
{ "AXPE", SAVEDATA_FLASH1M, GPIO_RTC, -1 },
|
|
||||||
{ "AXPP", SAVEDATA_FLASH1M, GPIO_RTC, -1 },
|
|
||||||
{ "AXPI", SAVEDATA_FLASH1M, GPIO_RTC, -1 },
|
|
||||||
{ "AXPS", SAVEDATA_FLASH1M, GPIO_RTC, -1 },
|
|
||||||
{ "AXPD", SAVEDATA_FLASH1M, GPIO_RTC, -1 },
|
|
||||||
{ "AXPF", SAVEDATA_FLASH1M, GPIO_RTC, -1 },
|
|
||||||
|
|
||||||
// Pokemon Emerald
|
|
||||||
{ "BPEJ", SAVEDATA_FLASH1M, GPIO_RTC, -1 },
|
|
||||||
{ "BPEE", SAVEDATA_FLASH1M, GPIO_RTC, -1 },
|
|
||||||
{ "BPEP", SAVEDATA_FLASH1M, GPIO_RTC, -1 },
|
|
||||||
{ "BPEI", SAVEDATA_FLASH1M, GPIO_RTC, -1 },
|
|
||||||
{ "BPES", SAVEDATA_FLASH1M, GPIO_RTC, -1 },
|
|
||||||
{ "BPED", SAVEDATA_FLASH1M, GPIO_RTC, -1 },
|
|
||||||
{ "BPEF", SAVEDATA_FLASH1M, GPIO_RTC, -1 },
|
|
||||||
|
|
||||||
// Pokemon Mystery Dungeon
|
|
||||||
{ "B24J", SAVEDATA_FLASH1M, GPIO_NONE, -1 },
|
|
||||||
{ "B24E", SAVEDATA_FLASH1M, GPIO_NONE, -1 },
|
|
||||||
{ "B24P", SAVEDATA_FLASH1M, GPIO_NONE, -1 },
|
|
||||||
{ "B24U", SAVEDATA_FLASH1M, GPIO_NONE, -1 },
|
|
||||||
|
|
||||||
// Pokemon FireRed
|
|
||||||
{ "BPRJ", SAVEDATA_FLASH1M, GPIO_NONE, -1 },
|
|
||||||
{ "BPRE", SAVEDATA_FLASH1M, GPIO_NONE, -1 },
|
|
||||||
{ "BPRP", SAVEDATA_FLASH1M, GPIO_NONE, -1 },
|
|
||||||
|
|
||||||
// Pokemon LeafGreen
|
|
||||||
{ "BPGJ", SAVEDATA_FLASH1M, GPIO_NONE, -1 },
|
|
||||||
{ "BPGE", SAVEDATA_FLASH1M, GPIO_NONE, -1 },
|
|
||||||
{ "BPGP", SAVEDATA_FLASH1M, GPIO_NONE, -1 },
|
|
||||||
|
|
||||||
// RockMan EXE 4.5 - Real Operation
|
|
||||||
{ "BR4J", SAVEDATA_FLASH512, GPIO_RTC, -1 },
|
|
||||||
|
|
||||||
// Shin Bokura no Taiyou: Gyakushuu no Sabata
|
|
||||||
{ "U33J", SAVEDATA_EEPROM, GPIO_RTC | GPIO_LIGHT_SENSOR, -1 },
|
|
||||||
|
|
||||||
// Super Mario Advance 4
|
|
||||||
{ "AX4J", SAVEDATA_FLASH1M, GPIO_NONE, -1 },
|
|
||||||
{ "AX4E", SAVEDATA_FLASH1M, GPIO_NONE, -1 },
|
|
||||||
{ "AX4P", SAVEDATA_FLASH1M, GPIO_NONE, -1 },
|
|
||||||
|
|
||||||
// Top Gun - Combat Zones
|
|
||||||
{ "A2YE", SAVEDATA_FORCE_NONE, GPIO_NONE, -1 },
|
|
||||||
|
|
||||||
// Wario Ware Twisted
|
|
||||||
{ "RZWJ", SAVEDATA_SRAM, GPIO_RUMBLE | GPIO_GYRO, -1 },
|
|
||||||
{ "RZWE", SAVEDATA_SRAM, GPIO_RUMBLE | GPIO_GYRO, -1 },
|
|
||||||
{ "RZWP", SAVEDATA_SRAM, GPIO_RUMBLE | GPIO_GYRO, -1 },
|
|
||||||
|
|
||||||
// Yoshi's Universal Gravitation
|
|
||||||
{ "KYGJ", SAVEDATA_EEPROM, GPIO_TILT, -1 },
|
|
||||||
{ "KYGE", SAVEDATA_EEPROM, GPIO_TILT, -1 },
|
|
||||||
{ "KYGP", SAVEDATA_EEPROM, GPIO_TILT, -1 },
|
|
||||||
|
|
||||||
{ { 0, 0, 0, 0 }, 0, 0, -1 }
|
|
||||||
};
|
|
||||||
|
|
||||||
static void GBAInit(struct ARMCore* cpu, struct ARMComponent* component);
|
static void GBAInit(struct ARMCore* cpu, struct ARMComponent* component);
|
||||||
static void GBAInterruptHandlerInit(struct ARMInterruptHandler* irqh);
|
static void GBAInterruptHandlerInit(struct ARMInterruptHandler* irqh);
|
||||||
static void GBAProcessEvents(struct ARMCore* cpu);
|
static void GBAProcessEvents(struct ARMCore* cpu);
|
||||||
|
@ -132,8 +31,6 @@ static int32_t GBATimersProcessEvents(struct GBA* gba, int32_t cycles);
|
||||||
static void GBAHitStub(struct ARMCore* cpu, uint32_t opcode);
|
static void GBAHitStub(struct ARMCore* cpu, uint32_t opcode);
|
||||||
static void GBAIllegal(struct ARMCore* cpu, uint32_t opcode);
|
static void GBAIllegal(struct ARMCore* cpu, uint32_t opcode);
|
||||||
|
|
||||||
static void _checkOverrides(struct GBA* gba, uint32_t code);
|
|
||||||
|
|
||||||
void GBACreate(struct GBA* gba) {
|
void GBACreate(struct GBA* gba) {
|
||||||
gba->d.id = GBA_COMPONENT_MAGIC;
|
gba->d.id = GBA_COMPONENT_MAGIC;
|
||||||
gba->d.init = GBAInit;
|
gba->d.init = GBAInit;
|
||||||
|
@ -464,7 +361,6 @@ void GBALoadROM(struct GBA* gba, struct VFile* vf, struct VFile* sav, const char
|
||||||
gba->romCrc32 = doCrc32(gba->memory.rom, gba->memory.romSize);
|
gba->romCrc32 = doCrc32(gba->memory.rom, gba->memory.romSize);
|
||||||
GBASavedataInit(&gba->memory.savedata, sav);
|
GBASavedataInit(&gba->memory.savedata, sav);
|
||||||
GBAGPIOInit(&gba->memory.gpio, &((uint16_t*) gba->memory.rom)[GPIO_REG_DATA >> 1]);
|
GBAGPIOInit(&gba->memory.gpio, &((uint16_t*) gba->memory.rom)[GPIO_REG_DATA >> 1]);
|
||||||
_checkOverrides(gba, ((struct GBACartridge*) gba->memory.rom)->id);
|
|
||||||
// TODO: error check
|
// TODO: error check
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -739,43 +635,3 @@ void GBAIllegal(struct ARMCore* cpu, uint32_t opcode) {
|
||||||
ARMDebuggerEnter(gba->debugger, DEBUGGER_ENTER_ILLEGAL_OP);
|
ARMDebuggerEnter(gba->debugger, DEBUGGER_ENTER_ILLEGAL_OP);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _checkOverrides(struct GBA* gba, uint32_t id) {
|
|
||||||
int i;
|
|
||||||
gba->busyLoop = -1;
|
|
||||||
if ((id & 0xFF) == 'F') {
|
|
||||||
GBALog(gba, GBA_LOG_DEBUG, "Found Classic NES Series game, using EEPROM saves");
|
|
||||||
GBASavedataInitEEPROM(&gba->memory.savedata);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (i = 0; _overrides[i].id[0]; ++i) {
|
|
||||||
const uint32_t* overrideId = (const uint32_t*) _overrides[i].id;
|
|
||||||
if (*overrideId == id) {
|
|
||||||
GBALog(gba, GBA_LOG_DEBUG, "Found override for game %s!", _overrides[i].id);
|
|
||||||
GBASavedataForceType(&gba->memory.savedata, _overrides[i].type);
|
|
||||||
|
|
||||||
if (_overrides[i].gpio & GPIO_RTC) {
|
|
||||||
GBAGPIOInitRTC(&gba->memory.gpio);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_overrides[i].gpio & GPIO_GYRO) {
|
|
||||||
GBAGPIOInitGyro(&gba->memory.gpio);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_overrides[i].gpio & GPIO_RUMBLE) {
|
|
||||||
GBAGPIOInitRumble(&gba->memory.gpio);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_overrides[i].gpio & GPIO_LIGHT_SENSOR) {
|
|
||||||
GBAGPIOInitLightSensor(&gba->memory.gpio);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_overrides[i].gpio & GPIO_TILT) {
|
|
||||||
GBAGPIOInitTilt(&gba->memory.gpio);
|
|
||||||
}
|
|
||||||
|
|
||||||
gba->busyLoop = _overrides[i].busyLoop;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -76,6 +76,7 @@ int main(int argc, char** argv) {
|
||||||
}
|
}
|
||||||
|
|
||||||
context.debugger = createDebugger(&args, &context);
|
context.debugger = createDebugger(&args, &context);
|
||||||
|
context.overrides = &config.configTable;
|
||||||
char gameCode[5] = { 0 };
|
char gameCode[5] = { 0 };
|
||||||
|
|
||||||
GBAConfigMap(&config, &opts);
|
GBAConfigMap(&config, &opts);
|
||||||
|
|
|
@ -75,6 +75,8 @@ public:
|
||||||
QList<QString> getMRU() const;
|
QList<QString> getMRU() const;
|
||||||
void setMRU(const QList<QString>& mru);
|
void setMRU(const QList<QString>& mru);
|
||||||
|
|
||||||
|
Configuration* overrides() { return &m_config.configTable; } // TODO: Make this not return the whole table
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void setOption(const char* key, bool value);
|
void setOption(const char* key, bool value);
|
||||||
void setOption(const char* key, int value);
|
void setOption(const char* key, int value);
|
||||||
|
|
|
@ -22,6 +22,7 @@ extern "C" {
|
||||||
|
|
||||||
struct GBAAudio;
|
struct GBAAudio;
|
||||||
struct GBAVideoSoftwareRenderer;
|
struct GBAVideoSoftwareRenderer;
|
||||||
|
struct Configuration;
|
||||||
|
|
||||||
class QThread;
|
class QThread;
|
||||||
|
|
||||||
|
@ -53,6 +54,7 @@ public:
|
||||||
bool videoSync() const { return m_videoSync; }
|
bool videoSync() const { return m_videoSync; }
|
||||||
|
|
||||||
void setInputController(InputController* controller) { m_inputController = controller; }
|
void setInputController(InputController* controller) { m_inputController = controller; }
|
||||||
|
void setOverrides(Configuration* overrides) { m_threadContext.overrides = overrides; }
|
||||||
|
|
||||||
#ifdef USE_GDB_STUB
|
#ifdef USE_GDB_STUB
|
||||||
ARMDebugger* debugger();
|
ARMDebugger* debugger();
|
||||||
|
|
|
@ -56,6 +56,7 @@ Window::Window(ConfigController* config, QWidget* parent)
|
||||||
setFocusPolicy(Qt::StrongFocus);
|
setFocusPolicy(Qt::StrongFocus);
|
||||||
m_controller = new GameController(this);
|
m_controller = new GameController(this);
|
||||||
m_controller->setInputController(&m_inputController);
|
m_controller->setInputController(&m_inputController);
|
||||||
|
m_controller->setOverrides(m_config->overrides());
|
||||||
|
|
||||||
QGLFormat format(QGLFormat(QGL::Rgba | QGL::DoubleBuffer));
|
QGLFormat format(QGLFormat(QGL::Rgba | QGL::DoubleBuffer));
|
||||||
format.setSwapInterval(1);
|
format.setSwapInterval(1);
|
||||||
|
|
|
@ -103,6 +103,7 @@ int main(int argc, char** argv) {
|
||||||
GBASDLInitBindings(&inputMap);
|
GBASDLInitBindings(&inputMap);
|
||||||
GBASDLInitEvents(&renderer.events);
|
GBASDLInitEvents(&renderer.events);
|
||||||
GBASDLEventsLoadConfig(&renderer.events, &config.configTable); // TODO: Don't use this directly
|
GBASDLEventsLoadConfig(&renderer.events, &config.configTable); // TODO: Don't use this directly
|
||||||
|
context.overrides = &config.configTable;
|
||||||
|
|
||||||
GBAThreadStart(&context);
|
GBAThreadStart(&context);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue