From 4acc481463032972fa6bb44955af5f80b5b95588 Mon Sep 17 00:00:00 2001 From: MerryMage Date: Fri, 19 Aug 2016 00:24:31 +0100 Subject: [PATCH] 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. --- src/frontend/decoder/arm.h | 46 ++- .../disassembler/disassembler_arm.cpp | 23 ++ .../translate/translate_arm/load_store.cpp | 374 ++++++++++++++---- .../translate/translate_arm/translate_arm.h | 38 +- tests/arm/fuzz_arm.cpp | 2 +- 5 files changed, 376 insertions(+), 107 deletions(-) diff --git a/src/frontend/decoder/arm.h b/src/frontend/decoder/arm.h index f5ea1f6d..5e242f79 100644 --- a/src/frontend/decoder/arm.h +++ b/src/frontend/decoder/arm.h @@ -185,42 +185,48 @@ std::vector> 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 diff --git a/src/frontend/disassembler/disassembler_arm.cpp b/src/frontend/disassembler/disassembler_arm.cpp index 20bc4a64..26fe0e7b 100644 --- a/src/frontend/disassembler/disassembler_arm.cpp +++ b/src/frontend/disassembler/disassembler_arm.cpp @@ -337,6 +337,10 @@ public: std::string arm_YIELD() { return "yield "; } // 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) { diff --git a/src/frontend/translate/translate_arm/load_store.cpp b/src/frontend/translate/translate_arm/load_store.cpp index 17f819c7..17f75e20 100644 --- a/src/frontend/translate/translate_arm/load_store.cpp +++ b/src/frontend/translate/translate_arm/load_store.cpp @@ -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(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(std::min(d + 1, Reg::R15)); + const Reg reg_b = static_cast(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(std::min(d + 1, Reg::R15)); + const Reg reg_b = static_cast(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++) { diff --git a/src/frontend/translate/translate_arm/translate_arm.h b/src/frontend/translate/translate_arm/translate_arm.h index a7532c0f..74cb7186 100644 --- a/src/frontend/translate/translate_arm/translate_arm.h +++ b/src/frontend/translate/translate_arm/translate_arm.h @@ -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); diff --git a/tests/arm/fuzz_arm.cpp b/tests/arm/fuzz_arm.cpp index b53208f9..61db571f 100644 --- a/tests/arm/fuzz_arm.cpp +++ b/tests/arm/fuzz_arm.cpp @@ -643,7 +643,7 @@ TEST_CASE("Fuzz ARM load/store instructions (byte, half-word, word)", "[JitX64]" u32 rand = RandInt(0, 0xFF); u32 Rm = RandInt(0, 14); - if (W) { + if (!P || W) { while (Rn == Rd) { Rn = RandInt(0, 14); Rd = RandInt(0, 14);