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 // MLA{S}<c> <Rd>, <Rn>, <Rm>, <Ra>
arm_MLA(Cond cond,bool S,Reg d,Reg a,Reg m,Reg n)11 bool ArmTranslatorVisitor::arm_MLA(Cond cond, bool S, Reg d, Reg a, Reg m, Reg n) {
12 if (d == Reg::PC || n == Reg::PC || m == Reg::PC || a == Reg::PC) {
13 return UnpredictableInstruction();
14 }
15
16 if (!ConditionPassed(cond)) {
17 return true;
18 }
19
20 const auto result = ir.Add(ir.Mul(ir.GetRegister(n), ir.GetRegister(m)), ir.GetRegister(a));
21 ir.SetRegister(d, result);
22 if (S) {
23 ir.SetNFlag(ir.MostSignificantBit(result));
24 ir.SetZFlag(ir.IsZero(result));
25 }
26
27 return true;
28 }
29
30 // MLS<c> <Rd>, <Rn>, <Rm>, <Ra>
arm_MLS(Cond cond,Reg d,Reg a,Reg m,Reg n)31 bool ArmTranslatorVisitor::arm_MLS(Cond cond, Reg d, Reg a, Reg m, Reg n) {
32 if (d == Reg::PC || a == Reg::PC || m == Reg::PC || n == Reg::PC) {
33 return UnpredictableInstruction();
34 }
35
36 if (!ConditionPassed(cond)) {
37 return true;
38 }
39
40 const IR::U32 operand1 = ir.GetRegister(n);
41 const IR::U32 operand2 = ir.GetRegister(m);
42 const IR::U32 operand3 = ir.GetRegister(a);
43 const IR::U32 result = ir.Sub(operand3, ir.Mul(operand1, operand2));
44
45 ir.SetRegister(d, result);
46 return true;
47 }
48
49 // MUL{S}<c> <Rd>, <Rn>, <Rm>
arm_MUL(Cond cond,bool S,Reg d,Reg m,Reg n)50 bool ArmTranslatorVisitor::arm_MUL(Cond cond, bool S, Reg d, Reg m, Reg n) {
51 if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
52 return UnpredictableInstruction();
53 }
54
55 if (!ConditionPassed(cond)) {
56 return true;
57 }
58
59 const auto result = ir.Mul(ir.GetRegister(n), ir.GetRegister(m));
60 ir.SetRegister(d, result);
61 if (S) {
62 ir.SetNFlag(ir.MostSignificantBit(result));
63 ir.SetZFlag(ir.IsZero(result));
64 }
65
66 return true;
67 }
68
69
70 // SMLAL{S}<c> <RdLo>, <RdHi>, <Rn>, <Rm>
arm_SMLAL(Cond cond,bool S,Reg dHi,Reg dLo,Reg m,Reg n)71 bool ArmTranslatorVisitor::arm_SMLAL(Cond cond, bool S, Reg dHi, Reg dLo, Reg m, Reg n) {
72 if (dLo == Reg::PC || dHi == Reg::PC || n == Reg::PC || m == Reg::PC) {
73 return UnpredictableInstruction();
74 }
75
76 if (dLo == dHi) {
77 return UnpredictableInstruction();
78 }
79
80 if (!ConditionPassed(cond)) {
81 return true;
82 }
83
84 const auto n64 = ir.SignExtendWordToLong(ir.GetRegister(n));
85 const auto m64 = ir.SignExtendWordToLong(ir.GetRegister(m));
86 const auto product = ir.Mul(n64, m64);
87 const auto addend = ir.Pack2x32To1x64(ir.GetRegister(dLo), ir.GetRegister(dHi));
88 const auto result = ir.Add(product, addend);
89 const auto lo = ir.LeastSignificantWord(result);
90 const auto hi = ir.MostSignificantWord(result).result;
91
92 ir.SetRegister(dLo, lo);
93 ir.SetRegister(dHi, hi);
94 if (S) {
95 ir.SetNFlag(ir.MostSignificantBit(hi));
96 ir.SetZFlag(ir.IsZero(result));
97 }
98
99 return true;
100 }
101
102 // SMULL{S}<c> <RdLo>, <RdHi>, <Rn>, <Rm>
arm_SMULL(Cond cond,bool S,Reg dHi,Reg dLo,Reg m,Reg n)103 bool ArmTranslatorVisitor::arm_SMULL(Cond cond, bool S, Reg dHi, Reg dLo, Reg m, Reg n) {
104 if (dLo == Reg::PC || dHi == Reg::PC || n == Reg::PC || m == Reg::PC) {
105 return UnpredictableInstruction();
106 }
107
108 if (dLo == dHi) {
109 return UnpredictableInstruction();
110 }
111
112 if (!ConditionPassed(cond)) {
113 return true;
114 }
115
116 const auto n64 = ir.SignExtendWordToLong(ir.GetRegister(n));
117 const auto m64 = ir.SignExtendWordToLong(ir.GetRegister(m));
118 const auto result = ir.Mul(n64, m64);
119 const auto lo = ir.LeastSignificantWord(result);
120 const auto hi = ir.MostSignificantWord(result).result;
121
122 ir.SetRegister(dLo, lo);
123 ir.SetRegister(dHi, hi);
124 if (S) {
125 ir.SetNFlag(ir.MostSignificantBit(hi));
126 ir.SetZFlag(ir.IsZero(result));
127 }
128
129 return true;
130 }
131
132 // UMAAL<c> <RdLo>, <RdHi>, <Rn>, <Rm>
arm_UMAAL(Cond cond,Reg dHi,Reg dLo,Reg m,Reg n)133 bool ArmTranslatorVisitor::arm_UMAAL(Cond cond, Reg dHi, Reg dLo, Reg m, Reg n) {
134 if (dLo == Reg::PC || dHi == Reg::PC || n == Reg::PC || m == Reg::PC) {
135 return UnpredictableInstruction();
136 }
137
138 if (dLo == dHi) {
139 return UnpredictableInstruction();
140 }
141
142 if (!ConditionPassed(cond)) {
143 return true;
144 }
145
146 const auto lo64 = ir.ZeroExtendWordToLong(ir.GetRegister(dLo));
147 const auto hi64 = ir.ZeroExtendWordToLong(ir.GetRegister(dHi));
148 const auto n64 = ir.ZeroExtendWordToLong(ir.GetRegister(n));
149 const auto m64 = ir.ZeroExtendWordToLong(ir.GetRegister(m));
150 const auto result = ir.Add(ir.Add(ir.Mul(n64, m64), hi64), lo64);
151
152 ir.SetRegister(dLo, ir.LeastSignificantWord(result));
153 ir.SetRegister(dHi, ir.MostSignificantWord(result).result);
154 return true;
155 }
156
157 // UMLAL{S}<c> <RdLo>, <RdHi>, <Rn>, <Rm>
arm_UMLAL(Cond cond,bool S,Reg dHi,Reg dLo,Reg m,Reg n)158 bool ArmTranslatorVisitor::arm_UMLAL(Cond cond, bool S, Reg dHi, Reg dLo, Reg m, Reg n) {
159 if (dLo == Reg::PC || dHi == Reg::PC || n == Reg::PC || m == Reg::PC) {
160 return UnpredictableInstruction();
161 }
162
163 if (dLo == dHi) {
164 return UnpredictableInstruction();
165 }
166
167 if (!ConditionPassed(cond)) {
168 return true;
169 }
170
171 const auto addend = ir.Pack2x32To1x64(ir.GetRegister(dLo), ir.GetRegister(dHi));
172 const auto n64 = ir.ZeroExtendWordToLong(ir.GetRegister(n));
173 const auto m64 = ir.ZeroExtendWordToLong(ir.GetRegister(m));
174 const auto result = ir.Add(ir.Mul(n64, m64), addend);
175 const auto lo = ir.LeastSignificantWord(result);
176 const auto hi = ir.MostSignificantWord(result).result;
177
178 ir.SetRegister(dLo, lo);
179 ir.SetRegister(dHi, hi);
180 if (S) {
181 ir.SetNFlag(ir.MostSignificantBit(hi));
182 ir.SetZFlag(ir.IsZero(result));
183 }
184
185 return true;
186 }
187
188 // UMULL{S}<c> <RdLo>, <RdHi>, <Rn>, <Rm>
arm_UMULL(Cond cond,bool S,Reg dHi,Reg dLo,Reg m,Reg n)189 bool ArmTranslatorVisitor::arm_UMULL(Cond cond, bool S, Reg dHi, Reg dLo, Reg m, Reg n) {
190 if (dLo == Reg::PC || dHi == Reg::PC || n == Reg::PC || m == Reg::PC) {
191 return UnpredictableInstruction();
192 }
193
194 if (dLo == dHi) {
195 return UnpredictableInstruction();
196 }
197
198 if (!ConditionPassed(cond)) {
199 return true;
200 }
201
202 const auto n64 = ir.ZeroExtendWordToLong(ir.GetRegister(n));
203 const auto m64 = ir.ZeroExtendWordToLong(ir.GetRegister(m));
204 const auto result = ir.Mul(n64, m64);
205 const auto lo = ir.LeastSignificantWord(result);
206 const auto hi = ir.MostSignificantWord(result).result;
207
208 ir.SetRegister(dLo, lo);
209 ir.SetRegister(dHi, hi);
210 if (S) {
211 ir.SetNFlag(ir.MostSignificantBit(hi));
212 ir.SetZFlag(ir.IsZero(result));
213 }
214
215 return true;
216 }
217
218 // SMLAL<x><y><c> <RdLo>, <RdHi>, <Rn>, <Rm>
arm_SMLALxy(Cond cond,Reg dHi,Reg dLo,Reg m,bool M,bool N,Reg n)219 bool ArmTranslatorVisitor::arm_SMLALxy(Cond cond, Reg dHi, Reg dLo, Reg m, bool M, bool N, Reg n) {
220 if (dLo == Reg::PC || dHi == Reg::PC || n == Reg::PC || m == Reg::PC) {
221 return UnpredictableInstruction();
222 }
223
224 if (dLo == dHi) {
225 return UnpredictableInstruction();
226 }
227
228 if (!ConditionPassed(cond)) {
229 return true;
230 }
231
232 const IR::U32 n32 = ir.GetRegister(n);
233 const IR::U32 m32 = ir.GetRegister(m);
234 const IR::U32 n16 = N ? ir.ArithmeticShiftRight(n32, ir.Imm8(16), ir.Imm1(0)).result
235 : ir.SignExtendHalfToWord(ir.LeastSignificantHalf(n32));
236 const IR::U32 m16 = M ? ir.ArithmeticShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result
237 : ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32));
238 const IR::U64 product = ir.SignExtendWordToLong(ir.Mul(n16, m16));
239 const auto addend = ir.Pack2x32To1x64(ir.GetRegister(dLo), ir.GetRegister(dHi));
240 const auto result = ir.Add(product, addend);
241
242 ir.SetRegister(dLo, ir.LeastSignificantWord(result));
243 ir.SetRegister(dHi, ir.MostSignificantWord(result).result);
244 return true;
245 }
246
247 // SMLA<x><y><c> <Rd>, <Rn>, <Rm>, <Ra>
arm_SMLAxy(Cond cond,Reg d,Reg a,Reg m,bool M,bool N,Reg n)248 bool ArmTranslatorVisitor::arm_SMLAxy(Cond cond, Reg d, Reg a, Reg m, bool M, bool N, Reg n) {
249 if (d == Reg::PC || n == Reg::PC || m == Reg::PC || a == Reg::PC) {
250 return UnpredictableInstruction();
251 }
252
253 if (!ConditionPassed(cond)) {
254 return true;
255 }
256
257 const IR::U32 n32 = ir.GetRegister(n);
258 const IR::U32 m32 = ir.GetRegister(m);
259 const IR::U32 n16 = N ? ir.ArithmeticShiftRight(n32, ir.Imm8(16), ir.Imm1(0)).result
260 : ir.SignExtendHalfToWord(ir.LeastSignificantHalf(n32));
261 const IR::U32 m16 = M ? ir.ArithmeticShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result
262 : ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32));
263 const IR::U32 product = ir.Mul(n16, m16);
264 const auto result_overflow = ir.AddWithCarry(product, ir.GetRegister(a), ir.Imm1(0));
265
266 ir.SetRegister(d, result_overflow.result);
267 ir.OrQFlag(result_overflow.overflow);
268 return true;
269 }
270
271 // SMUL<x><y><c> <Rd>, <Rn>, <Rm>
arm_SMULxy(Cond cond,Reg d,Reg m,bool M,bool N,Reg n)272 bool ArmTranslatorVisitor::arm_SMULxy(Cond cond, Reg d, Reg m, bool M, bool N, Reg n) {
273 if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
274 return UnpredictableInstruction();
275 }
276
277 if (!ConditionPassed(cond)) {
278 return true;
279 }
280
281 const IR::U32 n32 = ir.GetRegister(n);
282 const IR::U32 m32 = ir.GetRegister(m);
283 const IR::U32 n16 = N ? ir.ArithmeticShiftRight(n32, ir.Imm8(16), ir.Imm1(0)).result
284 : ir.SignExtendHalfToWord(ir.LeastSignificantHalf(n32));
285 const IR::U32 m16 = M ? ir.ArithmeticShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result
286 : ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32));
287 const IR::U32 result = ir.Mul(n16, m16);
288
289 ir.SetRegister(d, result);
290 return true;
291 }
292
293 // SMLAW<y><c> <Rd>, <Rn>, <Rm>, <Ra>
arm_SMLAWy(Cond cond,Reg d,Reg a,Reg m,bool M,Reg n)294 bool ArmTranslatorVisitor::arm_SMLAWy(Cond cond, Reg d, Reg a, Reg m, bool M, Reg n) {
295 if (d == Reg::PC || n == Reg::PC || m == Reg::PC || a == Reg::PC) {
296 return UnpredictableInstruction();
297 }
298
299 if (!ConditionPassed(cond)) {
300 return true;
301 }
302
303 const IR::U64 n32 = ir.SignExtendWordToLong(ir.GetRegister(n));
304 IR::U32 m32 = ir.GetRegister(m);
305 if (M) {
306 m32 = ir.LogicalShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result;
307 }
308 const IR::U64 m16 = ir.SignExtendWordToLong(ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32)));
309 const auto product = ir.LeastSignificantWord(ir.LogicalShiftRight(ir.Mul(n32, m16), ir.Imm8(16)));
310 const auto result_overflow = ir.AddWithCarry(product, ir.GetRegister(a), ir.Imm1(0));
311
312 ir.SetRegister(d, result_overflow.result);
313 ir.OrQFlag(result_overflow.overflow);
314 return true;
315 }
316
317 // SMULW<y><c> <Rd>, <Rn>, <Rm>
arm_SMULWy(Cond cond,Reg d,Reg m,bool M,Reg n)318 bool ArmTranslatorVisitor::arm_SMULWy(Cond cond, Reg d, Reg m, bool M, Reg n) {
319 if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
320 return UnpredictableInstruction();
321 }
322
323 if (!ConditionPassed(cond)) {
324 return true;
325 }
326
327 const IR::U64 n32 = ir.SignExtendWordToLong(ir.GetRegister(n));
328 IR::U32 m32 = ir.GetRegister(m);
329 if (M) {
330 m32 = ir.LogicalShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result;
331 }
332 const IR::U64 m16 = ir.SignExtendWordToLong(ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32)));
333 const auto result = ir.LogicalShiftRight(ir.Mul(n32, m16), ir.Imm8(16));
334
335 ir.SetRegister(d, ir.LeastSignificantWord(result));
336 return true;
337 }
338
339 // SMMLA{R}<c> <Rd>, <Rn>, <Rm>, <Ra>
arm_SMMLA(Cond cond,Reg d,Reg a,Reg m,bool R,Reg n)340 bool ArmTranslatorVisitor::arm_SMMLA(Cond cond, Reg d, Reg a, Reg m, bool R, Reg n) {
341 if (d == Reg::PC || n == Reg::PC || m == Reg::PC /* no check for a */) {
342 return UnpredictableInstruction();
343 }
344
345 if (!ConditionPassed(cond)) {
346 return true;
347 }
348
349 const auto n64 = ir.SignExtendWordToLong(ir.GetRegister(n));
350 const auto m64 = ir.SignExtendWordToLong(ir.GetRegister(m));
351 const auto a64 = ir.Pack2x32To1x64(ir.Imm32(0), ir.GetRegister(a));
352 const auto temp = ir.Add(a64, ir.Mul(n64, m64));
353 const auto result_carry = ir.MostSignificantWord(temp);
354 auto result = result_carry.result;
355 if (R) {
356 result = ir.AddWithCarry(result, ir.Imm32(0), result_carry.carry).result;
357 }
358
359 ir.SetRegister(d, result);
360 return true;
361 }
362
363 // SMMLS{R}<c> <Rd>, <Rn>, <Rm>, <Ra>
arm_SMMLS(Cond cond,Reg d,Reg a,Reg m,bool R,Reg n)364 bool ArmTranslatorVisitor::arm_SMMLS(Cond cond, Reg d, Reg a, Reg m, bool R, Reg n) {
365 if (d == Reg::PC || n == Reg::PC || m == Reg::PC || a == Reg::PC) {
366 return UnpredictableInstruction();
367 }
368
369 if (!ConditionPassed(cond)) {
370 return true;
371 }
372
373 const auto n64 = ir.SignExtendWordToLong(ir.GetRegister(n));
374 const auto m64 = ir.SignExtendWordToLong(ir.GetRegister(m));
375 const auto a64 = ir.Pack2x32To1x64(ir.Imm32(0), ir.GetRegister(a));
376 const auto temp = ir.Sub(a64, ir.Mul(n64, m64));
377 const auto result_carry = ir.MostSignificantWord(temp);
378 auto result = result_carry.result;
379 if (R) {
380 result = ir.AddWithCarry(result, ir.Imm32(0), result_carry.carry).result;
381 }
382
383 ir.SetRegister(d, result);
384 return true;
385 }
386
387 // SMMUL{R}<c> <Rd>, <Rn>, <Rm>
arm_SMMUL(Cond cond,Reg d,Reg m,bool R,Reg n)388 bool ArmTranslatorVisitor::arm_SMMUL(Cond cond, Reg d, Reg m, bool R, Reg n) {
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 n64 = ir.SignExtendWordToLong(ir.GetRegister(n));
398 const auto m64 = ir.SignExtendWordToLong(ir.GetRegister(m));
399 const auto product = ir.Mul(n64, m64);
400 const auto result_carry = ir.MostSignificantWord(product);
401 auto result = result_carry.result;
402 if (R) {
403 result = ir.AddWithCarry(result, ir.Imm32(0), result_carry.carry).result;
404 }
405
406 ir.SetRegister(d, result);
407 return true;
408 }
409
410 // SMLAD{X}<c> <Rd>, <Rn>, <Rm>, <Ra>
arm_SMLAD(Cond cond,Reg d,Reg a,Reg m,bool M,Reg n)411 bool ArmTranslatorVisitor::arm_SMLAD(Cond cond, Reg d, Reg a, Reg m, bool M, Reg n) {
412 if (a == Reg::PC) {
413 return arm_SMUAD(cond, d, m, M, n);
414 }
415
416 if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
417 return UnpredictableInstruction();
418 }
419
420 if (!ConditionPassed(cond)) {
421 return true;
422 }
423
424 const IR::U32 n32 = ir.GetRegister(n);
425 const IR::U32 m32 = ir.GetRegister(m);
426 const IR::U32 n_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(n32));
427 const IR::U32 n_hi = ir.ArithmeticShiftRight(n32, ir.Imm8(16), ir.Imm1(0)).result;
428
429 IR::U32 m_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32));
430 IR::U32 m_hi = ir.ArithmeticShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result;
431 if (M) {
432 std::swap(m_lo, m_hi);
433 }
434
435 const IR::U32 product_lo = ir.Mul(n_lo, m_lo);
436 const IR::U32 product_hi = ir.Mul(n_hi, m_hi);
437 const IR::U32 addend = ir.GetRegister(a);
438
439 auto result_overflow = ir.AddWithCarry(product_lo, product_hi, ir.Imm1(0));
440 ir.OrQFlag(result_overflow.overflow);
441 result_overflow = ir.AddWithCarry(result_overflow.result, addend, ir.Imm1(0));
442 ir.SetRegister(d, result_overflow.result);
443 ir.OrQFlag(result_overflow.overflow);
444 return true;
445 }
446
447 // SMLALD{X}<c> <RdLo>, <RdHi>, <Rn>, <Rm>
arm_SMLALD(Cond cond,Reg dHi,Reg dLo,Reg m,bool M,Reg n)448 bool ArmTranslatorVisitor::arm_SMLALD(Cond cond, Reg dHi, Reg dLo, Reg m, bool M, Reg n) {
449 if (dLo == Reg::PC || dHi == Reg::PC || n == Reg::PC || m == Reg::PC) {
450 return UnpredictableInstruction();
451 }
452
453 if (dLo == dHi) {
454 return UnpredictableInstruction();
455 }
456
457 if (!ConditionPassed(cond)) {
458 return true;
459 }
460
461 const IR::U32 n32 = ir.GetRegister(n);
462 const IR::U32 m32 = ir.GetRegister(m);
463 const IR::U32 n_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(n32));
464 const IR::U32 n_hi = ir.ArithmeticShiftRight(n32, ir.Imm8(16), ir.Imm1(0)).result;
465
466 IR::U32 m_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32));
467 IR::U32 m_hi = ir.ArithmeticShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result;
468 if (M) {
469 std::swap(m_lo, m_hi);
470 }
471
472 const IR::U64 product_lo = ir.SignExtendWordToLong(ir.Mul(n_lo, m_lo));
473 const IR::U64 product_hi = ir.SignExtendWordToLong(ir.Mul(n_hi, m_hi));
474 const auto addend = ir.Pack2x32To1x64(ir.GetRegister(dLo), ir.GetRegister(dHi));
475 const auto result = ir.Add(ir.Add(product_lo, product_hi), addend);
476
477 ir.SetRegister(dLo, ir.LeastSignificantWord(result));
478 ir.SetRegister(dHi, ir.MostSignificantWord(result).result);
479 return true;
480 }
481
482 // SMLSD{X}<c> <Rd>, <Rn>, <Rm>, <Ra>
arm_SMLSD(Cond cond,Reg d,Reg a,Reg m,bool M,Reg n)483 bool ArmTranslatorVisitor::arm_SMLSD(Cond cond, Reg d, Reg a, Reg m, bool M, Reg n) {
484 if (a == Reg::PC) {
485 return arm_SMUSD(cond, d, m, M, n);
486 }
487
488 if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
489 return UnpredictableInstruction();
490 }
491
492 if (!ConditionPassed(cond)) {
493 return true;
494 }
495
496 const IR::U32 n32 = ir.GetRegister(n);
497 const IR::U32 m32 = ir.GetRegister(m);
498 const IR::U32 n_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(n32));
499 const IR::U32 n_hi = ir.ArithmeticShiftRight(n32, ir.Imm8(16), ir.Imm1(0)).result;
500
501 IR::U32 m_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32));
502 IR::U32 m_hi = ir.ArithmeticShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result;
503 if (M) {
504 std::swap(m_lo, m_hi);
505 }
506
507 const IR::U32 product_lo = ir.Mul(n_lo, m_lo);
508 const IR::U32 product_hi = ir.Mul(n_hi, m_hi);
509 const IR::U32 addend = ir.GetRegister(a);
510 const IR::U32 product = ir.Sub(product_lo, product_hi);
511 auto result_overflow = ir.AddWithCarry(product, addend, ir.Imm1(0));
512
513 ir.SetRegister(d, result_overflow.result);
514 ir.OrQFlag(result_overflow.overflow);
515 return true;
516 }
517
518 // SMLSLD{X}<c> <RdLo>, <RdHi>, <Rn>, <Rm>
arm_SMLSLD(Cond cond,Reg dHi,Reg dLo,Reg m,bool M,Reg n)519 bool ArmTranslatorVisitor::arm_SMLSLD(Cond cond, Reg dHi, Reg dLo, Reg m, bool M, Reg n) {
520 if (dLo == Reg::PC || dHi == Reg::PC || n == Reg::PC || m == Reg::PC) {
521 return UnpredictableInstruction();
522 }
523
524 if (dLo == dHi) {
525 return UnpredictableInstruction();
526 }
527
528 if (!ConditionPassed(cond)) {
529 return true;
530 }
531
532 const IR::U32 n32 = ir.GetRegister(n);
533 const IR::U32 m32 = ir.GetRegister(m);
534 const IR::U32 n_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(n32));
535 const IR::U32 n_hi = ir.ArithmeticShiftRight(n32, ir.Imm8(16), ir.Imm1(0)).result;
536
537 IR::U32 m_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32));
538 IR::U32 m_hi = ir.ArithmeticShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result;
539 if (M) {
540 std::swap(m_lo, m_hi);
541 }
542
543 const IR::U64 product_lo = ir.SignExtendWordToLong(ir.Mul(n_lo, m_lo));
544 const IR::U64 product_hi = ir.SignExtendWordToLong(ir.Mul(n_hi, m_hi));
545 const auto addend = ir.Pack2x32To1x64(ir.GetRegister(dLo), ir.GetRegister(dHi));
546 const auto result = ir.Add(ir.Sub(product_lo, product_hi), addend);
547
548 ir.SetRegister(dLo, ir.LeastSignificantWord(result));
549 ir.SetRegister(dHi, ir.MostSignificantWord(result).result);
550 return true;
551 }
552
553 // SMUAD{X}<c> <Rd>, <Rn>, <Rm>
arm_SMUAD(Cond cond,Reg d,Reg m,bool M,Reg n)554 bool ArmTranslatorVisitor::arm_SMUAD(Cond cond, Reg d, Reg m, bool M, Reg n) {
555 if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
556 return UnpredictableInstruction();
557 }
558
559 if (!ConditionPassed(cond)) {
560 return true;
561 }
562
563 const IR::U32 n32 = ir.GetRegister(n);
564 const IR::U32 m32 = ir.GetRegister(m);
565 const IR::U32 n_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(n32));
566 const IR::U32 n_hi = ir.ArithmeticShiftRight(n32, ir.Imm8(16), ir.Imm1(0)).result;
567
568 IR::U32 m_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32));
569 IR::U32 m_hi = ir.ArithmeticShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result;
570 if (M) {
571 std::swap(m_lo, m_hi);
572 }
573
574 const IR::U32 product_lo = ir.Mul(n_lo, m_lo);
575 const IR::U32 product_hi = ir.Mul(n_hi, m_hi);
576 const auto result_overflow = ir.AddWithCarry(product_lo, product_hi, ir.Imm1(0));
577
578 ir.SetRegister(d, result_overflow.result);
579 ir.OrQFlag(result_overflow.overflow);
580 return true;
581 }
582
583 // SMUSD{X}<c> <Rd>, <Rn>, <Rm>
arm_SMUSD(Cond cond,Reg d,Reg m,bool M,Reg n)584 bool ArmTranslatorVisitor::arm_SMUSD(Cond cond, Reg d, Reg m, bool M, Reg n) {
585 if (d == Reg::PC || n == Reg::PC || m == Reg::PC) {
586 return UnpredictableInstruction();
587 }
588
589 if (!ConditionPassed(cond)) {
590 return true;
591 }
592
593 const IR::U32 n32 = ir.GetRegister(n);
594 const IR::U32 m32 = ir.GetRegister(m);
595 const IR::U32 n_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(n32));
596 const IR::U32 n_hi = ir.ArithmeticShiftRight(n32, ir.Imm8(16), ir.Imm1(0)).result;
597
598 IR::U32 m_lo = ir.SignExtendHalfToWord(ir.LeastSignificantHalf(m32));
599 IR::U32 m_hi = ir.ArithmeticShiftRight(m32, ir.Imm8(16), ir.Imm1(0)).result;
600 if (M) {
601 std::swap(m_lo, m_hi);
602 }
603
604 const IR::U32 product_lo = ir.Mul(n_lo, m_lo);
605 const IR::U32 product_hi = ir.Mul(n_hi, m_hi);
606 auto result = ir.Sub(product_lo, product_hi);
607 ir.SetRegister(d, result);
608 return true;
609 }
610
611 } // namespace Dynarmic::A32
612