From 6241ff6be2acdaa34dd555963f22c168fc40b261 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Thu, 1 Apr 2021 19:18:52 -0400 Subject: [PATCH] thumb32: Implement STREX variants Implements the exclusive store instructions. Now all that remains for ARMv7 load/stores to be done is the exclusive loads. --- src/frontend/A32/decoder/thumb32.inc | 8 +-- .../impl/thumb32_load_store_dual.cpp | 61 +++++++++++++++++++ .../A32/translate/impl/translate_thumb.h | 4 ++ tests/A32/fuzz_arm.cpp | 6 ++ 4 files changed, 75 insertions(+), 4 deletions(-) diff --git a/src/frontend/A32/decoder/thumb32.inc b/src/frontend/A32/decoder/thumb32.inc index 2e133989..6347fd0b 100644 --- a/src/frontend/A32/decoder/thumb32.inc +++ b/src/frontend/A32/decoder/thumb32.inc @@ -11,7 +11,7 @@ INST(thumb32_LDMDB, "LDMDB/LDMEA", "1110100100W1nnnniiiiii //INST(thumb32_RFE_2, "RFE", "1110100110-1--------------------") // Load/Store Dual, Load/Store Exclusive, Table Branch -//INST(thumb32_STREX, "STREX", "111010000100--------------------") +INST(thumb32_STREX, "STREX", "111010000100nnnnttttddddiiiiiiii") //INST(thumb32_LDREX, "LDREX", "111010000101--------------------") INST(thumb32_STRD_imm_1, "STRD (imm)", "11101000U110nnnnttttssssiiiiiiii") INST(thumb32_STRD_imm_2, "STRD (imm)", "11101001U1W0nnnnttttssssiiiiiiii") @@ -19,9 +19,9 @@ INST(thumb32_LDRD_lit_1, "LDRD (lit)", "11101000U1111111ttttss INST(thumb32_LDRD_lit_2, "LDRD (lit)", "11101001U1W11111ttttssssiiiiiiii") INST(thumb32_LDRD_imm_1, "LDRD (imm)", "11101000U111nnnnttttssssiiiiiiii") INST(thumb32_LDRD_imm_2, "LDRD (imm)", "11101001U1W1nnnnttttssssiiiiiiii") -//INST(thumb32_STREXB, "STREXB", "111010001100------------0100----") -//INST(thumb32_STREXH, "STREXH", "111010001100------------0101----") -//INST(thumb32_STREXD, "STREXD", "111010001100------------0111----") +INST(thumb32_STREXB, "STREXB", "111010001100nnnntttt11110100dddd") +INST(thumb32_STREXH, "STREXH", "111010001100nnnntttt11110101dddd") +INST(thumb32_STREXD, "STREXD", "111010001100nnnnttttuuuu0111dddd") INST(thumb32_TBB, "TBB", "111010001101nnnn111100000000mmmm") INST(thumb32_TBH, "TBH", "111010001101nnnn111100000001mmmm") //INST(thumb32_LDREXB, "LDREXB", "111010001101------------0100----") 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 c3d5323a..09918e65 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,67 @@ 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_STREX(Reg n, Reg t, Reg d, Imm<8> imm8) { + if (d == Reg::PC || t == Reg::PC || n == Reg::PC) { + return UnpredictableInstruction(); + } + if (d == n || d == t) { + return UnpredictableInstruction(); + } + + const auto address = ir.Add(ir.GetRegister(n), ir.Imm32(imm8.ZeroExtend())); + const auto value = ir.GetRegister(t); + const auto passed = ir.ExclusiveWriteMemory32(address, value); + ir.SetRegister(d, passed); + return true; +} + +bool ThumbTranslatorVisitor::thumb32_STREXB(Reg n, Reg t, Reg d) { + if (d == Reg::PC || t == Reg::PC || n == Reg::PC) { + return UnpredictableInstruction(); + } + if (d == n || d == t) { + return UnpredictableInstruction(); + } + + const auto address = ir.GetRegister(n); + const auto value = ir.LeastSignificantByte(ir.GetRegister(t)); + const auto passed = ir.ExclusiveWriteMemory8(address, value); + ir.SetRegister(d, passed); + return true; +} + +bool ThumbTranslatorVisitor::thumb32_STREXD(Reg n, Reg t, Reg t2, Reg d) { + if (d == Reg::PC || t == Reg::PC || t2 == Reg::PC || n == Reg::PC) { + return UnpredictableInstruction(); + } + if (d == n || d == t || d == t2) { + return UnpredictableInstruction(); + } + + const auto address = ir.GetRegister(n); + const auto value_lo = ir.GetRegister(t); + const auto value_hi = ir.GetRegister(t2); + const auto passed = ir.ExclusiveWriteMemory64(address, value_lo, value_hi); + ir.SetRegister(d, passed); + return true; +} + +bool ThumbTranslatorVisitor::thumb32_STREXH(Reg n, Reg t, Reg d) { + if (d == Reg::PC || t == Reg::PC || n == Reg::PC) { + return UnpredictableInstruction(); + } + if (d == n || d == t) { + return UnpredictableInstruction(); + } + + const auto address = ir.GetRegister(n); + const auto value = ir.LeastSignificantHalf(ir.GetRegister(t)); + const auto passed = ir.ExclusiveWriteMemory16(address, value); + ir.SetRegister(d, passed); + return true; +} + bool ThumbTranslatorVisitor::thumb32_TBB(Reg n, Reg m) { return TableBranch(*this, n, m, false); } diff --git a/src/frontend/A32/translate/impl/translate_thumb.h b/src/frontend/A32/translate/impl/translate_thumb.h index ce43eba5..46a35e48 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_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); + bool thumb32_STREXH(Reg n, Reg t, Reg d); bool thumb32_TBB(Reg n, Reg m); bool thumb32_TBH(Reg n, Reg m); diff --git a/tests/A32/fuzz_arm.cpp b/tests/A32/fuzz_arm.cpp index b0dcf94d..311b6bb3 100644 --- a/tests/A32/fuzz_arm.cpp +++ b/tests/A32/fuzz_arm.cpp @@ -166,6 +166,12 @@ std::vector GenRandomThumbInst(u32 pc, bool is_last_inst, A32::ITState it_s "thumb16_BKPT", "thumb16_IT", "thumb16_SETEND", + + // Exclusive load/stores + "thumb32_STREX", + "thumb32_STREXB", + "thumb32_STREXD", + "thumb32_STREXH", }; for (const auto& [fn, bitstring] : list) {