From 85549d7ae2df1037925d4023761e808a9b94b13b Mon Sep 17 00:00:00 2001 From: MerryMage Date: Mon, 8 Aug 2016 22:21:10 +0100 Subject: [PATCH] TranslateArm: Implement LDM, LDMDA, LDMDB, LDMIB --- src/frontend/decoder/arm.h | 5 +- .../disassembler/disassembler_arm.cpp | 13 +++- .../translate/translate_arm/load_store.cpp | 68 ++++++++++++++++++- .../translate/translate_arm/translate_arm.h | 5 +- 4 files changed, 86 insertions(+), 5 deletions(-) diff --git a/src/frontend/decoder/arm.h b/src/frontend/decoder/arm.h index 3f4d445f..26a6a3a0 100644 --- a/src/frontend/decoder/arm.h +++ b/src/frontend/decoder/arm.h @@ -223,7 +223,10 @@ std::vector> GetArmDecodeTable() { INST(&V::arm_STRT, "STRT (A2)", "----0110-010---------------0----"), // Load/Store Multiple instructions - INST(&V::arm_LDM, "LDM", "cccc100pu0w1nnnnxxxxxxxxxxxxxxxx"), // all + INST(&V::arm_LDM, "LDM", "cccc100010w1nnnnxxxxxxxxxxxxxxxx"), // all + INST(&V::arm_LDMDA, "LDMDA", "cccc100000w1nnnnxxxxxxxxxxxxxxxx"), // all + INST(&V::arm_LDMDB, "LDMDB", "cccc100100w1nnnnxxxxxxxxxxxxxxxx"), // all + INST(&V::arm_LDMIB, "LDMIB", "cccc100110w1nnnnxxxxxxxxxxxxxxxx"), // all INST(&V::arm_LDM_usr, "LDM (usr reg)", "----100--101--------------------"), // all INST(&V::arm_LDM_eret, "LDM (exce ret)", "----100--1-1----1---------------"), // all INST(&V::arm_STM, "STM", "cccc100pu0w0nnnnxxxxxxxxxxxxxxxx"), // all diff --git a/src/frontend/disassembler/disassembler_arm.cpp b/src/frontend/disassembler/disassembler_arm.cpp index e5214ec9..ba3a8ac5 100644 --- a/src/frontend/disassembler/disassembler_arm.cpp +++ b/src/frontend/disassembler/disassembler_arm.cpp @@ -367,7 +367,18 @@ public: std::string arm_STRT() { return "ice"; } // Load/Store multiple instructions - std::string arm_LDM(Cond cond, bool P, bool U, bool W, Reg n, RegList list) { return "ice"; } + std::string arm_LDM(Cond cond, bool W, Reg n, RegList list) { + return Common::StringFromFormat("ldm%s %s%s, {%s}", CondToString(cond), RegToString(n), W ? "!" : "", RegListToString(list).c_str()); + } + std::string arm_LDMDA(Cond cond, bool W, Reg n, RegList list) { + return Common::StringFromFormat("ldmda%s %s%s, {%s}", CondToString(cond), RegToString(n), W ? "!" : "", RegListToString(list).c_str()); + } + std::string arm_LDMDB(Cond cond, bool W, Reg n, RegList list) { + return Common::StringFromFormat("ldmdb%s %s%s, {%s}", CondToString(cond), RegToString(n), W ? "!" : "", RegListToString(list).c_str()); + } + std::string arm_LDMIB(Cond cond, bool W, Reg n, RegList list) { + return Common::StringFromFormat("ldmib%s %s%s, {%s}", CondToString(cond), RegToString(n), W ? "!" : "", RegListToString(list).c_str()); + } std::string arm_LDM_usr() { return "ice"; } std::string arm_LDM_eret() { return "ice"; } std::string arm_STM(Cond cond, bool P, bool U, bool W, Reg n, RegList list) { return "ice"; } diff --git a/src/frontend/translate/translate_arm/load_store.cpp b/src/frontend/translate/translate_arm/load_store.cpp index 2237ea47..b39bc9e7 100644 --- a/src/frontend/translate/translate_arm/load_store.cpp +++ b/src/frontend/translate/translate_arm/load_store.cpp @@ -352,8 +352,72 @@ bool ArmTranslatorVisitor::arm_STRT() { return InterpretThisInstruction(); } -bool ArmTranslatorVisitor::arm_LDM(Cond cond, bool P, bool U, bool W, Reg n, RegList list) { - return InterpretThisInstruction(); +static bool LDMHelper(IREmitter& ir, bool W, Reg n, RegList list, IR::Value start_address, IR::Value writeback_address) { + auto address = start_address; + for (size_t i = 0; i <= 14; i++) { + if (Common::Bit(i, list)) { + ir.SetRegister(static_cast(i), ir.ReadMemory32(address)); + address = ir.Add(address, ir.Imm32(4)); + } + } + if (W) { + ir.SetRegister(n, writeback_address); + } + if (Common::Bit<15>(list)) { + ir.LoadWritePC(ir.ReadMemory32(address)); + ir.SetTerm(IR::Term::ReturnToDispatch{}); + return false; + } + return true; +} + + +bool ArmTranslatorVisitor::arm_LDM(Cond cond, bool W, Reg n, RegList list) { + if (n == Reg::PC || Common::BitCount(list) < 1) + return UnpredictableInstruction(); + // LDM {!}, + if (ConditionPassed(cond)) { + auto start_address = ir.GetRegister(n); + auto writeback_address = ir.Add(start_address, ir.Imm32(u32(Common::BitCount(list) * 4))); + return LDMHelper(ir, W, n, list, start_address, writeback_address); + } + return true; +} + +bool ArmTranslatorVisitor::arm_LDMDA(Cond cond, bool W, Reg n, RegList list) { + if (n == Reg::PC || Common::BitCount(list) < 1) + return UnpredictableInstruction(); + // LDMDA {!}, + if (ConditionPassed(cond)) { + auto start_address = ir.Sub(ir.GetRegister(n), ir.Imm32(u32(4 * Common::BitCount(list) - 4))); + auto writeback_address = ir.Add(start_address, ir.Imm32(4)); + return LDMHelper(ir, W, n, list, start_address, writeback_address); + } + return true; +} + +bool ArmTranslatorVisitor::arm_LDMDB(Cond cond, bool W, Reg n, RegList list) { + if (n == Reg::PC || Common::BitCount(list) < 1) + return UnpredictableInstruction(); + // LDMDB {!}, + if (ConditionPassed(cond)) { + auto start_address = ir.Sub(ir.GetRegister(n), ir.Imm32(u32(4 * Common::BitCount(list)))); + auto writeback_address = start_address; + return LDMHelper(ir, W, n, list, start_address, writeback_address); + } + return true; +} + +bool ArmTranslatorVisitor::arm_LDMIB(Cond cond, bool W, Reg n, RegList list) { + if (n == Reg::PC || Common::BitCount(list) < 1) + return UnpredictableInstruction(); + // LDMIB {!}, + if (ConditionPassed(cond)) { + auto start_address = ir.Add(ir.GetRegister(n), ir.Imm32(4)); + auto writeback_address = ir.Add(ir.GetRegister(n), ir.Imm32(u32(4 * Common::BitCount(list)))); + return LDMHelper(ir, W, n, list, start_address, writeback_address); + } + return true; } bool ArmTranslatorVisitor::arm_LDM_usr() { diff --git a/src/frontend/translate/translate_arm/translate_arm.h b/src/frontend/translate/translate_arm/translate_arm.h index 05c3ec93..2ed2bf15 100644 --- a/src/frontend/translate/translate_arm/translate_arm.h +++ b/src/frontend/translate/translate_arm/translate_arm.h @@ -186,7 +186,10 @@ struct ArmTranslatorVisitor final { bool arm_STRT(); // Load/Store multiple instructions - bool arm_LDM(Cond cond, bool P, bool U, bool W, Reg n, RegList list); + bool arm_LDM(Cond cond, bool W, Reg n, RegList list); + bool arm_LDMDA(Cond cond, bool W, Reg n, RegList list); + bool arm_LDMDB(Cond cond, bool W, Reg n, RegList list); + bool arm_LDMIB(Cond cond, bool W, Reg n, RegList list); bool arm_LDM_usr(); bool arm_LDM_eret(); bool arm_STM(Cond cond, bool P, bool U, bool W, Reg n, RegList list);