From 676f471ebe788120efebc69271f58d5e2af2564b Mon Sep 17 00:00:00 2001 From: Jaklyy <102590697+Jaklyy@users.noreply.github.com> Date: Fri, 8 Nov 2024 01:36:14 -0500 Subject: [PATCH 1/7] fix edge case with thumb prefetch aborts --- src/ARM.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ARM.cpp b/src/ARM.cpp index 7f5d2e86..beefc132 100644 --- a/src/ARM.cpp +++ b/src/ARM.cpp @@ -667,7 +667,7 @@ void ARMv5::Execute() if (IRQ && !(CPSR & 0x80)) TriggerIRQ(); - else if (CurInstr & ((u64)1<<63)) [[unlikely]] // handle aborted instructions + else if (CurInstr > 0xFFFFFFFF) [[unlikely]] // handle aborted instructions { PrefetchAbort(); } From 9f8cf8dad20d9c65fbf458ff610ec37361e6f3fc Mon Sep 17 00:00:00 2001 From: Jaklyy <102590697+Jaklyy@users.noreply.github.com> Date: Sat, 9 Nov 2024 14:49:34 -0500 Subject: [PATCH 2/7] ldm base writeback fails with r15 --- src/ARMInterpreter_LoadStore.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ARMInterpreter_LoadStore.cpp b/src/ARMInterpreter_LoadStore.cpp index 9dc14ea4..77628d7d 100644 --- a/src/ARMInterpreter_LoadStore.cpp +++ b/src/ARMInterpreter_LoadStore.cpp @@ -568,7 +568,7 @@ void A_LDM(ARM* cpu) } // writeback to base - if (cpu->CurInstr & (1<<21)) + if (cpu->CurInstr & (1<<21) && (baseid != 15)) { // post writeback if (cpu->CurInstr & (1<<23)) @@ -624,7 +624,7 @@ void A_STM(ARM* cpu) base -= 4; } - if (cpu->CurInstr & (1<<21)) + if ((cpu->CurInstr & (1<<21)) && (baseid != 15)) cpu->R[baseid] = base; preinc = !preinc; @@ -681,7 +681,7 @@ void A_STM(ARM* cpu) return; } - if ((cpu->CurInstr & (1<<23)) && (cpu->CurInstr & (1<<21))) + if ((cpu->CurInstr & (1<<23)) && (cpu->CurInstr & (1<<21)) && (baseid != 15)) cpu->R[baseid] = base; From e4dd913ba3a1151fca3cba1ab76ad386a85eef58 Mon Sep 17 00:00:00 2001 From: Jaklyy <102590697+Jaklyy@users.noreply.github.com> Date: Sat, 9 Nov 2024 15:38:08 -0500 Subject: [PATCH 3/7] arm7 RORs unaligned ldr(s)h ty mgba discord --- src/ARMInterpreter_LoadStore.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/ARMInterpreter_LoadStore.cpp b/src/ARMInterpreter_LoadStore.cpp index 77628d7d..80f82755 100644 --- a/src/ARMInterpreter_LoadStore.cpp +++ b/src/ARMInterpreter_LoadStore.cpp @@ -100,7 +100,10 @@ void LoadSingle(ARM* cpu, u8 rd, u8 rn, s32 offset) return; } if constexpr (size == 8 && signror) val = (s32)(s8)val; - if constexpr (size == 16 && signror) val = (s32)(s16)val; + + if constexpr (size == 16) if (cpu->Num == 1) val = ROR(val, ((addr&0x1)<<3)); // unaligned 16 bit loads are ROR'd on arm7 + if constexpr (size == 16 && signror) val = (s32)(((cpu->Num == 1) && (addr & 1)) ? (s8)val : (s16)val); // sign extend like a ldrsb if we ror'd the value. + if constexpr (size == 32 && signror) val = ROR(val, ((addr&0x3)<<3)); if constexpr (writeback != Writeback::None) cpu->R[rn] += offset; From bdc315198f302ed03fdaf435e58e42b1095e4366 Mon Sep 17 00:00:00 2001 From: Jaklyy <102590697+Jaklyy@users.noreply.github.com> Date: Sat, 9 Nov 2024 16:12:19 -0500 Subject: [PATCH 4/7] T_LDR_SPREL does ROR + misc cleanup --- src/ARMInterpreter_LoadStore.cpp | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/src/ARMInterpreter_LoadStore.cpp b/src/ARMInterpreter_LoadStore.cpp index 80f82755..4cd9a8fb 100644 --- a/src/ARMInterpreter_LoadStore.cpp +++ b/src/ARMInterpreter_LoadStore.cpp @@ -66,7 +66,7 @@ enum class Writeback Trans, }; -template +template void LoadSingle(ARM* cpu, u8 rd, u8 rn, s32 offset) { static_assert((size == 8) || (size == 16) || (size == 32), "dummy this function only takes 8/16/32 for size!!!"); @@ -99,14 +99,21 @@ void LoadSingle(ARM* cpu, u8 rd, u8 rn, s32 offset) ((ARMv5*)cpu)->DataAbort(); return; } - if constexpr (size == 8 && signror) val = (s32)(s8)val; + if constexpr (size == 8 && signextend) val = (s32)(s8)val; - if constexpr (size == 16) if (cpu->Num == 1) val = ROR(val, ((addr&0x1)<<3)); // unaligned 16 bit loads are ROR'd on arm7 - if constexpr (size == 16 && signror) val = (s32)(((cpu->Num == 1) && (addr & 1)) ? (s8)val : (s16)val); // sign extend like a ldrsb if we ror'd the value. + if constexpr (size == 16) + { + if (cpu->Num == 1) val = ROR(val, ((addr&0x1)<<3)); // unaligned 16 bit loads are ROR'd on arm7 + { + if constexpr (signextend) val = (s32)((addr&0x1) ? (s8)val : (s16)val); // sign extend like a ldrsb if we ror'd the value. + } + else if constexpr (signextend) val = (s32)(s16)val; + } - if constexpr (size == 32 && signror) val = ROR(val, ((addr&0x3)<<3)); + if constexpr (size == 32) val = ROR(val, ((addr&0x3)<<3)); - if constexpr (writeback != Writeback::None) cpu->R[rn] += offset; + + if constexpr (writeback != Writeback::None) cpu->R[rn] = addr; if (rd == 15) { @@ -173,12 +180,12 @@ void StoreSingle(ARM* cpu, u8 rd, u8 rn, s32 offset) else StoreSingle<8, Writeback::Post>(cpu, ((cpu->CurInstr>>12) & 0xF), ((cpu->CurInstr>>16) & 0xF), offset); #define A_LDR \ - if (cpu->CurInstr & (1<<21)) LoadSingle(cpu, ((cpu->CurInstr>>12) & 0xF), ((cpu->CurInstr>>16) & 0xF), offset); \ - else LoadSingle(cpu, ((cpu->CurInstr>>12) & 0xF), ((cpu->CurInstr>>16) & 0xF), offset); + if (cpu->CurInstr & (1<<21)) LoadSingle(cpu, ((cpu->CurInstr>>12) & 0xF), ((cpu->CurInstr>>16) & 0xF), offset); \ + else LoadSingle(cpu, ((cpu->CurInstr>>12) & 0xF), ((cpu->CurInstr>>16) & 0xF), offset); #define A_LDR_POST \ - if (cpu->CurInstr & (1<<21)) LoadSingle(cpu, ((cpu->CurInstr>>12) & 0xF), ((cpu->CurInstr>>16) & 0xF), offset); \ - else LoadSingle(cpu, ((cpu->CurInstr>>12) & 0xF), ((cpu->CurInstr>>16) & 0xF), offset); + if (cpu->CurInstr & (1<<21)) LoadSingle(cpu, ((cpu->CurInstr>>12) & 0xF), ((cpu->CurInstr>>16) & 0xF), offset); \ + else LoadSingle(cpu, ((cpu->CurInstr>>12) & 0xF), ((cpu->CurInstr>>16) & 0xF), offset); #define A_LDRB \ if (cpu->CurInstr & (1<<21)) LoadSingle(cpu, ((cpu->CurInstr>>12) & 0xF), ((cpu->CurInstr>>16) & 0xF), offset); \ @@ -723,7 +730,7 @@ void T_STRB_REG(ARM* cpu) void T_LDR_REG(ARM* cpu) { - LoadSingle(cpu, (cpu->CurInstr & 0x7), ((cpu->CurInstr >> 3) & 0x7), cpu->R[(cpu->CurInstr >> 6) & 0x7]); + LoadSingle(cpu, (cpu->CurInstr & 0x7), ((cpu->CurInstr >> 3) & 0x7), cpu->R[(cpu->CurInstr >> 6) & 0x7]); } void T_LDRB_REG(ARM* cpu) @@ -760,7 +767,7 @@ void T_STR_IMM(ARM* cpu) void T_LDR_IMM(ARM* cpu) { - LoadSingle(cpu, (cpu->CurInstr & 0x7), ((cpu->CurInstr >> 3) & 0x7), ((cpu->CurInstr >> 4) & 0x7C)); + LoadSingle(cpu, (cpu->CurInstr & 0x7), ((cpu->CurInstr >> 3) & 0x7), ((cpu->CurInstr >> 4) & 0x7C)); } void T_STRB_IMM(ARM* cpu) From ec241a822428392d4558245b9fc3bdc6aed148e5 Mon Sep 17 00:00:00 2001 From: Jaklyy <102590697+Jaklyy@users.noreply.github.com> Date: Sat, 9 Nov 2024 16:18:48 -0500 Subject: [PATCH 5/7] im smrat :D --- src/ARMInterpreter_LoadStore.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ARMInterpreter_LoadStore.cpp b/src/ARMInterpreter_LoadStore.cpp index 4cd9a8fb..97bef0b0 100644 --- a/src/ARMInterpreter_LoadStore.cpp +++ b/src/ARMInterpreter_LoadStore.cpp @@ -99,12 +99,14 @@ void LoadSingle(ARM* cpu, u8 rd, u8 rn, s32 offset) ((ARMv5*)cpu)->DataAbort(); return; } + if constexpr (size == 8 && signextend) val = (s32)(s8)val; if constexpr (size == 16) { - if (cpu->Num == 1) val = ROR(val, ((addr&0x1)<<3)); // unaligned 16 bit loads are ROR'd on arm7 + if (cpu->Num == 1) { + val = ROR(val, ((addr&0x1)<<3)); // unaligned 16 bit loads are ROR'd on arm7 if constexpr (signextend) val = (s32)((addr&0x1) ? (s8)val : (s16)val); // sign extend like a ldrsb if we ror'd the value. } else if constexpr (signextend) val = (s32)(s16)val; From fce0555a09283f7d5fdf6f195b4a9d8d2088b484 Mon Sep 17 00:00:00 2001 From: Jaklyy <102590697+Jaklyy@users.noreply.github.com> Date: Sat, 9 Nov 2024 22:07:17 -0500 Subject: [PATCH 6/7] slightly fix error in writeback handling --- src/ARMInterpreter_LoadStore.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ARMInterpreter_LoadStore.cpp b/src/ARMInterpreter_LoadStore.cpp index 97bef0b0..159fc86f 100644 --- a/src/ARMInterpreter_LoadStore.cpp +++ b/src/ARMInterpreter_LoadStore.cpp @@ -115,6 +115,7 @@ void LoadSingle(ARM* cpu, u8 rd, u8 rn, s32 offset) if constexpr (size == 32) val = ROR(val, ((addr&0x3)<<3)); + if constexpr (writeback >= Writeback::Post) addr += offset; if constexpr (writeback != Writeback::None) cpu->R[rn] = addr; if (rd == 15) @@ -160,8 +161,9 @@ void StoreSingle(ARM* cpu, u8 rd, u8 rn, s32 offset) ((ARMv5*)cpu)->DataAbort(); return; } - - if constexpr (writeback != Writeback::None) cpu->R[rn] += offset; + + if constexpr (writeback >= Writeback::Post) addr += offset; + if constexpr (writeback != Writeback::None) cpu->R[rn] = addr; } From 9d92b8708a2b805dbefe75fbf59612ec996d9f8d Mon Sep 17 00:00:00 2001 From: Jaklyy <102590697+Jaklyy@users.noreply.github.com> Date: Sun, 10 Nov 2024 02:56:16 -0500 Subject: [PATCH 7/7] r15 writeback is very weird with ldr/str --- src/ARMInterpreter_Branch.cpp | 2 +- src/ARMInterpreter_LoadStore.cpp | 30 ++++++++++++++++++++++++++---- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/src/ARMInterpreter_Branch.cpp b/src/ARMInterpreter_Branch.cpp index 88b14ab7..5731a0b6 100644 --- a/src/ARMInterpreter_Branch.cpp +++ b/src/ARMInterpreter_Branch.cpp @@ -104,7 +104,7 @@ void T_BL_LONG_1(ARM* cpu) void T_BL_LONG_2(ARM* cpu) { - if ((cpu->CurInstr & 0x1801) == 0x0801) // "BLX" with bit 0 set is an unvalid instruction. + if ((cpu->CurInstr & 0x1801) == 0x0801) // "BLX" with bit 0 set is an undefined instruction. return T_UNK(cpu); // TODO: Check ARM7 for exceptions s32 offset = (cpu->CurInstr & 0x7FF) << 1; diff --git a/src/ARMInterpreter_LoadStore.cpp b/src/ARMInterpreter_LoadStore.cpp index 159fc86f..a2c9d7cc 100644 --- a/src/ARMInterpreter_LoadStore.cpp +++ b/src/ARMInterpreter_LoadStore.cpp @@ -67,7 +67,7 @@ enum class Writeback }; template -void LoadSingle(ARM* cpu, u8 rd, u8 rn, s32 offset) +void LoadSingle(ARM* cpu, const u8 rd, const u8 rn, const s32 offset) { static_assert((size == 8) || (size == 16) || (size == 32), "dummy this function only takes 8/16/32 for size!!!"); @@ -116,7 +116,19 @@ void LoadSingle(ARM* cpu, u8 rd, u8 rn, s32 offset) if constexpr (writeback >= Writeback::Post) addr += offset; - if constexpr (writeback != Writeback::None) cpu->R[rn] = addr; + if constexpr (writeback != Writeback::None) + { + if (rn != 15) [[likely]] // r15 writeback fails on arm9 + { + cpu->R[rn] = addr; + } + else if (cpu->Num == 1) // arm 7 + { + // note that at no point does it actually write the value it loaded to a register... + cpu->JumpTo((addr+4) & ~1); + return; + } + } if (rd == 15) { @@ -127,7 +139,7 @@ void LoadSingle(ARM* cpu, u8 rd, u8 rn, s32 offset) } template -void StoreSingle(ARM* cpu, u8 rd, u8 rn, s32 offset) +void StoreSingle(ARM* cpu, const u8 rd, const u8 rn, const s32 offset) { static_assert((size == 8) || (size == 16) || (size == 32), "dummy this function only takes 8/16/32 for size!!!"); @@ -163,7 +175,17 @@ void StoreSingle(ARM* cpu, u8 rd, u8 rn, s32 offset) } if constexpr (writeback >= Writeback::Post) addr += offset; - if constexpr (writeback != Writeback::None) cpu->R[rn] = addr; + if constexpr (writeback != Writeback::None) + { + if (rn != 15) [[likely]] // r15 writeback fails on arm9 + { + cpu->R[rn] = addr; + } + else if (cpu->Num == 1) // arm 7 + { + cpu->JumpTo(addr & ~1); + } + } }