diff --git a/src/frontend/A32/decoder/thumb32.inc b/src/frontend/A32/decoder/thumb32.inc index 6347fd0b..461a3f20 100644 --- a/src/frontend/A32/decoder/thumb32.inc +++ b/src/frontend/A32/decoder/thumb32.inc @@ -12,7 +12,7 @@ INST(thumb32_LDMDB, "LDMDB/LDMEA", "1110100100W1nnnniiiiii // Load/Store Dual, Load/Store Exclusive, Table Branch INST(thumb32_STREX, "STREX", "111010000100nnnnttttddddiiiiiiii") -//INST(thumb32_LDREX, "LDREX", "111010000101--------------------") +INST(thumb32_LDREX, "LDREX", "111010000101nnnntttt1111iiiiiiii") INST(thumb32_STRD_imm_1, "STRD (imm)", "11101000U110nnnnttttssssiiiiiiii") INST(thumb32_STRD_imm_2, "STRD (imm)", "11101001U1W0nnnnttttssssiiiiiiii") INST(thumb32_LDRD_lit_1, "LDRD (lit)", "11101000U1111111ttttssssiiiiiiii") @@ -24,9 +24,9 @@ INST(thumb32_STREXH, "STREXH", "111010001100nnnntttt11 INST(thumb32_STREXD, "STREXD", "111010001100nnnnttttuuuu0111dddd") INST(thumb32_TBB, "TBB", "111010001101nnnn111100000000mmmm") INST(thumb32_TBH, "TBH", "111010001101nnnn111100000001mmmm") -//INST(thumb32_LDREXB, "LDREXB", "111010001101------------0100----") -//INST(thumb32_LDREXH, "LDREXH", "111010001101------------0101----") -//INST(thumb32_LDREXD, "LDREXD", "111010001101------------0111----") +INST(thumb32_LDREXB, "LDREXB", "111010001101nnnntttt111101001111") +INST(thumb32_LDREXH, "LDREXH", "111010001101nnnntttt111101011111") +INST(thumb32_LDREXD, "LDREXD", "111010001101nnnnttttuuuu01111111") // Data Processing (Shifted Register) INST(thumb32_TST_reg, "TST (reg)", "111010100001nnnn0vvv1111vvttmmmm") diff --git a/src/frontend/A32/translate/impl/thumb32_load_store_dual.cpp b/src/frontend/A32/translate/impl/thumb32_load_store_dual.cpp index 1a462cb6..c4a3baa1 100644 --- a/src/frontend/A32/translate/impl/thumb32_load_store_dual.cpp +++ b/src/frontend/A32/translate/impl/thumb32_load_store_dual.cpp @@ -135,6 +135,56 @@ bool ThumbTranslatorVisitor::thumb32_STRD_imm_2(bool U, bool W, Reg n, Reg t, Re return StoreDual(*this, true, U, W, n, t, t2, imm8); } +bool ThumbTranslatorVisitor::thumb32_LDREX(Reg n, Reg t, Imm<8> imm8) { + if (t == Reg::PC || n == Reg::PC) { + return UnpredictableInstruction(); + } + + const auto address = ir.Add(ir.GetRegister(n), ir.Imm32(imm8.ZeroExtend() << 2)); + const auto value = ir.ExclusiveReadMemory32(address); + + ir.SetRegister(t, value); + return true; +} + +bool ThumbTranslatorVisitor::thumb32_LDREXB(Reg n, Reg t) { + if (t == Reg::PC || n == Reg::PC) { + return UnpredictableInstruction(); + } + + const auto address = ir.GetRegister(n); + const auto value = ir.ZeroExtendToWord(ir.ExclusiveReadMemory8(address)); + + ir.SetRegister(t, value); + return true; +} + +bool ThumbTranslatorVisitor::thumb32_LDREXD(Reg n, Reg t, Reg t2) { + if (t == Reg::PC || t2 == Reg::PC || t == t2 || n == Reg::PC) { + return UnpredictableInstruction(); + } + + const auto address = ir.GetRegister(n); + const auto [lo, hi] = ir.ExclusiveReadMemory64(address); + + // DO NOT SWAP hi AND lo IN BIG ENDIAN MODE, THIS IS CORRECT BEHAVIOUR + ir.SetRegister(t, lo); + ir.SetRegister(t2, hi); + return true; +} + +bool ThumbTranslatorVisitor::thumb32_LDREXH(Reg n, Reg t) { + if (t == Reg::PC || n == Reg::PC) { + return UnpredictableInstruction(); + } + + const auto address = ir.GetRegister(n); + const auto value = ir.ZeroExtendToWord(ir.ExclusiveReadMemory16(address)); + + ir.SetRegister(t, value); + return true; +} + bool ThumbTranslatorVisitor::thumb32_STREX(Reg n, Reg t, Reg d, Imm<8> imm8) { if (d == Reg::PC || t == Reg::PC || n == Reg::PC) { return UnpredictableInstruction(); diff --git a/src/frontend/A32/translate/impl/translate_thumb.h b/src/frontend/A32/translate/impl/translate_thumb.h index 46a35e48..7c328aa7 100644 --- a/src/frontend/A32/translate/impl/translate_thumb.h +++ b/src/frontend/A32/translate/impl/translate_thumb.h @@ -186,6 +186,10 @@ struct ThumbTranslatorVisitor final { bool thumb32_LDRD_lit_2(bool U, bool W, Reg t, Reg t2, Imm<8> imm8); bool thumb32_STRD_imm_1(bool U, Reg n, Reg t, Reg t2, Imm<8> imm8); bool thumb32_STRD_imm_2(bool U, bool W, Reg n, Reg t, Reg t2, Imm<8> imm8); + bool thumb32_LDREX(Reg n, Reg t, Imm<8> imm8); + bool thumb32_LDREXD(Reg n, Reg t, Reg t2); + bool thumb32_LDREXB(Reg n, Reg t); + bool thumb32_LDREXH(Reg n, Reg t); bool thumb32_STREX(Reg n, Reg t, Reg d, Imm<8> imm8); bool thumb32_STREXB(Reg n, Reg t, Reg d); bool thumb32_STREXD(Reg n, Reg t, Reg t2, Reg d); diff --git a/tests/A32/fuzz_arm.cpp b/tests/A32/fuzz_arm.cpp index 311b6bb3..bb492058 100644 --- a/tests/A32/fuzz_arm.cpp +++ b/tests/A32/fuzz_arm.cpp @@ -168,6 +168,10 @@ std::vector GenRandomThumbInst(u32 pc, bool is_last_inst, A32::ITState it_s "thumb16_SETEND", // Exclusive load/stores + "thumb32_LDREX", + "thumb32_LDREXB", + "thumb32_LDREXD", + "thumb32_LDREXH", "thumb32_STREX", "thumb32_STREXB", "thumb32_STREXD",