Implement thumb STM, LDM. Fix thumb POP implementation for P=1.

This commit is contained in:
MerryMage 2016-07-18 20:05:35 +01:00
parent 8a310777a1
commit 2363759c62
4 changed files with 78 additions and 39 deletions

View file

@ -137,8 +137,8 @@ boost::optional<const Thumb16Matcher<V>&> DecodeThumb16(u16 instruction) {
//INST(&V::thumb16_BKPT, "BKPT", "10111110xxxxxxxx"), // v5
// Store/Load multiple registers
//INST(&V::thumb16_STMIA, "STMIA", "11000nnnxxxxxxxx"),
//INST(&V::thumb16_LDMIA, "LDMIA", "11001nnnxxxxxxxx"),
INST(&V::thumb16_STMIA, "STMIA", "11000nnnxxxxxxxx"),
INST(&V::thumb16_LDMIA, "LDMIA", "11001nnnxxxxxxxx"),
// Branch instructions
//INST(&V::thumb16_BX, "BX (reg)", "010001110mmmm000"), // v4T

View file

@ -102,6 +102,20 @@ public:
return "<internal error>";
}
std::string RegListStr(RegList reg_list) {
std::string ret = "";
bool first_reg = true;
for (size_t i = 0; i < 16; i++) {
if (Common::Bit(i, reg_list)) {
if (!first_reg)
ret += ", ";
ret += RegStr(static_cast<Reg>(i));
first_reg = false;
}
}
return ret;
}
std::string thumb16_LSL_imm(Imm5 imm5, Reg m, Reg d) {
return Common::StringFromFormat("lsls %s, %s, #%u", RegStr(d), RegStr(m), imm5);
}
@ -336,39 +350,13 @@ public:
}
std::string thumb16_PUSH(bool M, RegList reg_list) {
if (M)
reg_list |= 1 << 14;
std::string ret = "PUSH ";
bool first_reg = true;
for (size_t i = 0; i < 16; i++) {
if (Common::Bit(i, reg_list)) {
if (!first_reg)
ret += ", ";
ret += RegStr(static_cast<Reg>(i));
first_reg = false;
}
}
return ret;
if (M) reg_list |= 1 << 14;
return "push " + RegListStr(reg_list);
}
std::string thumb16_POP(bool P, RegList reg_list) {
if (P)
reg_list |= 1 << 15;
std::string ret = "PUSH ";
bool first_reg = true;
for (size_t i = 0; i < 16; i++) {
if (Common::Bit(i, reg_list)) {
if (!first_reg)
ret += ", ";
ret += RegStr(static_cast<Reg>(i));
first_reg = false;
}
}
return ret;
if (P) reg_list |= 1 << 15;
return "pop " + RegListStr(reg_list);
}
std::string thumb16_REV(Reg m, Reg d) {
@ -383,6 +371,16 @@ public:
return Common::StringFromFormat("revsh %s, %s", RegStr(d), RegStr(m));
}
std::string thumb16_STMIA(Reg n, RegList reg_list) {
return Common::StringFromFormat("stm %s!, %s", RegStr(n), RegListStr(reg_list).c_str());
}
std::string thumb16_LDMIA(Reg n, RegList reg_list) {
bool write_back = !Dynarmic::Common::Bit(static_cast<size_t>(n), reg_list);
return Common::StringFromFormat("ldm %s%s, %s", RegStr(n), write_back ? "!" : "", RegListStr(reg_list).c_str());
}
std::string thumb16_UDF() {
return Common::StringFromFormat("udf");
}

View file

@ -661,9 +661,18 @@ struct ThumbTranslatorVisitor final {
address = ir.Add(address, ir.Imm32(4));
}
}
ir.SetRegister(Reg::SP, address);
// TODO(optimization): Possible location for an RSB push.
return true;
if (Common::Bit<15>(reg_list)) {
// TODO(optimization): Possible location for an RSB pop.
auto data = ir.ReadMemory32(address);
ir.LoadWritePC(data);
address = ir.Add(address, ir.Imm32(4));
ir.SetRegister(Reg::SP, address);
ir.SetTerm(IR::Term::ReturnToDispatch{});
return false;
} else {
ir.SetRegister(Reg::SP, address);
return true;
}
}
bool thumb16_REV(Reg m, Reg d) {
@ -696,6 +705,37 @@ struct ThumbTranslatorVisitor final {
return true;
}
bool thumb16_STMIA(Reg n, RegList reg_list) {
// STM <Rn>!, <reg_list>
auto address = ir.GetRegister(n);
for (size_t i = 0; i < 8; i++) {
if (Common::Bit(i, reg_list)) {
auto Ri = ir.GetRegister(static_cast<Reg>(i));
ir.WriteMemory32(address, Ri);
address = ir.Add(address, ir.Imm32(4));
}
}
ir.SetRegister(n, address);
return true;
}
bool thumb16_LDMIA(Reg n, RegList reg_list) {
bool write_back = !Dynarmic::Common::Bit(static_cast<size_t>(n), reg_list);
// STM <Rn>!, <reg_list>
auto address = ir.GetRegister(n);
for (size_t i = 0; i < 8; i++) {
if (Common::Bit(i, reg_list)) {
auto data = ir.ReadMemory32(address);
ir.SetRegister(static_cast<Reg>(i), data);
address = ir.Add(address, ir.Imm32(4));
}
}
if (write_back) {
ir.SetRegister(n, address);
}
return true;
}
bool thumb16_UDF() {
return InterpretThisInstruction();
}