GBA: Ability to boot directly into the BIOS

This commit is contained in:
Jeffrey Pfau 2015-06-08 00:19:13 -07:00
parent a51ae873bd
commit 596c7503b6
9 changed files with 65 additions and 24 deletions

View File

@ -20,6 +20,7 @@ Features:
- Ability to cap fast forward speed - Ability to cap fast forward speed
- Finer control over FPS target - Finer control over FPS target
- Holdable shortcut for rewinding one frame at a time - Holdable shortcut for rewinding one frame at a time
- Ability to boot directly into the BIOS
Bugfixes: Bugfixes:
- ARM7: Fix SWI and IRQ timings - ARM7: Fix SWI and IRQ timings
- GBA Audio: Force audio FIFOs to 32-bit - GBA Audio: Force audio FIFOs to 32-bit

View File

@ -633,10 +633,18 @@ bool GBAIsBIOS(struct VFile* vf) {
} }
void GBAGetGameCode(struct GBA* gba, char* out) { void GBAGetGameCode(struct GBA* gba, char* out) {
if (!gba->memory.rom) {
out[0] = '\0';
return;
}
memcpy(out, &((struct GBACartridge*) gba->memory.rom)->id, 4); memcpy(out, &((struct GBACartridge*) gba->memory.rom)->id, 4);
} }
void GBAGetGameTitle(struct GBA* gba, char* out) { void GBAGetGameTitle(struct GBA* gba, char* out) {
if (!gba->memory.rom) {
strncpy(out, "(BIOS)", 12);
return;
}
memcpy(out, &((struct GBACartridge*) gba->memory.rom)->title, 12); memcpy(out, &((struct GBACartridge*) gba->memory.rom)->title, 12);
} }

View File

@ -47,6 +47,7 @@ void GBAMemoryInit(struct GBA* gba) {
gba->memory.wram = 0; gba->memory.wram = 0;
gba->memory.iwram = 0; gba->memory.iwram = 0;
gba->memory.rom = 0; gba->memory.rom = 0;
gba->memory.romSize = 0;
gba->memory.hw.p = gba; gba->memory.hw.p = gba;
int i; int i;

View File

@ -29,8 +29,13 @@ void GBASerialize(struct GBA* gba, struct GBASerializedState* state) {
state->biosChecksum = gba->biosChecksum; state->biosChecksum = gba->biosChecksum;
state->romCrc32 = gba->romCrc32; state->romCrc32 = gba->romCrc32;
if (gba->memory.rom) {
state->id = ((struct GBACartridge*) gba->memory.rom)->id; state->id = ((struct GBACartridge*) gba->memory.rom)->id;
memcpy(state->title, ((struct GBACartridge*) gba->memory.rom)->title, sizeof(state->title)); memcpy(state->title, ((struct GBACartridge*) gba->memory.rom)->title, sizeof(state->title));
} else {
state->id = 0;
memset(state->title, 0, sizeof(state->title));
}
memcpy(state->cpu.gprs, gba->cpu->gprs, sizeof(state->cpu.gprs)); memcpy(state->cpu.gprs, gba->cpu->gprs, sizeof(state->cpu.gprs));
state->cpu.cpsr = gba->cpu->cpsr; state->cpu.cpsr = gba->cpu->cpsr;
@ -67,9 +72,12 @@ void GBADeserialize(struct GBA* gba, const struct GBASerializedState* state) {
return; return;
} }
} }
if (state->id != ((struct GBACartridge*) gba->memory.rom)->id || memcmp(state->title, ((struct GBACartridge*) gba->memory.rom)->title, sizeof(state->title))) { if (gba->memory.rom && state->id != ((struct GBACartridge*) gba->memory.rom)->id || memcmp(state->title, ((struct GBACartridge*) gba->memory.rom)->title, sizeof(state->title))) {
GBALog(gba, GBA_LOG_WARN, "Savestate is for a different game"); GBALog(gba, GBA_LOG_WARN, "Savestate is for a different game");
return; return;
} else if (!gba->memory.rom && state->id != 0) {
GBALog(gba, GBA_LOG_WARN, "Savestate is for a game, but no game loaded");
return;
} }
if (state->romCrc32 != gba->romCrc32) { if (state->romCrc32 != gba->romCrc32) {
GBALog(gba, GBA_LOG_WARN, "Savestate is for a different version of the game"); GBALog(gba, GBA_LOG_WARN, "Savestate is for a different version of the game");

View File

@ -167,15 +167,15 @@ static THREAD_ENTRY _GBAThreadRun(void* context) {
GBAOverrideApply(&gba, &threadContext->override); GBAOverrideApply(&gba, &threadContext->override);
} }
if (threadContext->bios && GBAIsBIOS(threadContext->bios)) {
GBALoadBIOS(&gba, threadContext->bios);
}
if (threadContext->patch && loadPatch(threadContext->patch, &patch)) { if (threadContext->patch && loadPatch(threadContext->patch, &patch)) {
GBAApplyPatch(&gba, &patch); GBAApplyPatch(&gba, &patch);
} }
} }
if (threadContext->bios && GBAIsBIOS(threadContext->bios)) {
GBALoadBIOS(&gba, threadContext->bios);
}
if (threadContext->movie) { if (threadContext->movie) {
struct VDir* movieDir = VDirOpen(threadContext->movie); struct VDir* movieDir = VDirOpen(threadContext->movie);
#ifdef USE_LIBZIP #ifdef USE_LIBZIP
@ -400,7 +400,9 @@ bool GBAThreadStart(struct GBAThread* threadContext) {
threadContext->fpsTarget = _defaultFPSTarget; threadContext->fpsTarget = _defaultFPSTarget;
} }
if (threadContext->rom && !GBAIsROM(threadContext->rom)) { bool bootBios = threadContext->bootBios && threadContext->bios;
if (threadContext->rom && (!GBAIsROM(threadContext->rom) || bootBios)) {
threadContext->rom->close(threadContext->rom); threadContext->rom->close(threadContext->rom);
threadContext->rom = 0; threadContext->rom = 0;
} }
@ -427,7 +429,7 @@ bool GBAThreadStart(struct GBAThread* threadContext) {
} }
if (!threadContext->rom) { if (!threadContext->rom && !bootBios) {
threadContext->state = THREAD_SHUTDOWN; threadContext->state = THREAD_SHUTDOWN;
return false; return false;
} }

