diff --git a/src/frontend/A32/decoder/thumb32.inc b/src/frontend/A32/decoder/thumb32.inc index 8095927c..8aabfc88 100644 --- a/src/frontend/A32/decoder/thumb32.inc +++ b/src/frontend/A32/decoder/thumb32.inc @@ -5,7 +5,7 @@ INST(thumb32_STMIA, "STMIA/STMEA", "1110100010W0nnnn0iiiii //INST(thumb32_POP, "POP", "1110100010111101----------------") //INST(thumb32_LDMIA, "LDMIA/LDMFD", "1110100010-1--------------------") //INST(thumb32_PUSH, "PUSH", "1110100100101101----------------") -//INST(thumb32_STMDB, "STMDB/STMFD", "1110100100-0--------------------") +INST(thumb32_STMDB, "STMDB/STMFD", "1110100100W0nnnn0iiiiiiiiiiiiiii") //INST(thumb32_LDMDB, "LDMDB/LDMEA", "1110100100-1--------------------") //INST(thumb32_SRS_1, "SRS", "1110100110-0--------------------") //INST(thumb32_RFE_2, "RFE", "1110100110-1--------------------") diff --git a/src/frontend/A32/translate/impl/thumb32_load_store_multiple.cpp b/src/frontend/A32/translate/impl/thumb32_load_store_multiple.cpp index a821d0aa..f6fb751d 100644 --- a/src/frontend/A32/translate/impl/thumb32_load_store_multiple.cpp +++ b/src/frontend/A32/translate/impl/thumb32_load_store_multiple.cpp @@ -26,9 +26,8 @@ bool ThumbTranslatorVisitor::thumb32_STMIA(bool W, Reg n, Imm<15> reg_list) { for (size_t i = 0; i < 15; i++) { if (Common::Bit(i, regs_imm)) { ir.WriteMemory32(address, ir.GetRegister(static_cast(i))); + address = ir.Add(address, ir.Imm32(4)); } - - address = ir.Add(address, ir.Imm32(4)); } if (W) { @@ -37,4 +36,34 @@ bool ThumbTranslatorVisitor::thumb32_STMIA(bool W, Reg n, Imm<15> reg_list) { return true; } +bool ThumbTranslatorVisitor::thumb32_STMDB(bool W, Reg n, Imm<15> reg_list) { + const auto regs_imm = reg_list.ZeroExtend(); + const auto num_regs = static_cast(Common::BitCount(regs_imm)); + + if (n == Reg::PC || num_regs < 2) { + return UnpredictableInstruction(); + } + if (W && Common::Bit(static_cast(n), regs_imm)) { + return UnpredictableInstruction(); + } + if (reg_list.Bit<13>()) { + return UnpredictableInstruction(); + } + + const IR::U32 start_address = ir.Sub(ir.GetRegister(n), ir.Imm32(4 * num_regs)); + IR::U32 address = start_address; + + for (size_t i = 0; i < 15; i++) { + if (Common::Bit(i, regs_imm)) { + ir.WriteMemory32(address, ir.GetRegister(static_cast(i))); + address = ir.Add(address, ir.Imm32(4)); + } + } + + if (W) { + ir.SetRegister(n, start_address); + } + return true; +} + } // namespace Dynarmic::A32 diff --git a/src/frontend/A32/translate/impl/translate_thumb.h b/src/frontend/A32/translate/impl/translate_thumb.h index 044bd9dd..33fa6147 100644 --- a/src/frontend/A32/translate/impl/translate_thumb.h +++ b/src/frontend/A32/translate/impl/translate_thumb.h @@ -173,6 +173,7 @@ struct ThumbTranslatorVisitor final { // thumb32 load/store multiple instructions bool thumb32_STMIA(bool W, Reg n, Imm<15> reg_list); + bool thumb32_STMDB(bool W, Reg n, Imm<15> reg_list); // thumb32 data processing (shifted register) instructions bool thumb32_TST_reg(Reg n, Imm<3> imm3, Imm<2> imm2, ShiftType type, Reg m);