From 647be137f62fd12965d7c6bfe36f611823ce77b4 Mon Sep 17 00:00:00 2001 From: Ruben <40356555+Aikku93@users.noreply.github.com> Date: Sat, 13 Apr 2024 01:49:45 +1000 Subject: [PATCH] gba: set cpsr=spsr when switching to FIQ mode The CPSR register needs to be restored from SPSR when switching modes. This is currently being done for all mode switches /except/ for FIQ, which is very likely just an oversight rather than intended behaviour. This fixes the random crashing in OpenLara, as well as fixing random glitching of my own project that uses FIQ mode switches. The issue happens "at random" because it requires an interrupt to occur while in FIQ mode, and it must also fire inside a section of code that relies on the status flags (or the CPSR register in general): When exiting the interrupt exception, the CPSR register is supposed to be restored from SPSR, but this isn't being done when switching from IRQ mode back to FIQ mode, which results in CPSR (and thus the status flags) being corrupted. For example, SUBS r0, #1; [interrupt]; BNE 1b would trigger the bug, but [interrupt]; SUBS r0, #1; BNE 1b wouldn't, and neither would SUBS r0,#1; BNE 1b; [interrupt]. --- src/core/gba/gba.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/gba/gba.cpp b/src/core/gba/gba.cpp index 8a937cc2..c09e9b6b 100644 --- a/src/core/gba/gba.cpp +++ b/src/core/gba/gba.cpp @@ -1936,6 +1936,7 @@ void CPUSwitchMode(int mode, bool saveState, bool breakLoop) CPUSwap(®[12].I, ®[R12_FIQ].I); reg[13].I = reg[R13_FIQ].I; reg[14].I = reg[R14_FIQ].I; + reg[16].I = SPSR; if (saveState) reg[17].I = CPSR; else