Merge pull request #490 from lioncash/crc32
A32: Implement ARM-mode CRC32 instructions
This commit is contained in:
commit
a132b56d57
5 changed files with 122 additions and 0 deletions
|
@ -99,6 +99,7 @@ add_library(dynarmic
|
||||||
frontend/A32/translate/translate_arm/barrier.cpp
|
frontend/A32/translate/translate_arm/barrier.cpp
|
||||||
frontend/A32/translate/translate_arm/branch.cpp
|
frontend/A32/translate/translate_arm/branch.cpp
|
||||||
frontend/A32/translate/translate_arm/coprocessor.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/data_processing.cpp
|
||||||
frontend/A32/translate/translate_arm/divide.cpp
|
frontend/A32/translate/translate_arm/divide.cpp
|
||||||
frontend/A32/translate/translate_arm/exception_generating.cpp
|
frontend/A32/translate/translate_arm/exception_generating.cpp
|
||||||
|
|
|
@ -11,6 +11,10 @@ INST(arm_BL, "BL", "cccc1011vvvvvvvvvvvvvvvvvvvvvvvv
|
||||||
INST(arm_BX, "BX", "cccc000100101111111111110001mmmm") // v4T
|
INST(arm_BX, "BX", "cccc000100101111111111110001mmmm") // v4T
|
||||||
INST(arm_BXJ, "BXJ", "cccc000100101111111111110010mmmm") // v5J
|
INST(arm_BXJ, "BXJ", "cccc000100101111111111110010mmmm") // v5J
|
||||||
|
|
||||||
|
// CRC32 instructions
|
||||||
|
INST(arm_CRC32, "CRC32", "cccc00010zz0nnnndddd00000100mmmm") // v8
|
||||||
|
INST(arm_CRC32C, "CRC32C", "cccc00010zz0nnnndddd00100100mmmm") // v8
|
||||||
|
|
||||||
// Coprocessor instructions
|
// Coprocessor instructions
|
||||||
INST(arm_CDP, "CDP", "cccc1110ooooNNNNDDDDppppooo0MMMM") // v2 (CDP2: v5)
|
INST(arm_CDP, "CDP", "cccc1110ooooNNNNDDDDppppooo0MMMM") // v2 (CDP2: v5)
|
||||||
INST(arm_LDC, "LDC", "cccc110pudw1nnnnDDDDppppvvvvvvvv") // v2 (LDC2: v5)
|
INST(arm_LDC, "LDC", "cccc110pudw1nnnnDDDDppppvvvvvvvv") // v2 (LDC2: v5)
|
||||||
|
|
|
@ -224,6 +224,22 @@ public:
|
||||||
return "<internal error>";
|
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
|
// Data processing instructions
|
||||||
std::string arm_ADC_imm(Cond cond, bool S, Reg n, Reg d, int rotate, Imm<8> imm8) {
|
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));
|
return fmt::format("adc{}{} {}, {}, #{}", CondToString(cond), S ? "s" : "", d, n, ArmExpandImm(rotate, imm8));
|
||||||
|
|
97
src/frontend/A32/translate/translate_arm/crc32.cpp
Normal file
97
src/frontend/A32/translate/translate_arm/crc32.cpp
Normal 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
|
|
@ -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_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);
|
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
|
// Data processing instructions
|
||||||
bool arm_ADC_imm(Cond cond, bool S, Reg n, Reg d, int rotate, Imm<8> imm8);
|
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);
|
bool arm_ADC_reg(Cond cond, bool S, Reg n, Reg d, Imm<5> imm5, ShiftType shift, Reg m);
|
||||||
|
|
Loading…
Reference in a new issue