1 /* This file is part of the dynarmic project.
2  * Copyright (c) 2018 MerryMage
3  * SPDX-License-Identifier: 0BSD
4  */
5 
6 #include "frontend/A64/translate/impl/impl.h"
7 
8 namespace Dynarmic::A64 {
9 
ADD_imm(bool sf,Imm<2> shift,Imm<12> imm12,Reg Rn,Reg Rd)10 bool TranslatorVisitor::ADD_imm(bool sf, Imm<2> shift, Imm<12> imm12, Reg Rn, Reg Rd) {
11     u64 imm;
12     switch (shift.ZeroExtend()) {
13     case 0b00:
14         imm = imm12.ZeroExtend<u64>();
15         break;
16     case 0b01:
17         imm = imm12.ZeroExtend<u64>() << 12;
18         break;
19     default:
20         return ReservedValue();
21     }
22 
23     const size_t datasize = sf ? 64 : 32;
24     const auto operand1 = Rn == Reg::SP ? SP(datasize) : IR::U32U64(X(datasize, Rn));
25 
26     const auto result = ir.Add(operand1, I(datasize, imm));
27 
28     if (Rd == Reg::SP) {
29         SP(datasize, result);
30     } else {
31         X(datasize, Rd, result);
32     }
33 
34     return true;
35 }
36 
ADDS_imm(bool sf,Imm<2> shift,Imm<12> imm12,Reg Rn,Reg Rd)37 bool TranslatorVisitor::ADDS_imm(bool sf, Imm<2> shift, Imm<12> imm12, Reg Rn, Reg Rd) {
38     u64 imm;
39     switch (shift.ZeroExtend()) {
40     case 0b00:
41         imm = imm12.ZeroExtend<u64>();
42         break;
43     case 0b01:
44         imm = imm12.ZeroExtend<u64>() << 12;
45         break;
46     default:
47         return ReservedValue();
48     }
49 
50     const size_t datasize = sf ? 64 : 32;
51     const auto operand1 = Rn == Reg::SP ? SP(datasize) : IR::U32U64(X(datasize, Rn));
52 
53     const auto result = ir.Add(operand1, I(datasize, imm));
54 
55     ir.SetNZCV(ir.NZCVFrom(result));
56 
57     X(datasize, Rd, result);
58     return true;
59 }
60 
SUB_imm(bool sf,Imm<2> shift,Imm<12> imm12,Reg Rn,Reg Rd)61 bool TranslatorVisitor::SUB_imm(bool sf, Imm<2> shift, Imm<12> imm12, Reg Rn, Reg Rd) {
62     u64 imm;
63     switch (shift.ZeroExtend()) {
64     case 0b00:
65         imm = imm12.ZeroExtend<u64>();
66         break;
67     case 0b01:
68         imm = imm12.ZeroExtend<u64>() << 12;
69         break;
70     default:
71         return ReservedValue();
72     }
73 
74     const size_t datasize = sf ? 64 : 32;
75     const auto operand1 = Rn == Reg::SP ? SP(datasize) : IR::U32U64(X(datasize, Rn));
76 
77     const auto result = ir.Sub(operand1, I(datasize, imm));
78 
79     if (Rd == Reg::SP) {
80         SP(datasize, result);
81     } else {
82         X(datasize, Rd, result);
83     }
84 
85     return true;
86 }
87 
SUBS_imm(bool sf,Imm<2> shift,Imm<12> imm12,Reg Rn,Reg Rd)88 bool TranslatorVisitor::SUBS_imm(bool sf, Imm<2> shift, Imm<12> imm12, Reg Rn, Reg Rd) {
89     u64 imm;
90     switch (shift.ZeroExtend()) {
91     case 0b00:
92         imm = imm12.ZeroExtend<u64>();
93         break;
94     case 0b01:
95         imm = imm12.ZeroExtend<u64>() << 12;
96         break;
97     default:
98         return ReservedValue();
99     }
100 
101     const size_t datasize = sf ? 64 : 32;
102     const auto operand1 = Rn == Reg::SP ? SP(datasize) : IR::U32U64(X(datasize, Rn));
103 
104     const auto result = ir.Sub(operand1, I(datasize, imm));
105 
106     ir.SetNZCV(ir.NZCVFrom(result));
107 
108     X(datasize, Rd, result);
109     return true;
110 }
111 
ADD_shift(bool sf,Imm<2> shift,Reg Rm,Imm<6> imm6,Reg Rn,Reg Rd)112 bool TranslatorVisitor::ADD_shift(bool sf, Imm<2> shift, Reg Rm, Imm<6> imm6, Reg Rn, Reg Rd) {
113     if (shift == 0b11) {
114         return ReservedValue();
115     }
116 
117     if (!sf && imm6.Bit<5>()) {
118         return ReservedValue();
119     }
120 
121     const size_t datasize = sf ? 64 : 32;
122     const u8 shift_amount = imm6.ZeroExtend<u8>();
123 
124     const auto operand1 = X(datasize, Rn);
125     const auto operand2 = ShiftReg(datasize, Rm, shift, ir.Imm8(shift_amount));
126 
127     const auto result = ir.Add(operand1, operand2);
128 
129     X(datasize, Rd, result);
130     return true;
131 }
132 
ADDS_shift(bool sf,Imm<2> shift,Reg Rm,Imm<6> imm6,Reg Rn,Reg Rd)133 bool TranslatorVisitor::ADDS_shift(bool sf, Imm<2> shift, Reg Rm, Imm<6> imm6, Reg Rn, Reg Rd) {
134     if (shift == 0b11) {
135         return ReservedValue();
136     }
137 
138     if (!sf && imm6.Bit<5>()) {
139         return ReservedValue();
140     }
141 
142     const size_t datasize = sf ? 64 : 32;
143     const u8 shift_amount = imm6.ZeroExtend<u8>();
144 
145     const auto operand1 = X(datasize, Rn);
146     const auto operand2 = ShiftReg(datasize, Rm, shift, ir.Imm8(shift_amount));
147 
148     const auto result = ir.Add(operand1, operand2);
149 
150     ir.SetNZCV(ir.NZCVFrom(result));
151 
152     X(datasize, Rd, result);
153     return true;
154 }
155 
SUB_shift(bool sf,Imm<2> shift,Reg Rm,Imm<6> imm6,Reg Rn,Reg Rd)156 bool TranslatorVisitor::SUB_shift(bool sf, Imm<2> shift, Reg Rm, Imm<6> imm6, Reg Rn, Reg Rd) {
157     if (shift == 0b11) {
158         return ReservedValue();
159     }
160 
161     if (!sf && imm6.Bit<5>()) {
162         return ReservedValue();
163     }
164 
165     const size_t datasize = sf ? 64 : 32;
166     const u8 shift_amount = imm6.ZeroExtend<u8>();
167 
168     const auto operand1 = X(datasize, Rn);
169     const auto operand2 = ShiftReg(datasize, Rm, shift, ir.Imm8(shift_amount));
170 
171     const auto result = ir.Sub(operand1, operand2);
172 
173     X(datasize, Rd, result);
174     return true;
175 }
176 
SUBS_shift(bool sf,Imm<2> shift,Reg Rm,Imm<6> imm6,Reg Rn,Reg Rd)177 bool TranslatorVisitor::SUBS_shift(bool sf, Imm<2> shift, Reg Rm, Imm<6> imm6, Reg Rn, Reg Rd) {
178     if (shift == 0b11) {
179         return ReservedValue();
180     }
181 
182     if (!sf && imm6.Bit<5>()) {
183         return ReservedValue();
184     }
185 
186     const size_t datasize = sf ? 64 : 32;
187     const u8 shift_amount = imm6.ZeroExtend<u8>();
188 
189     const auto operand1 = X(datasize, Rn);
190     const auto operand2 = ShiftReg(datasize, Rm, shift, ir.Imm8(shift_amount));
191 
192     const auto result = ir.Sub(operand1, operand2);
193 
194     ir.SetNZCV(ir.NZCVFrom(result));
195 
196     X(datasize, Rd, result);
197     return true;
198 }
199 
ADD_ext(bool sf,Reg Rm,Imm<3> option,Imm<3> imm3,Reg Rn,Reg Rd)200 bool TranslatorVisitor::ADD_ext(bool sf, Reg Rm, Imm<3> option, Imm<3> imm3, Reg Rn, Reg Rd) {
201     const u8 shift = imm3.ZeroExtend<u8>();
202     if (shift > 4) {
203         return ReservedValue();
204     }
205 
206     const size_t datasize = sf ? 64 : 32;
207     const auto operand1 = Rn == Reg::SP ? SP(datasize) : IR::U32U64(X(datasize, Rn));
208     const auto operand2 = ExtendReg(datasize, Rm, option, shift);
209 
210     const auto result = ir.Add(operand1, operand2);
211 
212     if (Rd == Reg::SP) {
213         SP(datasize, result);
214     } else {
215         X(datasize, Rd, result);
216     }
217 
218     return true;
219 }
220 
ADDS_ext(bool sf,Reg Rm,Imm<3> option,Imm<3> imm3,Reg Rn,Reg Rd)221 bool TranslatorVisitor::ADDS_ext(bool sf, Reg Rm, Imm<3> option, Imm<3> imm3, Reg Rn, Reg Rd) {
222     const u8 shift = imm3.ZeroExtend<u8>();
223     if (shift > 4) {
224         return ReservedValue();
225     }
226 
227     const size_t datasize = sf ? 64 : 32;
228     const auto operand1 = Rn == Reg::SP ? SP(datasize) : IR::U32U64(X(datasize, Rn));
229     const auto operand2 = ExtendReg(datasize, Rm, option, shift);
230 
231     const auto result = ir.Add(operand1, operand2);
232 
233     ir.SetNZCV(ir.NZCVFrom(result));
234 
235     X(datasize, Rd, result);
236     return true;
237 }
238 
SUB_ext(bool sf,Reg Rm,Imm<3> option,Imm<3> imm3,Reg Rn,Reg Rd)239 bool TranslatorVisitor::SUB_ext(bool sf, Reg Rm, Imm<3> option, Imm<3> imm3, Reg Rn, Reg Rd) {
240     const u8 shift = imm3.ZeroExtend<u8>();
241     if (shift > 4) {
242         return ReservedValue();
243     }
244 
245     const size_t datasize = sf ? 64 : 32;
246     const auto operand1 = Rn == Reg::SP ? SP(datasize) : IR::U32U64(X(datasize, Rn));
247     const auto operand2 = ExtendReg(datasize, Rm, option, shift);
248 
249     const auto result = ir.Sub(operand1, operand2);
250 
251     if (Rd == Reg::SP) {
252         SP(datasize, result);
253     } else {
254         X(datasize, Rd, result);
255     }
256 
257     return true;
258 }
259 
SUBS_ext(bool sf,Reg Rm,Imm<3> option,Imm<3> imm3,Reg Rn,Reg Rd)260 bool TranslatorVisitor::SUBS_ext(bool sf, Reg Rm, Imm<3> option, Imm<3> imm3, Reg Rn, Reg Rd) {
261     const u8 shift = imm3.ZeroExtend<u8>();
262     if (shift > 4) {
263         return ReservedValue();
264     }
265 
266     const size_t datasize = sf ? 64 : 32;
267     const auto operand1 = Rn == Reg::SP ? SP(datasize) : IR::U32U64(X(datasize, Rn));
268     const auto operand2 = ExtendReg(datasize, Rm, option, shift);
269 
270     const auto result = ir.Sub(operand1, operand2);
271 
272     ir.SetNZCV(ir.NZCVFrom(result));
273 
274     X(datasize, Rd, result);
275     return true;
276 }
277 
ADC(bool sf,Reg Rm,Reg Rn,Reg Rd)278 bool TranslatorVisitor::ADC(bool sf, Reg Rm, Reg Rn, Reg Rd) {
279     const size_t datasize = sf ? 64 : 32;
280 
281     const IR::U32U64 operand1 = X(datasize, Rn);
282     const IR::U32U64 operand2 = X(datasize, Rm);
283 
284     const auto result = ir.AddWithCarry(operand1, operand2, ir.GetCFlag());
285 
286     X(datasize, Rd, result);
287     return true;
288 }
289 
ADCS(bool sf,Reg Rm,Reg Rn,Reg Rd)290 bool TranslatorVisitor::ADCS(bool sf, Reg Rm, Reg Rn, Reg Rd) {
291     const size_t datasize = sf ? 64 : 32;
292 
293     const IR::U32U64 operand1 = X(datasize, Rn);
294     const IR::U32U64 operand2 = X(datasize, Rm);
295 
296     const auto result = ir.AddWithCarry(operand1, operand2, ir.GetCFlag());
297 
298     ir.SetNZCV(ir.NZCVFrom(result));
299 
300     X(datasize, Rd, result);
301     return true;
302 }
303 
SBC(bool sf,Reg Rm,Reg Rn,Reg Rd)304 bool TranslatorVisitor::SBC(bool sf, Reg Rm, Reg Rn, Reg Rd) {
305     const size_t datasize = sf ? 64 : 32;
306 
307     const IR::U32U64 operand1 = X(datasize, Rn);
308     const IR::U32U64 operand2 = X(datasize, Rm);
309 
310     const auto result = ir.SubWithCarry(operand1, operand2, ir.GetCFlag());
311 
312     X(datasize, Rd, result);
313     return true;
314 }
315 
SBCS(bool sf,Reg Rm,Reg Rn,Reg Rd)316 bool TranslatorVisitor::SBCS(bool sf, Reg Rm, Reg Rn, Reg Rd) {
317     const size_t datasize = sf ? 64 : 32;
318 
319     const IR::U32U64 operand1 = X(datasize, Rn);
320     const IR::U32U64 operand2 = X(datasize, Rm);
321 
322     const auto result = ir.SubWithCarry(operand1, operand2, ir.GetCFlag());
323 
324     ir.SetNZCV(ir.NZCVFrom(result));
325 
326     X(datasize, Rd, result);
327     return true;
328 }
329 
330 } // namespace Dynarmic::A64
331