View File

@ -72,6 +72,7 @@ struct GBAThread {
struct GBAAVStream* stream; struct GBAAVStream* stream;
struct Configuration* overrides; struct Configuration* overrides;
enum GBAIdleLoopOptimization idleOptimization; enum GBAIdleLoopOptimization idleOptimization;
bool bootBios;
bool hasOverride; bool hasOverride;
struct GBACartridgeOverride override; struct GBACartridgeOverride override;

View File

@ -247,7 +247,18 @@ void GameController::loadGame(const QString& path, bool dirmode) {
openGame(); openGame();
} }
void GameController::openGame() { void GameController::bootBIOS() {
closeGame();
m_fname = QString();
m_dirmode = false;
openGame(true);
}
void GameController::openGame(bool biosOnly) {
if (biosOnly && (!m_useBios || m_bios.isNull())) {
return;
}
m_gameOpen = true; m_gameOpen = true;
m_pauseAfterFrame = false; m_pauseAfterFrame = false;
@ -261,6 +272,10 @@ void GameController::openGame() {
} }
m_threadContext.gameDir = 0; m_threadContext.gameDir = 0;
m_threadContext.bootBios = biosOnly;
if (biosOnly) {
m_threadContext.fname = nullptr;
} else {
m_threadContext.fname = strdup(m_fname.toLocal8Bit().constData()); m_threadContext.fname = strdup(m_fname.toLocal8Bit().constData());
if (m_dirmode) { if (m_dirmode) {
m_threadContext.gameDir = VDirOpen(m_threadContext.fname); m_threadContext.gameDir = VDirOpen(m_threadContext.fname);
@ -278,6 +293,7 @@ void GameController::openGame() {
} }
#endif #endif
} }
}
if (!m_bios.isNull() && m_useBios) { if (!m_bios.isNull() && m_useBios) {
m_threadContext.bios = VFileDevice::open(m_bios, O_RDONLY); m_threadContext.bios = VFileDevice::open(m_bios, O_RDONLY);

View File

@ -102,7 +102,7 @@ public slots:
void loadPatch(const QString& path); void loadPatch(const QString& path);
void importSharkport(const QString& path); void importSharkport(const QString& path);
void exportSharkport(const QString& path); void exportSharkport(const QString& path);
void openGame(); void bootBIOS();
void closeGame(); void closeGame();
void setPaused(bool paused); void setPaused(bool paused);
void reset(); void reset();
@ -148,6 +148,7 @@ public slots:
void disableLogLevel(int); void disableLogLevel(int);
private slots: private slots:
void openGame(bool bios = false);
void crashGame(const QString& crashMessage); void crashGame(const QString& crashMessage);
void pollEvents(); void pollEvents();

View File

@ -482,7 +482,9 @@ void Window::gameStarted(GBAThread* context) {
foreach (QAction* action, m_gameActions) { foreach (QAction* action, m_gameActions) {
action->setDisabled(false); action->setDisabled(false);
} }
if (context->fname) {
appendMRU(context->fname); appendMRU(context->fname);
}
updateTitle(); updateTitle();
attachWidget(m_display); attachWidget(m_display);
@ -609,6 +611,7 @@ void Window::setupMenu(QMenuBar* menubar) {
addControlledAction(fileMenu, fileMenu->addAction(tr("Load &ROM..."), this, SLOT(selectROM()), QKeySequence::Open), "loadROM"); addControlledAction(fileMenu, fileMenu->addAction(tr("Load &ROM..."), this, SLOT(selectROM()), QKeySequence::Open), "loadROM");
addControlledAction(fileMenu, fileMenu->addAction(tr("Load &BIOS..."), this, SLOT(selectBIOS())), "loadBIOS"); addControlledAction(fileMenu, fileMenu->addAction(tr("Load &BIOS..."), this, SLOT(selectBIOS())), "loadBIOS");
addControlledAction(fileMenu, fileMenu->addAction(tr("Load &patch..."), this, SLOT(selectPatch())), "loadPatch"); addControlledAction(fileMenu, fileMenu->addAction(tr("Load &patch..."), this, SLOT(selectPatch())), "loadPatch");
addControlledAction(fileMenu, fileMenu->addAction(tr("Boot BIOS"), m_controller, SLOT(bootBIOS())), "bootBIOS");
m_mruMenu = fileMenu->addMenu(tr("Recent")); m_mruMenu = fileMenu->addMenu(tr("Recent"));