Merge pull request #490 from lioncash/crc32

A32: Implement ARM-mode CRC32 instructions
This commit is contained in:
Merry 2019-05-02 23:45:09 +01:00 committed by MerryMage
commit a132b56d57
5 changed files with 122 additions and 0 deletions

View file

@ -99,6 +99,7 @@ add_library(dynarmic
frontend/A32/translate/translate_arm/barrier.cpp
frontend/A32/translate/translate_arm/branch.cpp
frontend/A32/translate/translate_arm/coprocessor.cpp
frontend/A32/translate/translate_arm/crc32.cpp
frontend/A32/translate/translate_arm/data_processing.cpp
frontend/A32/translate/translate_arm/divide.cpp
frontend/A32/translate/translate_arm/exception_generating.cpp

View file

@ -11,6 +11,10 @@ INST(arm_BL, "BL", "cccc1011vvvvvvvvvvvvvvvvvvvvvvvv
INST(arm_BX, "BX", "cccc000100101111111111110001mmmm") // v4T
INST(arm_BXJ, "BXJ", "cccc000100101111111111110010mmmm") // v5J
// CRC32 instructions
INST(arm_CRC32, "CRC32", "cccc00010zz0nnnndddd00000100mmmm") // v8
INST(arm_CRC32C, "CRC32C", "cccc00010zz0nnnndddd00100100mmmm") // v8
// Coprocessor instructions
INST(arm_CDP, "CDP", "cccc1110ooooNNNNDDDDppppooo0MMMM") // v2 (CDP2: v5)
INST(arm_LDC, "LDC", "cccc110pudw1nnnnDDDDppppvvvvvvvv") // v2 (LDC2: v5)

View file

@ -224,6 +224,22 @@ public:
return "<internal error>";
}
// CRC32 instructions
std::string arm_CRC32([[maybe_unused]] Cond cond, Imm<2> sz, Reg n, Reg d, Reg m) {
static constexpr std::array data_type{
"b", "h", "w", "invalid",
};
return fmt::format("crc32{} {}, {}, {}", data_type[sz.ZeroExtend()], d, n, m);
}
std::string arm_CRC32C([[maybe_unused]] Cond cond, Imm<2> sz, Reg n, Reg d, Reg m) {
static constexpr std::array data_type{
"b", "h", "w", "invalid",
};
return fmt::format("crc32c{} {}, {}, {}", data_type[sz.ZeroExtend()], d, n, m);
}
// Data processing instructions
std::string arm_ADC_imm(Cond cond, bool S, Reg n, Reg d, int rotate, Imm<8> imm8) {
return fmt::format("adc{}{} {}, {}, #{}", CondToString(cond), S ? "s" : "", d, n, ArmExpandImm(rotate, imm8));

View file

@ -0,0 +1,97 @@
/* This file is part of the dynarmic project.
* Copyright (c) 2019 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::A32 {
// It's considered constrained UNPREDICTABLE behavior if either
// CRC32 instruction variant is executed with a condition code
// that is *not* 0xE (Always execute). ARM defines one of the following
// as being a requirement in this case. Either:
//
// 1. The instruction is undefined.
// 2. The instruction executes as a NOP.
// 3. The instruction executes unconditionally.
// 4. The instruction executes conditionally.
//
// It's also considered constrained UNPREDICTABLE behavior if
// either CRC32 instruction variant is executed with a size specifier
// of 64-bit (sz -> 0b11)
//
// In this case, either:
//
// 1. The instruction is undefined
// 2. The instruction executes as a NOP.
// 3. The instruction executes with the additional decode: size = 32.
//
// In both cases, we treat as unpredictable, to allow
// library users to provide their own intended behavior
// in the unpredictable exception handler.
namespace {
enum class CRCType {
Castagnoli,
ISO,
};
bool CRC32Variant(ArmTranslatorVisitor& v, Cond cond, Imm<2> sz, Reg n, Reg d, Reg m, CRCType type) {
if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
return v.UnpredictableInstruction();
}
if (sz == 0b11) {
return v.UnpredictableInstruction();
}
if (cond != Cond::AL) {
return v.UnpredictableInstruction();
}
const IR::U32 result = [m, n, sz, type, &v] {
const IR::U32 accumulator = v.ir.GetRegister(n);
const IR::U32 data = v.ir.GetRegister(m);
if (type == CRCType::ISO) {
switch (sz.ZeroExtend()) {
case 0b00:
return v.ir.CRC32ISO8(accumulator, v.ir.And(data, v.ir.Imm32(0xFF)));
case 0b01:
return v.ir.CRC32ISO16(accumulator, v.ir.And(data, v.ir.Imm32(0xFFFF)));
case 0b10:
return v.ir.CRC32ISO32(accumulator, data);
}
} else {
switch (sz.ZeroExtend()) {
case 0b00:
return v.ir.CRC32Castagnoli8(accumulator, v.ir.And(data, v.ir.Imm32(0xFF)));
case 0b01:
return v.ir.CRC32Castagnoli16(accumulator, v.ir.And(data, v.ir.Imm32(0xFFFF)));
case 0b10:
return v.ir.CRC32Castagnoli32(accumulator, data);
}
}
UNREACHABLE();
return IR::U32{};
}();
v.ir.SetRegister(d, result);
return true;
}
} // Anonymous namespace
// CRC32{B,H,W}{<q>} <Rd>, <Rn>, <Rm>
bool ArmTranslatorVisitor::arm_CRC32(Cond cond, Imm<2> sz, Reg n, Reg d, Reg m) {
return CRC32Variant(*this, cond, sz, n, d, m, CRCType::ISO);
}
// CRC32C{B,H,W}{<q>} <Rd>, <Rn>, <Rm>
bool ArmTranslatorVisitor::arm_CRC32C(Cond cond, Imm<2> sz, Reg n, Reg d, Reg m) {
return CRC32Variant(*this, cond, sz, n, d, m, CRCType::Castagnoli);
}
} // namespace Dynarmic::A32

View file

@ -87,6 +87,10 @@ struct ArmTranslatorVisitor final {
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, Imm<8> imm8);
// CRC32 instructions
bool arm_CRC32(Cond cond, Imm<2> sz, Reg n, Reg d, Reg m);
bool arm_CRC32C(Cond cond, Imm<2> sz, Reg n, Reg d, Reg m);
// Data processing instructions
bool arm_ADC_imm(Cond cond, bool S, Reg n, Reg d, int rotate, Imm<8> imm8);
bool arm_ADC_reg(Cond cond, bool S, Reg n, Reg d, Imm<5> imm5, ShiftType shift, Reg m);