2016-08-02 21:59:33 +01:00
|
|
|
/* This file is part of the dynarmic project.
|
|
|
|
* Copyright (c) 2016 MerryMage
|
|
|
|
* This software may be used and distributed according to the terms of the GNU
|
|
|
|
* General Public License version 2 or any later version.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "translate_arm.h"
|
|
|
|
|
|
|
|
namespace Dynarmic {
|
|
|
|
namespace Arm {
|
|
|
|
|
2016-08-03 21:59:43 +01:00
|
|
|
static IR::Value GetAddressingMode(IREmitter& ir, bool P, bool U, bool W, Reg n, IR::Value index) {
|
|
|
|
IR::Value address;
|
|
|
|
if (P) {
|
|
|
|
// Pre-indexed addressing
|
|
|
|
if (n == Reg::PC && index.IsImmediate()) {
|
|
|
|
address = U ? ir.Imm32(ir.AlignPC(4) + index.GetU32()) : ir.Imm32(ir.AlignPC(4) - index.GetU32());
|
|
|
|
} else {
|
|
|
|
address = U ? ir.Add(ir.GetRegister(n), index) : ir.Sub(ir.GetRegister(n), index);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Wrote calculated address back to the base register
|
|
|
|
if (W) {
|
|
|
|
ir.SetRegister(n, address);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Post-indexed addressing
|
|
|
|
address = (n == Reg::PC) ? ir.Imm32(ir.AlignPC(4)) : ir.GetRegister(n);
|
|
|
|
|
|
|
|
if (U) {
|
|
|
|
ir.SetRegister(n, ir.Add(ir.GetRegister(n), index));
|
|
|
|
} else {
|
|
|
|
ir.SetRegister(n, ir.Sub(ir.GetRegister(n), index));
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO(bunnei): Handle W=1 mode, which in this scenario does an unprivileged (User mode) access.
|
|
|
|
}
|
|
|
|
return address;
|
|
|
|
}
|
|
|
|
|
2016-08-02 21:59:33 +01:00
|
|
|
bool ArmTranslatorVisitor::arm_LDR_imm(Cond cond, bool P, bool U, bool W, Reg n, Reg d, Imm12 imm12) {
|
2016-08-03 21:59:43 +01:00
|
|
|
if (ConditionPassed(cond)) {
|
|
|
|
const auto data = ir.ReadMemory32(GetAddressingMode(ir, P, U, W, n, ir.Imm32(imm12)));
|
|
|
|
|
|
|
|
if (d == Reg::PC) {
|
|
|
|
ir.BXWritePC(data);
|
2016-08-13 00:10:23 +01:00
|
|
|
if (!P && W && n == Reg::R13)
|
|
|
|
ir.SetTerm(IR::Term::PopRSBHint{});
|
|
|
|
else
|
|
|
|
ir.SetTerm(IR::Term::ReturnToDispatch{});
|
2016-08-03 21:59:43 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
ir.SetRegister(d, data);
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
2016-08-02 21:59:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool ArmTranslatorVisitor::arm_LDR_reg(Cond cond, bool P, bool U, bool W, Reg n, Reg d, Imm5 imm5, ShiftType shift, Reg m) {
|
2016-08-03 21:59:43 +01:00
|
|
|
if (ConditionPassed(cond)) {
|
|
|
|
const auto shifted = EmitImmShift(ir.GetRegister(m), shift, imm5, ir.GetCFlag());
|
|
|
|
const auto data = ir.ReadMemory32(GetAddressingMode(ir, P, U, W, n, shifted.result));
|
|
|
|
|
|
|
|
if (d == Reg::PC) {
|
|
|
|
ir.BXWritePC(data);
|
|
|
|
ir.SetTerm(IR::Term::ReturnToDispatch{});
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
ir.SetRegister(d, data);
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
2016-08-02 21:59:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool ArmTranslatorVisitor::arm_LDRB_imm(Cond cond, bool P, bool U, bool W, Reg n, Reg d, Imm12 imm12) {
|
2016-08-05 04:12:11 +01:00
|
|
|
if (ConditionPassed(cond)) {
|
2016-08-06 01:51:32 +01:00
|
|
|
const auto data = ir.ZeroExtendByteToWord(ir.ReadMemory8(GetAddressingMode(ir, P, U, W, n, ir.Imm32(imm12))));
|
2016-08-05 04:12:11 +01:00
|
|
|
|
|
|
|
if (d == Reg::PC) {
|
|
|
|
ir.ALUWritePC(ir.Add(data, ir.Imm32(4)));
|
|
|
|
ir.SetTerm(IR::Term::ReturnToDispatch{});
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
ir.SetRegister(d, data);
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
2016-08-02 21:59:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool ArmTranslatorVisitor::arm_LDRB_reg(Cond cond, bool P, bool U, bool W, Reg n, Reg d, Imm5 imm5, ShiftType shift, Reg m) {
|
2016-08-05 04:12:11 +01:00
|
|
|
if (ConditionPassed(cond)) {
|
|
|
|
const auto shifted = EmitImmShift(ir.GetRegister(m), shift, imm5, ir.GetCFlag());
|
2016-08-06 01:51:32 +01:00
|
|
|
const auto data = ir.ZeroExtendByteToWord(ir.ReadMemory8(GetAddressingMode(ir, P, U, W, n, shifted.result)));
|
2016-08-05 04:12:11 +01:00
|
|
|
|
|
|
|
if (d == Reg::PC) {
|
|
|
|
ir.ALUWritePC(ir.Add(data, ir.Imm32(4)));
|
|
|
|
ir.SetTerm(IR::Term::ReturnToDispatch{});
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
ir.SetRegister(d, data);
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
2016-08-02 21:59:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool ArmTranslatorVisitor::arm_LDRBT() {
|
|
|
|
return InterpretThisInstruction();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ArmTranslatorVisitor::arm_LDRD_imm(Cond cond, bool P, bool U, bool W, Reg n, Reg d, Imm4 imm8a, Imm4 imm8b) {
|
2016-08-05 04:36:58 +01:00
|
|
|
if (ConditionPassed(cond)) {
|
|
|
|
const auto address_a = GetAddressingMode(ir, P, U, W, n, ir.Imm32(imm8a << 4 | imm8b));
|
|
|
|
const auto address_b = ir.Add(address_a, ir.Imm32(4));
|
|
|
|
auto data_a = ir.ReadMemory32(address_a);
|
|
|
|
auto data_b = ir.ReadMemory32(address_b);
|
|
|
|
|
2016-08-06 20:42:06 +01:00
|
|
|
switch (d) {
|
2016-08-05 04:36:58 +01:00
|
|
|
case Reg::PC:
|
|
|
|
data_a = ir.Add(data_a, ir.Imm32(4));
|
|
|
|
break;
|
|
|
|
case Reg::LR:
|
|
|
|
data_b = ir.Add(data_b, ir.Imm32(4));
|
|
|
|
break;
|
2016-08-06 20:42:06 +01:00
|
|
|
default:
|
|
|
|
break;
|
2016-08-05 04:36:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (d == Reg::PC) {
|
|
|
|
ir.ALUWritePC(data_a);
|
|
|
|
} else {
|
|
|
|
ir.SetRegister(d, data_a);
|
|
|
|
}
|
|
|
|
|
|
|
|
const Reg reg_b = static_cast<Reg>(std::min(d + 1, Reg::R15));
|
|
|
|
if (reg_b == Reg::PC) {
|
|
|
|
ir.ALUWritePC(data_b);
|
|
|
|
} else {
|
|
|
|
ir.SetRegister(reg_b, data_b);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (d == Reg::PC || reg_b == Reg::PC) {
|
|
|
|
ir.SetTerm(IR::Term::ReturnToDispatch{});
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
2016-08-02 21:59:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool ArmTranslatorVisitor::arm_LDRD_reg(Cond cond, bool P, bool U, bool W, Reg n, Reg d, Reg m) {
|
2016-08-05 04:36:58 +01:00
|
|
|
if (ConditionPassed(cond)) {
|
|
|
|
const auto address_a = GetAddressingMode(ir, P, U, W, n, ir.GetRegister(m));
|
|
|
|
const auto address_b = ir.Add(address_a, ir.Imm32(4));
|
|
|
|
auto data_a = ir.ReadMemory32(address_a);
|
|
|
|
auto data_b = ir.ReadMemory32(address_b);
|
|
|
|
|
2016-08-06 20:42:06 +01:00
|
|
|
switch (d) {
|
2016-08-05 04:36:58 +01:00
|
|
|
case Reg::PC:
|
|
|
|
data_a = ir.Add(data_a, ir.Imm32(4));
|
|
|
|
break;
|
|
|
|
case Reg::LR:
|
|
|
|
data_b = ir.Add(data_b, ir.Imm32(4));
|
|
|
|
break;
|
2016-08-06 20:42:06 +01:00
|
|
|
default:
|
|
|
|
break;
|
2016-08-05 04:36:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (d == Reg::PC) {
|
|
|
|
ir.ALUWritePC(data_a);
|
|
|
|
} else {
|
|
|
|
ir.SetRegister(d, data_a);
|
|
|
|
}
|
|
|
|
|
|
|
|
const Reg reg_b = static_cast<Reg>(std::min(d + 1, Reg::R15));
|
|
|
|
if (reg_b == Reg::PC) {
|
|
|
|
ir.ALUWritePC(data_b);
|
|
|
|
} else {
|
|
|
|
ir.SetRegister(reg_b, data_b);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (d == Reg::PC || reg_b == Reg::PC) {
|
|
|
|
ir.SetTerm(IR::Term::ReturnToDispatch{});
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
2016-08-02 21:59:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool ArmTranslatorVisitor::arm_LDRH_imm(Cond cond, bool P, bool U, bool W, Reg n, Reg d, Imm4 imm8a, Imm4 imm8b) {
|
2016-08-05 04:12:45 +01:00
|
|
|
if (ConditionPassed(cond)) {
|
2016-08-06 01:51:32 +01:00
|
|
|
const auto data = ir.ZeroExtendHalfToWord(ir.ReadMemory16(GetAddressingMode(ir, P, U, W, n, ir.Imm32(imm8a << 4 | imm8b))));
|
2016-08-05 04:12:45 +01:00
|
|
|
|
|
|
|
if (d == Reg::PC) {
|
|
|
|
ir.ALUWritePC(ir.Add(data, ir.Imm32(4)));
|
|
|
|
ir.SetTerm(IR::Term::ReturnToDispatch{});
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
ir.SetRegister(d, data);
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
2016-08-02 21:59:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool ArmTranslatorVisitor::arm_LDRH_reg(Cond cond, bool P, bool U, bool W, Reg n, Reg d, Reg m) {
|
2016-08-05 04:12:45 +01:00
|
|
|
if (ConditionPassed(cond)) {
|
2016-08-06 01:51:32 +01:00
|
|
|
const auto data = ir.ZeroExtendHalfToWord(ir.ReadMemory16(GetAddressingMode(ir, P, U, W, n, ir.GetRegister(m))));
|
2016-08-05 04:12:45 +01:00
|
|
|
|
|
|
|
if (d == Reg::PC) {
|
|
|
|
ir.ALUWritePC(ir.Add(data, ir.Imm32(4)));
|
|
|
|
ir.SetTerm(IR::Term::ReturnToDispatch{});
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
ir.SetRegister(d, data);
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
2016-08-02 21:59:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool ArmTranslatorVisitor::arm_LDRHT() {
|
|
|
|
return InterpretThisInstruction();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ArmTranslatorVisitor::arm_LDRSB_imm(Cond cond, bool P, bool U, bool W, Reg n, Reg d, Imm4 imm8a, Imm4 imm8b) {
|
2016-08-11 17:18:20 +01:00
|
|
|
if (ConditionPassed(cond)) {
|
|
|
|
const auto data = ir.SignExtendByteToWord(ir.ReadMemory8(GetAddressingMode(ir, P, U, W, n, ir.Imm32(imm8a << 4 | imm8b))));
|
|
|
|
|
|
|
|
if (d == Reg::PC) {
|
|
|
|
ir.ALUWritePC(ir.Add(data, ir.Imm32(4)));
|
|
|
|
ir.SetTerm(IR::Term::ReturnToDispatch{});
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
ir.SetRegister(d, data);
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
2016-08-02 21:59:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool ArmTranslatorVisitor::arm_LDRSB_reg(Cond cond, bool P, bool U, bool W, Reg n, Reg d, Reg m) {
|
2016-08-11 17:18:20 +01:00
|
|
|
if (ConditionPassed(cond)) {
|
|
|
|
const auto data = ir.SignExtendByteToWord(ir.ReadMemory8(GetAddressingMode(ir, P, U, W, n, ir.GetRegister(m))));
|
|
|
|
|
|
|
|
if (d == Reg::PC) {
|
|
|
|
ir.ALUWritePC(ir.Add(data, ir.Imm32(4)));
|
|
|
|
ir.SetTerm(IR::Term::ReturnToDispatch{});
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
ir.SetRegister(d, data);
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
2016-08-02 21:59:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool ArmTranslatorVisitor::arm_LDRSBT() {
|
|
|
|
return InterpretThisInstruction();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ArmTranslatorVisitor::arm_LDRSH_imm(Cond cond, bool P, bool U, bool W, Reg n, Reg d, Imm4 imm8a, Imm4 imm8b) {
|
2016-08-11 17:18:20 +01:00
|
|
|
if (ConditionPassed(cond)) {
|
|
|
|
const auto data = ir.SignExtendHalfToWord(ir.ReadMemory16(GetAddressingMode(ir, P, U, W, n, ir.Imm32(imm8a << 4 | imm8b))));
|
|
|
|
|
|
|
|
if (d == Reg::PC) {
|
|
|
|
ir.ALUWritePC(ir.Add(data, ir.Imm32(4)));
|
|
|
|
ir.SetTerm(IR::Term::ReturnToDispatch{});
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
ir.SetRegister(d, data);
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
2016-08-02 21:59:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool ArmTranslatorVisitor::arm_LDRSH_reg(Cond cond, bool P, bool U, bool W, Reg n, Reg d, Reg m) {
|
2016-08-11 17:18:20 +01:00
|
|
|
if (ConditionPassed(cond)) {
|
|
|
|
const auto data = ir.SignExtendHalfToWord(ir.ReadMemory16(GetAddressingMode(ir, P, U, W, n, ir.GetRegister(m))));
|
|
|
|
|
|
|
|
if (d == Reg::PC) {
|
|
|
|
ir.ALUWritePC(ir.Add(data, ir.Imm32(4)));
|
|
|
|
ir.SetTerm(IR::Term::ReturnToDispatch{});
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
ir.SetRegister(d, data);
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
2016-08-02 21:59:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool ArmTranslatorVisitor::arm_LDRSHT() {
|
|
|
|
return InterpretThisInstruction();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ArmTranslatorVisitor::arm_LDRT() {
|
|
|
|
return InterpretThisInstruction();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ArmTranslatorVisitor::arm_STR_imm(Cond cond, bool P, bool U, bool W, Reg n, Reg d, Imm12 imm12) {
|
2016-08-05 00:35:17 +01:00
|
|
|
if (ConditionPassed(cond)) {
|
|
|
|
const auto address = GetAddressingMode(ir, P, U, W, n, ir.Imm32(imm12));
|
|
|
|
ir.WriteMemory32(address, ir.GetRegister(d));
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
2016-08-02 21:59:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool ArmTranslatorVisitor::arm_STR_reg(Cond cond, bool P, bool U, bool W, Reg n, Reg d, Imm5 imm5, ShiftType shift, Reg m) {
|
2016-08-05 00:35:17 +01:00
|
|
|
if (ConditionPassed(cond)) {
|
|
|
|
const auto shifted = EmitImmShift(ir.GetRegister(m), shift, imm5, ir.GetCFlag());
|
|
|
|
const auto address = GetAddressingMode(ir, P, U, W, n, shifted.result);
|
|
|
|
ir.WriteMemory32(address, ir.GetRegister(d));
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
2016-08-02 21:59:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool ArmTranslatorVisitor::arm_STRB_imm(Cond cond, bool P, bool U, bool W, Reg n, Reg d, Imm12 imm12) {
|
2016-08-05 00:50:01 +01:00
|
|
|
if (ConditionPassed(cond)) {
|
|
|
|
const auto address = GetAddressingMode(ir, P, U, W, n, ir.Imm32(imm12));
|
|
|
|
const auto value = (d == Reg::PC) ? ir.Imm8(ir.PC() - 8) : ir.GetRegister(d);
|
2016-08-06 01:51:32 +01:00
|
|
|
ir.WriteMemory8(address, ir.LeastSignificantByte(value));
|
2016-08-05 00:50:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
2016-08-02 21:59:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool ArmTranslatorVisitor::arm_STRB_reg(Cond cond, bool P, bool U, bool W, Reg n, Reg d, Imm5 imm5, ShiftType shift, Reg m) {
|
2016-08-05 00:50:01 +01:00
|
|
|
if (ConditionPassed(cond)) {
|
|
|
|
const auto shifted = EmitImmShift(ir.GetRegister(m), shift, imm5, ir.GetCFlag());
|
|
|
|
const auto address = GetAddressingMode(ir, P, U, W, n, shifted.result);
|
|
|
|
const auto value = (d == Reg::PC) ? ir.Imm8(ir.PC() - 8) : ir.GetRegister(d);
|
2016-08-06 01:51:32 +01:00
|
|
|
ir.WriteMemory8(address, ir.LeastSignificantByte(value));
|
2016-08-05 00:50:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
2016-08-02 21:59:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool ArmTranslatorVisitor::arm_STRBT() {
|
|
|
|
return InterpretThisInstruction();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ArmTranslatorVisitor::arm_STRD_imm(Cond cond, bool P, bool U, bool W, Reg n, Reg d, Imm4 imm8a, Imm4 imm8b) {
|
2016-08-05 03:47:27 +01:00
|
|
|
if (ConditionPassed(cond)) {
|
|
|
|
const auto address_a = GetAddressingMode(ir, P, U, W, n, ir.Imm32(imm8a << 4 | imm8b));
|
|
|
|
const auto address_b = ir.Add(address_a, ir.Imm32(4));
|
|
|
|
const auto value_a = (d == Reg::PC) ? ir.Imm32(ir.PC() - 8) : ir.GetRegister(d);
|
|
|
|
const Reg reg_b = static_cast<Reg>(std::min(d + 1, Reg::R15));
|
|
|
|
const auto value_b = (reg_b == Reg::PC) ? ir.Imm32(ir.PC() - 8) : ir.GetRegister(reg_b);
|
|
|
|
ir.WriteMemory32(address_a, value_a);
|
|
|
|
ir.WriteMemory32(address_b, value_b);
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
2016-08-02 21:59:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool ArmTranslatorVisitor::arm_STRD_reg(Cond cond, bool P, bool U, bool W, Reg n, Reg d, Reg m) {
|
2016-08-05 03:47:27 +01:00
|
|
|
if (ConditionPassed(cond)) {
|
|
|
|
const auto address_a = GetAddressingMode(ir, P, U, W, n, ir.GetRegister(m));
|
|
|
|
const auto address_b = ir.Add(address_a, ir.Imm32(4));
|
|
|
|
const auto value_a = (d == Reg::PC) ? ir.Imm32(ir.PC() - 8) : ir.GetRegister(d);
|
|
|
|
const Reg reg_b = static_cast<Reg>(std::min(d + 1, Reg::R15));
|
|
|
|
const auto value_b = (reg_b == Reg::PC) ? ir.Imm32(ir.PC() - 8) : ir.GetRegister(reg_b);
|
|
|
|
ir.WriteMemory32(address_a, value_a);
|
|
|
|
ir.WriteMemory32(address_b, value_b);
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
2016-08-02 21:59:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool ArmTranslatorVisitor::arm_STRH_imm(Cond cond, bool P, bool U, bool W, Reg n, Reg d, Imm4 imm8a, Imm4 imm8b) {
|
2016-08-05 01:47:08 +01:00
|
|
|
if (ConditionPassed(cond)) {
|
|
|
|
const auto address = GetAddressingMode(ir, P, U, W, n, ir.Imm32(imm8a << 4 | imm8b));
|
|
|
|
const auto value = (d == Reg::PC) ? ir.Imm32(ir.PC() - 8) : ir.GetRegister(d);
|
2016-08-06 01:51:32 +01:00
|
|
|
ir.WriteMemory16(address, ir.LeastSignificantHalf(value));
|
2016-08-05 01:47:08 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
2016-08-02 21:59:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool ArmTranslatorVisitor::arm_STRH_reg(Cond cond, bool P, bool U, bool W, Reg n, Reg d, Reg m) {
|
2016-08-05 01:47:08 +01:00
|
|
|
if (ConditionPassed(cond)) {
|
|
|
|
const auto address = GetAddressingMode(ir, P, U, W, n, ir.GetRegister(m));
|
|
|
|
const auto value = (d == Reg::PC) ? ir.Imm32(ir.PC() - 8) : ir.GetRegister(d);
|
2016-08-06 01:51:32 +01:00
|
|
|
ir.WriteMemory16(address, ir.LeastSignificantHalf(value));
|
2016-08-05 01:47:08 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
2016-08-02 21:59:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool ArmTranslatorVisitor::arm_STRHT() {
|
|
|
|
return InterpretThisInstruction();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ArmTranslatorVisitor::arm_STRT() {
|
|
|
|
return InterpretThisInstruction();
|
|
|
|
}
|
|
|
|
|
2016-08-08 22:21:10 +01:00
|
|
|
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<Reg>(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));
|
2016-08-13 00:10:23 +01:00
|
|
|
if (n == Reg::R13)
|
|
|
|
ir.SetTerm(IR::Term::PopRSBHint{});
|
|
|
|
else
|
|
|
|
ir.SetTerm(IR::Term::ReturnToDispatch{});
|
2016-08-08 22:21:10 +01:00
|
|
|
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 <Rn>{!}, <reg_list>
|
|
|
|
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 <Rn>{!}, <reg_list>
|
|
|
|
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 <Rn>{!}, <reg_list>
|
|
|
|
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 <Rn>{!}, <reg_list>
|
|
|
|
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;
|
2016-08-02 21:59:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool ArmTranslatorVisitor::arm_LDM_usr() {
|
|
|
|
return InterpretThisInstruction();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ArmTranslatorVisitor::arm_LDM_eret() {
|
|
|
|
return InterpretThisInstruction();
|
|
|
|
}
|
|
|
|
|
2016-08-08 22:49:11 +01:00
|
|
|
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<Reg>(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 <Rn>{!}, <reg_list>
|
|
|
|
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 <Rn>{!}, <reg_list>
|
|
|
|
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 <Rn>{!}, <reg_list>
|
|
|
|
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 <Rn>{!}, <reg_list>
|
|
|
|
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;
|
2016-08-02 21:59:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool ArmTranslatorVisitor::arm_STM_usr() {
|
|
|
|
return InterpretThisInstruction();
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace Arm
|
|
|
|
} // namespace Dynarmic
|