From 54ef61f715d59e50429a3b3982c7f32e56b7b8eb Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Sat, 10 Jan 2015 14:20:09 -0800 Subject: [PATCH 01/12] GBA: Implement idle loop detection --- CHANGES | 1 + src/gba/gba-io.c | 1 + src/gba/gba-memory.c | 94 +++++++++++++++++++++++++++++++++++++++++++- src/gba/gba.h | 7 +++- 4 files changed, 101 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index f8ef6a01b..44f58dcc8 100644 --- a/CHANGES +++ b/CHANGES @@ -16,6 +16,7 @@ Features: - Rewinding of emulation - Implemented BIOS routines SoftReset, RegisterRamReset, Diff8bitUnFilterWram, Diff8bitUnFilterVram, and Diff16bitUnFilter - Support IPv6 + - Automatically detect and optimize out idle loops Bugfixes: - Qt: Fix issue with set frame sizes being the wrong height - Qt: Fix emulator crashing when full screen if a game is not running diff --git a/src/gba/gba-io.c b/src/gba/gba-io.c index 11552f3f5..908e64edf 100644 --- a/src/gba/gba-io.c +++ b/src/gba/gba-io.c @@ -555,6 +555,7 @@ void GBAIOWrite32(struct GBA* gba, uint32_t address, uint32_t value) { } uint16_t GBAIORead(struct GBA* gba, uint32_t address) { + gba->lastJump = -1; // IO reads need to invalidate detected idle loops switch (address) { case REG_TM0CNT_LO: GBATimerUpdateRegister(gba, 0); diff --git a/src/gba/gba-memory.c b/src/gba/gba-memory.c index 5de5be05a..853f34904 100644 --- a/src/gba/gba-memory.c +++ b/src/gba/gba-memory.c @@ -7,6 +7,7 @@ #include "macros.h" +#include "decoder.h" #include "gba-gpio.h" #include "gba-io.h" #include "gba-serialize.h" @@ -113,16 +114,107 @@ void GBAMemoryReset(struct GBA* gba) { } } +static void _analyzeForIdleLoop(struct GBA* gba, struct ARMCore* cpu, uint32_t address) { + struct ARMInstructionInfo info; + uint32_t nextAddress = address; + memset(gba->taintedRegisters, 0, sizeof(gba->taintedRegisters)); + if (cpu->executionMode == MODE_THUMB) { + while (true) { + uint16_t opcode; + LOAD_16(opcode, nextAddress & cpu->memory.activeMask, cpu->memory.activeRegion); + ARMDecodeThumb(opcode, &info); + switch (info.branchType) { + case ARM_BRANCH_NONE: + if (info.operandFormat & ARM_OPERAND_MEMORY_2) { + if (info.mnemonic == ARM_MN_STR || gba->taintedRegisters[info.memory.baseReg]) { + gba->idleDetectionStep = -1; + return; + } + uint32_t loadAddress = gba->cachedRegisters[info.memory.baseReg]; + uint32_t offset = 0; + if (info.memory.format & ARM_MEMORY_IMMEDIATE_OFFSET) { + offset = info.memory.offset.immediate; + } else if (info.memory.format & ARM_MEMORY_REGISTER_OFFSET) { + int reg = info.memory.offset.reg; + if (gba->cachedRegisters[reg]) { + gba->idleDetectionStep = -1; + return; + } + offset = gba->cachedRegisters[reg]; + } + if (info.memory.format & ARM_MEMORY_OFFSET_SUBTRACT) { + loadAddress -= offset; + } else { + loadAddress += offset; + } + if ((loadAddress >> BASE_OFFSET) == REGION_IO) { + gba->idleDetectionStep = -1; + return; + } + if ((loadAddress >> BASE_OFFSET) < REGION_CART0 || (loadAddress >> BASE_OFFSET) > REGION_CART2_EX) { + gba->taintedRegisters[info.op1.reg] = true; + } else { + switch (info.memory.width) { + case 1: + gba->cachedRegisters[info.op1.reg] = GBALoad8(cpu, loadAddress, 0); + break; + case 2: + gba->cachedRegisters[info.op1.reg] = GBALoad16(cpu, loadAddress, 0); + break; + case 4: + gba->cachedRegisters[info.op1.reg] = GBALoad32(cpu, loadAddress, 0); + break; + } + } + } else if (info.operandFormat & ARM_OPERAND_AFFECTED_1) { + gba->taintedRegisters[info.op1.reg] = true; + } + nextAddress += WORD_SIZE_THUMB; + break; + case ARM_BRANCH: + if ((uint32_t) info.op1.immediate + nextAddress + WORD_SIZE_THUMB * 2 == address) { + gba->busyLoop = address; + } + gba->idleDetectionStep = -1; + return; + default: + gba->idleDetectionStep = -1; + return; + } + } + } else { + gba->idleDetectionStep = -1; + } +} + static void GBASetActiveRegion(struct ARMCore* cpu, uint32_t address) { struct GBA* gba = (struct GBA*) cpu->master; struct GBAMemory* memory = &gba->memory; - if (address == gba->busyLoop && memory->activeRegion != REGION_BIOS) { + if (address == gba->lastJump && address == gba->busyLoop && memory->activeRegion != REGION_BIOS) { GBAHalt(gba); } int newRegion = address >> BASE_OFFSET; if (newRegion == memory->activeRegion) { + if (address == gba->lastJump) { + switch (gba->idleDetectionStep) { + case 0: + memcpy(gba->cachedRegisters, cpu->gprs, sizeof(gba->cachedRegisters)); + ++gba->idleDetectionStep; + break; + case 1: + if (memcmp(gba->cachedRegisters, cpu->gprs, sizeof(gba->cachedRegisters))) { + gba->idleDetectionStep = -1; + break; + } + _analyzeForIdleLoop(gba, cpu, address); + break; + } + } else { + gba->lastJump = address; + gba->idleDetectionStep = 0; + } return; } if (memory->activeRegion == REGION_BIOS) { diff --git a/src/gba/gba.h b/src/gba/gba.h index a7b13ed3a..6ea19de00 100644 --- a/src/gba/gba.h +++ b/src/gba/gba.h @@ -119,7 +119,6 @@ struct GBA { int springIRQ; uint32_t biosChecksum; int* keySource; - uint32_t busyLoop; struct GBARotationSource* rotationSource; struct GBALuminanceSource* luminanceSource; struct GBARTCSource* rtcSource; @@ -135,6 +134,12 @@ struct GBA { const char* activeFile; int logLevel; + + uint32_t busyLoop; + uint32_t lastJump; + int idleDetectionStep; + int32_t cachedRegisters[16]; + bool taintedRegisters[16]; }; struct GBACartridge { From 5f62e33717f8da0b22673621253cf2e265a71603 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Tue, 13 Jan 2015 01:18:07 -0800 Subject: [PATCH 02/12] GBA: Configurable game overrides --- src/gba/gba-overrides.c | 199 +++++++++++++++++++++++++++++ src/gba/gba-overrides.h | 27 ++++ src/gba/gba-thread.c | 9 ++ src/gba/gba-thread.h | 1 + src/gba/gba.c | 144 --------------------- src/platform/perf-main.c | 1 + src/platform/qt/ConfigController.h | 2 + src/platform/qt/GameController.h | 2 + src/platform/qt/Window.cpp | 1 + src/platform/sdl/main.c | 1 + 10 files changed, 243 insertions(+), 144 deletions(-) create mode 100644 src/gba/gba-overrides.c create mode 100644 src/gba/gba-overrides.h diff --git a/src/gba/gba-overrides.c b/src/gba/gba-overrides.c new file mode 100644 index 000000000..d82ccda8f --- /dev/null +++ b/src/gba/gba-overrides.c @@ -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; +} diff --git a/src/gba/gba-overrides.h b/src/gba/gba-overrides.h new file mode 100644 index 000000000..9dbbfe36e --- /dev/null +++ b/src/gba/gba-overrides.h @@ -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 diff --git a/src/gba/gba-thread.c b/src/gba/gba-thread.c index ce0814acd..5226e1f45 100644 --- a/src/gba/gba-thread.c +++ b/src/gba/gba-thread.c @@ -8,6 +8,7 @@ #include "arm.h" #include "gba.h" #include "gba-config.h" +#include "gba-overrides.h" #include "gba-serialize.h" #include "debugger/debugger.h" @@ -141,6 +142,14 @@ static THREAD_ENTRY _GBAThreadRun(void* context) { if (threadContext->rom) { 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)) { GBALoadBIOS(&gba, threadContext->bios); } diff --git a/src/gba/gba-thread.h b/src/gba/gba-thread.h index 4a923ec75..7c1d6e795 100644 --- a/src/gba/gba-thread.h +++ b/src/gba/gba-thread.h @@ -70,6 +70,7 @@ struct GBAThread { const char* fname; int activeKeys; struct GBAAVStream* stream; + struct Configuration* overrides; // Run-time options int frameskip; diff --git a/src/gba/gba.c b/src/gba/gba.c index 26dab4876..74cf1203f 100644 --- a/src/gba/gba.c +++ b/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 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 GBAInterruptHandlerInit(struct ARMInterruptHandler* irqh); 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 GBAIllegal(struct ARMCore* cpu, uint32_t opcode); -static void _checkOverrides(struct GBA* gba, uint32_t code); - void GBACreate(struct GBA* gba) { gba->d.id = GBA_COMPONENT_MAGIC; 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); GBASavedataInit(&gba->memory.savedata, sav); GBAGPIOInit(&gba->memory.gpio, &((uint16_t*) gba->memory.rom)[GPIO_REG_DATA >> 1]); - _checkOverrides(gba, ((struct GBACartridge*) gba->memory.rom)->id); // TODO: error check } @@ -739,43 +635,3 @@ void GBAIllegal(struct ARMCore* cpu, uint32_t opcode) { 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; - } - } -} diff --git a/src/platform/perf-main.c b/src/platform/perf-main.c index 27ad38e37..d7487af53 100644 --- a/src/platform/perf-main.c +++ b/src/platform/perf-main.c @@ -76,6 +76,7 @@ int main(int argc, char** argv) { } context.debugger = createDebugger(&args, &context); + context.overrides = &config.configTable; char gameCode[5] = { 0 }; GBAConfigMap(&config, &opts); diff --git a/src/platform/qt/ConfigController.h b/src/platform/qt/ConfigController.h index af9da687b..5b8ed80b3 100644 --- a/src/platform/qt/ConfigController.h +++ b/src/platform/qt/ConfigController.h @@ -75,6 +75,8 @@ public: QList getMRU() const; void setMRU(const QList& mru); + Configuration* overrides() { return &m_config.configTable; } // TODO: Make this not return the whole table + public slots: void setOption(const char* key, bool value); void setOption(const char* key, int value); diff --git a/src/platform/qt/GameController.h b/src/platform/qt/GameController.h index fc91a8868..453500f32 100644 --- a/src/platform/qt/GameController.h +++ b/src/platform/qt/GameController.h @@ -22,6 +22,7 @@ extern "C" { struct GBAAudio; struct GBAVideoSoftwareRenderer; +struct Configuration; class QThread; @@ -53,6 +54,7 @@ public: bool videoSync() const { return m_videoSync; } void setInputController(InputController* controller) { m_inputController = controller; } + void setOverrides(Configuration* overrides) { m_threadContext.overrides = overrides; } #ifdef USE_GDB_STUB ARMDebugger* debugger(); diff --git a/src/platform/qt/Window.cpp b/src/platform/qt/Window.cpp index 44f7a6efb..2da102fbf 100644 --- a/src/platform/qt/Window.cpp +++ b/src/platform/qt/Window.cpp @@ -56,6 +56,7 @@ Window::Window(ConfigController* config, QWidget* parent) setFocusPolicy(Qt::StrongFocus); m_controller = new GameController(this); m_controller->setInputController(&m_inputController); + m_controller->setOverrides(m_config->overrides()); QGLFormat format(QGLFormat(QGL::Rgba | QGL::DoubleBuffer)); format.setSwapInterval(1); diff --git a/src/platform/sdl/main.c b/src/platform/sdl/main.c index 978a803e4..50331adb1 100644 --- a/src/platform/sdl/main.c +++ b/src/platform/sdl/main.c @@ -103,6 +103,7 @@ int main(int argc, char** argv) { GBASDLInitBindings(&inputMap); GBASDLInitEvents(&renderer.events); GBASDLEventsLoadConfig(&renderer.events, &config.configTable); // TODO: Don't use this directly + context.overrides = &config.configTable; GBAThreadStart(&context); From cafc67a6061990f623fea3c84919bd881fbb47dc Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Tue, 13 Jan 2015 02:39:48 -0800 Subject: [PATCH 03/12] GBA: Make idle loop detection configurable --- src/gba/gba-config.c | 24 ++++++++++++++++++++++ src/gba/gba-config.h | 4 ++++ src/gba/gba-memory.c | 44 ++++++++++++++++++++++------------------- src/gba/gba-overrides.c | 2 +- src/gba/gba-thread.c | 3 +++ src/gba/gba-thread.h | 1 + src/gba/gba.c | 5 ++++- src/gba/gba.h | 9 ++++++++- 8 files changed, 69 insertions(+), 23 deletions(-) diff --git a/src/gba/gba-config.c b/src/gba/gba-config.c index 9c1abd6f2..4354bfa20 100644 --- a/src/gba/gba-config.c +++ b/src/gba/gba-config.c @@ -212,6 +212,18 @@ void GBAConfigMap(const struct GBAConfig* config, struct GBAOptions* opts) { _lookupIntValue(config, "fullscreen", &opts->fullscreen); _lookupIntValue(config, "width", &opts->width); _lookupIntValue(config, "height", &opts->height); + + char* idleOptimization; + if (_lookupCharValue(config, "idleOptimization", &idleOptimization)) { + if (strcasecmp(idleOptimization, "ignore") == 0) { + opts->idleOptimization = IDLE_LOOP_IGNORE; + } else if (strcasecmp(idleOptimization, "remove") == 0) { + opts->idleOptimization = IDLE_LOOP_REMOVE; + } else if (strcasecmp(idleOptimization, "detect") == 0) { + opts->idleOptimization = IDLE_LOOP_DETECT; + } + free(idleOptimization); + } } void GBAConfigLoadDefaults(struct GBAConfig* config, const struct GBAOptions* opts) { @@ -231,6 +243,18 @@ void GBAConfigLoadDefaults(struct GBAConfig* config, const struct GBAOptions* op ConfigurationSetIntValue(&config->defaultsTable, 0, "height", opts->height); ConfigurationSetIntValue(&config->defaultsTable, 0, "lockAspectRatio", opts->lockAspectRatio); ConfigurationSetIntValue(&config->defaultsTable, 0, "resampleVideo", opts->resampleVideo); + + switch (opts->idleOptimization) { + case IDLE_LOOP_IGNORE: + ConfigurationSetValue(&config->defaultsTable, 0, "idleOptimization", "ignore"); + break; + case IDLE_LOOP_REMOVE: + ConfigurationSetValue(&config->defaultsTable, 0, "idleOptimization", "remove"); + break; + case IDLE_LOOP_DETECT: + ConfigurationSetValue(&config->defaultsTable, 0, "idleOptimization", "detect"); + break; + } } void GBAConfigFreeOpts(struct GBAOptions* opts) { diff --git a/src/gba/gba-config.h b/src/gba/gba-config.h index 93d68b219..ad64f16f4 100644 --- a/src/gba/gba-config.h +++ b/src/gba/gba-config.h @@ -8,6 +8,8 @@ #include "util/common.h" +#include "gba.h" + #include "util/configuration.h" struct GBAConfig { @@ -35,6 +37,8 @@ struct GBAOptions { bool videoSync; bool audioSync; + + enum GBAIdleLoopOptimization idleOptimization; }; void GBAConfigInit(struct GBAConfig*, const char* port); diff --git a/src/gba/gba-memory.c b/src/gba/gba-memory.c index b99c7bb14..344f10efd 100644 --- a/src/gba/gba-memory.c +++ b/src/gba/gba-memory.c @@ -173,7 +173,7 @@ static void _analyzeForIdleLoop(struct GBA* gba, struct ARMCore* cpu, uint32_t a break; case ARM_BRANCH: if ((uint32_t) info.op1.immediate + nextAddress + WORD_SIZE_THUMB * 2 == address) { - gba->busyLoop = address; + gba->idleLoop = address; } gba->idleDetectionStep = -1; return; @@ -191,32 +191,36 @@ static void GBASetActiveRegion(struct ARMCore* cpu, uint32_t address) { struct GBA* gba = (struct GBA*) cpu->master; struct GBAMemory* memory = &gba->memory; - if (address == gba->lastJump && address == gba->busyLoop && memory->activeRegion != REGION_BIOS) { - GBAHalt(gba); - } - int newRegion = address >> BASE_OFFSET; - if (newRegion == memory->activeRegion) { - if (address == gba->lastJump) { - switch (gba->idleDetectionStep) { - case 0: - memcpy(gba->cachedRegisters, cpu->gprs, sizeof(gba->cachedRegisters)); - ++gba->idleDetectionStep; - break; - case 1: - if (memcmp(gba->cachedRegisters, cpu->gprs, sizeof(gba->cachedRegisters))) { - gba->idleDetectionStep = -1; + if (gba->idleOptimization >= IDLE_LOOP_REMOVE) { + if (address == gba->lastJump && address == gba->idleLoop && memory->activeRegion != REGION_BIOS) { + GBAHalt(gba); + } else if (gba->idleOptimization >= IDLE_LOOP_DETECT && newRegion == memory->activeRegion) { + if (address == gba->lastJump) { + switch (gba->idleDetectionStep) { + case 0: + memcpy(gba->cachedRegisters, cpu->gprs, sizeof(gba->cachedRegisters)); + ++gba->idleDetectionStep; + break; + case 1: + if (memcmp(gba->cachedRegisters, cpu->gprs, sizeof(gba->cachedRegisters))) { + gba->idleDetectionStep = -1; + break; + } + _analyzeForIdleLoop(gba, cpu, address); break; } - _analyzeForIdleLoop(gba, cpu, address); - break; + } else { + gba->idleDetectionStep = 0; } - } else { - gba->lastJump = address; - gba->idleDetectionStep = 0; } + } + + gba->lastJump = address; + if (newRegion == memory->activeRegion) { return; } + if (memory->activeRegion == REGION_BIOS) { memory->biosPrefetch = cpu->prefetch[1]; } diff --git a/src/gba/gba-overrides.c b/src/gba/gba-overrides.c index d82ccda8f..57168591e 100644 --- a/src/gba/gba-overrides.c +++ b/src/gba/gba-overrides.c @@ -195,5 +195,5 @@ void GBAOverrideApply(struct GBA* gba, const struct GBACartridgeOverride* overri GBAGPIOInitTilt(&gba->memory.gpio); } - gba->busyLoop = override->idleLoop; + gba->idleLoop = override->idleLoop; } diff --git a/src/gba/gba-thread.c b/src/gba/gba-thread.c index 5226e1f45..f34130ce5 100644 --- a/src/gba/gba-thread.c +++ b/src/gba/gba-thread.c @@ -173,6 +173,7 @@ static THREAD_ENTRY _GBAThreadRun(void* context) { GBASIOSetDriverSet(&gba.sio, &threadContext->sioDrivers); gba.keySource = &threadContext->activeKeys; + gba.idleOptimization = threadContext->idleOptimization; if (threadContext->startCallback) { threadContext->startCallback(threadContext); @@ -261,6 +262,8 @@ void GBAMapOptionsToContext(const struct GBAOptions* opts, struct GBAThread* thr if (opts->audioBuffers) { threadContext->audioBuffers = opts->audioBuffers; } + + threadContext->idleOptimization = opts->idleOptimization; } void GBAMapArgumentsToContext(const struct GBAArguments* args, struct GBAThread* threadContext) { diff --git a/src/gba/gba-thread.h b/src/gba/gba-thread.h index 7c1d6e795..71f3948bc 100644 --- a/src/gba/gba-thread.h +++ b/src/gba/gba-thread.h @@ -71,6 +71,7 @@ struct GBAThread { int activeKeys; struct GBAAVStream* stream; struct Configuration* overrides; + enum GBAIdleLoopOptimization idleOptimization; // Run-time options int frameskip; diff --git a/src/gba/gba.c b/src/gba/gba.c index 74cf1203f..8a5934b56 100644 --- a/src/gba/gba.c +++ b/src/gba/gba.c @@ -75,7 +75,10 @@ static void GBAInit(struct ARMCore* cpu, struct ARMComponent* component) { gba->biosChecksum = GBAChecksum(gba->memory.bios, SIZE_BIOS); - gba->busyLoop = -1; + gba->idleOptimization = IDLE_LOOP_REMOVE; + gba->idleLoop = -1; + gba->lastJump = 0; + gba->idleDetectionStep = 0; } void GBADestroy(struct GBA* gba) { diff --git a/src/gba/gba.h b/src/gba/gba.h index 6ea19de00..b806e98e6 100644 --- a/src/gba/gba.h +++ b/src/gba/gba.h @@ -75,6 +75,12 @@ enum GBAComponent { GBA_COMPONENT_MAX }; +enum GBAIdleLoopOptimization { + IDLE_LOOP_IGNORE = -1, + IDLE_LOOP_REMOVE = 0, + IDLE_LOOP_DETECT +}; + enum { SP_BASE_SYSTEM = 0x03007F00, SP_BASE_IRQ = 0x03007FA0, @@ -135,7 +141,8 @@ struct GBA { int logLevel; - uint32_t busyLoop; + enum GBAIdleLoopOptimization idleOptimization; + uint32_t idleLoop; uint32_t lastJump; int idleDetectionStep; int32_t cachedRegisters[16]; From eb81fc3c65f918c16f0e9ddeeb6cbea662155731 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Tue, 13 Jan 2015 02:40:01 -0800 Subject: [PATCH 04/12] Perf: Load the config file --- src/platform/perf-main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/platform/perf-main.c b/src/platform/perf-main.c index d7487af53..5fc3ab72a 100644 --- a/src/platform/perf-main.c +++ b/src/platform/perf-main.c @@ -54,6 +54,7 @@ int main(int argc, char** argv) { struct GBAConfig config; GBAConfigInit(&config, "perf"); + GBAConfigLoad(&config); struct GBAOptions opts = {}; struct GBAArguments args = {}; From 3a7bdbf8dd2ce3dcea2c09c9bca5c39a72ecd3d2 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Sat, 17 Jan 2015 00:53:14 -0800 Subject: [PATCH 05/12] GBA: Only run idle loop detection outside of BIOS region --- src/gba/gba-memory.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gba/gba-memory.c b/src/gba/gba-memory.c index c2e261025..d5848cb89 100644 --- a/src/gba/gba-memory.c +++ b/src/gba/gba-memory.c @@ -193,8 +193,8 @@ static void GBASetActiveRegion(struct ARMCore* cpu, uint32_t address) { struct GBAMemory* memory = &gba->memory; int newRegion = address >> BASE_OFFSET; - if (gba->idleOptimization >= IDLE_LOOP_REMOVE) { - if (address == gba->lastJump && address == gba->idleLoop && memory->activeRegion != REGION_BIOS) { + if (gba->idleOptimization >= IDLE_LOOP_REMOVE && memory->activeRegion != REGION_BIOS) { + if (address == gba->lastJump && address == gba->idleLoop) { GBAHalt(gba); } else if (gba->idleOptimization >= IDLE_LOOP_DETECT && newRegion == memory->activeRegion) { if (address == gba->lastJump) { From fc172147eea8a5c8a7fba3b74d21caab845e6705 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Tue, 20 Jan 2015 22:16:21 -0800 Subject: [PATCH 06/12] GBA: Stop trying to detect idle loops if it fails too many times --- src/gba/gba-memory.c | 7 +++++++ src/gba/gba.c | 1 + src/gba/gba.h | 1 + 3 files changed, 9 insertions(+) diff --git a/src/gba/gba-memory.c b/src/gba/gba-memory.c index d5848cb89..9722d5309 100644 --- a/src/gba/gba-memory.c +++ b/src/gba/gba-memory.c @@ -14,6 +14,8 @@ #include "hle-bios.h" #include "util/memory.h" +#define IDLE_LOOP_THRESHOLD 200 + static uint32_t _popcount32(unsigned bits); static uint32_t _deadbeef[2] = { 0xDEADBEEF, 0xFEEDFACE }; @@ -175,6 +177,7 @@ static void _analyzeForIdleLoop(struct GBA* gba, struct ARMCore* cpu, uint32_t a case ARM_BRANCH: if ((uint32_t) info.op1.immediate + nextAddress + WORD_SIZE_THUMB * 2 == address) { gba->idleLoop = address; + gba->idleOptimization = IDLE_LOOP_REMOVE; } gba->idleDetectionStep = -1; return; @@ -206,6 +209,10 @@ static void GBASetActiveRegion(struct ARMCore* cpu, uint32_t address) { case 1: if (memcmp(gba->cachedRegisters, cpu->gprs, sizeof(gba->cachedRegisters))) { gba->idleDetectionStep = -1; + ++gba->idleDetectionFailures; + if (gba->idleDetectionFailures > IDLE_LOOP_THRESHOLD) { + gba->idleOptimization = IDLE_LOOP_IGNORE; + } break; } _analyzeForIdleLoop(gba, cpu, address); diff --git a/src/gba/gba.c b/src/gba/gba.c index befa19e1d..4ee826a67 100644 --- a/src/gba/gba.c +++ b/src/gba/gba.c @@ -79,6 +79,7 @@ static void GBAInit(struct ARMCore* cpu, struct ARMComponent* component) { gba->idleLoop = -1; gba->lastJump = 0; gba->idleDetectionStep = 0; + gba->idleDetectionFailures = 0; } void GBADestroy(struct GBA* gba) { diff --git a/src/gba/gba.h b/src/gba/gba.h index b806e98e6..0bd9b222f 100644 --- a/src/gba/gba.h +++ b/src/gba/gba.h @@ -145,6 +145,7 @@ struct GBA { uint32_t idleLoop; uint32_t lastJump; int idleDetectionStep; + int idleDetectionFailures; int32_t cachedRegisters[16]; bool taintedRegisters[16]; }; From 030f12e39fe947a34c5fcd841bfc4e8ff7fe9071 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Tue, 20 Jan 2015 23:26:48 -0800 Subject: [PATCH 07/12] Perf: Detect idle loops by default --- src/platform/perf-main.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/platform/perf-main.c b/src/platform/perf-main.c index 5fc3ab72a..85f944938 100644 --- a/src/platform/perf-main.c +++ b/src/platform/perf-main.c @@ -56,7 +56,11 @@ int main(int argc, char** argv) { GBAConfigInit(&config, "perf"); GBAConfigLoad(&config); - struct GBAOptions opts = {}; + struct GBAOptions opts = { + .idleOptimization = IDLE_LOOP_DETECT + }; + GBAConfigLoadDefaults(&config, &opts); + struct GBAArguments args = {}; if (!parseArguments(&args, &config, argc, argv, &subparser)) { usage(argv[0], PERF_USAGE); @@ -69,7 +73,7 @@ int main(int argc, char** argv) { renderer.outputBuffer = malloc(256 * 256 * 4); renderer.outputBufferStride = 256; - struct GBAThread context = { }; + struct GBAThread context = {}; _thread = &context; if (!perfOpts.noVideo) { From dba275c5705f54501ae6819fb34b9f93a29185c6 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Wed, 21 Jan 2015 23:07:04 -0800 Subject: [PATCH 08/12] GBA: Fix warning in config loader --- src/gba/gba-config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gba/gba-config.c b/src/gba/gba-config.c index 4354bfa20..45769b6e6 100644 --- a/src/gba/gba-config.c +++ b/src/gba/gba-config.c @@ -213,7 +213,7 @@ void GBAConfigMap(const struct GBAConfig* config, struct GBAOptions* opts) { _lookupIntValue(config, "width", &opts->width); _lookupIntValue(config, "height", &opts->height); - char* idleOptimization; + char* idleOptimization = 0; if (_lookupCharValue(config, "idleOptimization", &idleOptimization)) { if (strcasecmp(idleOptimization, "ignore") == 0) { opts->idleOptimization = IDLE_LOOP_IGNORE; From 075308e837ea70061044e6a6bc0b1b3015ccb084 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Sat, 24 Jan 2015 14:42:35 -0800 Subject: [PATCH 09/12] GBA Thread: Make sure idle loop setting is set at the right time --- src/gba/gba-thread.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gba/gba-thread.c b/src/gba/gba-thread.c index f34130ce5..8cb6e2a29 100644 --- a/src/gba/gba-thread.c +++ b/src/gba/gba-thread.c @@ -124,6 +124,7 @@ static THREAD_ENTRY _GBAThreadRun(void* context) { gba.sync = &threadContext->sync; threadContext->gba = &gba; gba.logLevel = threadContext->logLevel; + gba.idleOptimization = threadContext->idleOptimization; #ifdef USE_PTHREADS pthread_setspecific(_contextKey, threadContext); #else @@ -173,7 +174,6 @@ static THREAD_ENTRY _GBAThreadRun(void* context) { GBASIOSetDriverSet(&gba.sio, &threadContext->sioDrivers); gba.keySource = &threadContext->activeKeys; - gba.idleOptimization = threadContext->idleOptimization; if (threadContext->startCallback) { threadContext->startCallback(threadContext); From e1fc839ed84c8a3b58f1184d391a6df714eac0b1 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Sat, 24 Jan 2015 13:36:53 -0800 Subject: [PATCH 10/12] GBA: Bump idle detection down to idle removal if a pre-vetted idle loop is known --- src/gba/gba-overrides.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/gba/gba-overrides.c b/src/gba/gba-overrides.c index 57168591e..404b4b447 100644 --- a/src/gba/gba-overrides.c +++ b/src/gba/gba-overrides.c @@ -196,4 +196,7 @@ void GBAOverrideApply(struct GBA* gba, const struct GBACartridgeOverride* overri } gba->idleLoop = override->idleLoop; + if (override->idleLoop != 0xFFFFFFFF && gba->idleOptimization == IDLE_LOOP_DETECT) { + gba->idleOptimization = IDLE_LOOP_REMOVE; + } } From d11428ad40996c66e9ef831461373c38e8d3db7d Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Sat, 24 Jan 2015 14:43:16 -0800 Subject: [PATCH 11/12] GBA: Bump idle loop detection threshold to 10000 --- src/gba/gba-memory.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gba/gba-memory.c b/src/gba/gba-memory.c index 9722d5309..c9f45f735 100644 --- a/src/gba/gba-memory.c +++ b/src/gba/gba-memory.c @@ -14,7 +14,7 @@ #include "hle-bios.h" #include "util/memory.h" -#define IDLE_LOOP_THRESHOLD 200 +#define IDLE_LOOP_THRESHOLD 10000 static uint32_t _popcount32(unsigned bits); static uint32_t _deadbeef[2] = { 0xDEADBEEF, 0xFEEDFACE }; From 10ba7d16b30b675261ce65d9741119eb930250eb Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Sat, 24 Jan 2015 14:28:35 -0800 Subject: [PATCH 12/12] GBA: Fix FFTA idle loop location --- src/gba/gba-overrides.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gba/gba-overrides.c b/src/gba/gba-overrides.c index 404b4b447..fb393fa4a 100644 --- a/src/gba/gba-overrides.c +++ b/src/gba/gba-overrides.c @@ -26,7 +26,7 @@ static const struct GBACartridgeOverride _overrides[] = { { "V49E", SAVEDATA_SRAM, GPIO_RUMBLE, -1 }, // Final Fantasy Tactics Advance - { "AFXE", SAVEDATA_FLASH512, GPIO_NONE, 0x8000418 }, + { "AFXE", SAVEDATA_FLASH512, GPIO_NONE, 0x8000428 }, // Koro Koro Puzzle - Happy Panechu! { "KHPJ", SAVEDATA_EEPROM, GPIO_TILT, -1 },