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].
This commit is contained in:
parent
8abe3e79da
commit
647be137f6
|
@ -1936,6 +1936,7 @@ void CPUSwitchMode(int mode, bool saveState, bool breakLoop)
|
||||||
CPUSwap(®[12].I, ®[R12_FIQ].I);
|
CPUSwap(®[12].I, ®[R12_FIQ].I);
|
||||||
reg[13].I = reg[R13_FIQ].I;
|
reg[13].I = reg[R13_FIQ].I;
|
||||||
reg[14].I = reg[R14_FIQ].I;
|
reg[14].I = reg[R14_FIQ].I;
|
||||||
|
reg[16].I = SPSR;
|
||||||
if (saveState)
|
if (saveState)
|
||||||
reg[17].I = CPSR;
|
reg[17].I = CPSR;
|
||||||
else
|
else
|
||||||
|
|
Loading…
Reference in New Issue