diff --git a/src/ARM.cpp b/src/ARM.cpp index 6ec14682..94f2debf 100644 --- a/src/ARM.cpp +++ b/src/ARM.cpp @@ -290,20 +290,20 @@ void ARMv5::BuggedJumpTo32(const u32 addr) { // ldrd to pc // behavior seems to be related to if a bugged 8/16 bit write has prefetch aborted (does any p.abort work?) - // switching to thumb mode only seems to work the first time after one of the above aborts? - // writing to pc seems to fail entirely if an abort hasn't occured and thumb interworking is in v4 mode + // switching to thumb mode only seems to work the first time an ldrd pc is executed after one of the above aborts? + // also it can restore cpsr but only if the PU is disabled (?????????????????????????????????????) if (BuggyJump == 1) { BuggyJump = 2; - JumpTo(addr); - } - else if ((BuggyJump == 0) && (CP15Control & (1<<15))) - { - return; // checkme + + if (CP15Control & (1<<15)) + JumpTo(addr & ~0x1, !(CP15Control & 1)); + else + JumpTo(addr, !(CP15Control & 1)); } else { - JumpTo(addr & ~0x1); + JumpTo(addr & ~0x1, !(CP15Control & 1)); } } @@ -313,23 +313,18 @@ void ARMv5::BuggedJumpTo(const u32 addr) // if they're misaligned they'll prefetch abort // but they can only prefetch abort once, every time afterwards will succeed (more testing needed) // if the lsb is set they will try to switch to thumb state, though it'll fail if they haven't prefetch aborted yet - // they work as expected if thumb interwork is set to v4 mode - if (BuggyJump == 0) + if ((BuggyJump == 0) && (addr & 0x3)) { - if (CP15Control & (1<<15)) - { - JumpTo(addr & ~1); - return; - } - else if (addr & 0x3) - { - if (addr & 0x1) CPSR |= 0x20; - BuggyJump = 1; - PrefetchAbort(); - return; - } + if (addr & 0x1) CPSR |= 0x20; + BuggyJump = 1; + PrefetchAbort(); + return; } - JumpTo(addr); + + if (CP15Control & (1<<15)) + JumpTo(addr & ~0x1); + else + JumpTo(addr); } void ARMv5::JumpTo(u32 addr, bool restorecpsr)