Implement CDP, LDC, MCR, MCRR, MRC, MRRC, STC

This commit is contained in:
MerryMage 2016-12-31 11:24:47 +00:00 committed by Merry
parent 48693eb6ff
commit e3bc7d039f
5 changed files with 217 additions and 28 deletions

View file

@ -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

View file

@ -40,20 +40,13 @@ std::vector<ArmMatcher<V>> 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

View file

@ -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 <unimplemented>"; }
std::string arm_LDC() { return "ldc <unimplemented>"; }
std::string arm_MCR() { return "mcr <unimplemented>"; }
std::string arm_MCRR() { return "mcrr <unimplemented>"; }
std::string arm_MRC() { return "mrc <unimplemented>"; }
std::string arm_MRRC() { return "mrrc <unimplemented>"; }
std::string arm_STC() { return "stc <unimplemented>"; }
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<u32>(imm8) << 2;
if (!p && !u && !d && !w)
return "<undefined>";
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 "<internal error>";
}
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<u32>(imm8) << 2;
if (!p && !u && !d && !w)
return "<undefined>";
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 "<internal error>";
}
// Data processing instructions
std::string arm_ADC_imm(Cond cond, bool S, Reg n, Reg d, int rotate, Imm8 imm8) {

View file

@ -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} <coproc_no>, #<opc1>, <CRd>, <CRn>, <CRm>, #<opc2>
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<u8>(imm8) << 2;
const bool index = p;
const bool add = u;
const bool wback = w;
const bool has_option = !p & !w & u;
// LDC{2}{L} <coproc_no>, <CRd>, [<Rn>, #+/-<imm32>]{!}
// LDC{2}{L} <coproc_no>, <CRd>, [<Rn>], #+/-<imm32>
// LDC{2}{L} <coproc_no>, <CRd>, [<Rn>], <imm8>
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} <coproc_no>, #<opc1>, <Rt>, <CRn>, <CRm>, #<opc2>
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} <coproc_no>, #<opc>, <Rt>, <Rt2>, <CRm>
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} <coproc_no>, #<opc1>, <Rt>, <CRn>, <CRm>, #<opc2>
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} <coproc_no>, #<opc>, <Rt>, <Rt2>, <CRm>
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<u8>(imm8) << 2;
const bool index = p;
const bool add = u;
const bool wback = w;
const bool has_option = !p & !w & u;
// STC{2}{L} <coproc>, <CRd>, [<Rn>, #+/-<imm32>]{!}
// STC{2}{L} <coproc>, <CRd>, [<Rn>], #+/-<imm32>
// STC{2}{L} <coproc>, <CRd>, [<Rn>], <imm8>
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

View file

@ -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);