1 /* This file is part of the dynarmic project.
2  * Copyright (c) 2019 MerryMage
3  * SPDX-License-Identifier: 0BSD
4  */
5 
6 #include "frontend/A32/translate/impl/translate_arm.h"
7 
8 namespace Dynarmic::A32 {
9 
10 // It's considered constrained UNPREDICTABLE behavior if either
11 // CRC32 instruction variant is executed with a condition code
12 // that is *not* 0xE (Always execute). ARM defines one of the following
13 // as being a requirement in this case. Either:
14 //
15 // 1. The instruction is undefined.
16 // 2. The instruction executes as a NOP.
17 // 3. The instruction executes unconditionally.
18 // 4. The instruction executes conditionally.
19 //
20 // It's also considered constrained UNPREDICTABLE behavior if
21 // either CRC32 instruction variant is executed with a size specifier
22 // of 64-bit (sz -> 0b11)
23 //
24 // In this case, either:
25 //
26 // 1. The instruction is undefined
27 // 2. The instruction executes as a NOP.
28 // 3. The instruction executes with the additional decode: size = 32.
29 //
30 // In both cases, we treat as unpredictable, to allow
31 // library users to provide their own intended behavior
32 // in the unpredictable exception handler.
33 
34 namespace {
35 enum class CRCType {
36     Castagnoli,
37     ISO,
38 };
39 
CRC32Variant(ArmTranslatorVisitor & v,Cond cond,Imm<2> sz,Reg n,Reg d,Reg m,CRCType type)40 bool CRC32Variant(ArmTranslatorVisitor& v, Cond cond, Imm<2> sz, Reg n, Reg d, Reg m, CRCType type) {
41     if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
42         return v.UnpredictableInstruction();
43     }
44 
45     if (sz == 0b11) {
46         return v.UnpredictableInstruction();
47     }
48 
49     if (cond != Cond::AL) {
50         return v.UnpredictableInstruction();
51     }
52 
53     const IR::U32 result = [m, n, sz, type, &v] {
54         const IR::U32 accumulator = v.ir.GetRegister(n);
55         const IR::U32 data = v.ir.GetRegister(m);
56 
57         if (type == CRCType::ISO) {
58             switch (sz.ZeroExtend()) {
59             case 0b00:
60                 return v.ir.CRC32ISO8(accumulator, data);
61             case 0b01:
62                 return v.ir.CRC32ISO16(accumulator, data);
63             case 0b10:
64                 return v.ir.CRC32ISO32(accumulator, data);
65             }
66         } else {
67             switch (sz.ZeroExtend()) {
68             case 0b00:
69                 return v.ir.CRC32Castagnoli8(accumulator, data);
70             case 0b01:
71                 return v.ir.CRC32Castagnoli16(accumulator, data);
72             case 0b10:
73                 return v.ir.CRC32Castagnoli32(accumulator, data);
74             }
75         }
76 
77         UNREACHABLE();
78     }();
79 
80     v.ir.SetRegister(d, result);
81     return true;
82 }
83 } // Anonymous namespace
84 
85 // CRC32{B,H,W}{<q>} <Rd>, <Rn>, <Rm>
arm_CRC32(Cond cond,Imm<2> sz,Reg n,Reg d,Reg m)86 bool ArmTranslatorVisitor::arm_CRC32(Cond cond, Imm<2> sz, Reg n, Reg d, Reg m) {
87     return CRC32Variant(*this, cond, sz, n, d, m, CRCType::ISO);
88 }
89 
90 // CRC32C{B,H,W}{<q>} <Rd>, <Rn>, <Rm>
arm_CRC32C(Cond cond,Imm<2> sz,Reg n,Reg d,Reg m)91 bool ArmTranslatorVisitor::arm_CRC32C(Cond cond, Imm<2> sz, Reg n, Reg d, Reg m) {
92     return CRC32Variant(*this, cond, sz, n, d, m, CRCType::Castagnoli);
93 }
94 
95 } // namespace Dynarmic::A32
96