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