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 
arm_LDRBT()10 bool ArmTranslatorVisitor::arm_LDRBT() {
11     // System instructions unimplemented
12     return UndefinedInstruction();
13 }
14 
arm_LDRHT()15 bool ArmTranslatorVisitor::arm_LDRHT() {
16     // System instructions unimplemented
17     return UndefinedInstruction();
18 }
19 
arm_LDRSBT()20 bool ArmTranslatorVisitor::arm_LDRSBT() {
21     // System instructions unimplemented
22     return UndefinedInstruction();
23 }
24 
arm_LDRSHT()25 bool ArmTranslatorVisitor::arm_LDRSHT() {
26     // System instructions unimplemented
27     return UndefinedInstruction();
28 }
29 
arm_LDRT()30 bool ArmTranslatorVisitor::arm_LDRT() {
31     // System instructions unimplemented
32     return UndefinedInstruction();
33 }
34 
arm_STRBT()35 bool ArmTranslatorVisitor::arm_STRBT() {
36     // System instructions unimplemented
37     return UndefinedInstruction();
38 }
39 
arm_STRHT()40 bool ArmTranslatorVisitor::arm_STRHT() {
41     // System instructions unimplemented
42     return UndefinedInstruction();
43 }
44 
arm_STRT()45 bool ArmTranslatorVisitor::arm_STRT() {
46     // System instructions unimplemented
47     return UndefinedInstruction();
48 }
49 
GetAddress(A32::IREmitter & ir,bool P,bool U,bool W,Reg n,IR::U32 offset)50 static IR::U32 GetAddress(A32::IREmitter& ir, bool P, bool U, bool W, Reg n, IR::U32 offset) {
51     const bool index = P;
52     const bool add = U;
53     const bool wback = !P || W;
54 
55     const IR::U32 offset_addr = add ? ir.Add(ir.GetRegister(n), offset) : ir.Sub(ir.GetRegister(n), offset);
56     const IR::U32 address = index ? offset_addr : ir.GetRegister(n);
57 
58     if (wback) {
59         ir.SetRegister(n, offset_addr);
60     }
61 
62     return address;
63 }
64 
65 // LDR <Rt>, [PC, #+/-<imm>]
arm_LDR_lit(Cond cond,bool U,Reg t,Imm<12> imm12)66 bool ArmTranslatorVisitor::arm_LDR_lit(Cond cond, bool U, Reg t, Imm<12> imm12) {
67     if (!ConditionPassed(cond)) {
68         return true;
69     }
70 
71     const bool add = U;
72     const u32 base = ir.AlignPC(4);
73     const u32 address = add ? (base + imm12.ZeroExtend()) : (base - imm12.ZeroExtend());
74     const auto data = ir.ReadMemory32(ir.Imm32(address));
75 
76     if (t == Reg::PC) {
77         ir.LoadWritePC(data);
78         ir.SetTerm(IR::Term::FastDispatchHint{});
79         return false;
80     }
81 
82     ir.SetRegister(t, data);
83     return true;
84 }
85 
86 // LDR <Rt>, [<Rn>, #+/-<imm>]{!}
87 // LDR <Rt>, [<Rn>], #+/-<imm>
arm_LDR_imm(Cond cond,bool P,bool U,bool W,Reg n,Reg t,Imm<12> imm12)88 bool ArmTranslatorVisitor::arm_LDR_imm(Cond cond, bool P, bool U, bool W, Reg n, Reg t, Imm<12> imm12) {
89     if (n == Reg::PC) {
90         return UnpredictableInstruction();
91     }
92 
93     ASSERT_MSG(!(!P && W), "T form of instruction unimplemented");
94     if ((!P || W) && n == t) {
95         return UnpredictableInstruction();
96     }
97 
98     if (!ConditionPassed(cond)) {
99         return true;
100     }
101 
102     const u32 imm32 = imm12.ZeroExtend();
103     const auto offset = ir.Imm32(imm32);
104     const auto address = GetAddress(ir, P, U, W, n, offset);
105     const auto data = ir.ReadMemory32(address);
106 
107     if (t == Reg::PC) {
108         ir.LoadWritePC(data);
109 
110         if (!P && W && n == Reg::R13) {
111             ir.SetTerm(IR::Term::PopRSBHint{});
112         } else {
113             ir.SetTerm(IR::Term::FastDispatchHint{});
114         }
115 
116         return false;
117     }
118 
119     ir.SetRegister(t, data);
120     return true;
121 }
122 
123 // LDR <Rt>, [<Rn>, #+/-<Rm>]{!}
124 // LDR <Rt>, [<Rn>], #+/-<Rm>
arm_LDR_reg(Cond cond,bool P,bool U,bool W,Reg n,Reg t,Imm<5> imm5,ShiftType shift,Reg m)125 bool ArmTranslatorVisitor::arm_LDR_reg(Cond cond, bool P, bool U, bool W, Reg n, Reg t, Imm<5> imm5, ShiftType shift, Reg m) {
126     ASSERT_MSG(!(!P && W), "T form of instruction unimplemented");
127     if (m == Reg::PC) {
128         return UnpredictableInstruction();
129     }
130 
131     if ((!P || W) && (n == Reg::PC || n == t)) {
132         return UnpredictableInstruction();
133     }
134 
135     if (!ConditionPassed(cond)) {
136         return true;
137     }
138 
139     const auto offset = EmitImmShift(ir.GetRegister(m), shift, imm5, ir.GetCFlag()).result;
140     const auto address = GetAddress(ir, P, U, W, n, offset);
141     const auto data = ir.ReadMemory32(address);
142 
143     if (t == Reg::PC) {
144         ir.LoadWritePC(data);
145         ir.SetTerm(IR::Term::FastDispatchHint{});
146         return false;
147     }
148 
149     ir.SetRegister(t, data);
150     return true;
151 }
152 
153 // LDRB <Rt>, [PC, #+/-<imm>]
arm_LDRB_lit(Cond cond,bool U,Reg t,Imm<12> imm12)154 bool ArmTranslatorVisitor::arm_LDRB_lit(Cond cond, bool U, Reg t, Imm<12> imm12) {
155     if (t == Reg::PC) {
156         return UnpredictableInstruction();
157     }
158 
159     if (!ConditionPassed(cond)) {
160         return true;
161     }
162 
163     const u32 imm32 = imm12.ZeroExtend();
164     const bool add = U;
165     const u32 base = ir.AlignPC(4);
166     const u32 address = add ? (base + imm32) : (base - imm32);
167     const auto data = ir.ZeroExtendByteToWord(ir.ReadMemory8(ir.Imm32(address)));
168 
169     ir.SetRegister(t, data);
170     return true;
171 }
172 
173 // LDRB <Rt>, [<Rn>, #+/-<imm>]{!}
174 // LDRB <Rt>, [<Rn>], #+/-<imm>
arm_LDRB_imm(Cond cond,bool P,bool U,bool W,Reg n,Reg t,Imm<12> imm12)175 bool ArmTranslatorVisitor::arm_LDRB_imm(Cond cond, bool P, bool U, bool W, Reg n, Reg t, Imm<12> imm12) {
176     if (n == Reg::PC) {
177         return UnpredictableInstruction();
178     }
179 
180     ASSERT_MSG(!(!P && W), "T form of instruction unimplemented");
181     if ((!P || W) && n == t) {
182         return UnpredictableInstruction();
183     }
184 
185     if (t == Reg::PC) {
186         return UnpredictableInstruction();
187     }
188 
189     if (!ConditionPassed(cond)) {
190         return true;
191     }
192 
193     const u32 imm32 = imm12.ZeroExtend();
194     const auto offset = ir.Imm32(imm32);
195     const auto address = GetAddress(ir, P, U, W, n, offset);
196     const auto data = ir.ZeroExtendByteToWord(ir.ReadMemory8(address));
197 
198     ir.SetRegister(t, data);
199     return true;
200 }
201 
202 // LDRB <Rt>, [<Rn>, #+/-<Rm>]{!}
203 // LDRB <Rt>, [<Rn>], #+/-<Rm>
arm_LDRB_reg(Cond cond,bool P,bool U,bool W,Reg n,Reg t,Imm<5> imm5,ShiftType shift,Reg m)204 bool ArmTranslatorVisitor::arm_LDRB_reg(Cond cond, bool P, bool U, bool W, Reg n, Reg t, Imm<5> imm5, ShiftType shift, Reg m) {
205     ASSERT_MSG(!(!P && W), "T form of instruction unimplemented");
206     if (t == Reg::PC || m == Reg::PC) {
207         return UnpredictableInstruction();
208     }
209 
210     if ((!P || W) && (n == Reg::PC || n == t)) {
211         return UnpredictableInstruction();
212     }
213 
214     if (!ConditionPassed(cond)) {
215         return true;
216     }
217 
218     const auto offset = EmitImmShift(ir.GetRegister(m), shift, imm5, ir.GetCFlag()).result;
219     const auto address = GetAddress(ir, P, U, W, n, offset);
220     const auto data = ir.ZeroExtendByteToWord(ir.ReadMemory8(address));
221 
222     ir.SetRegister(t, data);
223     return true;
224 }
225 
226 // LDRD <Rt>, <Rt2>, [PC, #+/-<imm>]
arm_LDRD_lit(Cond cond,bool U,Reg t,Imm<4> imm8a,Imm<4> imm8b)227 bool ArmTranslatorVisitor::arm_LDRD_lit(Cond cond, bool U, Reg t, Imm<4> imm8a, Imm<4> imm8b) {
228     if (RegNumber(t) % 2 == 1) {
229         return UnpredictableInstruction();
230     }
231 
232     if (t+1 == Reg::PC) {
233         return UnpredictableInstruction();
234     }
235 
236     if (!ConditionPassed(cond)) {
237         return true;
238     }
239 
240     const Reg t2 = t+1;
241     const u32 imm32 = concatenate(imm8a, imm8b).ZeroExtend();
242     const bool add = U;
243 
244     const u32 base = ir.AlignPC(4);
245     const u32 address = add ? (base + imm32) : (base - imm32);
246     const auto data_a = ir.ReadMemory32(ir.Imm32(address));
247     const auto data_b = ir.ReadMemory32(ir.Imm32(address + 4));
248 
249     ir.SetRegister(t, data_a);
250     ir.SetRegister(t2, data_b);
251     return true;
252 }
253 
254 // LDRD <Rt>, [<Rn>, #+/-<imm>]{!}
255 // LDRD <Rt>, [<Rn>], #+/-<imm>
arm_LDRD_imm(Cond cond,bool P,bool U,bool W,Reg n,Reg t,Imm<4> imm8a,Imm<4> imm8b)256 bool ArmTranslatorVisitor::arm_LDRD_imm(Cond cond, bool P, bool U, bool W, Reg n, Reg t, Imm<4> imm8a, Imm<4> imm8b) {
257     if (n == Reg::PC) {
258         return UnpredictableInstruction();
259     }
260 
261     if (RegNumber(t) % 2 == 1) {
262         return UnpredictableInstruction();
263     }
264 
265     if (!P && W) {
266         return UnpredictableInstruction();
267     }
268 
269     if ((!P || W) && (n == t || n == t+1)) {
270         return UnpredictableInstruction();
271     }
272 
273     if (t+1 == Reg::PC) {
274         return UnpredictableInstruction();
275     }
276 
277     if (!ConditionPassed(cond)) {
278         return true;
279     }
280 
281     const Reg t2 = t+1;
282     const u32 imm32 = concatenate(imm8a, imm8b).ZeroExtend();
283 
284     const auto offset = ir.Imm32(imm32);
285     const auto address_a = GetAddress(ir, P, U, W, n, offset);
286     const auto address_b = ir.Add(address_a, ir.Imm32(4));
287     const auto data_a = ir.ReadMemory32(address_a);
288     const auto data_b = ir.ReadMemory32(address_b);
289 
290     ir.SetRegister(t, data_a);
291     ir.SetRegister(t2, data_b);
292     return true;
293 }
294 
295 // LDRD <Rt>, [<Rn>, #+/-<Rm>]{!}
296 // LDRD <Rt>, [<Rn>], #+/-<Rm>
arm_LDRD_reg(Cond cond,bool P,bool U,bool W,Reg n,Reg t,Reg m)297 bool ArmTranslatorVisitor::arm_LDRD_reg(Cond cond, bool P, bool U, bool W, Reg n, Reg t, Reg m) {
298     if (RegNumber(t) % 2 == 1) {
299         return UnpredictableInstruction();
300     }
301 
302     if (!P && W) {
303         return UnpredictableInstruction();
304     }
305 
306     if (t+1 == Reg::PC || m == Reg::PC || m == t || m == t+1) {
307         return UnpredictableInstruction();
308     }
309 
310     if ((!P || W) && (n == Reg::PC || n == t || n == t+1)) {
311         return UnpredictableInstruction();
312     }
313 
314     if (!ConditionPassed(cond)) {
315         return true;
316     }
317 
318     const Reg t2 = t+1;
319     const auto offset = ir.GetRegister(m);
320     const auto address_a = GetAddress(ir, P, U, W, n, offset);
321     const auto address_b = ir.Add(address_a, ir.Imm32(4));
322     const auto data_a = ir.ReadMemory32(address_a);
323     const auto data_b = ir.ReadMemory32(address_b);
324 
325     ir.SetRegister(t, data_a);
326     ir.SetRegister(t2, data_b);
327     return true;
328 }
329 
330 // LDRH <Rt>, [PC, #-/+<imm>]
arm_LDRH_lit(Cond cond,bool P,bool U,bool W,Reg t,Imm<4> imm8a,Imm<4> imm8b)331 bool ArmTranslatorVisitor::arm_LDRH_lit(Cond cond, bool P, bool U, bool W, Reg t, Imm<4> imm8a, Imm<4> imm8b) {
332     ASSERT_MSG(!(!P && W), "T form of instruction unimplemented");
333     if (P == W) {
334         return UnpredictableInstruction();
335     }
336 
337     if (t == Reg::PC) {
338         return UnpredictableInstruction();
339     }
340 
341     if (!ConditionPassed(cond)) {
342         return true;
343     }
344 
345     const u32 imm32 = concatenate(imm8a, imm8b).ZeroExtend();
346     const bool add = U;
347     const u32 base = ir.AlignPC(4);
348     const u32 address = add ? (base + imm32) : (base - imm32);
349     const auto data = ir.ZeroExtendHalfToWord(ir.ReadMemory16(ir.Imm32(address)));
350 
351     ir.SetRegister(t, data);
352     return true;
353 }
354 
355 // LDRH <Rt>, [<Rn>, #+/-<imm>]{!}
356 // LDRH <Rt>, [<Rn>], #+/-<imm>
arm_LDRH_imm(Cond cond,bool P,bool U,bool W,Reg n,Reg t,Imm<4> imm8a,Imm<4> imm8b)357 bool ArmTranslatorVisitor::arm_LDRH_imm(Cond cond, bool P, bool U, bool W, Reg n, Reg t, Imm<4> imm8a, Imm<4> imm8b) {
358     if (n == Reg::PC) {
359         return UnpredictableInstruction();
360     }
361 
362     ASSERT_MSG(!(!P && W), "T form of instruction unimplemented");
363     if ((!P || W) && n == t) {
364         return UnpredictableInstruction();
365     }
366 
367     if (t == Reg::PC) {
368         return UnpredictableInstruction();
369     }
370 
371     if (!ConditionPassed(cond)) {
372         return true;
373     }
374 
375     const u32 imm32 = concatenate(imm8a, imm8b).ZeroExtend();
376     const auto offset = ir.Imm32(imm32);
377     const auto address = GetAddress(ir, P, U, W, n, offset);
378     const auto data = ir.ZeroExtendHalfToWord(ir.ReadMemory16(address));
379 
380     ir.SetRegister(t, data);
381     return true;
382 }
383 
384 // LDRH <Rt>, [<Rn>, #+/-<Rm>]{!}
385 // LDRH <Rt>, [<Rn>], #+/-<Rm>
arm_LDRH_reg(Cond cond,bool P,bool U,bool W,Reg n,Reg t,Reg m)386 bool ArmTranslatorVisitor::arm_LDRH_reg(Cond cond, bool P, bool U, bool W, Reg n, Reg t, Reg m) {
387     ASSERT_MSG(!(!P && W), "T form of instruction unimplemented");
388     if (t == Reg::PC || m == Reg::PC) {
389         return UnpredictableInstruction();
390     }
391 
392     if ((!P || W) && (n == Reg::PC || n == t)) {
393         return UnpredictableInstruction();
394     }
395 
396     if (!ConditionPassed(cond)) {
397         return true;
398     }
399 
400     const auto offset = ir.GetRegister(m);
401     const auto address = GetAddress(ir, P, U, W, n, offset);
402     const auto data = ir.ZeroExtendHalfToWord(ir.ReadMemory16(address));
403 
404     ir.SetRegister(t, data);
405     return true;
406 }
407 
408 // LDRSB <Rt>, [PC, #+/-<imm>]
arm_LDRSB_lit(Cond cond,bool U,Reg t,Imm<4> imm8a,Imm<4> imm8b)409 bool ArmTranslatorVisitor::arm_LDRSB_lit(Cond cond, bool U, Reg t, Imm<4> imm8a, Imm<4> imm8b) {
410     if (t == Reg::PC) {
411         return UnpredictableInstruction();
412     }
413 
414     if (!ConditionPassed(cond)) {
415         return true;
416     }
417 
418     const u32 imm32 = concatenate(imm8a, imm8b).ZeroExtend();
419     const bool add = U;
420 
421     const u32 base = ir.AlignPC(4);
422     const u32 address = add ? (base + imm32) : (base - imm32);
423     const auto data = ir.SignExtendByteToWord(ir.ReadMemory8(ir.Imm32(address)));
424 
425     ir.SetRegister(t, data);
426     return true;
427 }
428 
429 // LDRSB <Rt>, [<Rn>, #+/-<imm>]{!}
430 // LDRSB <Rt>, [<Rn>], #+/-<imm>
arm_LDRSB_imm(Cond cond,bool P,bool U,bool W,Reg n,Reg t,Imm<4> imm8a,Imm<4> imm8b)431 bool ArmTranslatorVisitor::arm_LDRSB_imm(Cond cond, bool P, bool U, bool W, Reg n, Reg t, Imm<4> imm8a, Imm<4> imm8b) {
432     if (n == Reg::PC) {
433         return UnpredictableInstruction();
434     }
435 
436     ASSERT_MSG(!(!P && W), "T form of instruction unimplemented");
437     if ((!P || W) && n == t) {
438         return UnpredictableInstruction();
439     }
440 
441     if (t == Reg::PC) {
442         return UnpredictableInstruction();
443     }
444 
445     if (!ConditionPassed(cond)) {
446         return true;
447     }
448 
449     const u32 imm32 = concatenate(imm8a, imm8b).ZeroExtend();
450     const auto offset = ir.Imm32(imm32);
451     const auto address = GetAddress(ir, P, U, W, n, offset);
452     const auto data = ir.SignExtendByteToWord(ir.ReadMemory8(address));
453 
454     ir.SetRegister(t, data);
455     return true;
456 }
457 
458 // LDRSB <Rt>, [<Rn>, #+/-<Rm>]{!}
459 // LDRSB <Rt>, [<Rn>], #+/-<Rm>
arm_LDRSB_reg(Cond cond,bool P,bool U,bool W,Reg n,Reg t,Reg m)460 bool ArmTranslatorVisitor::arm_LDRSB_reg(Cond cond, bool P, bool U, bool W, Reg n, Reg t, Reg m) {
461     ASSERT_MSG(!(!P && W), "T form of instruction unimplemented");
462     if (t == Reg::PC || m == Reg::PC) {
463         return UnpredictableInstruction();
464     }
465 
466     if ((!P || W) && (n == Reg::PC || n == t)) {
467         return UnpredictableInstruction();
468     }
469 
470     if (!ConditionPassed(cond)) {
471         return true;
472     }
473 
474     const auto offset = ir.GetRegister(m);
475     const auto address = GetAddress(ir, P, U, W, n, offset);
476     const auto data = ir.SignExtendByteToWord(ir.ReadMemory8(address));
477 
478     ir.SetRegister(t, data);
479     return true;
480 }
481 
482 // LDRSH <Rt>, [PC, #-/+<imm>]
arm_LDRSH_lit(Cond cond,bool U,Reg t,Imm<4> imm8a,Imm<4> imm8b)483 bool ArmTranslatorVisitor::arm_LDRSH_lit(Cond cond, bool U, Reg t, Imm<4> imm8a, Imm<4> imm8b) {
484     if (t == Reg::PC) {
485         return UnpredictableInstruction();
486     }
487 
488     if (!ConditionPassed(cond)) {
489         return true;
490     }
491 
492     const u32 imm32 = concatenate(imm8a, imm8b).ZeroExtend();
493     const bool add = U;
494     const u32 base = ir.AlignPC(4);
495     const u32 address = add ? (base + imm32) : (base - imm32);
496     const auto data = ir.SignExtendHalfToWord(ir.ReadMemory16(ir.Imm32(address)));
497 
498     ir.SetRegister(t, data);
499     return true;
500 }
501 
502 // LDRSH <Rt>, [<Rn>, #+/-<imm>]{!}
503 // LDRSH <Rt>, [<Rn>], #+/-<imm>
arm_LDRSH_imm(Cond cond,bool P,bool U,bool W,Reg n,Reg t,Imm<4> imm8a,Imm<4> imm8b)504 bool ArmTranslatorVisitor::arm_LDRSH_imm(Cond cond, bool P, bool U, bool W, Reg n, Reg t, Imm<4> imm8a, Imm<4> imm8b) {
505     if (n == Reg::PC) {
506         return UnpredictableInstruction();
507     }
508 
509     ASSERT_MSG(!(!P && W), "T form of instruction unimplemented");
510     if ((!P || W) && n == t) {
511         return UnpredictableInstruction();
512     }
513 
514     if (t == Reg::PC) {
515         return UnpredictableInstruction();
516     }
517 
518     if (!ConditionPassed(cond)) {
519         return true;
520     }
521 
522     const u32 imm32 = concatenate(imm8a, imm8b).ZeroExtend();
523     const auto offset = ir.Imm32(imm32);
524     const auto address = GetAddress(ir, P, U, W, n, offset);
525     const auto data = ir.SignExtendHalfToWord(ir.ReadMemory16(address));
526 
527     ir.SetRegister(t, data);
528     return true;
529 }
530 
531 // LDRSH <Rt>, [<Rn>, #+/-<Rm>]{!}
532 // LDRSH <Rt>, [<Rn>], #+/-<Rm>
arm_LDRSH_reg(Cond cond,bool P,bool U,bool W,Reg n,Reg t,Reg m)533 bool ArmTranslatorVisitor::arm_LDRSH_reg(Cond cond, bool P, bool U, bool W, Reg n, Reg t, Reg m) {
534     ASSERT_MSG(!(!P && W), "T form of instruction unimplemented");
535     if (t == Reg::PC || m == Reg::PC) {
536         return UnpredictableInstruction();
537     }
538 
539     if ((!P || W) && (n == Reg::PC || n == t)) {
540         return UnpredictableInstruction();
541     }
542 
543     if (!ConditionPassed(cond)) {
544         return true;
545     }
546 
547     const auto offset = ir.GetRegister(m);
548     const auto address = GetAddress(ir, P, U, W, n, offset);
549     const auto data = ir.SignExtendHalfToWord(ir.ReadMemory16(address));
550 
551     ir.SetRegister(t, data);
552     return true;
553 }
554 
555 // STR <Rt>, [<Rn>, #+/-<imm>]{!}
556 // STR <Rt>, [<Rn>], #+/-<imm>
arm_STR_imm(Cond cond,bool P,bool U,bool W,Reg n,Reg t,Imm<12> imm12)557 bool ArmTranslatorVisitor::arm_STR_imm(Cond cond, bool P, bool U, bool W, Reg n, Reg t, Imm<12> imm12) {
558     if ((!P || W) && (n == Reg::PC || n == t)) {
559         return UnpredictableInstruction();
560     }
561 
562     if (!ConditionPassed(cond)) {
563         return true;
564     }
565 
566     const auto offset = ir.Imm32(imm12.ZeroExtend());
567     const auto address = GetAddress(ir, P, U, W, n, offset);
568     ir.WriteMemory32(address, ir.GetRegister(t));
569     return true;
570 }
571 
572 // STR <Rt>, [<Rn>, #+/-<Rm>]{!}
573 // STR <Rt>, [<Rn>], #+/-<Rm>
arm_STR_reg(Cond cond,bool P,bool U,bool W,Reg n,Reg t,Imm<5> imm5,ShiftType shift,Reg m)574 bool ArmTranslatorVisitor::arm_STR_reg(Cond cond, bool P, bool U, bool W, Reg n, Reg t, Imm<5> imm5, ShiftType shift, Reg m) {
575     if (m == Reg::PC) {
576         return UnpredictableInstruction();
577     }
578 
579     if ((!P || W) && (n == Reg::PC || n == t)) {
580         return UnpredictableInstruction();
581     }
582 
583     if (!ConditionPassed(cond)) {
584         return true;
585     }
586 
587     const auto offset = EmitImmShift(ir.GetRegister(m), shift, imm5, ir.GetCFlag()).result;
588     const auto address = GetAddress(ir, P, U, W, n, offset);
589     ir.WriteMemory32(address, ir.GetRegister(t));
590     return true;
591 }
592 
593 // STRB <Rt>, [<Rn>, #+/-<imm>]{!}
594 // STRB <Rt>, [<Rn>], #+/-<imm>
arm_STRB_imm(Cond cond,bool P,bool U,bool W,Reg n,Reg t,Imm<12> imm12)595 bool ArmTranslatorVisitor::arm_STRB_imm(Cond cond, bool P, bool U, bool W, Reg n, Reg t, Imm<12> imm12) {
596     if (t == Reg::PC) {
597         return UnpredictableInstruction();
598     }
599 
600     if ((!P || W) && (n == Reg::PC || n == t)) {
601         return UnpredictableInstruction();
602     }
603 
604     if (!ConditionPassed(cond)) {
605         return true;
606     }
607 
608     const auto offset = ir.Imm32(imm12.ZeroExtend());
609     const auto address = GetAddress(ir, P, U, W, n, offset);
610     ir.WriteMemory8(address, ir.LeastSignificantByte(ir.GetRegister(t)));
611     return true;
612 }
613 
614 // STRB <Rt>, [<Rn>, #+/-<Rm>]{!}
615 // STRB <Rt>, [<Rn>], #+/-<Rm>
arm_STRB_reg(Cond cond,bool P,bool U,bool W,Reg n,Reg t,Imm<5> imm5,ShiftType shift,Reg m)616 bool ArmTranslatorVisitor::arm_STRB_reg(Cond cond, bool P, bool U, bool W, Reg n, Reg t, Imm<5> imm5, ShiftType shift, Reg m) {
617     if (t == Reg::PC || m == Reg::PC) {
618         return UnpredictableInstruction();
619     }
620 
621     if ((!P || W) && (n == Reg::PC || n == t)) {
622         return UnpredictableInstruction();
623     }
624 
625     if (!ConditionPassed(cond)) {
626         return true;
627     }
628 
629     const auto offset = EmitImmShift(ir.GetRegister(m), shift, imm5, ir.GetCFlag()).result;
630     const auto address = GetAddress(ir, P, U, W, n, offset);
631     ir.WriteMemory8(address, ir.LeastSignificantByte(ir.GetRegister(t)));
632     return true;
633 }
634 
635 // STRD <Rt>, [<Rn>, #+/-<imm>]{!}
636 // STRD <Rt>, [<Rn>], #+/-<imm>
arm_STRD_imm(Cond cond,bool P,bool U,bool W,Reg n,Reg t,Imm<4> imm8a,Imm<4> imm8b)637 bool ArmTranslatorVisitor::arm_STRD_imm(Cond cond, bool P, bool U, bool W, Reg n, Reg t, Imm<4> imm8a, Imm<4> imm8b) {
638     if (size_t(t) % 2 != 0) {
639         return UnpredictableInstruction();
640     }
641 
642     if (!P && W) {
643         return UnpredictableInstruction();
644     }
645 
646     const Reg t2 = t + 1;
647     if ((!P || W) && (n == Reg::PC || n == t || n == t2)) {
648         return UnpredictableInstruction();
649     }
650 
651     if (t2 == Reg::PC) {
652         return UnpredictableInstruction();
653     }
654 
655     if (!ConditionPassed(cond)) {
656         return true;
657     }
658 
659     const u32 imm32 = concatenate(imm8a, imm8b).ZeroExtend();
660     const auto offset = ir.Imm32(imm32);
661     const auto address_a = GetAddress(ir, P, U, W, n, offset);
662     const auto address_b = ir.Add(address_a, ir.Imm32(4));
663     const auto value_a = ir.GetRegister(t);
664     const auto value_b = ir.GetRegister(t2);
665 
666     ir.WriteMemory32(address_a, value_a);
667     ir.WriteMemory32(address_b, value_b);
668     return true;
669 }
670 
671 // STRD <Rt>, [<Rn>, #+/-<Rm>]{!}
672 // STRD <Rt>, [<Rn>], #+/-<Rm>
arm_STRD_reg(Cond cond,bool P,bool U,bool W,Reg n,Reg t,Reg m)673 bool ArmTranslatorVisitor::arm_STRD_reg(Cond cond, bool P, bool U, bool W, Reg n, Reg t, Reg m) {
674     if (size_t(t) % 2 != 0) {
675         return UnpredictableInstruction();
676     }
677 
678     if (!P && W) {
679         return UnpredictableInstruction();
680     }
681 
682     const Reg t2 = t + 1;
683     if (t2 == Reg::PC || m == Reg::PC) {
684         return UnpredictableInstruction();
685     }
686 
687     if ((!P || W) && (n == Reg::PC || n == t || n == t2)) {
688         return UnpredictableInstruction();
689     }
690 
691     if (!ConditionPassed(cond)) {
692         return true;
693     }
694 
695     const auto offset = ir.GetRegister(m);
696     const auto address_a = GetAddress(ir, P, U, W, n, offset);
697     const auto address_b = ir.Add(address_a, ir.Imm32(4));
698     const auto value_a = ir.GetRegister(t);
699     const auto value_b = ir.GetRegister(t2);
700 
701     ir.WriteMemory32(address_a, value_a);
702     ir.WriteMemory32(address_b, value_b);
703     return true;
704 }
705 
706 // STRH <Rt>, [<Rn>, #+/-<imm>]{!}
707 // STRH <Rt>, [<Rn>], #+/-<imm>
arm_STRH_imm(Cond cond,bool P,bool U,bool W,Reg n,Reg t,Imm<4> imm8a,Imm<4> imm8b)708 bool ArmTranslatorVisitor::arm_STRH_imm(Cond cond, bool P, bool U, bool W, Reg n, Reg t, Imm<4> imm8a, Imm<4> imm8b) {
709     if (t == Reg::PC) {
710         return UnpredictableInstruction();
711     }
712 
713     if ((!P || W) && (n == Reg::PC || n == t)) {
714         return UnpredictableInstruction();
715     }
716 
717     if (!ConditionPassed(cond)) {
718         return true;
719     }
720 
721     const u32 imm32 = concatenate(imm8a, imm8b).ZeroExtend();
722     const auto offset = ir.Imm32(imm32);
723     const auto address = GetAddress(ir, P, U, W, n, offset);
724 
725     ir.WriteMemory16(address, ir.LeastSignificantHalf(ir.GetRegister(t)));
726     return true;
727 }
728 
729 // STRH <Rt>, [<Rn>, #+/-<Rm>]{!}
730 // STRH <Rt>, [<Rn>], #+/-<Rm>
arm_STRH_reg(Cond cond,bool P,bool U,bool W,Reg n,Reg t,Reg m)731 bool ArmTranslatorVisitor::arm_STRH_reg(Cond cond, bool P, bool U, bool W, Reg n, Reg t, Reg m) {
732     if (t == Reg::PC || m == Reg::PC) {
733         return UnpredictableInstruction();
734     }
735 
736     if ((!P || W) && (n == Reg::PC || n == t)) {
737         return UnpredictableInstruction();
738     }
739 
740     if (!ConditionPassed(cond)) {
741         return true;
742     }
743 
744     const auto offset = ir.GetRegister(m);
745     const auto address = GetAddress(ir, P, U, W, n, offset);
746 
747     ir.WriteMemory16(address, ir.LeastSignificantHalf(ir.GetRegister(t)));
748     return true;
749 }
750 
LDMHelper(A32::IREmitter & ir,bool W,Reg n,RegList list,IR::U32 start_address,IR::U32 writeback_address)751 static bool LDMHelper(A32::IREmitter& ir, bool W, Reg n, RegList list, IR::U32 start_address, IR::U32 writeback_address) {
752     auto address = start_address;
753     for (size_t i = 0; i <= 14; i++) {
754         if (Common::Bit(i, list)) {
755             ir.SetRegister(static_cast<Reg>(i), ir.ReadMemory32(address));
756             address = ir.Add(address, ir.Imm32(4));
757         }
758     }
759     if (W && !Common::Bit(RegNumber(n), list)) {
760         ir.SetRegister(n, writeback_address);
761     }
762     if (Common::Bit<15>(list)) {
763         ir.LoadWritePC(ir.ReadMemory32(address));
764         if (n == Reg::R13)
765             ir.SetTerm(IR::Term::PopRSBHint{});
766         else
767             ir.SetTerm(IR::Term::FastDispatchHint{});
768         return false;
769     }
770     return true;
771 }
772 
773 // LDM <Rn>{!}, <reg_list>
arm_LDM(Cond cond,bool W,Reg n,RegList list)774 bool ArmTranslatorVisitor::arm_LDM(Cond cond, bool W, Reg n, RegList list) {
775     if (n == Reg::PC || Common::BitCount(list) < 1) {
776         return UnpredictableInstruction();
777     }
778     if (W && Common::Bit(static_cast<size_t>(n), list)) {
779         return UnpredictableInstruction();
780     }
781 
782     if (!ConditionPassed(cond)) {
783         return true;
784     }
785 
786     const auto start_address = ir.GetRegister(n);
787     const auto writeback_address = ir.Add(start_address, ir.Imm32(u32(Common::BitCount(list) * 4)));
788     return LDMHelper(ir, W, n, list, start_address, writeback_address);
789 }
790 
791 // LDMDA <Rn>{!}, <reg_list>
arm_LDMDA(Cond cond,bool W,Reg n,RegList list)792 bool ArmTranslatorVisitor::arm_LDMDA(Cond cond, bool W, Reg n, RegList list) {
793     if (n == Reg::PC || Common::BitCount(list) < 1) {
794         return UnpredictableInstruction();
795     }
796     if (W && Common::Bit(static_cast<size_t>(n), list)) {
797         return UnpredictableInstruction();
798     }
799 
800     if (!ConditionPassed(cond)) {
801         return true;
802     }
803 
804     const auto start_address = ir.Sub(ir.GetRegister(n), ir.Imm32(u32(4 * Common::BitCount(list) - 4)));
805     const auto writeback_address = ir.Sub(start_address, ir.Imm32(4));
806     return LDMHelper(ir, W, n, list, start_address, writeback_address);
807 }
808 
809 // LDMDB <Rn>{!}, <reg_list>
arm_LDMDB(Cond cond,bool W,Reg n,RegList list)810 bool ArmTranslatorVisitor::arm_LDMDB(Cond cond, bool W, Reg n, RegList list) {
811     if (n == Reg::PC || Common::BitCount(list) < 1) {
812         return UnpredictableInstruction();
813     }
814     if (W && Common::Bit(static_cast<size_t>(n), list)) {
815         return UnpredictableInstruction();
816     }
817 
818     if (!ConditionPassed(cond)) {
819         return true;
820     }
821 
822     const auto start_address = ir.Sub(ir.GetRegister(n), ir.Imm32(u32(4 * Common::BitCount(list))));
823     const auto writeback_address = start_address;
824     return LDMHelper(ir, W, n, list, start_address, writeback_address);
825 }
826 
827 // LDMIB <Rn>{!}, <reg_list>
arm_LDMIB(Cond cond,bool W,Reg n,RegList list)828 bool ArmTranslatorVisitor::arm_LDMIB(Cond cond, bool W, Reg n, RegList list) {
829     if (n == Reg::PC || Common::BitCount(list) < 1) {
830         return UnpredictableInstruction();
831     }
832     if (W && Common::Bit(static_cast<size_t>(n), list)) {
833         return UnpredictableInstruction();
834     }
835 
836     if (!ConditionPassed(cond)) {
837         return true;
838     }
839 
840     const auto start_address = ir.Add(ir.GetRegister(n), ir.Imm32(4));
841     const auto writeback_address = ir.Add(ir.GetRegister(n), ir.Imm32(u32(4 * Common::BitCount(list))));
842     return LDMHelper(ir, W, n, list, start_address, writeback_address);
843 }
844 
arm_LDM_usr()845 bool ArmTranslatorVisitor::arm_LDM_usr() {
846     return InterpretThisInstruction();
847 }
848 
arm_LDM_eret()849 bool ArmTranslatorVisitor::arm_LDM_eret() {
850     return InterpretThisInstruction();
851 }
852 
STMHelper(A32::IREmitter & ir,bool W,Reg n,RegList list,IR::U32 start_address,IR::U32 writeback_address)853 static bool STMHelper(A32::IREmitter& ir, bool W, Reg n, RegList list, IR::U32 start_address, IR::U32 writeback_address) {
854     auto address = start_address;
855     for (size_t i = 0; i <= 14; i++) {
856         if (Common::Bit(i, list)) {
857             ir.WriteMemory32(address, ir.GetRegister(static_cast<Reg>(i)));
858             address = ir.Add(address, ir.Imm32(4));
859         }
860     }
861     if (W) {
862         ir.SetRegister(n, writeback_address);
863     }
864     if (Common::Bit<15>(list)) {
865         ir.WriteMemory32(address, ir.Imm32(ir.PC()));
866     }
867     return true;
868 }
869 
870 // STM <Rn>{!}, <reg_list>
arm_STM(Cond cond,bool W,Reg n,RegList list)871 bool ArmTranslatorVisitor::arm_STM(Cond cond, bool W, Reg n, RegList list) {
872     if (n == Reg::PC || Common::BitCount(list) < 1) {
873         return UnpredictableInstruction();
874     }
875 
876     if (!ConditionPassed(cond)) {
877         return true;
878     }
879 
880     const auto start_address = ir.GetRegister(n);
881     const auto writeback_address = ir.Add(start_address, ir.Imm32(u32(Common::BitCount(list) * 4)));
882     return STMHelper(ir, W, n, list, start_address, writeback_address);
883 }
884 
885 // STMDA <Rn>{!}, <reg_list>
arm_STMDA(Cond cond,bool W,Reg n,RegList list)886 bool ArmTranslatorVisitor::arm_STMDA(Cond cond, bool W, Reg n, RegList list) {
887     if (n == Reg::PC || Common::BitCount(list) < 1) {
888         return UnpredictableInstruction();
889     }
890 
891     if (!ConditionPassed(cond)) {
892         return true;
893     }
894 
895     const auto start_address = ir.Sub(ir.GetRegister(n), ir.Imm32(u32(4 * Common::BitCount(list) - 4)));
896     const auto writeback_address = ir.Sub(start_address, ir.Imm32(4));
897     return STMHelper(ir, W, n, list, start_address, writeback_address);
898 }
899 
900 // STMDB <Rn>{!}, <reg_list>
arm_STMDB(Cond cond,bool W,Reg n,RegList list)901 bool ArmTranslatorVisitor::arm_STMDB(Cond cond, bool W, Reg n, RegList list) {
902     if (n == Reg::PC || Common::BitCount(list) < 1) {
903         return UnpredictableInstruction();
904     }
905 
906     if (!ConditionPassed(cond)) {
907         return true;
908     }
909 
910     const auto start_address = ir.Sub(ir.GetRegister(n), ir.Imm32(u32(4 * Common::BitCount(list))));
911     const auto writeback_address = start_address;
912     return STMHelper(ir, W, n, list, start_address, writeback_address);
913 }
914 
915 // STMIB <Rn>{!}, <reg_list>
arm_STMIB(Cond cond,bool W,Reg n,RegList list)916 bool ArmTranslatorVisitor::arm_STMIB(Cond cond, bool W, Reg n, RegList list) {
917     if (n == Reg::PC || Common::BitCount(list) < 1) {
918         return UnpredictableInstruction();
919     }
920 
921     if (!ConditionPassed(cond)) {
922         return true;
923     }
924 
925     const auto start_address = ir.Add(ir.GetRegister(n), ir.Imm32(4));
926     const auto writeback_address = ir.Add(ir.GetRegister(n), ir.Imm32(u32(4 * Common::BitCount(list))));
927     return STMHelper(ir, W, n, list, start_address, writeback_address);
928 }
929 
arm_STM_usr()930 bool ArmTranslatorVisitor::arm_STM_usr() {
931     return InterpretThisInstruction();
932 }
933 
934 } // namespace Dynarmic::A32
935