diff --git a/src/ARM.h b/src/ARM.h index dae5d96a..3bbc8735 100644 --- a/src/ARM.h +++ b/src/ARM.h @@ -272,12 +272,23 @@ public: void AddCycles_CI(s32 numI) override { - // code+internal + // code||internal s32 numC = CodeCycles; numI += 1; Cycles += std::max(numC, numI); } + void AddCycles_CIL(s32 numI, s32 numL) + { + // (code||internal)+forced interlock + // used by S variants of multiply instructions on the ARM9 + // seems that instead of adding extra hardware logic to allow for handling the memory stage of the instructions during the execute stage + // it instead seems to force a two cycle interlock allowing for the interlocked cycle to be executed without any special logic + presumably an extra cycle to set flags + s32 numC = CodeCycles; + numI += 1; + Cycles += std::max(numC, numI) + numL; + } + void AddCycles_CDI_LDR() override; void AddCycles_CDI_LDM() override; void AddCycles_CDI_SWP() override { AddCycles_CD_STR(); } // uses the same behavior as str diff --git a/src/ARMInterpreter_ALU.cpp b/src/ARMInterpreter_ALU.cpp index bc655996..e7b3ffb5 100644 --- a/src/ARMInterpreter_ALU.cpp +++ b/src/ARMInterpreter_ALU.cpp @@ -774,18 +774,23 @@ void A_MUL(ARM* cpu) if (cpu->Num==1) cpu->SetC(0); } - u32 cycles; if (cpu->Num == 0) - cycles = (cpu->CurInstr & (1<<20)) ? 3 : 1; + { + if (cpu->CurInstr & (1<<20)) + ((ARMv5*)cpu)->AddCycles_CIL(1, 2); + else + cpu->AddCycles_CI(1); + } else { + u32 cycles; if ((rs & 0xFFFFFF00) == 0x00000000 || (rs & 0xFFFFFF00) == 0xFFFFFF00) cycles = 1; else if ((rs & 0xFFFF0000) == 0x00000000 || (rs & 0xFFFF0000) == 0xFFFF0000) cycles = 2; else if ((rs & 0xFF000000) == 0x00000000 || (rs & 0xFF000000) == 0xFF000000) cycles = 3; else cycles = 4; - } - cpu->AddCycles_CI(cycles); + cpu->AddCycles_CI(cycles); + } } void A_MLA(ARM* cpu) @@ -804,18 +809,23 @@ void A_MLA(ARM* cpu) if (cpu->Num==1) cpu->SetC(0); } - u32 cycles; if (cpu->Num == 0) - cycles = (cpu->CurInstr & (1<<20)) ? 3 : 1; + { + if (cpu->CurInstr & (1<<20)) + ((ARMv5*)cpu)->AddCycles_CIL(1, 2); + else + cpu->AddCycles_CI(1); + } else { + u32 cycles; if ((rs & 0xFFFFFF00) == 0x00000000 || (rs & 0xFFFFFF00) == 0xFFFFFF00) cycles = 2; else if ((rs & 0xFFFF0000) == 0x00000000 || (rs & 0xFFFF0000) == 0xFFFF0000) cycles = 3; else if ((rs & 0xFF000000) == 0x00000000 || (rs & 0xFF000000) == 0xFF000000) cycles = 4; else cycles = 5; - } - cpu->AddCycles_CI(cycles); + cpu->AddCycles_CI(cycles); + } } void A_UMULL(ARM* cpu) @@ -834,18 +844,24 @@ void A_UMULL(ARM* cpu) if (cpu->Num==1) cpu->SetC(0); } - u32 cycles; if (cpu->Num == 0) - cycles = (cpu->CurInstr & (1<<20)) ? 3 : 1; + { + if (cpu->CurInstr & (1<<20)) + ((ARMv5*)cpu)->AddCycles_CIL(1, 2); + else + cpu->AddCycles_CI(1); + } else { + u32 cycles; if ((rs & 0xFFFFFF00) == 0x00000000) cycles = 2; else if ((rs & 0xFFFF0000) == 0x00000000) cycles = 3; else if ((rs & 0xFF000000) == 0x00000000) cycles = 4; else cycles = 5; + + cpu->AddCycles_CI(cycles); } - cpu->AddCycles_CI(cycles); } void A_UMLAL(ARM* cpu) @@ -867,18 +883,24 @@ void A_UMLAL(ARM* cpu) if (cpu->Num==1) cpu->SetC(0); } - u32 cycles; if (cpu->Num == 0) - cycles = (cpu->CurInstr & (1<<20)) ? 3 : 1; + { + if (cpu->CurInstr & (1<<20)) + ((ARMv5*)cpu)->AddCycles_CIL(1, 2); + else + cpu->AddCycles_CI(1); + } else { + u32 cycles; if ((rs & 0xFFFFFF00) == 0x00000000) cycles = 2; else if ((rs & 0xFFFF0000) == 0x00000000) cycles = 3; else if ((rs & 0xFF000000) == 0x00000000) cycles = 4; else cycles = 5; + + cpu->AddCycles_CI(cycles); } - cpu->AddCycles_CI(cycles); } void A_SMULL(ARM* cpu) @@ -897,18 +919,24 @@ void A_SMULL(ARM* cpu) if (cpu->Num==1) cpu->SetC(0); } - u32 cycles; if (cpu->Num == 0) - cycles = (cpu->CurInstr & (1<<20)) ? 3 : 1; + { + if (cpu->CurInstr & (1<<20)) + ((ARMv5*)cpu)->AddCycles_CIL(1, 2); + else + cpu->AddCycles_CI(1); + } else { + u32 cycles; if ((rs & 0xFFFFFF00) == 0x00000000 || (rs & 0xFFFFFF00) == 0xFFFFFF00) cycles = 2; else if ((rs & 0xFFFF0000) == 0x00000000 || (rs & 0xFFFF0000) == 0xFFFF0000) cycles = 3; else if ((rs & 0xFF000000) == 0x00000000 || (rs & 0xFF000000) == 0xFF000000) cycles = 4; else cycles = 5; + + cpu->AddCycles_CI(cycles); } - cpu->AddCycles_CI(cycles); } void A_SMLAL(ARM* cpu) @@ -930,18 +958,24 @@ void A_SMLAL(ARM* cpu) if (cpu->Num==1) cpu->SetC(0); } - u32 cycles; if (cpu->Num == 0) - cycles = (cpu->CurInstr & (1<<20)) ? 3 : 1; + { + if (cpu->CurInstr & (1<<20)) + ((ARMv5*)cpu)->AddCycles_CIL(1, 2); + else + cpu->AddCycles_CI(1); + } else { + u32 cycles; if ((rs & 0xFFFFFF00) == 0x00000000 || (rs & 0xFFFFFF00) == 0xFFFFFF00) cycles = 2; else if ((rs & 0xFFFF0000) == 0x00000000 || (rs & 0xFFFF0000) == 0xFFFF0000) cycles = 3; else if ((rs & 0xFF000000) == 0x00000000 || (rs & 0xFF000000) == 0xFF000000) cycles = 4; else cycles = 5; + + cpu->AddCycles_CI(cycles); } - cpu->AddCycles_CI(cycles); } void A_SMLAxy(ARM* cpu) @@ -1461,20 +1495,21 @@ void T_MUL_REG(ARM* cpu) cpu->SetNZ(res & 0x80000000, !res); - s32 cycles = 0; if (cpu->Num == 0) { - cycles += 3; + ((ARMv5*)cpu)->AddCycles_CIL(1, 2); // checkme? } else { + s32 cycles = 0; cpu->SetC(0); // carry flag destroyed, they say. whatever that means... if (a & 0xFF000000) cycles += 4; else if (a & 0x00FF0000) cycles += 3; else if (a & 0x0000FF00) cycles += 2; else cycles += 1; + + cpu->AddCycles_CI(cycles); } - cpu->AddCycles_CI(cycles); } void T_BIC_REG(ARM* cpu)