A32: Implement ARM-mode CRC32 instructions
Implements the ARM-mode variants of the CRC32 instructions introduced within ARMv8. This is also one of the instruction cases where there is UNPREDICTABLE behavior that is constrained (we must do one of the options indicated by the reference manual). In both documented cases of constrained unpredictable behavior, we treat the instructions as unpredictable in order to allow library users to hook the unpredictable exception to provide the intended behavior they desire.
This commit is contained in:
parent
b1953c1cd4
commit
e37689315d
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