diff --git a/src/frontend/decoder/arm.h b/src/frontend/decoder/arm.h index 26a6a3a0..4400eede 100644 --- a/src/frontend/decoder/arm.h +++ b/src/frontend/decoder/arm.h @@ -229,7 +229,10 @@ std::vector> GetArmDecodeTable() { 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 + INST(&V::arm_STM, "STM", "cccc100010w0nnnnxxxxxxxxxxxxxxxx"), // all + INST(&V::arm_STMDA, "STMDA", "cccc100000w0nnnnxxxxxxxxxxxxxxxx"), // all + INST(&V::arm_STMDB, "STMDB", "cccc100100w0nnnnxxxxxxxxxxxxxxxx"), // all + INST(&V::arm_STMIB, "STMIB", "cccc100110w0nnnnxxxxxxxxxxxxxxxx"), // all INST(&V::arm_STM_usr, "STM (usr reg)", "----100--100--------------------"), // all // Miscellaneous instructions diff --git a/src/frontend/disassembler/disassembler_arm.cpp b/src/frontend/disassembler/disassembler_arm.cpp index ba3a8ac5..5a570a3d 100644 --- a/src/frontend/disassembler/disassembler_arm.cpp +++ b/src/frontend/disassembler/disassembler_arm.cpp @@ -381,7 +381,18 @@ public: } 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"; } + std::string arm_STM(Cond cond, bool W, Reg n, RegList list) { + return Common::StringFromFormat("stm%s %s%s, {%s}", CondToString(cond), RegToString(n), W ? "!" : "", RegListToString(list).c_str()); + } + std::string arm_STMDA(Cond cond, bool W, Reg n, RegList list) { + return Common::StringFromFormat("stmda%s %s%s, {%s}", CondToString(cond), RegToString(n), W ? "!" : "", RegListToString(list).c_str()); + } + std::string arm_STMDB(Cond cond, bool W, Reg n, RegList list) { + return Common::StringFromFormat("stmdb%s %s%s, {%s}", CondToString(cond), RegToString(n), W ? "!" : "", RegListToString(list).c_str()); + } + std::string arm_STMIB(Cond cond, bool W, Reg n, RegList list) { + return Common::StringFromFormat("stmib%s %s%s, {%s}", CondToString(cond), RegToString(n), W ? "!" : "", RegListToString(list).c_str()); + } std::string arm_STM_usr() { return "ice"; } // Miscellaneous instructions diff --git a/src/frontend/translate/translate_arm/load_store.cpp b/src/frontend/translate/translate_arm/load_store.cpp index b39bc9e7..2d652733 100644 --- a/src/frontend/translate/translate_arm/load_store.cpp +++ b/src/frontend/translate/translate_arm/load_store.cpp @@ -371,7 +371,6 @@ static bool LDMHelper(IREmitter& ir, bool W, Reg n, RegList list, IR::Value star return true; } - bool ArmTranslatorVisitor::arm_LDM(Cond cond, bool W, Reg n, RegList list) { if (n == Reg::PC || Common::BitCount(list) < 1) return UnpredictableInstruction(); @@ -428,8 +427,69 @@ bool ArmTranslatorVisitor::arm_LDM_eret() { return InterpretThisInstruction(); } -bool ArmTranslatorVisitor::arm_STM(Cond cond, bool P, bool U, bool W, Reg n, RegList list) { - return InterpretThisInstruction(); +static bool STMHelper(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.WriteMemory32(address, ir.GetRegister(static_cast(i))); + address = ir.Add(address, ir.Imm32(4)); + } + } + if (W) { + ir.SetRegister(n, writeback_address); + } + if (Common::Bit<15>(list)) { + ir.WriteMemory32(address, ir.Imm32(ir.PC())); + } + return true; +} + +bool ArmTranslatorVisitor::arm_STM(Cond cond, bool W, Reg n, RegList list) { + if (n == Reg::PC || Common::BitCount(list) < 1) + return UnpredictableInstruction(); + // STM {!}, + if (ConditionPassed(cond)) { + auto start_address = ir.GetRegister(n); + auto writeback_address = ir.Add(start_address, ir.Imm32(u32(Common::BitCount(list) * 4))); + return STMHelper(ir, W, n, list, start_address, writeback_address); + } + return true; +} + +bool ArmTranslatorVisitor::arm_STMDA(Cond cond, bool W, Reg n, RegList list) { + if (n == Reg::PC || Common::BitCount(list) < 1) + return UnpredictableInstruction(); + // STMDA {!}, + 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 STMHelper(ir, W, n, list, start_address, writeback_address); + } + return true; +} + +bool ArmTranslatorVisitor::arm_STMDB(Cond cond, bool W, Reg n, RegList list) { + if (n == Reg::PC || Common::BitCount(list) < 1) + return UnpredictableInstruction(); + // STMDB {!}, + if (ConditionPassed(cond)) { + auto start_address = ir.Sub(ir.GetRegister(n), ir.Imm32(u32(4 * Common::BitCount(list)))); + auto writeback_address = start_address; + return STMHelper(ir, W, n, list, start_address, writeback_address); + } + return true; +} + +bool ArmTranslatorVisitor::arm_STMIB(Cond cond, bool W, Reg n, RegList list) { + if (n == Reg::PC || Common::BitCount(list) < 1) + return UnpredictableInstruction(); + // STMIB {!}, + 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 STMHelper(ir, W, n, list, start_address, writeback_address); + } + return true; } bool ArmTranslatorVisitor::arm_STM_usr() { diff --git a/src/frontend/translate/translate_arm/translate_arm.h b/src/frontend/translate/translate_arm/translate_arm.h index 2ed2bf15..7d3374f4 100644 --- a/src/frontend/translate/translate_arm/translate_arm.h +++ b/src/frontend/translate/translate_arm/translate_arm.h @@ -192,7 +192,10 @@ struct ArmTranslatorVisitor final { 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); + bool arm_STM(Cond cond, bool W, Reg n, RegList list); + bool arm_STMDA(Cond cond, bool W, Reg n, RegList list); + bool arm_STMDB(Cond cond, bool W, Reg n, RegList list); + bool arm_STMIB(Cond cond, bool W, Reg n, RegList list); bool arm_STM_usr(); // Miscellaneous instructions