diff --git a/src/ARM.cpp b/src/ARM.cpp index 6518b751..ade9649f 100644 --- a/src/ARM.cpp +++ b/src/ARM.cpp @@ -385,6 +385,7 @@ void ARMv4::JumpTo(u32 addr, bool restorecpsr) if (addr & 0x1) { + Thumb = true; addr &= ~0x1; R[15] = addr+2; @@ -398,6 +399,7 @@ void ARMv4::JumpTo(u32 addr, bool restorecpsr) } else { + Thumb = false; addr &= ~0x3; R[15] = addr+4; @@ -831,35 +833,63 @@ void ARMv4::Execute() else #endif { - if (CPSR & 0x20) // THUMB + if (Thumb) // THUMB { + // attempt to delay t bit changes without a pipeline flush (msr) by one instruction + Thumb = CPSR & 0x20; if constexpr (mode == CPUExecuteMode::InterpreterGDB) GdbCheckC(); // prefetch - R[15] += 2; - CurInstr = NextInstr[0]; - NextInstr[0] = NextInstr[1]; - NextInstr[1] = CodeRead16(R[15]); + // thumb bit can change without a flush and is usually delayed 1 instruction + // but if the code fetch takes more than 1 cycle(?) it can take effect early for just the code fetch + if (!Thumb && (NDS.ARM7MemTimings[CodeCycles][2] > 1)) [[unlikely]] // checkme + { + R[15] = (R[15] + 4) & ~0x3; + CurInstr = NextInstr[0]; + NextInstr[0] = NextInstr[1]; + NextInstr[1] = CodeRead32(R[15]); + } + else + { + R[15] += 2; + CurInstr = NextInstr[0]; + NextInstr[0] = NextInstr[1]; + NextInstr[1] = CodeRead16(R[15]); + } if (IRQ && !(CPSR & 0x80)) TriggerIRQ(); else { // actually execute - u32 icode = (CurInstr >> 6); + u32 icode = (CurInstr >> 6) & 0x3FF; ARMInterpreter::THUMBInstrTable[icode](this); } } else { + // attempt to delay t bit changes without a pipeline flush (msr) by one instruction + Thumb = CPSR & 0x20; if constexpr (mode == CPUExecuteMode::InterpreterGDB) GdbCheckC(); - + // prefetch - R[15] += 4; - CurInstr = NextInstr[0]; - NextInstr[0] = NextInstr[1]; - NextInstr[1] = CodeRead32(R[15]); + // thumb bit can change without a flush and is usually delayed 1 instruction + // but if the code fetch takes more than 1 cycle(?) it can take effect early for just the code fetch + if (Thumb && (NDS.ARM7MemTimings[CodeCycles][2] > 1)) [[unlikely]] // checkme? + { + R[15] = (R[15] + 4) & ~0x3; + CurInstr = NextInstr[0]; + NextInstr[0] = NextInstr[1]; + NextInstr[1] = CodeRead16(R[15]); + } + else + { + R[15] = (R[15] + 4) & ~0x3; + CurInstr = NextInstr[0]; + NextInstr[0] = NextInstr[1]; + NextInstr[1] = CodeRead32(R[15]); + } if (IRQ && !(CPSR & 0x80)) TriggerIRQ(); else if (CheckCondition(CurInstr >> 28)) // actually execute diff --git a/src/ARM.h b/src/ARM.h index 26080b51..81d6be39 100644 --- a/src/ARM.h +++ b/src/ARM.h @@ -416,6 +416,9 @@ public: void AddCycles_CDI() override; void AddCycles_CD() override; +private: + bool Thumb; + protected: u8 BusRead8(u32 addr) override; u16 BusRead16(u32 addr) override; diff --git a/src/ARMInterpreter.cpp b/src/ARMInterpreter.cpp index 72d1e189..cc19df3b 100644 --- a/src/ARMInterpreter.cpp +++ b/src/ARMInterpreter.cpp @@ -129,11 +129,11 @@ void A_MSR_IMM(ARM* cpu) if (cpu->CPSR & 0x20) [[unlikely]] { if (cpu->Num == 0) cpu->NextInstr[1] &= 0xFFFF; // checkme: probably not the right way to handle this - else + /*else { Platform::Log(Platform::LogLevel::Warn, "UNIMPLEMENTED: MSR REG T bit change on ARM7\n"); cpu->CPSR &= ~0x20; // keep it from crashing the emulator at least - } + }*/ } cpu->AddCycles_C(); diff --git a/src/ARMInterpreter_ALU.cpp b/src/ARMInterpreter_ALU.cpp index 9305fc42..abe2bce0 100644 --- a/src/ARMInterpreter_ALU.cpp +++ b/src/ARMInterpreter_ALU.cpp @@ -585,16 +585,7 @@ A_IMPLEMENT_ALU_OP(RSC,) !res); \ if (((cpu->CurInstr>>12) & 0xF) == 15) [[unlikely]] /* yes this instruction has a secret rd for some reason */ \ { \ - if (cpu->Num == 1) \ - { \ - u32 oldpsr = cpu->CPSR; \ - cpu->RestoreCPSR(); /* ARM7TDMI restores cpsr and does ___not___ flush the pipeline. */ \ - if (cpu->CPSR & 0x20) \ - { \ - Platform::Log(Platform::LogLevel::Warn, "UNIMPLEMENTED: TST T bit change on ARM7\n"); \ - cpu->CPSR &= ~0x20; /* keep it from crashing the emulator at least */ \ - } \ - } \ + if (cpu->Num == 1) cpu->RestoreCPSR(); /* ARM7 restores cpsr and does ___not___ flush the pipeline. */ \ else Platform::Log(Platform::LogLevel::Warn, "UNIMPLEMENTED: TST w/ rd == 15 on ARM9\n"); \ } \ if (c) cpu->AddCycles_CI(c); else cpu->AddCycles_C(); @@ -609,16 +600,7 @@ A_IMPLEMENT_ALU_TEST(TST,_S) !res); \ if (((cpu->CurInstr>>12) & 0xF) == 15) [[unlikely]] /* yes this instruction has a secret rd for some reason */ \ { \ - if (cpu->Num == 1) \ - { \ - u32 oldpsr = cpu->CPSR; \ - cpu->RestoreCPSR(); /* ARM7TDMI restores cpsr and does ___not___ flush the pipeline. */ \ - if (cpu->CPSR & 0x20) \ - { \ - Platform::Log(Platform::LogLevel::Warn, "UNIMPLEMENTED: TEQ T bit change on ARM7\n"); \ - cpu->CPSR &= ~0x20; /* keep it from crashing the emulator at least */ \ - } \ - } \ + if (cpu->Num == 1) cpu->RestoreCPSR(); /* ARM7 restores cpsr and does ___not___ flush the pipeline. */ \ else Platform::Log(Platform::LogLevel::Warn, "UNIMPLEMENTED: TEQ w/ rd == 15 on ARM9\n"); \ } \ if (c) cpu->AddCycles_CI(c); else cpu->AddCycles_C(); @@ -635,16 +617,7 @@ A_IMPLEMENT_ALU_TEST(TEQ,_S) OverflowSub(a, b)); \ if (((cpu->CurInstr>>12) & 0xF) == 15) [[unlikely]] /* yes this instruction has a secret rd for some reason */ \ { \ - if (cpu->Num == 1) \ - { \ - u32 oldpsr = cpu->CPSR; \ - cpu->RestoreCPSR(); /* ARM7TDMI restores cpsr and does ___not___ flush the pipeline. */ \ - if (cpu->CPSR & 0x20) \ - { \ - Platform::Log(Platform::LogLevel::Warn, "UNIMPLEMENTED: CMP T bit change on ARM7\n"); \ - cpu->CPSR &= ~0x20; /* keep it from crashing the emulator at least */ \ - } \ - } \ + if (cpu->Num == 1) cpu->RestoreCPSR(); /* ARM7 restores cpsr and does ___not___ flush the pipeline. */ \ else Platform::Log(Platform::LogLevel::Warn, "UNIMPLEMENTED: CMP w/ rd == 15 on ARM9\n"); \ } \ if (c) cpu->AddCycles_CI(c); else cpu->AddCycles_C(); @@ -661,16 +634,7 @@ A_IMPLEMENT_ALU_TEST(CMP,) OverflowAdd(a, b)); \ if (((cpu->CurInstr>>12) & 0xF) == 15) [[unlikely]] /* yes this instruction has a secret rd for some reason */ \ { \ - if (cpu->Num == 1) \ - { \ - u32 oldpsr = cpu->CPSR; \ - cpu->RestoreCPSR(); /* ARM7TDMI restores cpsr and does ___not___ flush the pipeline. */ \ - if (cpu->CPSR & 0x20) \ - { \ - Platform::Log(Platform::LogLevel::Warn, "UNIMPLEMENTED: CMN T bit change on ARM7\n"); \ - cpu->CPSR &= ~0x20; /* keep it from crashing the emulator at least */ \ - } \ - } \ + if (cpu->Num == 1) cpu->RestoreCPSR(); /* ARM7 restores cpsr and does ___not___ flush the pipeline. */ \ else Platform::Log(Platform::LogLevel::Warn, "UNIMPLEMENTED: CMN w/ rd == 15 on ARM9\n"); \ } \ if (c) cpu->AddCycles_CI(c); else cpu->AddCycles_C(); @@ -1627,16 +1591,7 @@ void T_CMP_HIREG(ARM* cpu) OverflowSub(a, b)); if (rd == 15) [[unlikely]] { - if (cpu->Num == 1) - { - u32 oldpsr = cpu->CPSR; - cpu->RestoreCPSR(); // ARM7TDMI restores cpsr and does ___not___ flush the pipeline. - if (!(cpu->CPSR & 0x20)) - { - Platform::Log(Platform::LogLevel::Warn, "UNIMPLEMENTED: MSR REG T bit change on ARM7\n"); - cpu->CPSR |= 0x20; // keep it from crashing the emulator at least - } - } + if (cpu->Num == 1) cpu->RestoreCPSR(); // ARM7 restores cpsr and does ___not___ flush the pipeline. else Platform::Log(Platform::LogLevel::Warn, "UNIMPLEMENTED: CMP HIREG w/ rd == 15 on ARM9\n"); } cpu->AddCycles_C();