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