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 // SADD8<c> <Rd>, <Rn>, <Rm>
arm_SADD8(Cond cond,Reg n,Reg d,Reg m)11 bool ArmTranslatorVisitor::arm_SADD8(Cond cond, Reg n, Reg d, Reg m) {
12     if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
13         return UnpredictableInstruction();
14     }
15 
16     if (!ConditionPassed(cond)) {
17         return true;
18     }
19 
20     const auto result = ir.PackedAddS8(ir.GetRegister(n), ir.GetRegister(m));
21     ir.SetRegister(d, result.result);
22     ir.SetGEFlags(result.ge);
23     return true;
24 }
25 
26 // SADD16<c> <Rd>, <Rn>, <Rm>
arm_SADD16(Cond cond,Reg n,Reg d,Reg m)27 bool ArmTranslatorVisitor::arm_SADD16(Cond cond, Reg n, Reg d, Reg m) {
28     if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
29         return UnpredictableInstruction();
30     }
31 
32     if (!ConditionPassed(cond)) {
33         return true;
34     }
35 
36     const auto result = ir.PackedAddS16(ir.GetRegister(n), ir.GetRegister(m));
37     ir.SetRegister(d, result.result);
38     ir.SetGEFlags(result.ge);
39     return true;
40 }
41 
42 // SASX<c> <Rd>, <Rn>, <Rm>
arm_SASX(Cond cond,Reg n,Reg d,Reg m)43 bool ArmTranslatorVisitor::arm_SASX(Cond cond, Reg n, Reg d, Reg m) {
44     if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
45         return UnpredictableInstruction();
46     }
47 
48     if (!ConditionPassed(cond)) {
49         return true;
50     }
51 
52     const auto result = ir.PackedAddSubS16(ir.GetRegister(n), ir.GetRegister(m));
53     ir.SetRegister(d, result.result);
54     ir.SetGEFlags(result.ge);
55     return true;
56 }
57 
58 // SSAX<c> <Rd>, <Rn>, <Rm>
arm_SSAX(Cond cond,Reg n,Reg d,Reg m)59 bool ArmTranslatorVisitor::arm_SSAX(Cond cond, Reg n, Reg d, Reg m) {
60     if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
61         return UnpredictableInstruction();
62     }
63 
64     if (!ConditionPassed(cond)) {
65         return true;
66     }
67 
68     const auto result = ir.PackedSubAddS16(ir.GetRegister(n), ir.GetRegister(m));
69     ir.SetRegister(d, result.result);
70     ir.SetGEFlags(result.ge);
71     return true;
72 }
73 
74 // SSUB8<c> <Rd>, <Rn>, <Rm>
arm_SSUB8(Cond cond,Reg n,Reg d,Reg m)75 bool ArmTranslatorVisitor::arm_SSUB8(Cond cond, Reg n, Reg d, Reg m) {
76     if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
77         return UnpredictableInstruction();
78     }
79 
80     if (!ConditionPassed(cond)) {
81         return true;
82     }
83 
84     const auto result = ir.PackedSubS8(ir.GetRegister(n), ir.GetRegister(m));
85     ir.SetRegister(d, result.result);
86     ir.SetGEFlags(result.ge);
87     return true;
88 }
89 
90 // SSUB16<c> <Rd>, <Rn>, <Rm>
arm_SSUB16(Cond cond,Reg n,Reg d,Reg m)91 bool ArmTranslatorVisitor::arm_SSUB16(Cond cond, Reg n, Reg d, Reg m) {
92     if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
93         return UnpredictableInstruction();
94     }
95 
96     if (!ConditionPassed(cond)) {
97         return true;
98     }
99 
100     const auto result = ir.PackedSubS16(ir.GetRegister(n), ir.GetRegister(m));
101     ir.SetRegister(d, result.result);
102     ir.SetGEFlags(result.ge);
103     return true;
104 }
105 
106 // UADD8<c> <Rd>, <Rn>, <Rm>
arm_UADD8(Cond cond,Reg n,Reg d,Reg m)107 bool ArmTranslatorVisitor::arm_UADD8(Cond cond, Reg n, Reg d, Reg m) {
108     if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
109         return UnpredictableInstruction();
110     }
111 
112     if (!ConditionPassed(cond)) {
113         return true;
114     }
115 
116     const auto result = ir.PackedAddU8(ir.GetRegister(n), ir.GetRegister(m));
117     ir.SetRegister(d, result.result);
118     ir.SetGEFlags(result.ge);
119     return true;
120 }
121 
122 // UADD16<c> <Rd>, <Rn>, <Rm>
arm_UADD16(Cond cond,Reg n,Reg d,Reg m)123 bool ArmTranslatorVisitor::arm_UADD16(Cond cond, Reg n, Reg d, Reg m) {
124     if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
125        return UnpredictableInstruction();
126     }
127 
128     if (!ConditionPassed(cond)) {
129         return true;
130     }
131 
132     const auto result = ir.PackedAddU16(ir.GetRegister(n), ir.GetRegister(m));
133     ir.SetRegister(d, result.result);
134     ir.SetGEFlags(result.ge);
135     return true;
136 }
137 
138 // UASX<c> <Rd>, <Rn>, <Rm>
arm_UASX(Cond cond,Reg n,Reg d,Reg m)139 bool ArmTranslatorVisitor::arm_UASX(Cond cond, Reg n, Reg d, Reg m) {
140     if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
141         return UnpredictableInstruction();
142     }
143 
144     if (!ConditionPassed(cond)) {
145         return true;
146     }
147 
148     const auto result = ir.PackedAddSubU16(ir.GetRegister(n), ir.GetRegister(m));
149     ir.SetRegister(d, result.result);
150     ir.SetGEFlags(result.ge);
151     return true;
152 }
153 
154 // USAX<c> <Rd>, <Rn>, <Rm>
arm_USAX(Cond cond,Reg n,Reg d,Reg m)155 bool ArmTranslatorVisitor::arm_USAX(Cond cond, Reg n, Reg d, Reg m) {
156     if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
157         return UnpredictableInstruction();
158     }
159 
160     if (!ConditionPassed(cond)) {
161         return true;
162     }
163 
164     const auto result = ir.PackedSubAddU16(ir.GetRegister(n), ir.GetRegister(m));
165     ir.SetRegister(d, result.result);
166     ir.SetGEFlags(result.ge);
167     return true;
168 }
169 
170 // USAD8<c> <Rd>, <Rn>, <Rm>
arm_USAD8(Cond cond,Reg d,Reg m,Reg n)171 bool ArmTranslatorVisitor::arm_USAD8(Cond cond, Reg d, Reg m, Reg n) {
172     if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
173         return UnpredictableInstruction();
174     }
175 
176     if (!ConditionPassed(cond)) {
177         return true;
178     }
179 
180     const auto result = ir.PackedAbsDiffSumS8(ir.GetRegister(n), ir.GetRegister(m));
181     ir.SetRegister(d, result);
182     return true;
183 }
184 
185 // USADA8<c> <Rd>, <Rn>, <Rm>, <Ra>
arm_USADA8(Cond cond,Reg d,Reg a,Reg m,Reg n)186 bool ArmTranslatorVisitor::arm_USADA8(Cond cond, Reg d, Reg a, Reg m, Reg n){
187     if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
188         return UnpredictableInstruction();
189     }
190 
191     if (!ConditionPassed(cond)) {
192         return true;
193     }
194 
195     const auto tmp = ir.PackedAbsDiffSumS8(ir.GetRegister(n), ir.GetRegister(m));
196     const auto result = ir.AddWithCarry(ir.GetRegister(a), tmp, ir.Imm1(0));
197     ir.SetRegister(d, result.result);
198     return true;
199 }
200 
201 // USUB8<c> <Rd>, <Rn>, <Rm>
arm_USUB8(Cond cond,Reg n,Reg d,Reg m)202 bool ArmTranslatorVisitor::arm_USUB8(Cond cond, Reg n, Reg d, Reg m) {
203     if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
204         return UnpredictableInstruction();
205     }
206 
207     if (!ConditionPassed(cond)) {
208         return true;
209     }
210 
211     const auto result = ir.PackedSubU8(ir.GetRegister(n), ir.GetRegister(m));
212     ir.SetRegister(d, result.result);
213     ir.SetGEFlags(result.ge);
214     return true;
215 }
216 
217 // USUB16<c> <Rd>, <Rn>, <Rm>
arm_USUB16(Cond cond,Reg n,Reg d,Reg m)218 bool ArmTranslatorVisitor::arm_USUB16(Cond cond, Reg n, Reg d, Reg m) {
219     if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
220         return UnpredictableInstruction();
221     }
222 
223     if (!ConditionPassed(cond)) {
224         return true;
225     }
226 
227     const auto result = ir.PackedSubU16(ir.GetRegister(n), ir.GetRegister(m));
228     ir.SetRegister(d, result.result);
229     ir.SetGEFlags(result.ge);
230     return true;
231 }
232 
233 // Parallel Add/Subtract (Saturating) instructions
234 
235 // QADD8<c> <Rd>, <Rn>, <Rm>
arm_QADD8(Cond cond,Reg n,Reg d,Reg m)236 bool ArmTranslatorVisitor::arm_QADD8(Cond cond, Reg n, Reg d, Reg m) {
237     if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
238         return UnpredictableInstruction();
239     }
240 
241     if (!ConditionPassed(cond)) {
242         return true;
243     }
244 
245     const auto result = ir.PackedSaturatedAddS8(ir.GetRegister(n), ir.GetRegister(m));
246     ir.SetRegister(d, result);
247     return true;
248 }
249 
250 // QADD16<c> <Rd>, <Rn>, <Rm>
arm_QADD16(Cond cond,Reg n,Reg d,Reg m)251 bool ArmTranslatorVisitor::arm_QADD16(Cond cond, Reg n, Reg d, Reg m) {
252     if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
253         return UnpredictableInstruction();
254     }
255 
256     if (!ConditionPassed(cond)) {
257         return true;
258     }
259 
260     const auto result = ir.PackedSaturatedAddS16(ir.GetRegister(n), ir.GetRegister(m));
261     ir.SetRegister(d, result);
262     return true;
263 }
264 
265 // QSUB8<c> <Rd>, <Rn>, <Rm>
arm_QSUB8(Cond cond,Reg n,Reg d,Reg m)266 bool ArmTranslatorVisitor::arm_QSUB8(Cond cond, Reg n, Reg d, Reg m) {
267     if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
268         return UnpredictableInstruction();
269     }
270 
271     if (!ConditionPassed(cond)) {
272         return true;
273     }
274 
275     const auto result = ir.PackedSaturatedSubS8(ir.GetRegister(n), ir.GetRegister(m));
276     ir.SetRegister(d, result);
277     return true;
278 }
279 
280 // QSUB16<c> <Rd>, <Rn>, <Rm>
arm_QSUB16(Cond cond,Reg n,Reg d,Reg m)281 bool ArmTranslatorVisitor::arm_QSUB16(Cond cond, Reg n, Reg d, Reg m) {
282     if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
283         return UnpredictableInstruction();
284     }
285 
286     if (!ConditionPassed(cond)) {
287         return true;
288     }
289 
290     const auto result = ir.PackedSaturatedSubS16(ir.GetRegister(n), ir.GetRegister(m));
291     ir.SetRegister(d, result);
292     return true;
293 }
294 
295 // UQADD8<c> <Rd>, <Rn>, <Rm>
arm_UQADD8(Cond cond,Reg n,Reg d,Reg m)296 bool ArmTranslatorVisitor::arm_UQADD8(Cond cond, Reg n, Reg d, Reg m) {
297     if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
298         return UnpredictableInstruction();
299     }
300 
301     if (!ConditionPassed(cond)) {
302         return true;
303     }
304 
305     const auto result = ir.PackedSaturatedAddU8(ir.GetRegister(n), ir.GetRegister(m));
306     ir.SetRegister(d, result);
307     return true;
308 }
309 
310 // UQADD16<c> <Rd>, <Rn>, <Rm>
arm_UQADD16(Cond cond,Reg n,Reg d,Reg m)311 bool ArmTranslatorVisitor::arm_UQADD16(Cond cond, Reg n, Reg d, Reg m) {
312     if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
313         return UnpredictableInstruction();
314     }
315 
316     if (!ConditionPassed(cond)) {
317         return true;
318     }
319 
320     const auto result = ir.PackedSaturatedAddU16(ir.GetRegister(n), ir.GetRegister(m));
321     ir.SetRegister(d, result);
322     return true;
323 }
324 
325 // UQSUB8<c> <Rd>, <Rn>, <Rm>
arm_UQSUB8(Cond cond,Reg n,Reg d,Reg m)326 bool ArmTranslatorVisitor::arm_UQSUB8(Cond cond, Reg n, Reg d, Reg m) {
327     if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
328         return UnpredictableInstruction();
329     }
330 
331     if (!ConditionPassed(cond)) {
332         return true;
333     }
334 
335     const auto result = ir.PackedSaturatedSubU8(ir.GetRegister(n), ir.GetRegister(m));
336     ir.SetRegister(d, result);
337     return true;
338 }
339 
340 // UQSUB16<c> <Rd>, <Rn>, <Rm>
arm_UQSUB16(Cond cond,Reg n,Reg d,Reg m)341 bool ArmTranslatorVisitor::arm_UQSUB16(Cond cond, Reg n, Reg d, Reg m) {
342     if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
343         return UnpredictableInstruction();
344     }
345 
346     if (!ConditionPassed(cond)) {
347         return true;
348     }
349 
350     const auto result = ir.PackedSaturatedSubU16(ir.GetRegister(n), ir.GetRegister(m));
351     ir.SetRegister(d, result);
352     return true;
353 }
354 
355 // Parallel Add/Subtract (Halving) instructions
356 
357 // SHADD8<c> <Rd>, <Rn>, <Rm>
arm_SHADD8(Cond cond,Reg n,Reg d,Reg m)358 bool ArmTranslatorVisitor::arm_SHADD8(Cond cond, Reg n, Reg d, Reg m) {
359     if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
360         return UnpredictableInstruction();
361     }
362 
363     if (!ConditionPassed(cond)) {
364         return true;
365     }
366 
367     const auto result = ir.PackedHalvingAddS8(ir.GetRegister(n), ir.GetRegister(m));
368     ir.SetRegister(d, result);
369     return true;
370 }
371 
372 // SHADD16<c> <Rd>, <Rn>, <Rm>
arm_SHADD16(Cond cond,Reg n,Reg d,Reg m)373 bool ArmTranslatorVisitor::arm_SHADD16(Cond cond, Reg n, Reg d, Reg m) {
374     if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
375         return UnpredictableInstruction();
376     }
377 
378     if (!ConditionPassed(cond)) {
379         return true;
380     }
381 
382     const auto result = ir.PackedHalvingAddS16(ir.GetRegister(n), ir.GetRegister(m));
383     ir.SetRegister(d, result);
384     return true;
385 }
386 
387 // SHASX<c> <Rd>, <Rn>, <Rm>
arm_SHASX(Cond cond,Reg n,Reg d,Reg m)388 bool ArmTranslatorVisitor::arm_SHASX(Cond cond, Reg n, Reg d, Reg m) {
389     if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
390         return UnpredictableInstruction();
391     }
392 
393     if (!ConditionPassed(cond)) {
394         return true;
395     }
396 
397     const auto result = ir.PackedHalvingAddSubS16(ir.GetRegister(n), ir.GetRegister(m));
398     ir.SetRegister(d, result);
399     return true;
400 }
401 
402 // SHSAX<c> <Rd>, <Rn>, <Rm>
arm_SHSAX(Cond cond,Reg n,Reg d,Reg m)403 bool ArmTranslatorVisitor::arm_SHSAX(Cond cond, Reg n, Reg d, Reg m) {
404     if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
405         return UnpredictableInstruction();
406     }
407 
408     if (!ConditionPassed(cond)) {
409         return true;
410     }
411 
412     const auto result = ir.PackedHalvingSubAddS16(ir.GetRegister(n), ir.GetRegister(m));
413     ir.SetRegister(d, result);
414     return true;
415 }
416 
417 // SHSUB8<c> <Rd>, <Rn>, <Rm>
arm_SHSUB8(Cond cond,Reg n,Reg d,Reg m)418 bool ArmTranslatorVisitor::arm_SHSUB8(Cond cond, Reg n, Reg d, Reg m) {
419     if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
420         return UnpredictableInstruction();
421     }
422 
423     if (!ConditionPassed(cond)) {
424         return true;
425     }
426 
427     const auto result = ir.PackedHalvingSubS8(ir.GetRegister(n), ir.GetRegister(m));
428     ir.SetRegister(d, result);
429     return true;
430 }
431 
432 // SHSUB16<c> <Rd>, <Rn>, <Rm>
arm_SHSUB16(Cond cond,Reg n,Reg d,Reg m)433 bool ArmTranslatorVisitor::arm_SHSUB16(Cond cond, Reg n, Reg d, Reg m) {
434     if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
435         return UnpredictableInstruction();
436     }
437 
438     if (!ConditionPassed(cond)) {
439         return true;
440     }
441 
442     const auto result = ir.PackedHalvingSubS16(ir.GetRegister(n), ir.GetRegister(m));
443     ir.SetRegister(d, result);
444     return true;
445 }
446 
447 // UHADD8<c> <Rd>, <Rn>, <Rm>
arm_UHADD8(Cond cond,Reg n,Reg d,Reg m)448 bool ArmTranslatorVisitor::arm_UHADD8(Cond cond, Reg n, Reg d, Reg m) {
449     if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
450         return UnpredictableInstruction();
451     }
452 
453     if (!ConditionPassed(cond)) {
454         return true;
455     }
456 
457     const auto result = ir.PackedHalvingAddU8(ir.GetRegister(n), ir.GetRegister(m));
458     ir.SetRegister(d, result);
459     return true;
460 }
461 
462 // UHADD16<c> <Rd>, <Rn>, <Rm>
arm_UHADD16(Cond cond,Reg n,Reg d,Reg m)463 bool ArmTranslatorVisitor::arm_UHADD16(Cond cond, Reg n, Reg d, Reg m) {
464     if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
465         return UnpredictableInstruction();
466     }
467 
468     if (!ConditionPassed(cond)) {
469         return true;
470     }
471 
472     const auto result = ir.PackedHalvingAddU16(ir.GetRegister(n), ir.GetRegister(m));
473     ir.SetRegister(d, result);
474     return true;
475 }
476 
477 // UHASX<c> <Rd>, <Rn>, <Rm>
arm_UHASX(Cond cond,Reg n,Reg d,Reg m)478 bool ArmTranslatorVisitor::arm_UHASX(Cond cond, Reg n, Reg d, Reg m) {
479     if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
480         return UnpredictableInstruction();
481     }
482 
483     if (!ConditionPassed(cond)) {
484         return true;
485     }
486 
487     const auto result = ir.PackedHalvingAddSubU16(ir.GetRegister(n), ir.GetRegister(m));
488     ir.SetRegister(d, result);
489     return true;
490 }
491 
492 // UHSAX<c> <Rd>, <Rn>, <Rm>
arm_UHSAX(Cond cond,Reg n,Reg d,Reg m)493 bool ArmTranslatorVisitor::arm_UHSAX(Cond cond, Reg n, Reg d, Reg m) {
494     if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
495         return UnpredictableInstruction();
496     }
497 
498     if (!ConditionPassed(cond)) {
499         return true;
500     }
501 
502     const auto result = ir.PackedHalvingSubAddU16(ir.GetRegister(n), ir.GetRegister(m));
503     ir.SetRegister(d, result);
504     return true;
505 }
506 
507 // UHSUB8<c> <Rd>, <Rn>, <Rm>
arm_UHSUB8(Cond cond,Reg n,Reg d,Reg m)508 bool ArmTranslatorVisitor::arm_UHSUB8(Cond cond, Reg n, Reg d, Reg m) {
509     if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
510         return UnpredictableInstruction();
511     }
512 
513     if (!ConditionPassed(cond)) {
514         return true;
515     }
516 
517     const auto result = ir.PackedHalvingSubU8(ir.GetRegister(n), ir.GetRegister(m));
518     ir.SetRegister(d, result);
519     return true;
520 }
521 
522 // UHSUB16<c> <Rd>, <Rn>, <Rm>
arm_UHSUB16(Cond cond,Reg n,Reg d,Reg m)523 bool ArmTranslatorVisitor::arm_UHSUB16(Cond cond, Reg n, Reg d, Reg m) {
524     if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
525         return UnpredictableInstruction();
526     }
527 
528     if (!ConditionPassed(cond)) {
529         return true;
530     }
531 
532     const auto result = ir.PackedHalvingSubU16(ir.GetRegister(n), ir.GetRegister(m));
533     ir.SetRegister(d, result);
534     return true;
535 }
536 
537 } // namespace Dynarmic::A32
538