mirror of
https://git.suyu.dev/suyu/dynarmic.git
synced 2026-01-10 16:38:14 +01:00
95 lines
2.8 KiB
C++
95 lines
2.8 KiB
C++
/* This file is part of the dynarmic project.
|
|
* Copyright (c) 2019 MerryMage
|
|
* SPDX-License-Identifier: 0BSD
|
|
*/
|
|
|
|
#include "frontend/A32/translate/impl/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, data);
|
|
case 0b01:
|
|
return v.ir.CRC32ISO16(accumulator, data);
|
|
case 0b10:
|
|
return v.ir.CRC32ISO32(accumulator, data);
|
|
}
|
|
} else {
|
|
switch (sz.ZeroExtend()) {
|
|
case 0b00:
|
|
return v.ir.CRC32Castagnoli8(accumulator, data);
|
|
case 0b01:
|
|
return v.ir.CRC32Castagnoli16(accumulator, data);
|
|
case 0b10:
|
|
return v.ir.CRC32Castagnoli32(accumulator, data);
|
|
}
|
|
}
|
|
|
|
UNREACHABLE();
|
|
}();
|
|
|
|
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
|