translate_arm/load_store: Handle unpredictable instructions

This necessated handling literal versions of the instructions separately
as they had different requirements. The rationale for detecting
unpredictable instructions is because:

a. they are unlikely to be outputted by a well-behaved compiler
b. their behaviour may change between different processors

I would rather unpredictable instructions fail loudly than silently do
approximately the right thing.
This commit is contained in:
MerryMage 2016-08-19 00:24:31 +01:00
parent 5869e79b9c
commit 4acc481463
5 changed files with 376 additions and 107 deletions

View file

@ -185,42 +185,48 @@ std::vector<ArmMatcher<V>> GetArmDecodeTable() {
INST(&V::arm_SWPB, "SWPB", "cccc00010100nnnntttt00001001uuuu"), // v2S (v6: Deprecated)
// Load/Store instructions
INST(&V::arm_LDR_imm, "LDR (imm)", "cccc010pu0w1nnnnddddvvvvvvvvvvvv"),
INST(&V::arm_LDR_reg, "LDR (reg)", "cccc011pu0w1nnnnddddvvvvvrr0mmmm"),
INST(&V::arm_LDRB_imm, "LDRB (imm)", "cccc010pu1w1nnnnddddvvvvvvvvvvvv"),
INST(&V::arm_LDRB_reg, "LDRB (reg)", "cccc011pu1w1nnnnddddvvvvvrr0mmmm"),
INST(&V::arm_LDRBT, "LDRBT (A1)", "----0100-111--------------------"),
INST(&V::arm_LDRBT, "LDRBT (A2)", "----0110-111---------------0----"),
INST(&V::arm_LDRD_imm, "LDRD (imm)", "cccc000pu1w0nnnnddddvvvv1101vvvv"), // v5E
INST(&V::arm_LDRD_reg, "LDRD (reg)", "cccc000pu0w0nnnndddd00001101mmmm"), // v5E
INST(&V::arm_LDRH_imm, "LDRH (imm)", "cccc000pu1w1nnnnddddvvvv1011vvvv"),
INST(&V::arm_LDRH_reg, "LDRH (reg)", "cccc000pu0w1nnnndddd00001011mmmm"),
INST(&V::arm_LDRHT, "LDRHT (A1)", "----0000-111------------1011----"),
INST(&V::arm_LDRHT, "LDRHT (A2)", "----0000-011--------00001011----"),
INST(&V::arm_LDRSB_imm, "LDRSB (imm)", "cccc000pu1w1nnnnddddvvvv1101vvvv"),
INST(&V::arm_LDRSB_reg, "LDRSB (reg)", "cccc000pu0w1nnnndddd00001101mmmm"),
INST(&V::arm_LDRSBT, "LDRSBT (A1)", "----0000-111------------1101----"),
INST(&V::arm_LDRSBT, "LDRSBT (A2)", "----0000-011--------00001101----"),
INST(&V::arm_LDRSH_imm, "LDRSH (imm)", "cccc000pu1w1nnnnddddvvvv1111vvvv"),
INST(&V::arm_LDRSH_reg, "LDRSH (reg)", "cccc000pu0w1nnnndddd00001111mmmm"),
INST(&V::arm_LDRSHT, "LDRSHT (A1)", "----0000-111------------1111----"),
INST(&V::arm_LDRSHT, "LDRSHT (A2)", "----0000-011--------00001111----"),
INST(&V::arm_LDRT, "LDRT (A1)", "----0100-011--------------------"),
INST(&V::arm_LDRT, "LDRT (A2)", "----0110-011---------------0----"),
INST(&V::arm_STR_imm, "STR (imm)", "cccc010pu0w0nnnnddddvvvvvvvvvvvv"),
INST(&V::arm_STR_reg, "STR (reg)", "cccc011pu0w0nnnnddddvvvvvrr0mmmm"),
INST(&V::arm_STRB_imm, "STRB (imm)", "cccc010pu1w0nnnnddddvvvvvvvvvvvv"),
INST(&V::arm_STRB_reg, "STRB (reg)", "cccc011pu1w0nnnnddddvvvvvrr0mmmm"),
INST(&V::arm_STRBT, "STRBT (A1)", "----0100-110--------------------"),
INST(&V::arm_STRBT, "STRBT (A2)", "----0110-110---------------0----"),
INST(&V::arm_STRD_imm, "STRD (imm)", "cccc000pu1w0nnnnddddvvvv1111vvvv"), // v5E
INST(&V::arm_STRD_reg, "STRD (reg)", "cccc000pu0w0nnnndddd00001111mmmm"), // v5E
INST(&V::arm_STRH_imm, "STRH (imm)", "cccc000pu1w0nnnnddddvvvv1011vvvv"),
INST(&V::arm_STRH_reg, "STRH (reg)", "cccc000pu0w0nnnndddd00001011mmmm"),
INST(&V::arm_STRHT, "STRHT (A1)", "----0000-110------------1011----"),
INST(&V::arm_STRHT, "STRHT (A2)", "----0000-010--------00001011----"),
INST(&V::arm_STRT, "STRT (A1)", "----0100-010--------------------"),
INST(&V::arm_STRT, "STRT (A2)", "----0110-010---------------0----"),
INST(&V::arm_LDR_lit, "LDR (lit)", "cccc0101u0011111ttttvvvvvvvvvvvv"),
INST(&V::arm_LDR_imm, "LDR (imm)", "cccc010pu0w1nnnnttttvvvvvvvvvvvv"),
INST(&V::arm_LDR_reg, "LDR (reg)", "cccc011pu0w1nnnnttttvvvvvrr0mmmm"),
INST(&V::arm_LDRB_lit, "LDRB (lit)", "cccc0101u1011111ttttvvvvvvvvvvvv"),
INST(&V::arm_LDRB_imm, "LDRB (imm)", "cccc010pu1w1nnnnttttvvvvvvvvvvvv"),
INST(&V::arm_LDRB_reg, "LDRB (reg)", "cccc011pu1w1nnnnttttvvvvvrr0mmmm"),
INST(&V::arm_LDRD_lit, "LDRD (lit)", "cccc0001u1001111ttttvvvv1101vvvv"),
INST(&V::arm_LDRD_imm, "LDRD (imm)", "cccc000pu1w0nnnnttttvvvv1101vvvv"), // v5E
INST(&V::arm_LDRD_reg, "LDRD (reg)", "cccc000pu0w0nnnntttt00001101mmmm"), // v5E
INST(&V::arm_LDRH_lit, "LDRH (lit)", "cccc000pu1w11111ttttvvvv1011vvvv"),
INST(&V::arm_LDRH_imm, "LDRH (imm)", "cccc000pu1w1nnnnttttvvvv1011vvvv"),
INST(&V::arm_LDRH_reg, "LDRH (reg)", "cccc000pu0w1nnnntttt00001011mmmm"),
INST(&V::arm_LDRSB_lit, "LDRSB (lit)", "cccc0001u1011111ttttvvvv1101vvvv"),
INST(&V::arm_LDRSB_imm, "LDRSB (imm)", "cccc000pu1w1nnnnttttvvvv1101vvvv"),
INST(&V::arm_LDRSB_reg, "LDRSB (reg)", "cccc000pu0w1nnnntttt00001101mmmm"),
INST(&V::arm_LDRSH_lit, "LDRSH (lit)", "cccc0001u1011111ttttvvvv1111vvvv"),
INST(&V::arm_LDRSH_imm, "LDRSH (imm)", "cccc000pu1w1nnnnttttvvvv1111vvvv"),
INST(&V::arm_LDRSH_reg, "LDRSH (reg)", "cccc000pu0w1nnnntttt00001111mmmm"),
INST(&V::arm_STR_imm, "STR (imm)", "cccc010pu0w0nnnnttttvvvvvvvvvvvv"),
INST(&V::arm_STR_reg, "STR (reg)", "cccc011pu0w0nnnnttttvvvvvrr0mmmm"),
INST(&V::arm_STRB_imm, "STRB (imm)", "cccc010pu1w0nnnnttttvvvvvvvvvvvv"),
INST(&V::arm_STRB_reg, "STRB (reg)", "cccc011pu1w0nnnnttttvvvvvrr0mmmm"),
INST(&V::arm_STRD_imm, "STRD (imm)", "cccc000pu1w0nnnnttttvvvv1111vvvv"), // v5E
INST(&V::arm_STRD_reg, "STRD (reg)", "cccc000pu0w0nnnntttt00001111mmmm"), // v5E
INST(&V::arm_STRH_imm, "STRH (imm)", "cccc000pu1w0nnnnttttvvvv1011vvvv"),
INST(&V::arm_STRH_reg, "STRH (reg)", "cccc000pu0w0nnnntttt00001011mmmm"),
// Load/Store Multiple instructions
INST(&V::arm_LDM, "LDM", "cccc100010w1nnnnxxxxxxxxxxxxxxxx"), // all

View file

@ -337,6 +337,10 @@ public:
std::string arm_YIELD() { return "yield <unimplemented>"; }
// Load/Store instructions
std::string arm_LDR_lit(Cond cond, bool U, Reg t, Imm12 imm12) {
bool P = true, W = false;
return arm_LDR_imm(cond, P, U, W, Reg::PC, t, imm12);
}
std::string arm_LDR_imm(Cond cond, bool P, bool U, bool W, Reg n, Reg t, Imm12 imm12) {
if (P) {
return Common::StringFromFormat("ldr%s %s, [%s, #%c%u]%s", CondToString(cond), RegToString(t), RegToString(n), U ? '+' : '-', imm12, W ? "!" : "");
@ -351,6 +355,10 @@ public:
return Common::StringFromFormat("ldr%s %s, [%s], %c%s%s%s", CondToString(cond), RegToString(t), RegToString(n), U ? '+' : '-', RegToString(m), ShiftStr(shift, imm5).c_str(), W ? " (err: W == 1!!!)" : "");
}
}
std::string arm_LDRB_lit(Cond cond, bool U, Reg t, Imm12 imm12) {
bool P = true, W = false;
return arm_LDRB_imm(cond, P, U, W, Reg::PC, t, imm12);
}
std::string arm_LDRB_imm(Cond cond, bool P, bool U, bool W, Reg n, Reg t, Imm12 imm12) {
if (P) {
return Common::StringFromFormat("ldrb%s %s, [%s, #%c%u]%s", CondToString(cond), RegToString(t), RegToString(n), U ? '+' : '-', imm12, W ? "!" : "");
@ -366,6 +374,10 @@ public:
}
}
std::string arm_LDRBT() { return "ice"; }
std::string arm_LDRD_lit(Cond cond, bool U, Reg t, Imm4 imm8a, Imm4 imm8b) {
bool P = true, W = false;
return arm_LDRD_imm(cond, P, U, W, Reg::PC, t, imm8a, imm8b);
}
std::string arm_LDRD_imm(Cond cond, bool P, bool U, bool W, Reg n, Reg t, Imm4 imm8a, Imm4 imm8b) {
u32 imm32 = (imm8a << 4) | imm8b;
if (P) {
@ -381,6 +393,9 @@ public:
return Common::StringFromFormat("ldrd%s %s, %s, [%s], %c%s%s", CondToString(cond), RegToString(t), RegToString(t+1), RegToString(n), U ? '+' : '-', RegToString(m), W ? " (err: W == 1!!!)" : "");
}
}
std::string arm_LDRH_lit(Cond cond, bool P, bool U, bool W, Reg t, Imm4 imm8a, Imm4 imm8b) {
return arm_LDRH_imm(cond, P, U, W, Reg::PC, t, imm8a, imm8b);
}
std::string arm_LDRH_imm(Cond cond, bool P, bool U, bool W, Reg n, Reg t, Imm4 imm8a, Imm4 imm8b) {
u32 imm32 = (imm8a << 4) | imm8b;
if (P) {
@ -397,6 +412,10 @@ public:
}
}
std::string arm_LDRHT() { return "ice"; }
std::string arm_LDRSB_lit(Cond cond, bool U, Reg t, Imm4 imm8a, Imm4 imm8b) {
bool P = true, W = false;
return arm_LDRSB_imm(cond, P, U, W, Reg::PC, t, imm8a, imm8b);
}
std::string arm_LDRSB_imm(Cond cond, bool P, bool U, bool W, Reg n, Reg t, Imm4 imm8a, Imm4 imm8b) {
u32 imm32 = (imm8a << 4) | imm8b;
if (P) {
@ -413,6 +432,10 @@ public:
}
}
std::string arm_LDRSBT() { return "ice"; }
std::string arm_LDRSH_lit(Cond cond, bool U, Reg t, Imm4 imm8a, Imm4 imm8b) {
bool P = true, W = false;
return arm_LDRSH_imm(cond, P, U, W, Reg::PC, t, imm8a, imm8b);
}
std::string arm_LDRSH_imm(Cond cond, bool P, bool U, bool W, Reg n, Reg t, Imm4 imm8a, Imm4 imm8b) {
u32 imm32 = (imm8a << 4) | imm8b;
if (P) {

View file

@ -9,6 +9,38 @@
namespace Dynarmic {
namespace Arm {
bool ArmTranslatorVisitor::arm_LDRBT() {
ASSERT_MSG(false, "System instructions unimplemented");
}
bool ArmTranslatorVisitor::arm_LDRHT() {
ASSERT_MSG(false, "System instructions unimplemented");
}
bool ArmTranslatorVisitor::arm_LDRSBT() {
ASSERT_MSG(false, "System instructions unimplemented");
}
bool ArmTranslatorVisitor::arm_LDRSHT() {
ASSERT_MSG(false, "System instructions unimplemented");
}
bool ArmTranslatorVisitor::arm_LDRT() {
ASSERT_MSG(false, "System instructions unimplemented");
}
bool ArmTranslatorVisitor::arm_STRBT() {
ASSERT_MSG(false, "System instructions unimplemented");
}
bool ArmTranslatorVisitor::arm_STRHT() {
ASSERT_MSG(false, "System instructions unimplemented");
}
bool ArmTranslatorVisitor::arm_STRT() {
ASSERT_MSG(false, "System instructions unimplemented");
}
static IR::Value GetAddressingMode(IREmitter& ir, bool P, bool U, bool W, Reg n, IR::Value index) {
IR::Value address;
if (P) {
@ -38,11 +70,35 @@ static IR::Value GetAddressingMode(IREmitter& ir, bool P, bool U, bool W, Reg n,
return address;
}
bool ArmTranslatorVisitor::arm_LDR_imm(Cond cond, bool P, bool U, bool W, Reg n, Reg d, Imm12 imm12) {
bool ArmTranslatorVisitor::arm_LDR_lit(Cond cond, bool U, Reg t, Imm12 imm12) {
bool P = true, W = false;
if (ConditionPassed(cond)) {
const auto data = ir.ReadMemory32(GetAddressingMode(ir, P, U, W, Reg::PC, ir.Imm32(imm12)));
if (t == Reg::PC) {
ir.BXWritePC(data);
ir.SetTerm(IR::Term::ReturnToDispatch{});
return false;
}
ir.SetRegister(t, data);
}
return true;
}
bool ArmTranslatorVisitor::arm_LDR_imm(Cond cond, bool P, bool U, bool W, Reg n, Reg t, Imm12 imm12) {
if (n == Reg::PC)
return UnpredictableInstruction();
ASSERT_MSG(!(!P && W), "T form of instruction unimplemented");
if ((!P || W) && n == t)
return UnpredictableInstruction();
if (ConditionPassed(cond)) {
const auto data = ir.ReadMemory32(GetAddressingMode(ir, P, U, W, n, ir.Imm32(imm12)));
if (d == Reg::PC) {
if (t == Reg::PC) {
ir.BXWritePC(data);
if (!P && W && n == Reg::R13)
ir.SetTerm(IR::Term::PopRSBHint{});
@ -51,74 +107,167 @@ bool ArmTranslatorVisitor::arm_LDR_imm(Cond cond, bool P, bool U, bool W, Reg n,
return false;
}
ir.SetRegister(d, data);
ir.SetRegister(t, data);
}
return true;
}
bool ArmTranslatorVisitor::arm_LDR_reg(Cond cond, bool P, bool U, bool W, Reg n, Reg d, Imm5 imm5, ShiftType shift, Reg m) {
bool ArmTranslatorVisitor::arm_LDR_reg(Cond cond, bool P, bool U, bool W, Reg n, Reg t, Imm5 imm5, ShiftType shift, Reg m) {
ASSERT_MSG(!(!P && W), "T form of instruction unimplemented");
if (m == Reg::PC)
return UnpredictableInstruction();
if ((!P || W) && (n == Reg::PC || n == t))
return UnpredictableInstruction();
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) {
if (t == Reg::PC) {
ir.BXWritePC(data);
ir.SetTerm(IR::Term::ReturnToDispatch{});
return false;
}
ir.SetRegister(d, data);
ir.SetRegister(t, data);
}
return true;
}
bool ArmTranslatorVisitor::arm_LDRB_imm(Cond cond, bool P, bool U, bool W, Reg n, Reg d, Imm12 imm12) {
if (ConditionPassed(cond)) {
const auto data = ir.ZeroExtendByteToWord(ir.ReadMemory8(GetAddressingMode(ir, P, U, W, n, ir.Imm32(imm12))));
bool ArmTranslatorVisitor::arm_LDRB_lit(Cond cond, bool U, Reg t, Imm12 imm12) {
if (t == Reg::PC)
return UnpredictableInstruction();
if (d == Reg::PC) {
bool P = true, W = false;
if (ConditionPassed(cond)) {
const auto data = ir.ZeroExtendByteToWord(ir.ReadMemory8(GetAddressingMode(ir, P, U, W, Reg::PC, ir.Imm32(imm12))));
if (t == Reg::PC) {
ir.ALUWritePC(ir.Add(data, ir.Imm32(4)));
ir.SetTerm(IR::Term::ReturnToDispatch{});
return false;
}
ir.SetRegister(d, data);
ir.SetRegister(t, data);
}
return true;
}
bool ArmTranslatorVisitor::arm_LDRB_reg(Cond cond, bool P, bool U, bool W, Reg n, Reg d, Imm5 imm5, ShiftType shift, Reg m) {
bool ArmTranslatorVisitor::arm_LDRB_imm(Cond cond, bool P, bool U, bool W, Reg n, Reg t, Imm12 imm12) {
if (n == Reg::PC)
return UnpredictableInstruction();
ASSERT_MSG(!(!P && W), "T form of instruction unimplemented");
if ((!P || W) && n == t)
return UnpredictableInstruction();
if (t == Reg::PC)
return UnpredictableInstruction();
if (ConditionPassed(cond)) {
const auto data = ir.ZeroExtendByteToWord(ir.ReadMemory8(GetAddressingMode(ir, P, U, W, n, ir.Imm32(imm12))));
if (t == Reg::PC) {
ir.ALUWritePC(ir.Add(data, ir.Imm32(4)));
ir.SetTerm(IR::Term::ReturnToDispatch{});
return false;
}
ir.SetRegister(t, data);
}
return true;
}
bool ArmTranslatorVisitor::arm_LDRB_reg(Cond cond, bool P, bool U, bool W, Reg n, Reg t, Imm5 imm5, ShiftType shift, Reg m) {
ASSERT_MSG(!(!P && W), "T form of instruction unimplemented");
if (t == Reg::PC || m == Reg::PC)
return UnpredictableInstruction();
if ((!P || W) && (n == Reg::PC || n == t))
return UnpredictableInstruction();
if (ConditionPassed(cond)) {
const auto shifted = EmitImmShift(ir.GetRegister(m), shift, imm5, ir.GetCFlag());
const auto data = ir.ZeroExtendByteToWord(ir.ReadMemory8(GetAddressingMode(ir, P, U, W, n, shifted.result)));
if (d == Reg::PC) {
if (t == Reg::PC) {
ir.ALUWritePC(ir.Add(data, ir.Imm32(4)));
ir.SetTerm(IR::Term::ReturnToDispatch{});
return false;
}
ir.SetRegister(d, data);
ir.SetRegister(t, data);
}
return true;
}
bool ArmTranslatorVisitor::arm_LDRBT() {
return InterpretThisInstruction();
bool ArmTranslatorVisitor::arm_LDRD_lit(Cond cond, bool U, Reg t, Imm4 imm8a, Imm4 imm8b) {
if (RegNumber(t) % 2 == 1)
return UnpredictableInstruction();
if (t+1 == Reg::PC)
return UnpredictableInstruction();
bool P = true, W = false;
if (ConditionPassed(cond)) {
const auto address_a = GetAddressingMode(ir, P, U, W, Reg::PC, 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);
switch (t) {
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;
default:
break;
}
if (t == Reg::PC) {
ir.ALUWritePC(data_a);
} else {
ir.SetRegister(t, data_a);
}
const Reg reg_b = static_cast<Reg>(std::min(t + 1, Reg::R15));
if (reg_b == Reg::PC) {
ir.ALUWritePC(data_b);
} else {
ir.SetRegister(reg_b, data_b);
}
if (t == Reg::PC || reg_b == Reg::PC) {
ir.SetTerm(IR::Term::ReturnToDispatch{});
return false;
}
}
return true;
}
bool ArmTranslatorVisitor::arm_LDRD_imm(Cond cond, bool P, bool U, bool W, Reg n, Reg d, Imm4 imm8a, Imm4 imm8b) {
bool ArmTranslatorVisitor::arm_LDRD_imm(Cond cond, bool P, bool U, bool W, Reg n, Reg t, Imm4 imm8a, Imm4 imm8b) {
if (n == Reg::PC)
return UnpredictableInstruction();
if (RegNumber(t) % 2 == 1)
return UnpredictableInstruction();
if (!P && W)
return UnpredictableInstruction();
if ((!P || W) && (n == t || n == t+1))
return UnpredictableInstruction();
if (t+1 == Reg::PC)
return UnpredictableInstruction();
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);
switch (d) {
switch (t) {
case Reg::PC:
data_a = ir.Add(data_a, ir.Imm32(4));
break;
@ -129,20 +278,20 @@ bool ArmTranslatorVisitor::arm_LDRD_imm(Cond cond, bool P, bool U, bool W, Reg n
break;
}
if (d == Reg::PC) {
if (t == Reg::PC) {
ir.ALUWritePC(data_a);
} else {
ir.SetRegister(d, data_a);
ir.SetRegister(t, data_a);
}
const Reg reg_b = static_cast<Reg>(std::min(d + 1, Reg::R15));
const Reg reg_b = static_cast<Reg>(std::min(t + 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) {
if (t == Reg::PC || reg_b == Reg::PC) {
ir.SetTerm(IR::Term::ReturnToDispatch{});
return false;
}
@ -151,14 +300,23 @@ bool ArmTranslatorVisitor::arm_LDRD_imm(Cond cond, bool P, bool U, bool W, Reg n
return true;
}
bool ArmTranslatorVisitor::arm_LDRD_reg(Cond cond, bool P, bool U, bool W, Reg n, Reg d, Reg m) {
bool ArmTranslatorVisitor::arm_LDRD_reg(Cond cond, bool P, bool U, bool W, Reg n, Reg t, Reg m) {
if (RegNumber(t) % 2 == 1)
return UnpredictableInstruction();
if (!P && W)
return UnpredictableInstruction();
if (t+1 == Reg::PC || m == Reg::PC || m == t || m == t+1)
return UnpredictableInstruction();
if ((!P || W) && (n == Reg::PC || n == t || n == t+1))
return UnpredictableInstruction();
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);
switch (d) {
switch (t) {
case Reg::PC:
data_a = ir.Add(data_a, ir.Imm32(4));
break;
@ -169,20 +327,20 @@ bool ArmTranslatorVisitor::arm_LDRD_reg(Cond cond, bool P, bool U, bool W, Reg n
break;
}
if (d == Reg::PC) {
if (t == Reg::PC) {
ir.ALUWritePC(data_a);
} else {
ir.SetRegister(d, data_a);
ir.SetRegister(t, data_a);
}
const Reg reg_b = static_cast<Reg>(std::min(d + 1, Reg::R15));
const Reg reg_b = static_cast<Reg>(std::min(t + 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) {
if (t == Reg::PC || reg_b == Reg::PC) {
ir.SetTerm(IR::Term::ReturnToDispatch{});
return false;
}
@ -191,118 +349,206 @@ bool ArmTranslatorVisitor::arm_LDRD_reg(Cond cond, bool P, bool U, bool W, Reg n
return true;
}
bool ArmTranslatorVisitor::arm_LDRH_imm(Cond cond, bool P, bool U, bool W, Reg n, Reg d, Imm4 imm8a, Imm4 imm8b) {
bool ArmTranslatorVisitor::arm_LDRH_lit(Cond cond, bool P, bool U, bool W, Reg t, Imm4 imm8a, Imm4 imm8b) {
ASSERT_MSG(!(!P && W), "T form of instruction unimplemented");
if (P == W)
return UnpredictableInstruction();
if (t == Reg::PC)
return UnpredictableInstruction();
if (ConditionPassed(cond)) {
const auto data = ir.ZeroExtendHalfToWord(ir.ReadMemory16(GetAddressingMode(ir, P, U, W, Reg::PC, ir.Imm32(imm8a << 4 | imm8b))));
if (t == Reg::PC) {
ir.ALUWritePC(ir.Add(data, ir.Imm32(4)));
ir.SetTerm(IR::Term::ReturnToDispatch{});
return false;
}
ir.SetRegister(t, data);
}
return true;
}
bool ArmTranslatorVisitor::arm_LDRH_imm(Cond cond, bool P, bool U, bool W, Reg n, Reg t, Imm4 imm8a, Imm4 imm8b) {
if (n == Reg::PC)
return UnpredictableInstruction();
ASSERT_MSG(!(!P && W), "T form of instruction unimplemented");
if ((!P || W) && n == t)
return UnpredictableInstruction();
if (t == Reg::PC)
return UnpredictableInstruction();
if (ConditionPassed(cond)) {
const auto data = ir.ZeroExtendHalfToWord(ir.ReadMemory16(GetAddressingMode(ir, P, U, W, n, ir.Imm32(imm8a << 4 | imm8b))));
if (d == Reg::PC) {
if (t == Reg::PC) {
ir.ALUWritePC(ir.Add(data, ir.Imm32(4)));
ir.SetTerm(IR::Term::ReturnToDispatch{});
return false;
}
ir.SetRegister(d, data);
ir.SetRegister(t, data);
}
return true;
}
bool ArmTranslatorVisitor::arm_LDRH_reg(Cond cond, bool P, bool U, bool W, Reg n, Reg d, Reg m) {
bool ArmTranslatorVisitor::arm_LDRH_reg(Cond cond, bool P, bool U, bool W, Reg n, Reg t, Reg m) {
ASSERT_MSG(!(!P && W), "T form of instruction unimplemented");
if (t == Reg::PC || m == Reg::PC)
return UnpredictableInstruction();
if ((!P || W) && (n == Reg::PC || n == t))
return UnpredictableInstruction();
if (ConditionPassed(cond)) {
const auto data = ir.ZeroExtendHalfToWord(ir.ReadMemory16(GetAddressingMode(ir, P, U, W, n, ir.GetRegister(m))));
if (d == Reg::PC) {
if (t == Reg::PC) {
ir.ALUWritePC(ir.Add(data, ir.Imm32(4)));
ir.SetTerm(IR::Term::ReturnToDispatch{});
return false;
}
ir.SetRegister(d, data);
ir.SetRegister(t, data);
}
return true;
}
bool ArmTranslatorVisitor::arm_LDRHT() {
return InterpretThisInstruction();
bool ArmTranslatorVisitor::arm_LDRSB_lit(Cond cond, bool U, Reg t, Imm4 imm8a, Imm4 imm8b) {
if (t == Reg::PC)
return UnpredictableInstruction();
bool P = true, W = false;
if (ConditionPassed(cond)) {
const auto data = ir.SignExtendByteToWord(ir.ReadMemory8(GetAddressingMode(ir, P, U, W, Reg::PC, ir.Imm32(imm8a << 4 | imm8b))));
if (t == Reg::PC) {
ir.ALUWritePC(ir.Add(data, ir.Imm32(4)));
ir.SetTerm(IR::Term::ReturnToDispatch{});
return false;
}
ir.SetRegister(t, data);
}
return true;
}
bool ArmTranslatorVisitor::arm_LDRSB_imm(Cond cond, bool P, bool U, bool W, Reg n, Reg d, Imm4 imm8a, Imm4 imm8b) {
bool ArmTranslatorVisitor::arm_LDRSB_imm(Cond cond, bool P, bool U, bool W, Reg n, Reg t, Imm4 imm8a, Imm4 imm8b) {
if (n == Reg::PC)
return UnpredictableInstruction();
ASSERT_MSG(!(!P && W), "T form of instruction unimplemented");
if ((!P || W) && n == t)
return UnpredictableInstruction();
if (t == Reg::PC)
return UnpredictableInstruction();
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) {
if (t == Reg::PC) {
ir.ALUWritePC(ir.Add(data, ir.Imm32(4)));
ir.SetTerm(IR::Term::ReturnToDispatch{});
return false;
}
ir.SetRegister(d, data);
ir.SetRegister(t, data);
}
return true;
}
bool ArmTranslatorVisitor::arm_LDRSB_reg(Cond cond, bool P, bool U, bool W, Reg n, Reg d, Reg m) {
bool ArmTranslatorVisitor::arm_LDRSB_reg(Cond cond, bool P, bool U, bool W, Reg n, Reg t, Reg m) {
ASSERT_MSG(!(!P && W), "T form of instruction unimplemented");
if (t == Reg::PC || m == Reg::PC)
return UnpredictableInstruction();
if ((!P || W) && (n == Reg::PC || n == t))
return UnpredictableInstruction();
if (ConditionPassed(cond)) {
const auto data = ir.SignExtendByteToWord(ir.ReadMemory8(GetAddressingMode(ir, P, U, W, n, ir.GetRegister(m))));
if (d == Reg::PC) {
if (t == Reg::PC) {
ir.ALUWritePC(ir.Add(data, ir.Imm32(4)));
ir.SetTerm(IR::Term::ReturnToDispatch{});
return false;
}
ir.SetRegister(d, data);
ir.SetRegister(t, data);
}
return true;
}
bool ArmTranslatorVisitor::arm_LDRSBT() {
return InterpretThisInstruction();
bool ArmTranslatorVisitor::arm_LDRSH_lit(Cond cond, bool U, Reg t, Imm4 imm8a, Imm4 imm8b) {
if (t == Reg::PC)
return UnpredictableInstruction();
bool P = true, W = false;
if (ConditionPassed(cond)) {
const auto data = ir.SignExtendHalfToWord(ir.ReadMemory16(GetAddressingMode(ir, P, U, W, Reg::PC, ir.Imm32(imm8a << 4 | imm8b))));
if (t == Reg::PC) {
ir.ALUWritePC(ir.Add(data, ir.Imm32(4)));
ir.SetTerm(IR::Term::ReturnToDispatch{});
return false;
}
ir.SetRegister(t, data);
}
return true;
}
bool ArmTranslatorVisitor::arm_LDRSH_imm(Cond cond, bool P, bool U, bool W, Reg n, Reg d, Imm4 imm8a, Imm4 imm8b) {
bool ArmTranslatorVisitor::arm_LDRSH_imm(Cond cond, bool P, bool U, bool W, Reg n, Reg t, Imm4 imm8a, Imm4 imm8b) {
if (n == Reg::PC)
return UnpredictableInstruction();
ASSERT_MSG(!(!P && W), "T form of instruction unimplemented");
if ((!P || W) && n == t)
return UnpredictableInstruction();
if (t == Reg::PC)
return UnpredictableInstruction();
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) {
if (t == Reg::PC) {
ir.ALUWritePC(ir.Add(data, ir.Imm32(4)));
ir.SetTerm(IR::Term::ReturnToDispatch{});
return false;
}
ir.SetRegister(d, data);
ir.SetRegister(t, data);
}
return true;
}
bool ArmTranslatorVisitor::arm_LDRSH_reg(Cond cond, bool P, bool U, bool W, Reg n, Reg d, Reg m) {
bool ArmTranslatorVisitor::arm_LDRSH_reg(Cond cond, bool P, bool U, bool W, Reg n, Reg t, Reg m) {
ASSERT_MSG(!(!P && W), "T form of instruction unimplemented");
if (t == Reg::PC || m == Reg::PC)
return UnpredictableInstruction();
if ((!P || W) && (n == Reg::PC || n == t))
return UnpredictableInstruction();
if (ConditionPassed(cond)) {
const auto data = ir.SignExtendHalfToWord(ir.ReadMemory16(GetAddressingMode(ir, P, U, W, n, ir.GetRegister(m))));
if (d == Reg::PC) {
if (t == Reg::PC) {
ir.ALUWritePC(ir.Add(data, ir.Imm32(4)));
ir.SetTerm(IR::Term::ReturnToDispatch{});
return false;
}
ir.SetRegister(d, data);
ir.SetRegister(t, data);
}
return true;
}
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) {
if (ConditionPassed(cond)) {
const auto address = GetAddressingMode(ir, P, U, W, n, ir.Imm32(imm12));
@ -343,10 +589,6 @@ bool ArmTranslatorVisitor::arm_STRB_reg(Cond cond, bool P, bool U, bool W, Reg n
return true;
}
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) {
if (ConditionPassed(cond)) {
const auto address_a = GetAddressingMode(ir, P, U, W, n, ir.Imm32(imm8a << 4 | imm8b));
@ -395,14 +637,6 @@ bool ArmTranslatorVisitor::arm_STRH_reg(Cond cond, bool P, bool U, bool W, Reg n
return true;
}
bool ArmTranslatorVisitor::arm_STRHT() {
return InterpretThisInstruction();
}
bool ArmTranslatorVisitor::arm_STRT() {
return InterpretThisInstruction();
}
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++) {

View file

@ -155,35 +155,41 @@ struct ArmTranslatorVisitor final {
bool arm_WFI() { return true; }
bool arm_YIELD() { return true; }
// Load/Store instructions
bool arm_LDR_imm(Cond cond, bool P, bool U, bool W, Reg n, Reg d, Imm12 imm12);
bool arm_LDR_reg(Cond cond, bool P, bool U, bool W, Reg n, Reg d, Imm5 imm5, ShiftType shift, Reg m);
bool arm_LDRB_imm(Cond cond, bool P, bool U, bool W, Reg n, Reg d, Imm12 imm12);
bool arm_LDRB_reg(Cond cond, bool P, bool U, bool W, Reg n, Reg d, Imm5 imm5, ShiftType shift, Reg m);
// Load/Store
bool arm_LDRBT();
bool arm_LDRD_imm(Cond cond, bool P, bool U, bool W, Reg n, Reg d, Imm4 imm8a, Imm4 imm8b);
bool arm_LDRD_reg(Cond cond, bool P, bool U, bool W, Reg n, Reg d, Reg m);
bool arm_LDRH_imm(Cond cond, bool P, bool U, bool W, Reg n, Reg d, Imm4 imm8a, Imm4 imm8b);
bool arm_LDRH_reg(Cond cond, bool P, bool U, bool W, Reg n, Reg d, Reg m);
bool arm_LDRHT();
bool arm_LDRSB_imm(Cond cond, bool P, bool U, bool W, Reg n, Reg d, Imm4 imm8a, Imm4 imm8b);
bool arm_LDRSB_reg(Cond cond, bool P, bool U, bool W, Reg n, Reg d, Reg m);
bool arm_LDRSBT();
bool arm_LDRSH_imm(Cond cond, bool P, bool U, bool W, Reg n, Reg d, Imm4 imm8a, Imm4 imm8b);
bool arm_LDRSH_reg(Cond cond, bool P, bool U, bool W, Reg n, Reg d, Reg m);
bool arm_LDRSHT();
bool arm_LDRT();
bool arm_STRBT();
bool arm_STRHT();
bool arm_STRT();
bool arm_LDR_lit(Cond cond, bool U, Reg t, Imm12 imm12);
bool arm_LDR_imm(Cond cond, bool P, bool U, bool W, Reg n, Reg d, Imm12 imm12);
bool arm_LDR_reg(Cond cond, bool P, bool U, bool W, Reg n, Reg d, Imm5 imm5, ShiftType shift, Reg m);
bool arm_LDRB_lit(Cond cond, bool U, Reg t, Imm12 imm12);
bool arm_LDRB_imm(Cond cond, bool P, bool U, bool W, Reg n, Reg t, Imm12 imm12);
bool arm_LDRB_reg(Cond cond, bool P, bool U, bool W, Reg n, Reg t, Imm5 imm5, ShiftType shift, Reg m);
bool arm_LDRD_lit(Cond cond, bool U, Reg t, Imm4 imm8a, Imm4 imm8b);
bool arm_LDRD_imm(Cond cond, bool P, bool U, bool W, Reg n, Reg t, Imm4 imm8a, Imm4 imm8b);
bool arm_LDRD_reg(Cond cond, bool P, bool U, bool W, Reg n, Reg d, Reg m);
bool arm_LDRH_lit(Cond cond, bool P, bool U, bool W, Reg t, Imm4 imm8a, Imm4 imm8b);
bool arm_LDRH_imm(Cond cond, bool P, bool U, bool W, Reg n, Reg t, Imm4 imm8a, Imm4 imm8b);
bool arm_LDRH_reg(Cond cond, bool P, bool U, bool W, Reg n, Reg d, Reg m);
bool arm_LDRSB_lit(Cond cond, bool U, Reg t, Imm4 imm8a, Imm4 imm8b);
bool arm_LDRSB_imm(Cond cond, bool P, bool U, bool W, Reg n, Reg t, Imm4 imm8a, Imm4 imm8b);
bool arm_LDRSB_reg(Cond cond, bool P, bool U, bool W, Reg n, Reg t, Reg m);
bool arm_LDRSH_lit(Cond cond, bool U, Reg t, Imm4 imm8a, Imm4 imm8b);
bool arm_LDRSH_imm(Cond cond, bool P, bool U, bool W, Reg n, Reg t, Imm4 imm8a, Imm4 imm8b);
bool arm_LDRSH_reg(Cond cond, bool P, bool U, bool W, Reg n, Reg t, Reg m);
bool arm_STR_imm(Cond cond, bool P, bool U, bool W, Reg n, Reg d, Imm12 imm12);
bool arm_STR_reg(Cond cond, bool P, bool U, bool W, Reg n, Reg d, Imm5 imm5, ShiftType shift, Reg m);
bool arm_STRB_imm(Cond cond, bool P, bool U, bool W, Reg n, Reg d, Imm12 imm12);
bool arm_STRB_reg(Cond cond, bool P, bool U, bool W, Reg n, Reg d, Imm5 imm5, ShiftType shift, Reg m);
bool arm_STRBT();
bool arm_STRD_imm(Cond cond, bool P, bool U, bool W, Reg n, Reg d, Imm4 imm8a, Imm4 imm8b);
bool arm_STRD_reg(Cond cond, bool P, bool U, bool W, Reg n, Reg d, Reg m);
bool arm_STRH_imm(Cond cond, bool P, bool U, bool W, Reg n, Reg d, Imm4 imm8a, Imm4 imm8b);
bool arm_STRH_reg(Cond cond, bool P, bool U, bool W, Reg n, Reg d, Reg m);
bool arm_STRHT();
bool arm_STRT();
// Load/Store multiple instructions
bool arm_LDM(Cond cond, bool W, Reg n, RegList list);

View file

@ -643,7 +643,7 @@ TEST_CASE("Fuzz ARM load/store instructions (byte, half-word, word)", "[JitX64]"
u32 rand = RandInt<u32>(0, 0xFF);
u32 Rm = RandInt<u32>(0, 14);
if (W) {
if (!P || W) {
while (Rn == Rd) {
Rn = RandInt<u32>(0, 14);
Rd = RandInt<u32>(0, 14);