mirror of https://github.com/mgba-emu/mgba.git
GBA: Ability to boot directly into the BIOS
This commit is contained in:
parent
a51ae873bd
commit
596c7503b6
1
CHANGES
1
CHANGES
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
state->id = ((struct GBACartridge*) gba->memory.rom)->id;
|
if (gba->memory.rom) {
|
||||||
memcpy(state->title, ((struct GBACartridge*) gba->memory.rom)->title, sizeof(state->title));
|
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));
|
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");
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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,25 +272,30 @@ void GameController::openGame() {
|
||||||
}
|
}
|
||||||
|
|
||||||
m_threadContext.gameDir = 0;
|
m_threadContext.gameDir = 0;
|
||||||
m_threadContext.fname = strdup(m_fname.toLocal8Bit().constData());
|
m_threadContext.bootBios = biosOnly;
|
||||||
if (m_dirmode) {
|
if (biosOnly) {
|
||||||
m_threadContext.gameDir = VDirOpen(m_threadContext.fname);
|
m_threadContext.fname = nullptr;
|
||||||
m_threadContext.stateDir = m_threadContext.gameDir;
|
|
||||||
} else {
|
} 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 USE_LIBZIP
|
||||||
if (!m_threadContext.gameDir) {
|
if (!m_threadContext.gameDir) {
|
||||||
m_threadContext.gameDir = VDirOpenZip(m_threadContext.fname, 0);
|
m_threadContext.gameDir = VDirOpenZip(m_threadContext.fname, 0);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#if USE_LZMA
|
#if USE_LZMA
|
||||||
if (!m_threadContext.gameDir) {
|
if (!m_threadContext.gameDir) {
|
||||||
m_threadContext.gameDir = VDirOpen7z(m_threadContext.fname, 0);
|
m_threadContext.gameDir = VDirOpen7z(m_threadContext.fname, 0);
|
||||||
}
|
}
|
||||||
#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);
|
||||||
} else {
|
} else {
|
||||||
m_threadContext.bios = nullptr;
|
m_threadContext.bios = nullptr;
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
appendMRU(context->fname);
|
if (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"));
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue