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
- Finer control over FPS target
- Holdable shortcut for rewinding one frame at a time
- Ability to boot directly into the BIOS
Bugfixes:
- ARM7: Fix SWI and IRQ timings
- 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) {
if (!gba->memory.rom) {
out[0] = '\0';
return;
}
memcpy(out, &((struct GBACartridge*) gba->memory.rom)->id, 4);
}
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);
}

View File

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

View File

@ -29,8 +29,13 @@ void GBASerialize(struct GBA* gba, struct GBASerializedState* state) {
state->biosChecksum = gba->biosChecksum;
state->romCrc32 = gba->romCrc32;
state->id = ((struct GBACartridge*) gba->memory.rom)->id;
memcpy(state->title, ((struct GBACartridge*) gba->memory.rom)->title, sizeof(state->title));
if (gba->memory.rom) {
state->id = ((struct GBACartridge*) gba->memory.rom)->id;
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));
state->cpu.cpsr = gba->cpu->cpsr;
@ -67,9 +72,12 @@ void GBADeserialize(struct GBA* gba, const struct GBASerializedState* state) {
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");
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) {
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);
}
if (threadContext->bios && GBAIsBIOS(threadContext->bios)) {
GBALoadBIOS(&gba, threadContext->bios);
}
if (threadContext->patch && loadPatch(threadContext->patch, &patch)) {
GBAApplyPatch(&gba, &patch);
}
}
if (threadContext->bios && GBAIsBIOS(threadContext->bios)) {
GBALoadBIOS(&gba, threadContext->bios);
}
if (threadContext->movie) {
struct VDir* movieDir = VDirOpen(threadContext->movie);
#ifdef USE_LIBZIP
@ -400,7 +400,9 @@ bool GBAThreadStart(struct GBAThread* threadContext) {
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 = 0;
}
@ -427,7 +429,7 @@ bool GBAThreadStart(struct GBAThread* threadContext) {
}
if (!threadContext->rom) {
if (!threadContext->rom && !bootBios) {
threadContext->state = THREAD_SHUTDOWN;
return false;
}

View File

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

View File

@ -247,7 +247,18 @@ void GameController::loadGame(const QString& path, bool dirmode) {
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_pauseAfterFrame = false;
@ -261,25 +272,30 @@ void GameController::openGame() {
}
m_threadContext.gameDir = 0;
m_threadContext.fname = strdup(m_fname.toLocal8Bit().constData());
if (m_dirmode) {
m_threadContext.gameDir = VDirOpen(m_threadContext.fname);
m_threadContext.stateDir = m_threadContext.gameDir;
m_threadContext.bootBios = biosOnly;
if (biosOnly) {
m_threadContext.fname = nullptr;
} else {
m_threadContext.rom = VFileOpen(m_threadContext.fname, O_RDONLY);
m_threadContext.fname = strdup(m_fname.toLocal8Bit().constData());
if (m_dirmode) {
m_threadContext.gameDir = VDirOpen(m_threadContext.fname);
m_threadContext.stateDir = m_threadContext.gameDir;
} else {
m_threadContext.rom = VFileOpen(m_threadContext.fname, O_RDONLY);
#if USE_LIBZIP
if (!m_threadContext.gameDir) {
m_threadContext.gameDir = VDirOpenZip(m_threadContext.fname, 0);
}
if (!m_threadContext.gameDir) {
m_threadContext.gameDir = VDirOpenZip(m_threadContext.fname, 0);
}
#endif
#if USE_LZMA
if (!m_threadContext.gameDir) {
m_threadContext.gameDir = VDirOpen7z(m_threadContext.fname, 0);
}
if (!m_threadContext.gameDir) {
m_threadContext.gameDir = VDirOpen7z(m_threadContext.fname, 0);
}
#endif
}
}
if (!m_bios.isNull() &&m_useBios) {
if (!m_bios.isNull() && m_useBios) {
m_threadContext.bios = VFileDevice::open(m_bios, O_RDONLY);
} else {
m_threadContext.bios = nullptr;

View File

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

View File

@ -482,7 +482,9 @@ void Window::gameStarted(GBAThread* context) {
foreach (QAction* action, m_gameActions) {
action->setDisabled(false);
}
appendMRU(context->fname);
if (context->fname) {
appendMRU(context->fname);
}
updateTitle();
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 &BIOS..."), this, SLOT(selectBIOS())), "loadBIOS");
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"));