From e3bc7d039fca06ac5bd8339ef8048fbe094206b5 Mon Sep 17 00:00:00 2001 From: MerryMage Date: Sat, 31 Dec 2016 11:24:47 +0000 Subject: [PATCH] Implement CDP, LDC, MCR, MCRR, MRC, MRRC, STC --- src/CMakeLists.txt | 1 + src/frontend/decoder/arm.h | 21 +-- .../disassembler/disassembler_arm.cpp | 58 ++++++- .../translate/translate_arm/coprocessor.cpp | 151 ++++++++++++++++++ .../translate/translate_arm/translate_arm.h | 14 +- 5 files changed, 217 insertions(+), 28 deletions(-) create mode 100644 src/frontend/translate/translate_arm/coprocessor.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b029adb4..879eca9c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -12,6 +12,7 @@ set(SRCS frontend/translate/translate.cpp frontend/translate/translate_arm.cpp frontend/translate/translate_arm/branch.cpp + frontend/translate/translate_arm/coprocessor.cpp frontend/translate/translate_arm/data_processing.cpp frontend/translate/translate_arm/exception_generating.cpp frontend/translate/translate_arm/extension.cpp diff --git a/src/frontend/decoder/arm.h b/src/frontend/decoder/arm.h index d1a240a8..6bde0b6d 100644 --- a/src/frontend/decoder/arm.h +++ b/src/frontend/decoder/arm.h @@ -40,20 +40,13 @@ std::vector> GetArmDecodeTable() { INST(&V::arm_BXJ, "BXJ", "cccc000100101111111111110010mmmm"), // v5J // Coprocessor instructions - INST(&V::arm_CDP, "CDP2", "11111110-------------------1----"), // v5 - INST(&V::arm_CDP, "CDP", "----1110-------------------0----"), // v2 - INST(&V::arm_LDC, "LDC2", "1111110----1--------------------"), // v5 - INST(&V::arm_LDC, "LDC", "----110----1--------------------"), // v2 - INST(&V::arm_MCR, "MCR2", "11111110---0---------------1----"), // v5 - INST(&V::arm_MCR, "MCR", "----1110---0---------------1----"), // v2 - INST(&V::arm_MCRR, "MCRR2", "111111000100--------------------"), // v6 - INST(&V::arm_MCRR, "MCRR", "----11000100--------------------"), // v5E - INST(&V::arm_MRC, "MRC2", "11111110---1---------------1----"), // v5 - INST(&V::arm_MRC, "MRC", "----1110---1---------------1----"), // v2 - INST(&V::arm_MRRC, "MRRC2", "111111000101--------------------"), // v6 - INST(&V::arm_MRRC, "MRRC", "----11000101--------------------"), // v5E - INST(&V::arm_STC, "STC2", "1111110----0--------------------"), // v5 - INST(&V::arm_STC, "STC", "----110----0--------------------"), // v2 + INST(&V::arm_CDP, "CDP", "cccc1110ooooNNNNDDDDppppooo0MMMM"), // v2 (CDP2: v5) + INST(&V::arm_LDC, "LDC", "cccc110pudw1nnnnDDDDppppvvvvvvvv"), // v2 (LDC2: v5) + INST(&V::arm_MCR, "MCR", "cccc1110ooo0NNNNttttppppooo1MMMM"), // v2 (MCR2: v5) + INST(&V::arm_MCRR, "MCRR", "cccc11000100uuuuttttppppooooMMMM"), // v5E (MCRR2: v6) + INST(&V::arm_MRC, "MRC", "cccc1110ooo1NNNNttttppppooo1MMMM"), // v2 (MRC2: v5) + INST(&V::arm_MRRC, "MRRC", "cccc11000101uuuuttttppppooooMMMM"), // v5E (MRRC2: v6) + INST(&V::arm_STC, "STC", "cccc110pudw0nnnnDDDDppppvvvvvvvv"), // v2 (STC2: v5) // Data Processing instructions INST(&V::arm_ADC_imm, "ADC (imm)", "cccc0010101Snnnnddddrrrrvvvvvvvv"), // all diff --git a/src/frontend/disassembler/disassembler_arm.cpp b/src/frontend/disassembler/disassembler_arm.cpp index e98ff1f8..ba70a6c4 100644 --- a/src/frontend/disassembler/disassembler_arm.cpp +++ b/src/frontend/disassembler/disassembler_arm.cpp @@ -103,6 +103,10 @@ public: return fmt::format("{}{}", dp_operation ? 'd' : 's', reg_num + 1); } + std::string CondOrTwo(Cond cond) { + return cond == Cond::NV ? "2" : CondToString(cond); + } + // Branch instructions std::string arm_B(Cond cond, Imm24 imm24) { s32 offset = Common::SignExtend<26, s32>(imm24 << 2) + 8; @@ -127,13 +131,53 @@ public: } // Coprocessor instructions - std::string arm_CDP() { return "cdp "; } - std::string arm_LDC() { return "ldc "; } - std::string arm_MCR() { return "mcr "; } - std::string arm_MCRR() { return "mcrr "; } - std::string arm_MRC() { return "mrc "; } - std::string arm_MRRC() { return "mrrc "; } - std::string arm_STC() { return "stc "; } + std::string arm_CDP(Cond cond, size_t opc1, CoprocReg CRn, CoprocReg CRd, size_t coproc_no, size_t opc2, CoprocReg CRm) { + return fmt::format("cdp{} p{}, #{}, {}, {}, {}, #{}", CondToString(cond), coproc_no, opc1, CRd, CRn, CRm, opc2); + } + + std::string arm_LDC(Cond cond, bool p, bool u, bool d, bool w, Reg n, CoprocReg CRd, size_t coproc_no, Imm8 imm8) { + const u32 imm32 = static_cast(imm8) << 2; + if (!p && !u && !d && !w) + return ""; + if (p) + return fmt::format("ldc{}{} {}, {}, [{}, #{}{}]{}", d ? "l" : "", CondOrTwo(cond), coproc_no, CRd, n, u ? "+" : "-", imm32, w ? "!" : ""); + if (!p && w) + return fmt::format("ldc{}{} {}, {}, [{}], #{}{}", d ? "l" : "", CondOrTwo(cond), coproc_no, CRd, n, u ? "+" : "-", imm32); + if (!p && !w && u) + return fmt::format("ldc{}{} {}, {}, [{}], {}", d ? "l" : "", CondOrTwo(cond), coproc_no, CRd, n, imm8); + UNREACHABLE(); + return ""; + } + + std::string arm_MCR(Cond cond, size_t opc1, CoprocReg CRn, Reg t, size_t coproc_no, size_t opc2, CoprocReg CRm) { + return fmt::format("mcr{} p{}, #{}, {}, {}, {}, #{}", CondOrTwo(cond), coproc_no, opc1, t, CRn, CRm, opc2); + } + + std::string arm_MCRR(Cond cond, Reg t2, Reg t, size_t coproc_no, size_t opc, CoprocReg CRm) { + return fmt::format("mcr{} p{}, #{}, {}, {}, {}", CondOrTwo(cond), coproc_no, opc, t, t2, CRm); + } + + std::string arm_MRC(Cond cond, size_t opc1, CoprocReg CRn, Reg t, size_t coproc_no, size_t opc2, CoprocReg CRm) { + return fmt::format("mrc{} p{}, #{}, {}, {}, {}, #{}", CondOrTwo(cond), coproc_no, opc1, t, CRn, CRm, opc2); + } + + std::string arm_MRRC(Cond cond, Reg t2, Reg t, size_t coproc_no, size_t opc, CoprocReg CRm) { + return fmt::format("mrrc{} p{}, #{}, {}, {}, {}", CondOrTwo(cond), coproc_no, opc, t, t2, CRm); + } + + std::string arm_STC(Cond cond, bool p, bool u, bool d, bool w, Reg n, CoprocReg CRd, size_t coproc_no, Imm8 imm8) { + const u32 imm32 = static_cast(imm8) << 2; + if (!p && !u && !d && !w) + return ""; + if (p) + return fmt::format("stc{}{} {}, {}, [{}, #{}{}]{}", d ? "l" : "", CondOrTwo(cond), coproc_no, CRd, n, u ? "+" : "-", imm32, w ? "!" : ""); + if (!p && w) + return fmt::format("stc{}{} {}, {}, [{}], #{}{}", d ? "l" : "", CondOrTwo(cond), coproc_no, CRd, n, u ? "+" : "-", imm32); + if (!p && !w && u) + return fmt::format("stc{}{} {}, {}, [{}], {}", d ? "l" : "", CondOrTwo(cond), coproc_no, CRd, n, imm8); + UNREACHABLE(); + return ""; + } // Data processing instructions std::string arm_ADC_imm(Cond cond, bool S, Reg n, Reg d, int rotate, Imm8 imm8) { diff --git a/src/frontend/translate/translate_arm/coprocessor.cpp b/src/frontend/translate/translate_arm/coprocessor.cpp new file mode 100644 index 00000000..3227f55b --- /dev/null +++ b/src/frontend/translate/translate_arm/coprocessor.cpp @@ -0,0 +1,151 @@ +/* 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 { + +bool ArmTranslatorVisitor::arm_CDP(Cond cond, size_t opc1, CoprocReg CRn, CoprocReg CRd, size_t coproc_no, size_t opc2, CoprocReg CRm) { + if ((coproc_no & 0b1110) == 0b1010) + return arm_UDF(); + + const bool two = cond == Cond::NV; + + // CDP{2} , #, , , , # + if (two || ConditionPassed(cond)) { + ir.CoprocInternalOperation(coproc_no, two, opc1, CRd, CRn, CRm, opc2); + } + return true; +} + +bool ArmTranslatorVisitor::arm_LDC(Cond cond, bool p, bool u, bool d, bool w, Reg n, CoprocReg CRd, size_t coproc_no, Imm8 imm8) { + if (!p && !u && !d && !w) + return arm_UDF(); + if ((coproc_no & 0b1110) == 0b1010) + return arm_UDF(); + + const bool two = cond == Cond::NV; + const u32 imm32 = static_cast(imm8) << 2; + const bool index = p; + const bool add = u; + const bool wback = w; + const bool has_option = !p & !w & u; + + // LDC{2}{L} , , [, #+/-]{!} + // LDC{2}{L} , , [], #+/- + // LDC{2}{L} , , [], + if (two || ConditionPassed(cond)) { + auto reg_n = ir.GetRegister(n); + auto offset_address = add ? ir.Add(reg_n, ir.Imm32(imm32)) : ir.Sub(reg_n, ir.Imm32(imm32)); + auto address = index ? offset_address : reg_n; + ir.CoprocLoadWords(coproc_no, two, d, CRd, address, has_option, imm8); + if (wback) { + ir.SetRegister(n, offset_address); + } + } + return true; +} + +bool ArmTranslatorVisitor::arm_MCR(Cond cond, size_t opc1, CoprocReg CRn, Reg t, size_t coproc_no, size_t opc2, CoprocReg CRm) { + if ((coproc_no & 0b1110) == 0b1010) + return arm_UDF(); + if (t == Reg::PC) + return UnpredictableInstruction(); + + const bool two = cond == Cond::NV; + + // MCR{2} , #, , , , # + if (two || ConditionPassed(cond)) { + ir.CoprocSendOneWord(coproc_no, two, opc1, CRn, CRm, opc2, ir.GetRegister(t)); + } + return true; +} + +bool ArmTranslatorVisitor::arm_MCRR(Cond cond, Reg t2, Reg t, size_t coproc_no, size_t opc, CoprocReg CRm) { + if ((coproc_no & 0b1110) == 0b1010) + return arm_UDF(); + if (t == Reg::PC || t2 == Reg::PC) + return UnpredictableInstruction(); + + const bool two = cond == Cond::NV; + + // MCRR{2} , #, , , + if (two || ConditionPassed(cond)) { + ir.CoprocSendTwoWords(coproc_no, two, opc, CRm, ir.GetRegister(t), ir.GetRegister(t2)); + } + return true; +} + +bool ArmTranslatorVisitor::arm_MRC(Cond cond, size_t opc1, CoprocReg CRn, Reg t, size_t coproc_no, size_t opc2, CoprocReg CRm) { + if ((coproc_no & 0b1110) == 0b1010) + return arm_UDF(); + + const bool two = cond == Cond::NV; + + // MRC{2} , #, , , , # + if (two || ConditionPassed(cond)) { + auto word = ir.CoprocGetOneWord(coproc_no, two, opc1, CRn, CRm, opc2); + if (t != Reg::PC) { + ir.SetRegister(t, word); + } else { + auto old_cpsr = ir.And(ir.GetCpsr(), ir.Imm32(0x0FFFFFFF)); + auto new_cpsr_nzcv = ir.And(word, ir.Imm32(0xF0000000)); + ir.SetCpsr(ir.Or(old_cpsr, new_cpsr_nzcv)); + } + } + return true; +} + +bool ArmTranslatorVisitor::arm_MRRC(Cond cond, Reg t2, Reg t, size_t coproc_no, size_t opc, CoprocReg CRm) { + if ((coproc_no & 0b1110) == 0b1010) + return arm_UDF(); + if (t == Reg::PC || t2 == Reg::PC || t == t2) + return UnpredictableInstruction(); + + const bool two = cond == Cond::NV; + + // MRRC{2} , #, , , + if (two || ConditionPassed(cond)) { + auto two_words = ir.CoprocGetTwoWords(coproc_no, two, opc, CRm); + ir.SetRegister(t, ir.LeastSignificantWord(two_words)); + ir.SetRegister(t2, ir.MostSignificantWord(two_words).result); + } + return true; +} + +bool ArmTranslatorVisitor::arm_STC(Cond cond, bool p, bool u, bool d, bool w, Reg n, CoprocReg CRd, size_t coproc_no, Imm8 imm8) { + if ((coproc_no & 0b1110) == 0b1010) + return arm_UDF(); + if (!p && !u && !d && !w) + return arm_UDF(); + if (n == Reg::PC && w) + return UnpredictableInstruction(); + + const bool two = cond == Cond::NV; + const u32 imm32 = static_cast(imm8) << 2; + const bool index = p; + const bool add = u; + const bool wback = w; + const bool has_option = !p & !w & u; + + // STC{2}{L} , , [, #+/-]{!} + // STC{2}{L} , , [], #+/- + // STC{2}{L} , , [], + if (two || ConditionPassed(cond)) { + auto reg_n = ir.GetRegister(n); + auto offset_address = add ? ir.Add(reg_n, ir.Imm32(imm32)) : ir.Sub(reg_n, ir.Imm32(imm32)); + auto address = index ? offset_address : reg_n; + ir.CoprocStoreWords(coproc_no, two, d, CRd, address, has_option, imm8); + if (wback) { + ir.SetRegister(n, offset_address); + } + } + return true; +} + +} // namespace Arm +} // namespace Dynarmic diff --git a/src/frontend/translate/translate_arm/translate_arm.h b/src/frontend/translate/translate_arm/translate_arm.h index 1707d978..b2568afc 100644 --- a/src/frontend/translate/translate_arm/translate_arm.h +++ b/src/frontend/translate/translate_arm/translate_arm.h @@ -75,13 +75,13 @@ struct ArmTranslatorVisitor final { bool arm_BXJ(Cond cond, Reg m); // Coprocessor instructions - bool arm_CDP() { return InterpretThisInstruction(); } - bool arm_LDC() { return InterpretThisInstruction(); } - bool arm_MCR() { return InterpretThisInstruction(); } - bool arm_MCRR() { return InterpretThisInstruction(); } - bool arm_MRC() { return InterpretThisInstruction(); } - bool arm_MRRC() { return InterpretThisInstruction(); } - bool arm_STC() { return InterpretThisInstruction(); } + bool arm_CDP(Cond cond, size_t opc1, CoprocReg CRn, CoprocReg CRd, size_t coproc_no, size_t opc2, CoprocReg CRm); + bool arm_LDC(Cond cond, bool p, bool u, bool d, bool w, Reg n, CoprocReg CRd, size_t coproc_no, Imm8 imm8); + bool arm_MCR(Cond cond, size_t opc1, CoprocReg CRn, Reg t, size_t coproc_no, size_t opc2, CoprocReg CRm); + bool arm_MCRR(Cond cond, Reg t2, Reg t, size_t coproc_no, size_t opc, CoprocReg CRm); + bool arm_MRC(Cond cond, size_t opc1, CoprocReg CRn, Reg t, size_t coproc_no, size_t opc2, CoprocReg CRm); + bool arm_MRRC(Cond cond, Reg t2, Reg t, size_t coproc_no, size_t opc, CoprocReg CRm); + bool arm_STC(Cond cond, bool p, bool u, bool d, bool w, Reg n, CoprocReg CRd, size_t coproc_no, Imm8 imm8); // Data processing instructions bool arm_ADC_imm(Cond cond, bool S, Reg n, Reg d, int rotate, Imm8 imm8);