1 /* This file is part of the dynarmic project.
2  * Copyright (c) 2016 MerryMage
3  * SPDX-License-Identifier: 0BSD
4  */
5 
6 #include "frontend/A32/translate/impl/translate_arm.h"
7 
8 namespace Dynarmic::A32 {
9 
10 // CDP{2} <coproc_no>, #<opc1>, <CRd>, <CRn>, <CRm>, #<opc2>
arm_CDP(Cond cond,size_t opc1,CoprocReg CRn,CoprocReg CRd,size_t coproc_no,size_t opc2,CoprocReg CRm)11 bool ArmTranslatorVisitor::arm_CDP(Cond cond, size_t opc1, CoprocReg CRn, CoprocReg CRd, size_t coproc_no, size_t opc2, CoprocReg CRm) {
12     if ((coproc_no & 0b1110) == 0b1010) {
13         return arm_UDF();
14     }
15 
16     const bool two = cond == Cond::NV;
17 
18     if (two || ConditionPassed(cond)) {
19         ir.CoprocInternalOperation(coproc_no, two, opc1, CRd, CRn, CRm, opc2);
20     }
21     return true;
22 }
23 
24 // LDC{2}{L}<c> <coproc_no>, <CRd>, [<Rn>, #+/-<imm32>]{!}
25 // LDC{2}{L}<c> <coproc_no>, <CRd>, [<Rn>], #+/-<imm32>
26 // LDC{2}{L}<c> <coproc_no>, <CRd>, [<Rn>], <imm8>
arm_LDC(Cond cond,bool p,bool u,bool d,bool w,Reg n,CoprocReg CRd,size_t coproc_no,Imm<8> imm8)27 bool ArmTranslatorVisitor::arm_LDC(Cond cond, bool p, bool u, bool d, bool w, Reg n, CoprocReg CRd, size_t coproc_no, Imm<8> imm8) {
28     if (!p && !u && !d && !w) {
29         return arm_UDF();
30     }
31 
32     if ((coproc_no & 0b1110) == 0b1010) {
33         return arm_UDF();
34     }
35 
36     const bool two = cond == Cond::NV;
37 
38     if (two || ConditionPassed(cond)) {
39         const u32 imm32 = imm8.ZeroExtend() << 2;
40         const bool index = p;
41         const bool add = u;
42         const bool wback = w;
43         const bool has_option = !p && !w && u;
44         const IR::U32 reg_n = ir.GetRegister(n);
45         const IR::U32 offset_address = add ? ir.Add(reg_n, ir.Imm32(imm32)) : ir.Sub(reg_n, ir.Imm32(imm32));
46         const IR::U32 address = index ? offset_address : reg_n;
47         ir.CoprocLoadWords(coproc_no, two, d, CRd, address, has_option, imm8.ZeroExtend<u8>());
48         if (wback) {
49             ir.SetRegister(n, offset_address);
50         }
51     }
52     return true;
53 }
54 
55 // MCR{2}<c> <coproc_no>, #<opc1>, <Rt>, <CRn>, <CRm>, #<opc2>
arm_MCR(Cond cond,size_t opc1,CoprocReg CRn,Reg t,size_t coproc_no,size_t opc2,CoprocReg CRm)56 bool ArmTranslatorVisitor::arm_MCR(Cond cond, size_t opc1, CoprocReg CRn, Reg t, size_t coproc_no, size_t opc2, CoprocReg CRm) {
57     if ((coproc_no & 0b1110) == 0b1010) {
58         return arm_UDF();
59     }
60 
61     if (t == Reg::PC) {
62         return UnpredictableInstruction();
63     }
64 
65     const bool two = cond == Cond::NV;
66 
67     if (two || ConditionPassed(cond)) {
68         ir.CoprocSendOneWord(coproc_no, two, opc1, CRn, CRm, opc2, ir.GetRegister(t));
69     }
70     return true;
71 }
72 
73 // MCRR{2}<c> <coproc_no>, #<opc>, <Rt>, <Rt2>, <CRm>
arm_MCRR(Cond cond,Reg t2,Reg t,size_t coproc_no,size_t opc,CoprocReg CRm)74 bool ArmTranslatorVisitor::arm_MCRR(Cond cond, Reg t2, Reg t, size_t coproc_no, size_t opc, CoprocReg CRm) {
75     if ((coproc_no & 0b1110) == 0b1010) {
76         return arm_UDF();
77     }
78 
79     if (t == Reg::PC || t2 == Reg::PC) {
80         return UnpredictableInstruction();
81     }
82 
83     const bool two = cond == Cond::NV;
84 
85     if (two || ConditionPassed(cond)) {
86         ir.CoprocSendTwoWords(coproc_no, two, opc, CRm, ir.GetRegister(t), ir.GetRegister(t2));
87     }
88     return true;
89 }
90 
91 // MRC{2}<c> <coproc_no>, #<opc1>, <Rt>, <CRn>, <CRm>, #<opc2>
arm_MRC(Cond cond,size_t opc1,CoprocReg CRn,Reg t,size_t coproc_no,size_t opc2,CoprocReg CRm)92 bool ArmTranslatorVisitor::arm_MRC(Cond cond, size_t opc1, CoprocReg CRn, Reg t, size_t coproc_no, size_t opc2, CoprocReg CRm) {
93     if ((coproc_no & 0b1110) == 0b1010) {
94         return arm_UDF();
95     }
96 
97     const bool two = cond == Cond::NV;
98 
99     if (two || ConditionPassed(cond)) {
100         const auto word = ir.CoprocGetOneWord(coproc_no, two, opc1, CRn, CRm, opc2);
101         if (t != Reg::PC) {
102             ir.SetRegister(t, word);
103         } else {
104             const auto new_cpsr_nzcv = ir.And(word, ir.Imm32(0xF0000000));
105             ir.SetCpsrNZCV(new_cpsr_nzcv);
106         }
107     }
108     return true;
109 }
110 
111 // MRRC{2}<c> <coproc_no>, #<opc>, <Rt>, <Rt2>, <CRm>
arm_MRRC(Cond cond,Reg t2,Reg t,size_t coproc_no,size_t opc,CoprocReg CRm)112 bool ArmTranslatorVisitor::arm_MRRC(Cond cond, Reg t2, Reg t, size_t coproc_no, size_t opc, CoprocReg CRm) {
113     if ((coproc_no & 0b1110) == 0b1010) {
114         return arm_UDF();
115     }
116 
117     if (t == Reg::PC || t2 == Reg::PC || t == t2) {
118         return UnpredictableInstruction();
119     }
120 
121     const bool two = cond == Cond::NV;
122 
123     if (two || ConditionPassed(cond)) {
124         const auto two_words = ir.CoprocGetTwoWords(coproc_no, two, opc, CRm);
125         ir.SetRegister(t, ir.LeastSignificantWord(two_words));
126         ir.SetRegister(t2, ir.MostSignificantWord(two_words).result);
127     }
128     return true;
129 }
130 
131 // STC{2}{L}<c> <coproc>, <CRd>, [<Rn>, #+/-<imm32>]{!}
132 // STC{2}{L}<c> <coproc>, <CRd>, [<Rn>], #+/-<imm32>
133 // STC{2}{L}<c> <coproc>, <CRd>, [<Rn>], <imm8>
arm_STC(Cond cond,bool p,bool u,bool d,bool w,Reg n,CoprocReg CRd,size_t coproc_no,Imm<8> imm8)134 bool ArmTranslatorVisitor::arm_STC(Cond cond, bool p, bool u, bool d, bool w, Reg n, CoprocReg CRd, size_t coproc_no, Imm<8> imm8) {
135     if ((coproc_no & 0b1110) == 0b1010) {
136         return arm_UDF();
137     }
138 
139     if (!p && !u && !d && !w) {
140         return arm_UDF();
141     }
142 
143     if (n == Reg::PC && w) {
144         return UnpredictableInstruction();
145     }
146 
147     const bool two = cond == Cond::NV;
148 
149     if (two || ConditionPassed(cond)) {
150         const u32 imm32 = imm8.ZeroExtend() << 2;
151         const bool index = p;
152         const bool add = u;
153         const bool wback = w;
154         const bool has_option = !p && !w && u;
155         const IR::U32 reg_n = ir.GetRegister(n);
156         const IR::U32 offset_address = add ? ir.Add(reg_n, ir.Imm32(imm32)) : ir.Sub(reg_n, ir.Imm32(imm32));
157         const IR::U32 address = index ? offset_address : reg_n;
158         ir.CoprocStoreWords(coproc_no, two, d, CRd, address, has_option, imm8.ZeroExtend<u8>());
159         if (wback) {
160             ir.SetRegister(n, offset_address);
161         }
162     }
163     return true;
164 }
165 
166 } // namespace Dynarmic::A32
167