Merge pull request #591 from lioncash/multiple
thumb32: Implement LDM/STM variants
This commit is contained in:
commit
03575dea84
4 changed files with 165 additions and 6 deletions
|
@ -163,6 +163,7 @@ if ("A32" IN_LIST DYNARMIC_FRONTENDS)
|
||||||
frontend/A32/translate/impl/thumb32_data_processing_shifted_register.cpp
|
frontend/A32/translate/impl/thumb32_data_processing_shifted_register.cpp
|
||||||
frontend/A32/translate/impl/thumb32_load_byte.cpp
|
frontend/A32/translate/impl/thumb32_load_byte.cpp
|
||||||
frontend/A32/translate/impl/thumb32_load_halfword.cpp
|
frontend/A32/translate/impl/thumb32_load_halfword.cpp
|
||||||
|
frontend/A32/translate/impl/thumb32_load_store_multiple.cpp
|
||||||
frontend/A32/translate/impl/thumb32_load_word.cpp
|
frontend/A32/translate/impl/thumb32_load_word.cpp
|
||||||
frontend/A32/translate/impl/thumb32_long_multiply.cpp
|
frontend/A32/translate/impl/thumb32_long_multiply.cpp
|
||||||
frontend/A32/translate/impl/thumb32_misc.cpp
|
frontend/A32/translate/impl/thumb32_misc.cpp
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
// Load/Store Multiple
|
// Load/Store Multiple
|
||||||
//INST(thumb32_SRS_1, "SRS", "1110100000-0--------------------")
|
//INST(thumb32_SRS_1, "SRS", "1110100000-0--------------------")
|
||||||
//INST(thumb32_RFE_2, "RFE", "1110100000-1--------------------")
|
//INST(thumb32_RFE_2, "RFE", "1110100000-1--------------------")
|
||||||
//INST(thumb32_STMIA, "STMIA/STMEA", "1110100010-0--------------------")
|
INST(thumb32_STMIA, "STMIA/STMEA", "1110100010W0nnnn0iiiiiiiiiiiiiii")
|
||||||
//INST(thumb32_POP, "POP", "1110100010111101----------------")
|
INST(thumb32_POP, "POP", "1110100010111101iiiiiiiiiiiiiiii")
|
||||||
//INST(thumb32_LDMIA, "LDMIA/LDMFD", "1110100010-1--------------------")
|
INST(thumb32_LDMIA, "LDMIA/LDMFD", "1110100010W1nnnniiiiiiiiiiiiiiii")
|
||||||
//INST(thumb32_PUSH, "PUSH", "1110100100101101----------------")
|
INST(thumb32_PUSH, "PUSH", "11101001001011010iiiiiiiiiiiiiii")
|
||||||
//INST(thumb32_STMDB, "STMDB/STMFD", "1110100100-0--------------------")
|
INST(thumb32_STMDB, "STMDB/STMFD", "1110100100W0nnnn0iiiiiiiiiiiiiii")
|
||||||
//INST(thumb32_LDMDB, "LDMDB/LDMEA", "1110100100-1--------------------")
|
INST(thumb32_LDMDB, "LDMDB/LDMEA", "1110100100W1nnnniiiiiiiiiiiiiiii")
|
||||||
//INST(thumb32_SRS_1, "SRS", "1110100110-0--------------------")
|
//INST(thumb32_SRS_1, "SRS", "1110100110-0--------------------")
|
||||||
//INST(thumb32_RFE_2, "RFE", "1110100110-1--------------------")
|
//INST(thumb32_RFE_2, "RFE", "1110100110-1--------------------")
|
||||||
|
|
||||||
|
|
150
src/frontend/A32/translate/impl/thumb32_load_store_multiple.cpp
Normal file
150
src/frontend/A32/translate/impl/thumb32_load_store_multiple.cpp
Normal file
|
@ -0,0 +1,150 @@
|
||||||
|
/* This file is part of the dynarmic project.
|
||||||
|
* Copyright (c) 2021 MerryMage
|
||||||
|
* SPDX-License-Identifier: 0BSD
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "common/bit_util.h"
|
||||||
|
#include "frontend/A32/translate/impl/translate_thumb.h"
|
||||||
|
|
||||||
|
namespace Dynarmic::A32 {
|
||||||
|
static bool ITBlockCheck(const A32::IREmitter& ir) {
|
||||||
|
return ir.current_location.IT().IsInITBlock() && !ir.current_location.IT().IsLastInITBlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool LDMHelper(A32::IREmitter& ir, bool W, Reg n, u32 list,
|
||||||
|
const IR::U32& start_address, const IR::U32& writeback_address) {
|
||||||
|
auto address = start_address;
|
||||||
|
for (size_t i = 0; i <= 14; i++) {
|
||||||
|
if (Common::Bit(i, list)) {
|
||||||
|
ir.SetRegister(static_cast<Reg>(i), ir.ReadMemory32(address));
|
||||||
|
address = ir.Add(address, ir.Imm32(4));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (W && !Common::Bit(RegNumber(n), list)) {
|
||||||
|
ir.SetRegister(n, writeback_address);
|
||||||
|
}
|
||||||
|
if (Common::Bit<15>(list)) {
|
||||||
|
ir.UpdateUpperLocationDescriptor();
|
||||||
|
ir.LoadWritePC(ir.ReadMemory32(address));
|
||||||
|
if (n == Reg::R13) {
|
||||||
|
ir.SetTerm(IR::Term::PopRSBHint{});
|
||||||
|
} else {
|
||||||
|
ir.SetTerm(IR::Term::FastDispatchHint{});
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool STMHelper(A32::IREmitter& ir, bool W, Reg n, u32 list,
|
||||||
|
const IR::U32& start_address, const IR::U32& 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<Reg>(i)));
|
||||||
|
address = ir.Add(address, ir.Imm32(4));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (W) {
|
||||||
|
ir.SetRegister(n, writeback_address);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ThumbTranslatorVisitor::thumb32_LDMDB(bool W, Reg n, Imm<16> reg_list) {
|
||||||
|
const auto regs_imm = reg_list.ZeroExtend();
|
||||||
|
const auto num_regs = static_cast<u32>(Common::BitCount(regs_imm));
|
||||||
|
|
||||||
|
if (n == Reg::PC || num_regs < 2) {
|
||||||
|
return UnpredictableInstruction();
|
||||||
|
}
|
||||||
|
if (reg_list.Bit<15>() && reg_list.Bit<14>()) {
|
||||||
|
return UnpredictableInstruction();
|
||||||
|
}
|
||||||
|
if (W && Common::Bit(static_cast<size_t>(n), regs_imm)) {
|
||||||
|
return UnpredictableInstruction();
|
||||||
|
}
|
||||||
|
if (reg_list.Bit<13>()) {
|
||||||
|
return UnpredictableInstruction();
|
||||||
|
}
|
||||||
|
if (reg_list.Bit<15>() && ITBlockCheck(ir)) {
|
||||||
|
return UnpredictableInstruction();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start address is the same as the writeback address.
|
||||||
|
const IR::U32 start_address = ir.Sub(ir.GetRegister(n), ir.Imm32(4 * num_regs));
|
||||||
|
return LDMHelper(ir, W, n, regs_imm, start_address, start_address);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ThumbTranslatorVisitor::thumb32_LDMIA(bool W, Reg n, Imm<16> reg_list) {
|
||||||
|
const auto regs_imm = reg_list.ZeroExtend();
|
||||||
|
const auto num_regs = static_cast<u32>(Common::BitCount(regs_imm));
|
||||||
|
|
||||||
|
if (n == Reg::PC || num_regs < 2) {
|
||||||
|
return UnpredictableInstruction();
|
||||||
|
}
|
||||||
|
if (reg_list.Bit<15>() && reg_list.Bit<14>()) {
|
||||||
|
return UnpredictableInstruction();
|
||||||
|
}
|
||||||
|
if (W && Common::Bit(static_cast<size_t>(n), regs_imm)) {
|
||||||
|
return UnpredictableInstruction();
|
||||||
|
}
|
||||||
|
if (reg_list.Bit<13>()) {
|
||||||
|
return UnpredictableInstruction();
|
||||||
|
}
|
||||||
|
if (reg_list.Bit<15>() && ITBlockCheck(ir)) {
|
||||||
|
return UnpredictableInstruction();
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto start_address = ir.GetRegister(n);
|
||||||
|
const auto writeback_address = ir.Add(start_address, ir.Imm32(num_regs * 4));
|
||||||
|
return LDMHelper(ir, W, n, regs_imm, start_address, writeback_address);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ThumbTranslatorVisitor::thumb32_POP(Imm<16> reg_list) {
|
||||||
|
return thumb32_LDMIA(true, Reg::SP, reg_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ThumbTranslatorVisitor::thumb32_PUSH(Imm<15> reg_list) {
|
||||||
|
return thumb32_STMDB(true, Reg::SP, reg_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ThumbTranslatorVisitor::thumb32_STMIA(bool W, Reg n, Imm<15> reg_list) {
|
||||||
|
const auto regs_imm = reg_list.ZeroExtend();
|
||||||
|
const auto num_regs = static_cast<u32>(Common::BitCount(regs_imm));
|
||||||
|
|
||||||
|
if (n == Reg::PC || num_regs < 2) {
|
||||||
|
return UnpredictableInstruction();
|
||||||
|
}
|
||||||
|
if (W && Common::Bit(static_cast<size_t>(n), regs_imm)) {
|
||||||
|
return UnpredictableInstruction();
|
||||||
|
}
|
||||||
|
if (reg_list.Bit<13>()) {
|
||||||
|
return UnpredictableInstruction();
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto start_address = ir.GetRegister(n);
|
||||||
|
const auto writeback_address = ir.Add(start_address, ir.Imm32(num_regs * 4));
|
||||||
|
return STMHelper(ir, W, n, regs_imm, start_address, writeback_address);
|
||||||
|
}
|
||||||
|
|
||||||
|
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<u32>(Common::BitCount(regs_imm));
|
||||||
|
|
||||||
|
if (n == Reg::PC || num_regs < 2) {
|
||||||
|
return UnpredictableInstruction();
|
||||||
|
}
|
||||||
|
if (W && Common::Bit(static_cast<size_t>(n), regs_imm)) {
|
||||||
|
return UnpredictableInstruction();
|
||||||
|
}
|
||||||
|
if (reg_list.Bit<13>()) {
|
||||||
|
return UnpredictableInstruction();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start address is the same as the writeback address.
|
||||||
|
const IR::U32 start_address = ir.Sub(ir.GetRegister(n), ir.Imm32(4 * num_regs));
|
||||||
|
return STMHelper(ir, W, n, regs_imm, start_address, start_address);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Dynarmic::A32
|
|
@ -171,6 +171,14 @@ struct ThumbTranslatorVisitor final {
|
||||||
bool thumb16_B_t1(Cond cond, Imm<8> imm8);
|
bool thumb16_B_t1(Cond cond, Imm<8> imm8);
|
||||||
bool thumb16_B_t2(Imm<11> imm11);
|
bool thumb16_B_t2(Imm<11> imm11);
|
||||||
|
|
||||||
|
// thumb32 load/store multiple instructions
|
||||||
|
bool thumb32_LDMDB(bool W, Reg n, Imm<16> reg_list);
|
||||||
|
bool thumb32_LDMIA(bool W, Reg n, Imm<16> reg_list);
|
||||||
|
bool thumb32_POP(Imm<16> reg_list);
|
||||||
|
bool thumb32_PUSH(Imm<15> reg_list);
|
||||||
|
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
|
// thumb32 data processing (shifted register) instructions
|
||||||
bool thumb32_TST_reg(Reg n, Imm<3> imm3, Imm<2> imm2, ShiftType type, Reg m);
|
bool thumb32_TST_reg(Reg n, Imm<3> imm3, Imm<2> imm2, ShiftType type, Reg m);
|
||||||
bool thumb32_AND_reg(bool S, Reg n, Imm<3> imm3, Reg d, Imm<2> imm2, ShiftType type, Reg m);
|
bool thumb32_AND_reg(bool S, Reg n, Imm<3> imm3, Reg d, Imm<2> imm2, ShiftType type, Reg m);
|
||||||
|
|
Loading…
Reference in a new issue