all repos — mgba @ cafc67a6061990f623fea3c84919bd881fbb47dc

mGBA Game Boy Advance Emulator

GBA: Make idle loop detection configurable
Jeffrey Pfau jeffrey@endrift.com
Tue, 13 Jan 2015 02:39:48 -0800
commit

cafc67a6061990f623fea3c84919bd881fbb47dc

parent

542662ca682ce0df57849bde1636d5d45d764450

M src/gba/gba-config.csrc/gba/gba-config.c

@@ -212,6 +212,18 @@

_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 @@ ConfigurationSetIntValue(&config->defaultsTable, 0, "width", opts->width);

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) {
M src/gba/gba-config.hsrc/gba/gba-config.h

@@ -8,6 +8,8 @@ #define GBA_CONFIG_H

#include "util/common.h" +#include "gba.h" + #include "util/configuration.h" struct GBAConfig {

@@ -35,6 +37,8 @@ bool resampleVideo;

bool videoSync; bool audioSync; + + enum GBAIdleLoopOptimization idleOptimization; }; void GBAConfigInit(struct GBAConfig*, const char* port);
M src/gba/gba-memory.csrc/gba/gba-memory.c

@@ -173,7 +173,7 @@ nextAddress += WORD_SIZE_THUMB;

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]; }
M src/gba/gba-overrides.csrc/gba/gba-overrides.c

@@ -195,5 +195,5 @@ if (override->hardware & GPIO_TILT) {

GBAGPIOInitTilt(&gba->memory.gpio); } - gba->busyLoop = override->idleLoop; + gba->idleLoop = override->idleLoop; }
M src/gba/gba-thread.csrc/gba/gba-thread.c

@@ -173,6 +173,7 @@

GBASIOSetDriverSet(&gba.sio, &threadContext->sioDrivers); gba.keySource = &threadContext->activeKeys; + gba.idleOptimization = threadContext->idleOptimization; if (threadContext->startCallback) { threadContext->startCallback(threadContext);

@@ -261,6 +262,8 @@

if (opts->audioBuffers) { threadContext->audioBuffers = opts->audioBuffers; } + + threadContext->idleOptimization = opts->idleOptimization; } void GBAMapArgumentsToContext(const struct GBAArguments* args, struct GBAThread* threadContext) {
M src/gba/gba-thread.hsrc/gba/gba-thread.h

@@ -71,6 +71,7 @@ const char* fname;

int activeKeys; struct GBAAVStream* stream; struct Configuration* overrides; + enum GBAIdleLoopOptimization idleOptimization; // Run-time options int frameskip;
M src/gba/gba.csrc/gba/gba.c

@@ -75,7 +75,10 @@ gba->logLevel = GBA_LOG_INFO | GBA_LOG_WARN | GBA_LOG_ERROR | GBA_LOG_FATAL;

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) {
M src/gba/gba.hsrc/gba/gba.h

@@ -75,6 +75,12 @@ GBA_COMPONENT_DEBUGGER,

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 @@ const char* activeFile;

int logLevel; - uint32_t busyLoop; + enum GBAIdleLoopOptimization idleOptimization; + uint32_t idleLoop; uint32_t lastJump; int idleDetectionStep; int32_t cachedRegisters[16];