1 | //===-- EmulateInstructionARM.cpp -----------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include <cstdlib> |
10 | #include <optional> |
11 | |
12 | #include "EmulateInstructionARM.h" |
13 | #include "EmulationStateARM.h" |
14 | #include "lldb/Core/Address.h" |
15 | #include "lldb/Core/PluginManager.h" |
16 | #include "lldb/Host/PosixApi.h" |
17 | #include "lldb/Interpreter/OptionValueArray.h" |
18 | #include "lldb/Interpreter/OptionValueDictionary.h" |
19 | #include "lldb/Symbol/UnwindPlan.h" |
20 | #include "lldb/Utility/ArchSpec.h" |
21 | #include "lldb/Utility/Stream.h" |
22 | |
23 | #include "Plugins/Process/Utility/ARMDefines.h" |
24 | #include "Plugins/Process/Utility/ARMUtils.h" |
25 | #include "Utility/ARM_DWARF_Registers.h" |
26 | |
27 | #include "llvm/ADT/STLExtras.h" |
28 | #include "llvm/Support/MathExtras.h" |
29 | |
30 | using namespace lldb; |
31 | using namespace lldb_private; |
32 | |
33 | LLDB_PLUGIN_DEFINE_ADV(EmulateInstructionARM, InstructionARM) |
34 | |
35 | // Convenient macro definitions. |
36 | #define APSR_C Bit32(m_opcode_cpsr, CPSR_C_POS) |
37 | #define APSR_V Bit32(m_opcode_cpsr, CPSR_V_POS) |
38 | |
39 | #define AlignPC(pc_val) (pc_val & 0xFFFFFFFC) |
40 | |
41 | // |
42 | // ITSession implementation |
43 | // |
44 | |
45 | static std::optional<RegisterInfo> GetARMDWARFRegisterInfo(unsigned reg_num) { |
46 | RegisterInfo reg_info; |
47 | ::memset(s: ®_info, c: 0, n: sizeof(RegisterInfo)); |
48 | ::memset(s: reg_info.kinds, LLDB_INVALID_REGNUM, n: sizeof(reg_info.kinds)); |
49 | |
50 | if (reg_num >= dwarf_q0 && reg_num <= dwarf_q15) { |
51 | reg_info.byte_size = 16; |
52 | reg_info.format = eFormatVectorOfUInt8; |
53 | reg_info.encoding = eEncodingVector; |
54 | } |
55 | |
56 | if (reg_num >= dwarf_d0 && reg_num <= dwarf_d31) { |
57 | reg_info.byte_size = 8; |
58 | reg_info.format = eFormatFloat; |
59 | reg_info.encoding = eEncodingIEEE754; |
60 | } else if (reg_num >= dwarf_s0 && reg_num <= dwarf_s31) { |
61 | reg_info.byte_size = 4; |
62 | reg_info.format = eFormatFloat; |
63 | reg_info.encoding = eEncodingIEEE754; |
64 | } else if (reg_num >= dwarf_f0 && reg_num <= dwarf_f7) { |
65 | reg_info.byte_size = 12; |
66 | reg_info.format = eFormatFloat; |
67 | reg_info.encoding = eEncodingIEEE754; |
68 | } else { |
69 | reg_info.byte_size = 4; |
70 | reg_info.format = eFormatHex; |
71 | reg_info.encoding = eEncodingUint; |
72 | } |
73 | |
74 | reg_info.kinds[eRegisterKindDWARF] = reg_num; |
75 | |
76 | switch (reg_num) { |
77 | case dwarf_r0: |
78 | reg_info.name = "r0" ; |
79 | break; |
80 | case dwarf_r1: |
81 | reg_info.name = "r1" ; |
82 | break; |
83 | case dwarf_r2: |
84 | reg_info.name = "r2" ; |
85 | break; |
86 | case dwarf_r3: |
87 | reg_info.name = "r3" ; |
88 | break; |
89 | case dwarf_r4: |
90 | reg_info.name = "r4" ; |
91 | break; |
92 | case dwarf_r5: |
93 | reg_info.name = "r5" ; |
94 | break; |
95 | case dwarf_r6: |
96 | reg_info.name = "r6" ; |
97 | break; |
98 | case dwarf_r7: |
99 | reg_info.name = "r7" ; |
100 | reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FP; |
101 | break; |
102 | case dwarf_r8: |
103 | reg_info.name = "r8" ; |
104 | break; |
105 | case dwarf_r9: |
106 | reg_info.name = "r9" ; |
107 | break; |
108 | case dwarf_r10: |
109 | reg_info.name = "r10" ; |
110 | break; |
111 | case dwarf_r11: |
112 | reg_info.name = "r11" ; |
113 | break; |
114 | case dwarf_r12: |
115 | reg_info.name = "r12" ; |
116 | break; |
117 | case dwarf_sp: |
118 | reg_info.name = "sp" ; |
119 | reg_info.alt_name = "r13" ; |
120 | reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_SP; |
121 | break; |
122 | case dwarf_lr: |
123 | reg_info.name = "lr" ; |
124 | reg_info.alt_name = "r14" ; |
125 | reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_RA; |
126 | break; |
127 | case dwarf_pc: |
128 | reg_info.name = "pc" ; |
129 | reg_info.alt_name = "r15" ; |
130 | reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_PC; |
131 | break; |
132 | case dwarf_cpsr: |
133 | reg_info.name = "cpsr" ; |
134 | reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FLAGS; |
135 | break; |
136 | |
137 | case dwarf_s0: |
138 | reg_info.name = "s0" ; |
139 | break; |
140 | case dwarf_s1: |
141 | reg_info.name = "s1" ; |
142 | break; |
143 | case dwarf_s2: |
144 | reg_info.name = "s2" ; |
145 | break; |
146 | case dwarf_s3: |
147 | reg_info.name = "s3" ; |
148 | break; |
149 | case dwarf_s4: |
150 | reg_info.name = "s4" ; |
151 | break; |
152 | case dwarf_s5: |
153 | reg_info.name = "s5" ; |
154 | break; |
155 | case dwarf_s6: |
156 | reg_info.name = "s6" ; |
157 | break; |
158 | case dwarf_s7: |
159 | reg_info.name = "s7" ; |
160 | break; |
161 | case dwarf_s8: |
162 | reg_info.name = "s8" ; |
163 | break; |
164 | case dwarf_s9: |
165 | reg_info.name = "s9" ; |
166 | break; |
167 | case dwarf_s10: |
168 | reg_info.name = "s10" ; |
169 | break; |
170 | case dwarf_s11: |
171 | reg_info.name = "s11" ; |
172 | break; |
173 | case dwarf_s12: |
174 | reg_info.name = "s12" ; |
175 | break; |
176 | case dwarf_s13: |
177 | reg_info.name = "s13" ; |
178 | break; |
179 | case dwarf_s14: |
180 | reg_info.name = "s14" ; |
181 | break; |
182 | case dwarf_s15: |
183 | reg_info.name = "s15" ; |
184 | break; |
185 | case dwarf_s16: |
186 | reg_info.name = "s16" ; |
187 | break; |
188 | case dwarf_s17: |
189 | reg_info.name = "s17" ; |
190 | break; |
191 | case dwarf_s18: |
192 | reg_info.name = "s18" ; |
193 | break; |
194 | case dwarf_s19: |
195 | reg_info.name = "s19" ; |
196 | break; |
197 | case dwarf_s20: |
198 | reg_info.name = "s20" ; |
199 | break; |
200 | case dwarf_s21: |
201 | reg_info.name = "s21" ; |
202 | break; |
203 | case dwarf_s22: |
204 | reg_info.name = "s22" ; |
205 | break; |
206 | case dwarf_s23: |
207 | reg_info.name = "s23" ; |
208 | break; |
209 | case dwarf_s24: |
210 | reg_info.name = "s24" ; |
211 | break; |
212 | case dwarf_s25: |
213 | reg_info.name = "s25" ; |
214 | break; |
215 | case dwarf_s26: |
216 | reg_info.name = "s26" ; |
217 | break; |
218 | case dwarf_s27: |
219 | reg_info.name = "s27" ; |
220 | break; |
221 | case dwarf_s28: |
222 | reg_info.name = "s28" ; |
223 | break; |
224 | case dwarf_s29: |
225 | reg_info.name = "s29" ; |
226 | break; |
227 | case dwarf_s30: |
228 | reg_info.name = "s30" ; |
229 | break; |
230 | case dwarf_s31: |
231 | reg_info.name = "s31" ; |
232 | break; |
233 | |
234 | // FPA Registers 0-7 |
235 | case dwarf_f0: |
236 | reg_info.name = "f0" ; |
237 | break; |
238 | case dwarf_f1: |
239 | reg_info.name = "f1" ; |
240 | break; |
241 | case dwarf_f2: |
242 | reg_info.name = "f2" ; |
243 | break; |
244 | case dwarf_f3: |
245 | reg_info.name = "f3" ; |
246 | break; |
247 | case dwarf_f4: |
248 | reg_info.name = "f4" ; |
249 | break; |
250 | case dwarf_f5: |
251 | reg_info.name = "f5" ; |
252 | break; |
253 | case dwarf_f6: |
254 | reg_info.name = "f6" ; |
255 | break; |
256 | case dwarf_f7: |
257 | reg_info.name = "f7" ; |
258 | break; |
259 | |
260 | // Intel wireless MMX general purpose registers 0 - 7 XScale accumulator |
261 | // register 0 - 7 (they do overlap with wCGR0 - wCGR7) |
262 | case dwarf_wCGR0: |
263 | reg_info.name = "wCGR0/ACC0" ; |
264 | break; |
265 | case dwarf_wCGR1: |
266 | reg_info.name = "wCGR1/ACC1" ; |
267 | break; |
268 | case dwarf_wCGR2: |
269 | reg_info.name = "wCGR2/ACC2" ; |
270 | break; |
271 | case dwarf_wCGR3: |
272 | reg_info.name = "wCGR3/ACC3" ; |
273 | break; |
274 | case dwarf_wCGR4: |
275 | reg_info.name = "wCGR4/ACC4" ; |
276 | break; |
277 | case dwarf_wCGR5: |
278 | reg_info.name = "wCGR5/ACC5" ; |
279 | break; |
280 | case dwarf_wCGR6: |
281 | reg_info.name = "wCGR6/ACC6" ; |
282 | break; |
283 | case dwarf_wCGR7: |
284 | reg_info.name = "wCGR7/ACC7" ; |
285 | break; |
286 | |
287 | // Intel wireless MMX data registers 0 - 15 |
288 | case dwarf_wR0: |
289 | reg_info.name = "wR0" ; |
290 | break; |
291 | case dwarf_wR1: |
292 | reg_info.name = "wR1" ; |
293 | break; |
294 | case dwarf_wR2: |
295 | reg_info.name = "wR2" ; |
296 | break; |
297 | case dwarf_wR3: |
298 | reg_info.name = "wR3" ; |
299 | break; |
300 | case dwarf_wR4: |
301 | reg_info.name = "wR4" ; |
302 | break; |
303 | case dwarf_wR5: |
304 | reg_info.name = "wR5" ; |
305 | break; |
306 | case dwarf_wR6: |
307 | reg_info.name = "wR6" ; |
308 | break; |
309 | case dwarf_wR7: |
310 | reg_info.name = "wR7" ; |
311 | break; |
312 | case dwarf_wR8: |
313 | reg_info.name = "wR8" ; |
314 | break; |
315 | case dwarf_wR9: |
316 | reg_info.name = "wR9" ; |
317 | break; |
318 | case dwarf_wR10: |
319 | reg_info.name = "wR10" ; |
320 | break; |
321 | case dwarf_wR11: |
322 | reg_info.name = "wR11" ; |
323 | break; |
324 | case dwarf_wR12: |
325 | reg_info.name = "wR12" ; |
326 | break; |
327 | case dwarf_wR13: |
328 | reg_info.name = "wR13" ; |
329 | break; |
330 | case dwarf_wR14: |
331 | reg_info.name = "wR14" ; |
332 | break; |
333 | case dwarf_wR15: |
334 | reg_info.name = "wR15" ; |
335 | break; |
336 | |
337 | case dwarf_spsr: |
338 | reg_info.name = "spsr" ; |
339 | break; |
340 | case dwarf_spsr_fiq: |
341 | reg_info.name = "spsr_fiq" ; |
342 | break; |
343 | case dwarf_spsr_irq: |
344 | reg_info.name = "spsr_irq" ; |
345 | break; |
346 | case dwarf_spsr_abt: |
347 | reg_info.name = "spsr_abt" ; |
348 | break; |
349 | case dwarf_spsr_und: |
350 | reg_info.name = "spsr_und" ; |
351 | break; |
352 | case dwarf_spsr_svc: |
353 | reg_info.name = "spsr_svc" ; |
354 | break; |
355 | |
356 | case dwarf_r8_usr: |
357 | reg_info.name = "r8_usr" ; |
358 | break; |
359 | case dwarf_r9_usr: |
360 | reg_info.name = "r9_usr" ; |
361 | break; |
362 | case dwarf_r10_usr: |
363 | reg_info.name = "r10_usr" ; |
364 | break; |
365 | case dwarf_r11_usr: |
366 | reg_info.name = "r11_usr" ; |
367 | break; |
368 | case dwarf_r12_usr: |
369 | reg_info.name = "r12_usr" ; |
370 | break; |
371 | case dwarf_r13_usr: |
372 | reg_info.name = "r13_usr" ; |
373 | break; |
374 | case dwarf_r14_usr: |
375 | reg_info.name = "r14_usr" ; |
376 | break; |
377 | case dwarf_r8_fiq: |
378 | reg_info.name = "r8_fiq" ; |
379 | break; |
380 | case dwarf_r9_fiq: |
381 | reg_info.name = "r9_fiq" ; |
382 | break; |
383 | case dwarf_r10_fiq: |
384 | reg_info.name = "r10_fiq" ; |
385 | break; |
386 | case dwarf_r11_fiq: |
387 | reg_info.name = "r11_fiq" ; |
388 | break; |
389 | case dwarf_r12_fiq: |
390 | reg_info.name = "r12_fiq" ; |
391 | break; |
392 | case dwarf_r13_fiq: |
393 | reg_info.name = "r13_fiq" ; |
394 | break; |
395 | case dwarf_r14_fiq: |
396 | reg_info.name = "r14_fiq" ; |
397 | break; |
398 | case dwarf_r13_irq: |
399 | reg_info.name = "r13_irq" ; |
400 | break; |
401 | case dwarf_r14_irq: |
402 | reg_info.name = "r14_irq" ; |
403 | break; |
404 | case dwarf_r13_abt: |
405 | reg_info.name = "r13_abt" ; |
406 | break; |
407 | case dwarf_r14_abt: |
408 | reg_info.name = "r14_abt" ; |
409 | break; |
410 | case dwarf_r13_und: |
411 | reg_info.name = "r13_und" ; |
412 | break; |
413 | case dwarf_r14_und: |
414 | reg_info.name = "r14_und" ; |
415 | break; |
416 | case dwarf_r13_svc: |
417 | reg_info.name = "r13_svc" ; |
418 | break; |
419 | case dwarf_r14_svc: |
420 | reg_info.name = "r14_svc" ; |
421 | break; |
422 | |
423 | // Intel wireless MMX control register in co-processor 0 - 7 |
424 | case dwarf_wC0: |
425 | reg_info.name = "wC0" ; |
426 | break; |
427 | case dwarf_wC1: |
428 | reg_info.name = "wC1" ; |
429 | break; |
430 | case dwarf_wC2: |
431 | reg_info.name = "wC2" ; |
432 | break; |
433 | case dwarf_wC3: |
434 | reg_info.name = "wC3" ; |
435 | break; |
436 | case dwarf_wC4: |
437 | reg_info.name = "wC4" ; |
438 | break; |
439 | case dwarf_wC5: |
440 | reg_info.name = "wC5" ; |
441 | break; |
442 | case dwarf_wC6: |
443 | reg_info.name = "wC6" ; |
444 | break; |
445 | case dwarf_wC7: |
446 | reg_info.name = "wC7" ; |
447 | break; |
448 | |
449 | // VFP-v3/Neon |
450 | case dwarf_d0: |
451 | reg_info.name = "d0" ; |
452 | break; |
453 | case dwarf_d1: |
454 | reg_info.name = "d1" ; |
455 | break; |
456 | case dwarf_d2: |
457 | reg_info.name = "d2" ; |
458 | break; |
459 | case dwarf_d3: |
460 | reg_info.name = "d3" ; |
461 | break; |
462 | case dwarf_d4: |
463 | reg_info.name = "d4" ; |
464 | break; |
465 | case dwarf_d5: |
466 | reg_info.name = "d5" ; |
467 | break; |
468 | case dwarf_d6: |
469 | reg_info.name = "d6" ; |
470 | break; |
471 | case dwarf_d7: |
472 | reg_info.name = "d7" ; |
473 | break; |
474 | case dwarf_d8: |
475 | reg_info.name = "d8" ; |
476 | break; |
477 | case dwarf_d9: |
478 | reg_info.name = "d9" ; |
479 | break; |
480 | case dwarf_d10: |
481 | reg_info.name = "d10" ; |
482 | break; |
483 | case dwarf_d11: |
484 | reg_info.name = "d11" ; |
485 | break; |
486 | case dwarf_d12: |
487 | reg_info.name = "d12" ; |
488 | break; |
489 | case dwarf_d13: |
490 | reg_info.name = "d13" ; |
491 | break; |
492 | case dwarf_d14: |
493 | reg_info.name = "d14" ; |
494 | break; |
495 | case dwarf_d15: |
496 | reg_info.name = "d15" ; |
497 | break; |
498 | case dwarf_d16: |
499 | reg_info.name = "d16" ; |
500 | break; |
501 | case dwarf_d17: |
502 | reg_info.name = "d17" ; |
503 | break; |
504 | case dwarf_d18: |
505 | reg_info.name = "d18" ; |
506 | break; |
507 | case dwarf_d19: |
508 | reg_info.name = "d19" ; |
509 | break; |
510 | case dwarf_d20: |
511 | reg_info.name = "d20" ; |
512 | break; |
513 | case dwarf_d21: |
514 | reg_info.name = "d21" ; |
515 | break; |
516 | case dwarf_d22: |
517 | reg_info.name = "d22" ; |
518 | break; |
519 | case dwarf_d23: |
520 | reg_info.name = "d23" ; |
521 | break; |
522 | case dwarf_d24: |
523 | reg_info.name = "d24" ; |
524 | break; |
525 | case dwarf_d25: |
526 | reg_info.name = "d25" ; |
527 | break; |
528 | case dwarf_d26: |
529 | reg_info.name = "d26" ; |
530 | break; |
531 | case dwarf_d27: |
532 | reg_info.name = "d27" ; |
533 | break; |
534 | case dwarf_d28: |
535 | reg_info.name = "d28" ; |
536 | break; |
537 | case dwarf_d29: |
538 | reg_info.name = "d29" ; |
539 | break; |
540 | case dwarf_d30: |
541 | reg_info.name = "d30" ; |
542 | break; |
543 | case dwarf_d31: |
544 | reg_info.name = "d31" ; |
545 | break; |
546 | |
547 | // NEON 128-bit vector registers (overlays the d registers) |
548 | case dwarf_q0: |
549 | reg_info.name = "q0" ; |
550 | break; |
551 | case dwarf_q1: |
552 | reg_info.name = "q1" ; |
553 | break; |
554 | case dwarf_q2: |
555 | reg_info.name = "q2" ; |
556 | break; |
557 | case dwarf_q3: |
558 | reg_info.name = "q3" ; |
559 | break; |
560 | case dwarf_q4: |
561 | reg_info.name = "q4" ; |
562 | break; |
563 | case dwarf_q5: |
564 | reg_info.name = "q5" ; |
565 | break; |
566 | case dwarf_q6: |
567 | reg_info.name = "q6" ; |
568 | break; |
569 | case dwarf_q7: |
570 | reg_info.name = "q7" ; |
571 | break; |
572 | case dwarf_q8: |
573 | reg_info.name = "q8" ; |
574 | break; |
575 | case dwarf_q9: |
576 | reg_info.name = "q9" ; |
577 | break; |
578 | case dwarf_q10: |
579 | reg_info.name = "q10" ; |
580 | break; |
581 | case dwarf_q11: |
582 | reg_info.name = "q11" ; |
583 | break; |
584 | case dwarf_q12: |
585 | reg_info.name = "q12" ; |
586 | break; |
587 | case dwarf_q13: |
588 | reg_info.name = "q13" ; |
589 | break; |
590 | case dwarf_q14: |
591 | reg_info.name = "q14" ; |
592 | break; |
593 | case dwarf_q15: |
594 | reg_info.name = "q15" ; |
595 | break; |
596 | |
597 | default: |
598 | return {}; |
599 | } |
600 | return reg_info; |
601 | } |
602 | |
603 | // A8.6.50 |
604 | // Valid return values are {1, 2, 3, 4}, with 0 signifying an error condition. |
605 | static uint32_t CountITSize(uint32_t ITMask) { |
606 | // First count the trailing zeros of the IT mask. |
607 | uint32_t TZ = llvm::countr_zero(Val: ITMask); |
608 | if (TZ > 3) { |
609 | return 0; |
610 | } |
611 | return (4 - TZ); |
612 | } |
613 | |
614 | // Init ITState. Note that at least one bit is always 1 in mask. |
615 | bool ITSession::InitIT(uint32_t bits7_0) { |
616 | ITCounter = CountITSize(ITMask: Bits32(bits: bits7_0, msbit: 3, lsbit: 0)); |
617 | if (ITCounter == 0) |
618 | return false; |
619 | |
620 | // A8.6.50 IT |
621 | unsigned short FirstCond = Bits32(bits: bits7_0, msbit: 7, lsbit: 4); |
622 | if (FirstCond == 0xF) { |
623 | return false; |
624 | } |
625 | if (FirstCond == 0xE && ITCounter != 1) { |
626 | return false; |
627 | } |
628 | |
629 | ITState = bits7_0; |
630 | return true; |
631 | } |
632 | |
633 | // Update ITState if necessary. |
634 | void ITSession::ITAdvance() { |
635 | // assert(ITCounter); |
636 | --ITCounter; |
637 | if (ITCounter == 0) |
638 | ITState = 0; |
639 | else { |
640 | unsigned short NewITState4_0 = Bits32(bits: ITState, msbit: 4, lsbit: 0) << 1; |
641 | SetBits32(bits&: ITState, msbit: 4, lsbit: 0, val: NewITState4_0); |
642 | } |
643 | } |
644 | |
645 | // Return true if we're inside an IT Block. |
646 | bool ITSession::InITBlock() { return ITCounter != 0; } |
647 | |
648 | // Return true if we're the last instruction inside an IT Block. |
649 | bool ITSession::LastInITBlock() { return ITCounter == 1; } |
650 | |
651 | // Get condition bits for the current thumb instruction. |
652 | uint32_t ITSession::GetCond() { |
653 | if (InITBlock()) |
654 | return Bits32(bits: ITState, msbit: 7, lsbit: 4); |
655 | else |
656 | return COND_AL; |
657 | } |
658 | |
659 | // ARM constants used during decoding |
660 | #define REG_RD 0 |
661 | #define LDM_REGLIST 1 |
662 | #define SP_REG 13 |
663 | #define LR_REG 14 |
664 | #define PC_REG 15 |
665 | #define PC_REGLIST_BIT 0x8000 |
666 | |
667 | #define ARMv4 (1u << 0) |
668 | #define ARMv4T (1u << 1) |
669 | #define ARMv5T (1u << 2) |
670 | #define ARMv5TE (1u << 3) |
671 | #define ARMv5TEJ (1u << 4) |
672 | #define ARMv6 (1u << 5) |
673 | #define ARMv6K (1u << 6) |
674 | #define ARMv6T2 (1u << 7) |
675 | #define ARMv7 (1u << 8) |
676 | #define ARMv7S (1u << 9) |
677 | #define ARMv8 (1u << 10) |
678 | #define ARMvAll (0xffffffffu) |
679 | |
680 | #define ARMV4T_ABOVE \ |
681 | (ARMv4T | ARMv5T | ARMv5TE | ARMv5TEJ | ARMv6 | ARMv6K | ARMv6T2 | ARMv7 | \ |
682 | ARMv7S | ARMv8) |
683 | #define ARMV5_ABOVE \ |
684 | (ARMv5T | ARMv5TE | ARMv5TEJ | ARMv6 | ARMv6K | ARMv6T2 | ARMv7 | ARMv7S | \ |
685 | ARMv8) |
686 | #define ARMV5TE_ABOVE \ |
687 | (ARMv5TE | ARMv5TEJ | ARMv6 | ARMv6K | ARMv6T2 | ARMv7 | ARMv7S | ARMv8) |
688 | #define ARMV5J_ABOVE \ |
689 | (ARMv5TEJ | ARMv6 | ARMv6K | ARMv6T2 | ARMv7 | ARMv7S | ARMv8) |
690 | #define ARMV6_ABOVE (ARMv6 | ARMv6K | ARMv6T2 | ARMv7 | ARMv7S | ARMv8) |
691 | #define ARMV6T2_ABOVE (ARMv6T2 | ARMv7 | ARMv7S | ARMv8) |
692 | #define ARMV7_ABOVE (ARMv7 | ARMv7S | ARMv8) |
693 | |
694 | #define No_VFP 0 |
695 | #define VFPv1 (1u << 1) |
696 | #define VFPv2 (1u << 2) |
697 | #define VFPv3 (1u << 3) |
698 | #define AdvancedSIMD (1u << 4) |
699 | |
700 | #define VFPv1_ABOVE (VFPv1 | VFPv2 | VFPv3 | AdvancedSIMD) |
701 | #define VFPv2_ABOVE (VFPv2 | VFPv3 | AdvancedSIMD) |
702 | #define VFPv2v3 (VFPv2 | VFPv3) |
703 | |
704 | // |
705 | // EmulateInstructionARM implementation |
706 | // |
707 | |
708 | void EmulateInstructionARM::Initialize() { |
709 | PluginManager::RegisterPlugin(name: GetPluginNameStatic(), |
710 | description: GetPluginDescriptionStatic(), create_callback: CreateInstance); |
711 | } |
712 | |
713 | void EmulateInstructionARM::Terminate() { |
714 | PluginManager::UnregisterPlugin(create_callback: CreateInstance); |
715 | } |
716 | |
717 | llvm::StringRef EmulateInstructionARM::GetPluginDescriptionStatic() { |
718 | return "Emulate instructions for the ARM architecture." ; |
719 | } |
720 | |
721 | EmulateInstruction * |
722 | EmulateInstructionARM::CreateInstance(const ArchSpec &arch, |
723 | InstructionType inst_type) { |
724 | if (EmulateInstructionARM::SupportsEmulatingInstructionsOfTypeStatic( |
725 | inst_type)) { |
726 | if (arch.GetTriple().getArch() == llvm::Triple::arm) { |
727 | std::unique_ptr<EmulateInstructionARM> emulate_insn_up( |
728 | new EmulateInstructionARM(arch)); |
729 | |
730 | if (emulate_insn_up) |
731 | return emulate_insn_up.release(); |
732 | } else if (arch.GetTriple().getArch() == llvm::Triple::thumb) { |
733 | std::unique_ptr<EmulateInstructionARM> emulate_insn_up( |
734 | new EmulateInstructionARM(arch)); |
735 | |
736 | if (emulate_insn_up) |
737 | return emulate_insn_up.release(); |
738 | } |
739 | } |
740 | |
741 | return nullptr; |
742 | } |
743 | |
744 | bool EmulateInstructionARM::SetTargetTriple(const ArchSpec &arch) { |
745 | if (arch.GetTriple().getArch() == llvm::Triple::arm) |
746 | return true; |
747 | else if (arch.GetTriple().getArch() == llvm::Triple::thumb) |
748 | return true; |
749 | |
750 | return false; |
751 | } |
752 | |
753 | // Write "bits (32) UNKNOWN" to memory address "address". Helper function for |
754 | // many ARM instructions. |
755 | bool EmulateInstructionARM::WriteBits32UnknownToMemory(addr_t address) { |
756 | EmulateInstruction::Context context; |
757 | context.type = EmulateInstruction::eContextWriteMemoryRandomBits; |
758 | context.SetNoArgs(); |
759 | |
760 | uint32_t random_data = rand(); |
761 | const uint32_t addr_byte_size = GetAddressByteSize(); |
762 | |
763 | return MemAWrite(context, address, data_val: random_data, size: addr_byte_size); |
764 | } |
765 | |
766 | // Write "bits (32) UNKNOWN" to register n. Helper function for many ARM |
767 | // instructions. |
768 | bool EmulateInstructionARM::WriteBits32Unknown(int n) { |
769 | EmulateInstruction::Context context; |
770 | context.type = EmulateInstruction::eContextWriteRegisterRandomBits; |
771 | context.SetNoArgs(); |
772 | |
773 | bool success; |
774 | uint32_t data = |
775 | ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n, fail_value: 0, success_ptr: &success); |
776 | |
777 | if (!success) |
778 | return false; |
779 | |
780 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n, reg_value: data)) |
781 | return false; |
782 | |
783 | return true; |
784 | } |
785 | |
786 | std::optional<RegisterInfo> |
787 | EmulateInstructionARM::GetRegisterInfo(lldb::RegisterKind reg_kind, |
788 | uint32_t reg_num) { |
789 | if (reg_kind == eRegisterKindGeneric) { |
790 | switch (reg_num) { |
791 | case LLDB_REGNUM_GENERIC_PC: |
792 | reg_kind = eRegisterKindDWARF; |
793 | reg_num = dwarf_pc; |
794 | break; |
795 | case LLDB_REGNUM_GENERIC_SP: |
796 | reg_kind = eRegisterKindDWARF; |
797 | reg_num = dwarf_sp; |
798 | break; |
799 | case LLDB_REGNUM_GENERIC_FP: |
800 | reg_kind = eRegisterKindDWARF; |
801 | reg_num = dwarf_r7; |
802 | break; |
803 | case LLDB_REGNUM_GENERIC_RA: |
804 | reg_kind = eRegisterKindDWARF; |
805 | reg_num = dwarf_lr; |
806 | break; |
807 | case LLDB_REGNUM_GENERIC_FLAGS: |
808 | reg_kind = eRegisterKindDWARF; |
809 | reg_num = dwarf_cpsr; |
810 | break; |
811 | default: |
812 | return {}; |
813 | } |
814 | } |
815 | |
816 | if (reg_kind == eRegisterKindDWARF) |
817 | return GetARMDWARFRegisterInfo(reg_num); |
818 | return {}; |
819 | } |
820 | |
821 | uint32_t EmulateInstructionARM::GetFramePointerRegisterNumber() const { |
822 | if (m_arch.GetTriple().isAndroid()) |
823 | return LLDB_INVALID_REGNUM; // Don't use frame pointer on android |
824 | bool is_apple = false; |
825 | if (m_arch.GetTriple().getVendor() == llvm::Triple::Apple) |
826 | is_apple = true; |
827 | switch (m_arch.GetTriple().getOS()) { |
828 | case llvm::Triple::Darwin: |
829 | case llvm::Triple::MacOSX: |
830 | case llvm::Triple::IOS: |
831 | case llvm::Triple::TvOS: |
832 | case llvm::Triple::WatchOS: |
833 | case llvm::Triple::XROS: |
834 | case llvm::Triple::BridgeOS: |
835 | is_apple = true; |
836 | break; |
837 | default: |
838 | break; |
839 | } |
840 | |
841 | /* On Apple iOS et al, the frame pointer register is always r7. |
842 | * Typically on other ARM systems, thumb code uses r7; arm code uses r11. |
843 | * Windows on ARM, which is in thumb mode, uses r11 though. |
844 | */ |
845 | |
846 | uint32_t fp_regnum = 11; |
847 | |
848 | if (is_apple) |
849 | fp_regnum = 7; |
850 | |
851 | if (m_opcode_mode == eModeThumb && !m_arch.GetTriple().isOSWindows()) |
852 | fp_regnum = 7; |
853 | |
854 | return fp_regnum; |
855 | } |
856 | |
857 | uint32_t EmulateInstructionARM::GetFramePointerDWARFRegisterNumber() const { |
858 | bool is_apple = false; |
859 | if (m_arch.GetTriple().getVendor() == llvm::Triple::Apple) |
860 | is_apple = true; |
861 | switch (m_arch.GetTriple().getOS()) { |
862 | case llvm::Triple::Darwin: |
863 | case llvm::Triple::MacOSX: |
864 | case llvm::Triple::IOS: |
865 | is_apple = true; |
866 | break; |
867 | default: |
868 | break; |
869 | } |
870 | |
871 | /* On Apple iOS et al, the frame pointer register is always r7. |
872 | * Typically on other ARM systems, thumb code uses r7; arm code uses r11. |
873 | * Windows on ARM, which is in thumb mode, uses r11 though. |
874 | */ |
875 | |
876 | uint32_t fp_regnum = dwarf_r11; |
877 | |
878 | if (is_apple) |
879 | fp_regnum = dwarf_r7; |
880 | |
881 | if (m_opcode_mode == eModeThumb && !m_arch.GetTriple().isOSWindows()) |
882 | fp_regnum = dwarf_r7; |
883 | |
884 | return fp_regnum; |
885 | } |
886 | |
887 | // Push Multiple Registers stores multiple registers to the stack, storing to |
888 | // consecutive memory locations ending just below the address in SP, and |
889 | // updates |
890 | // SP to point to the start of the stored data. |
891 | bool EmulateInstructionARM::EmulatePUSH(const uint32_t opcode, |
892 | const ARMEncoding encoding) { |
893 | #if 0 |
894 | // ARM pseudo code... |
895 | if (ConditionPassed()) |
896 | { |
897 | EncodingSpecificOperations(); |
898 | NullCheckIfThumbEE(13); |
899 | address = SP - 4*BitCount(registers); |
900 | |
901 | for (i = 0 to 14) |
902 | { |
903 | if (registers<i> == '1') |
904 | { |
905 | if i == 13 && i != LowestSetBit(registers) // Only possible for encoding A1 |
906 | MemA[address,4] = bits(32) UNKNOWN; |
907 | else |
908 | MemA[address,4] = R[i]; |
909 | address = address + 4; |
910 | } |
911 | } |
912 | |
913 | if (registers<15> == '1') // Only possible for encoding A1 or A2 |
914 | MemA[address,4] = PCStoreValue(); |
915 | |
916 | SP = SP - 4*BitCount(registers); |
917 | } |
918 | #endif |
919 | |
920 | bool success = false; |
921 | if (ConditionPassed(opcode)) { |
922 | const uint32_t addr_byte_size = GetAddressByteSize(); |
923 | const addr_t sp = ReadCoreReg(SP_REG, success: &success); |
924 | if (!success) |
925 | return false; |
926 | uint32_t registers = 0; |
927 | uint32_t Rt; // the source register |
928 | switch (encoding) { |
929 | case eEncodingT1: |
930 | registers = Bits32(bits: opcode, msbit: 7, lsbit: 0); |
931 | // The M bit represents LR. |
932 | if (Bit32(bits: opcode, bit: 8)) |
933 | registers |= (1u << 14); |
934 | // if BitCount(registers) < 1 then UNPREDICTABLE; |
935 | if (BitCount(x: registers) < 1) |
936 | return false; |
937 | break; |
938 | case eEncodingT2: |
939 | // Ignore bits 15 & 13. |
940 | registers = Bits32(bits: opcode, msbit: 15, lsbit: 0) & ~0xa000; |
941 | // if BitCount(registers) < 2 then UNPREDICTABLE; |
942 | if (BitCount(x: registers) < 2) |
943 | return false; |
944 | break; |
945 | case eEncodingT3: |
946 | Rt = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
947 | // if BadReg(t) then UNPREDICTABLE; |
948 | if (BadReg(n: Rt)) |
949 | return false; |
950 | registers = (1u << Rt); |
951 | break; |
952 | case eEncodingA1: |
953 | registers = Bits32(bits: opcode, msbit: 15, lsbit: 0); |
954 | // Instead of return false, let's handle the following case as well, |
955 | // which amounts to pushing one reg onto the full descending stacks. |
956 | // if BitCount(register_list) < 2 then SEE STMDB / STMFD; |
957 | break; |
958 | case eEncodingA2: |
959 | Rt = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
960 | // if t == 13 then UNPREDICTABLE; |
961 | if (Rt == dwarf_sp) |
962 | return false; |
963 | registers = (1u << Rt); |
964 | break; |
965 | default: |
966 | return false; |
967 | } |
968 | addr_t sp_offset = addr_byte_size * BitCount(x: registers); |
969 | addr_t addr = sp - sp_offset; |
970 | uint32_t i; |
971 | |
972 | EmulateInstruction::Context context; |
973 | context.type = EmulateInstruction::eContextPushRegisterOnStack; |
974 | std::optional<RegisterInfo> sp_reg = |
975 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_sp); |
976 | for (i = 0; i < 15; ++i) { |
977 | if (BitIsSet(value: registers, bit: i)) { |
978 | std::optional<RegisterInfo> reg_info = |
979 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + i); |
980 | context.SetRegisterToRegisterPlusOffset(data_reg: *reg_info, base_reg: *sp_reg, offset: addr - sp); |
981 | uint32_t reg_value = ReadCoreReg(regnum: i, success: &success); |
982 | if (!success) |
983 | return false; |
984 | if (!MemAWrite(context, address: addr, data_val: reg_value, size: addr_byte_size)) |
985 | return false; |
986 | addr += addr_byte_size; |
987 | } |
988 | } |
989 | |
990 | if (BitIsSet(value: registers, bit: 15)) { |
991 | std::optional<RegisterInfo> reg_info = |
992 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_pc); |
993 | context.SetRegisterToRegisterPlusOffset(data_reg: *reg_info, base_reg: *sp_reg, offset: addr - sp); |
994 | const uint32_t pc = ReadCoreReg(PC_REG, success: &success); |
995 | if (!success) |
996 | return false; |
997 | if (!MemAWrite(context, address: addr, data_val: pc, size: addr_byte_size)) |
998 | return false; |
999 | } |
1000 | |
1001 | context.type = EmulateInstruction::eContextAdjustStackPointer; |
1002 | context.SetImmediateSigned(-sp_offset); |
1003 | |
1004 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindGeneric, |
1005 | LLDB_REGNUM_GENERIC_SP, reg_value: sp - sp_offset)) |
1006 | return false; |
1007 | } |
1008 | return true; |
1009 | } |
1010 | |
1011 | // Pop Multiple Registers loads multiple registers from the stack, loading from |
1012 | // consecutive memory locations staring at the address in SP, and updates |
1013 | // SP to point just above the loaded data. |
1014 | bool EmulateInstructionARM::EmulatePOP(const uint32_t opcode, |
1015 | const ARMEncoding encoding) { |
1016 | #if 0 |
1017 | // ARM pseudo code... |
1018 | if (ConditionPassed()) |
1019 | { |
1020 | EncodingSpecificOperations(); NullCheckIfThumbEE(13); |
1021 | address = SP; |
1022 | for i = 0 to 14 |
1023 | if registers<i> == '1' then |
1024 | R[i] = if UnalignedAllowed then MemU[address,4] else MemA[address,4]; address = address + 4; |
1025 | if registers<15> == '1' then |
1026 | if UnalignedAllowed then |
1027 | LoadWritePC(MemU[address,4]); |
1028 | else |
1029 | LoadWritePC(MemA[address,4]); |
1030 | if registers<13> == '0' then SP = SP + 4*BitCount(registers); |
1031 | if registers<13> == '1' then SP = bits(32) UNKNOWN; |
1032 | } |
1033 | #endif |
1034 | |
1035 | bool success = false; |
1036 | |
1037 | if (ConditionPassed(opcode)) { |
1038 | const uint32_t addr_byte_size = GetAddressByteSize(); |
1039 | const addr_t sp = ReadCoreReg(SP_REG, success: &success); |
1040 | if (!success) |
1041 | return false; |
1042 | uint32_t registers = 0; |
1043 | uint32_t Rt; // the destination register |
1044 | switch (encoding) { |
1045 | case eEncodingT1: |
1046 | registers = Bits32(bits: opcode, msbit: 7, lsbit: 0); |
1047 | // The P bit represents PC. |
1048 | if (Bit32(bits: opcode, bit: 8)) |
1049 | registers |= (1u << 15); |
1050 | // if BitCount(registers) < 1 then UNPREDICTABLE; |
1051 | if (BitCount(x: registers) < 1) |
1052 | return false; |
1053 | break; |
1054 | case eEncodingT2: |
1055 | // Ignore bit 13. |
1056 | registers = Bits32(bits: opcode, msbit: 15, lsbit: 0) & ~0x2000; |
1057 | // if BitCount(registers) < 2 || (P == '1' && M == '1') then |
1058 | // UNPREDICTABLE; |
1059 | if (BitCount(x: registers) < 2 || (Bit32(bits: opcode, bit: 15) && Bit32(bits: opcode, bit: 14))) |
1060 | return false; |
1061 | // if registers<15> == '1' && InITBlock() && !LastInITBlock() then |
1062 | // UNPREDICTABLE; |
1063 | if (BitIsSet(value: registers, bit: 15) && InITBlock() && !LastInITBlock()) |
1064 | return false; |
1065 | break; |
1066 | case eEncodingT3: |
1067 | Rt = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
1068 | // if t == 13 || (t == 15 && InITBlock() && !LastInITBlock()) then |
1069 | // UNPREDICTABLE; |
1070 | if (Rt == 13) |
1071 | return false; |
1072 | if (Rt == 15 && InITBlock() && !LastInITBlock()) |
1073 | return false; |
1074 | registers = (1u << Rt); |
1075 | break; |
1076 | case eEncodingA1: |
1077 | registers = Bits32(bits: opcode, msbit: 15, lsbit: 0); |
1078 | // Instead of return false, let's handle the following case as well, |
1079 | // which amounts to popping one reg from the full descending stacks. |
1080 | // if BitCount(register_list) < 2 then SEE LDM / LDMIA / LDMFD; |
1081 | |
1082 | // if registers<13> == '1' && ArchVersion() >= 7 then UNPREDICTABLE; |
1083 | if (BitIsSet(value: opcode, bit: 13) && ArchVersion() >= ARMv7) |
1084 | return false; |
1085 | break; |
1086 | case eEncodingA2: |
1087 | Rt = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
1088 | // if t == 13 then UNPREDICTABLE; |
1089 | if (Rt == dwarf_sp) |
1090 | return false; |
1091 | registers = (1u << Rt); |
1092 | break; |
1093 | default: |
1094 | return false; |
1095 | } |
1096 | addr_t sp_offset = addr_byte_size * BitCount(x: registers); |
1097 | addr_t addr = sp; |
1098 | uint32_t i, data; |
1099 | |
1100 | EmulateInstruction::Context context; |
1101 | context.type = EmulateInstruction::eContextPopRegisterOffStack; |
1102 | |
1103 | std::optional<RegisterInfo> sp_reg = |
1104 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_sp); |
1105 | |
1106 | for (i = 0; i < 15; ++i) { |
1107 | if (BitIsSet(value: registers, bit: i)) { |
1108 | context.SetAddress(addr); |
1109 | data = MemARead(context, address: addr, size: 4, fail_value: 0, success_ptr: &success); |
1110 | if (!success) |
1111 | return false; |
1112 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + i, |
1113 | reg_value: data)) |
1114 | return false; |
1115 | addr += addr_byte_size; |
1116 | } |
1117 | } |
1118 | |
1119 | if (BitIsSet(value: registers, bit: 15)) { |
1120 | context.SetRegisterPlusOffset(base_reg: *sp_reg, signed_offset: addr - sp); |
1121 | data = MemARead(context, address: addr, size: 4, fail_value: 0, success_ptr: &success); |
1122 | if (!success) |
1123 | return false; |
1124 | // In ARMv5T and above, this is an interworking branch. |
1125 | if (!LoadWritePC(context, addr: data)) |
1126 | return false; |
1127 | // addr += addr_byte_size; |
1128 | } |
1129 | |
1130 | context.type = EmulateInstruction::eContextAdjustStackPointer; |
1131 | context.SetImmediateSigned(sp_offset); |
1132 | |
1133 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindGeneric, |
1134 | LLDB_REGNUM_GENERIC_SP, reg_value: sp + sp_offset)) |
1135 | return false; |
1136 | } |
1137 | return true; |
1138 | } |
1139 | |
1140 | // Set r7 or ip to point to saved value residing within the stack. |
1141 | // ADD (SP plus immediate) |
1142 | bool EmulateInstructionARM::EmulateADDRdSPImm(const uint32_t opcode, |
1143 | const ARMEncoding encoding) { |
1144 | #if 0 |
1145 | // ARM pseudo code... |
1146 | if (ConditionPassed()) |
1147 | { |
1148 | EncodingSpecificOperations(); |
1149 | (result, carry, overflow) = AddWithCarry(SP, imm32, '0'); |
1150 | if d == 15 then |
1151 | ALUWritePC(result); // setflags is always FALSE here |
1152 | else |
1153 | R[d] = result; |
1154 | if setflags then |
1155 | APSR.N = result<31>; |
1156 | APSR.Z = IsZeroBit(result); |
1157 | APSR.C = carry; |
1158 | APSR.V = overflow; |
1159 | } |
1160 | #endif |
1161 | |
1162 | bool success = false; |
1163 | |
1164 | if (ConditionPassed(opcode)) { |
1165 | const addr_t sp = ReadCoreReg(SP_REG, success: &success); |
1166 | if (!success) |
1167 | return false; |
1168 | uint32_t Rd; // the destination register |
1169 | uint32_t imm32; |
1170 | switch (encoding) { |
1171 | case eEncodingT1: |
1172 | Rd = 7; |
1173 | imm32 = Bits32(bits: opcode, msbit: 7, lsbit: 0) << 2; // imm32 = ZeroExtend(imm8:'00', 32) |
1174 | break; |
1175 | case eEncodingA1: |
1176 | Rd = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
1177 | imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12) |
1178 | break; |
1179 | default: |
1180 | return false; |
1181 | } |
1182 | addr_t sp_offset = imm32; |
1183 | addr_t addr = sp + sp_offset; // a pointer to the stack area |
1184 | |
1185 | EmulateInstruction::Context context; |
1186 | if (Rd == GetFramePointerRegisterNumber()) |
1187 | context.type = eContextSetFramePointer; |
1188 | else |
1189 | context.type = EmulateInstruction::eContextRegisterPlusOffset; |
1190 | std::optional<RegisterInfo> sp_reg = |
1191 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_sp); |
1192 | context.SetRegisterPlusOffset(base_reg: *sp_reg, signed_offset: sp_offset); |
1193 | |
1194 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + Rd, |
1195 | reg_value: addr)) |
1196 | return false; |
1197 | } |
1198 | return true; |
1199 | } |
1200 | |
1201 | // Set r7 or ip to the current stack pointer. |
1202 | // MOV (register) |
1203 | bool EmulateInstructionARM::EmulateMOVRdSP(const uint32_t opcode, |
1204 | const ARMEncoding encoding) { |
1205 | #if 0 |
1206 | // ARM pseudo code... |
1207 | if (ConditionPassed()) |
1208 | { |
1209 | EncodingSpecificOperations(); |
1210 | result = R[m]; |
1211 | if d == 15 then |
1212 | ALUWritePC(result); // setflags is always FALSE here |
1213 | else |
1214 | R[d] = result; |
1215 | if setflags then |
1216 | APSR.N = result<31>; |
1217 | APSR.Z = IsZeroBit(result); |
1218 | // APSR.C unchanged |
1219 | // APSR.V unchanged |
1220 | } |
1221 | #endif |
1222 | |
1223 | bool success = false; |
1224 | |
1225 | if (ConditionPassed(opcode)) { |
1226 | const addr_t sp = ReadCoreReg(SP_REG, success: &success); |
1227 | if (!success) |
1228 | return false; |
1229 | uint32_t Rd; // the destination register |
1230 | switch (encoding) { |
1231 | case eEncodingT1: |
1232 | Rd = 7; |
1233 | break; |
1234 | case eEncodingA1: |
1235 | Rd = 12; |
1236 | break; |
1237 | default: |
1238 | return false; |
1239 | } |
1240 | |
1241 | EmulateInstruction::Context context; |
1242 | if (Rd == GetFramePointerRegisterNumber()) |
1243 | context.type = EmulateInstruction::eContextSetFramePointer; |
1244 | else |
1245 | context.type = EmulateInstruction::eContextRegisterPlusOffset; |
1246 | std::optional<RegisterInfo> sp_reg = |
1247 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_sp); |
1248 | context.SetRegisterPlusOffset(base_reg: *sp_reg, signed_offset: 0); |
1249 | |
1250 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + Rd, reg_value: sp)) |
1251 | return false; |
1252 | } |
1253 | return true; |
1254 | } |
1255 | |
1256 | // Move from high register (r8-r15) to low register (r0-r7). |
1257 | // MOV (register) |
1258 | bool EmulateInstructionARM::EmulateMOVLowHigh(const uint32_t opcode, |
1259 | const ARMEncoding encoding) { |
1260 | return EmulateMOVRdRm(opcode, encoding); |
1261 | } |
1262 | |
1263 | // Move from register to register. |
1264 | // MOV (register) |
1265 | bool EmulateInstructionARM::EmulateMOVRdRm(const uint32_t opcode, |
1266 | const ARMEncoding encoding) { |
1267 | #if 0 |
1268 | // ARM pseudo code... |
1269 | if (ConditionPassed()) |
1270 | { |
1271 | EncodingSpecificOperations(); |
1272 | result = R[m]; |
1273 | if d == 15 then |
1274 | ALUWritePC(result); // setflags is always FALSE here |
1275 | else |
1276 | R[d] = result; |
1277 | if setflags then |
1278 | APSR.N = result<31>; |
1279 | APSR.Z = IsZeroBit(result); |
1280 | // APSR.C unchanged |
1281 | // APSR.V unchanged |
1282 | } |
1283 | #endif |
1284 | |
1285 | bool success = false; |
1286 | |
1287 | if (ConditionPassed(opcode)) { |
1288 | uint32_t Rm; // the source register |
1289 | uint32_t Rd; // the destination register |
1290 | bool setflags; |
1291 | switch (encoding) { |
1292 | case eEncodingT1: |
1293 | Rd = Bit32(bits: opcode, bit: 7) << 3 | Bits32(bits: opcode, msbit: 2, lsbit: 0); |
1294 | Rm = Bits32(bits: opcode, msbit: 6, lsbit: 3); |
1295 | setflags = false; |
1296 | if (Rd == 15 && InITBlock() && !LastInITBlock()) |
1297 | return false; |
1298 | break; |
1299 | case eEncodingT2: |
1300 | Rd = Bits32(bits: opcode, msbit: 2, lsbit: 0); |
1301 | Rm = Bits32(bits: opcode, msbit: 5, lsbit: 3); |
1302 | setflags = true; |
1303 | if (InITBlock()) |
1304 | return false; |
1305 | break; |
1306 | case eEncodingT3: |
1307 | Rd = Bits32(bits: opcode, msbit: 11, lsbit: 8); |
1308 | Rm = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
1309 | setflags = BitIsSet(value: opcode, bit: 20); |
1310 | // if setflags && (BadReg(d) || BadReg(m)) then UNPREDICTABLE; |
1311 | if (setflags && (BadReg(n: Rd) || BadReg(n: Rm))) |
1312 | return false; |
1313 | // if !setflags && (d == 15 || m == 15 || (d == 13 && m == 13)) then |
1314 | // UNPREDICTABLE; |
1315 | if (!setflags && (Rd == 15 || Rm == 15 || (Rd == 13 && Rm == 13))) |
1316 | return false; |
1317 | break; |
1318 | case eEncodingA1: |
1319 | Rd = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
1320 | Rm = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
1321 | setflags = BitIsSet(value: opcode, bit: 20); |
1322 | |
1323 | // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related |
1324 | // instructions; |
1325 | if (Rd == 15 && setflags) |
1326 | return EmulateSUBSPcLrEtc(opcode, encoding); |
1327 | break; |
1328 | default: |
1329 | return false; |
1330 | } |
1331 | uint32_t result = ReadCoreReg(regnum: Rm, success: &success); |
1332 | if (!success) |
1333 | return false; |
1334 | |
1335 | // The context specifies that Rm is to be moved into Rd. |
1336 | EmulateInstruction::Context context; |
1337 | if (Rd == 13) |
1338 | context.type = EmulateInstruction::eContextAdjustStackPointer; |
1339 | else if (Rd == GetFramePointerRegisterNumber() && Rm == 13) |
1340 | context.type = EmulateInstruction::eContextSetFramePointer; |
1341 | else |
1342 | context.type = EmulateInstruction::eContextRegisterPlusOffset; |
1343 | std::optional<RegisterInfo> dwarf_reg = |
1344 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + Rm); |
1345 | context.SetRegisterPlusOffset(base_reg: *dwarf_reg, signed_offset: 0); |
1346 | |
1347 | if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags)) |
1348 | return false; |
1349 | } |
1350 | return true; |
1351 | } |
1352 | |
1353 | // Move (immediate) writes an immediate value to the destination register. It |
1354 | // can optionally update the condition flags based on the value. |
1355 | // MOV (immediate) |
1356 | bool EmulateInstructionARM::EmulateMOVRdImm(const uint32_t opcode, |
1357 | const ARMEncoding encoding) { |
1358 | #if 0 |
1359 | // ARM pseudo code... |
1360 | if (ConditionPassed()) |
1361 | { |
1362 | EncodingSpecificOperations(); |
1363 | result = imm32; |
1364 | if d == 15 then // Can only occur for ARM encoding |
1365 | ALUWritePC(result); // setflags is always FALSE here |
1366 | else |
1367 | R[d] = result; |
1368 | if setflags then |
1369 | APSR.N = result<31>; |
1370 | APSR.Z = IsZeroBit(result); |
1371 | APSR.C = carry; |
1372 | // APSR.V unchanged |
1373 | } |
1374 | #endif |
1375 | |
1376 | if (ConditionPassed(opcode)) { |
1377 | uint32_t Rd; // the destination register |
1378 | uint32_t imm32; // the immediate value to be written to Rd |
1379 | uint32_t carry = |
1380 | 0; // the carry bit after ThumbExpandImm_C or ARMExpandImm_C. |
1381 | // for setflags == false, this value is a don't care initialized to |
1382 | // 0 to silence the static analyzer |
1383 | bool setflags; |
1384 | switch (encoding) { |
1385 | case eEncodingT1: |
1386 | Rd = Bits32(bits: opcode, msbit: 10, lsbit: 8); |
1387 | setflags = !InITBlock(); |
1388 | imm32 = Bits32(bits: opcode, msbit: 7, lsbit: 0); // imm32 = ZeroExtend(imm8, 32) |
1389 | carry = APSR_C; |
1390 | |
1391 | break; |
1392 | |
1393 | case eEncodingT2: |
1394 | Rd = Bits32(bits: opcode, msbit: 11, lsbit: 8); |
1395 | setflags = BitIsSet(value: opcode, bit: 20); |
1396 | imm32 = ThumbExpandImm_C(opcode, APSR_C, carry_out&: carry); |
1397 | if (BadReg(n: Rd)) |
1398 | return false; |
1399 | |
1400 | break; |
1401 | |
1402 | case eEncodingT3: { |
1403 | // d = UInt(Rd); setflags = FALSE; imm32 = ZeroExtend(imm4:i:imm3:imm8, |
1404 | // 32); |
1405 | Rd = Bits32(bits: opcode, msbit: 11, lsbit: 8); |
1406 | setflags = false; |
1407 | uint32_t imm4 = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
1408 | uint32_t imm3 = Bits32(bits: opcode, msbit: 14, lsbit: 12); |
1409 | uint32_t i = Bit32(bits: opcode, bit: 26); |
1410 | uint32_t imm8 = Bits32(bits: opcode, msbit: 7, lsbit: 0); |
1411 | imm32 = (imm4 << 12) | (i << 11) | (imm3 << 8) | imm8; |
1412 | |
1413 | // if BadReg(d) then UNPREDICTABLE; |
1414 | if (BadReg(n: Rd)) |
1415 | return false; |
1416 | } break; |
1417 | |
1418 | case eEncodingA1: |
1419 | // d = UInt(Rd); setflags = (S == '1'); (imm32, carry) = |
1420 | // ARMExpandImm_C(imm12, APSR.C); |
1421 | Rd = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
1422 | setflags = BitIsSet(value: opcode, bit: 20); |
1423 | imm32 = ARMExpandImm_C(opcode, APSR_C, carry_out&: carry); |
1424 | |
1425 | // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related |
1426 | // instructions; |
1427 | if ((Rd == 15) && setflags) |
1428 | return EmulateSUBSPcLrEtc(opcode, encoding); |
1429 | |
1430 | break; |
1431 | |
1432 | case eEncodingA2: { |
1433 | // d = UInt(Rd); setflags = FALSE; imm32 = ZeroExtend(imm4:imm12, 32); |
1434 | Rd = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
1435 | setflags = false; |
1436 | uint32_t imm4 = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
1437 | uint32_t imm12 = Bits32(bits: opcode, msbit: 11, lsbit: 0); |
1438 | imm32 = (imm4 << 12) | imm12; |
1439 | |
1440 | // if d == 15 then UNPREDICTABLE; |
1441 | if (Rd == 15) |
1442 | return false; |
1443 | } break; |
1444 | |
1445 | default: |
1446 | return false; |
1447 | } |
1448 | uint32_t result = imm32; |
1449 | |
1450 | // The context specifies that an immediate is to be moved into Rd. |
1451 | EmulateInstruction::Context context; |
1452 | context.type = EmulateInstruction::eContextImmediate; |
1453 | context.SetNoArgs(); |
1454 | |
1455 | if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry)) |
1456 | return false; |
1457 | } |
1458 | return true; |
1459 | } |
1460 | |
1461 | // MUL multiplies two register values. The least significant 32 bits of the |
1462 | // result are written to the destination |
1463 | // register. These 32 bits do not depend on whether the source register values |
1464 | // are considered to be signed values or unsigned values. |
1465 | // |
1466 | // Optionally, it can update the condition flags based on the result. In the |
1467 | // Thumb instruction set, this option is limited to only a few forms of the |
1468 | // instruction. |
1469 | bool EmulateInstructionARM::EmulateMUL(const uint32_t opcode, |
1470 | const ARMEncoding encoding) { |
1471 | #if 0 |
1472 | if ConditionPassed() then |
1473 | EncodingSpecificOperations(); |
1474 | operand1 = SInt(R[n]); // operand1 = UInt(R[n]) produces the same final results |
1475 | operand2 = SInt(R[m]); // operand2 = UInt(R[m]) produces the same final results |
1476 | result = operand1 * operand2; |
1477 | R[d] = result<31:0>; |
1478 | if setflags then |
1479 | APSR.N = result<31>; |
1480 | APSR.Z = IsZeroBit(result); |
1481 | if ArchVersion() == 4 then |
1482 | APSR.C = bit UNKNOWN; |
1483 | // else APSR.C unchanged |
1484 | // APSR.V always unchanged |
1485 | #endif |
1486 | |
1487 | if (ConditionPassed(opcode)) { |
1488 | uint32_t d; |
1489 | uint32_t n; |
1490 | uint32_t m; |
1491 | bool setflags; |
1492 | |
1493 | // EncodingSpecificOperations(); |
1494 | switch (encoding) { |
1495 | case eEncodingT1: |
1496 | // d = UInt(Rdm); n = UInt(Rn); m = UInt(Rdm); setflags = !InITBlock(); |
1497 | d = Bits32(bits: opcode, msbit: 2, lsbit: 0); |
1498 | n = Bits32(bits: opcode, msbit: 5, lsbit: 3); |
1499 | m = Bits32(bits: opcode, msbit: 2, lsbit: 0); |
1500 | setflags = !InITBlock(); |
1501 | |
1502 | // if ArchVersion() < 6 && d == n then UNPREDICTABLE; |
1503 | if ((ArchVersion() < ARMv6) && (d == n)) |
1504 | return false; |
1505 | |
1506 | break; |
1507 | |
1508 | case eEncodingT2: |
1509 | // d = UInt(Rd); n = UInt(Rn); m = UInt(Rm); setflags = FALSE; |
1510 | d = Bits32(bits: opcode, msbit: 11, lsbit: 8); |
1511 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
1512 | m = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
1513 | setflags = false; |
1514 | |
1515 | // if BadReg(d) || BadReg(n) || BadReg(m) then UNPREDICTABLE; |
1516 | if (BadReg(n: d) || BadReg(n) || BadReg(n: m)) |
1517 | return false; |
1518 | |
1519 | break; |
1520 | |
1521 | case eEncodingA1: |
1522 | // d = UInt(Rd); n = UInt(Rn); m = UInt(Rm); setflags = (S == '1'); |
1523 | d = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
1524 | n = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
1525 | m = Bits32(bits: opcode, msbit: 11, lsbit: 8); |
1526 | setflags = BitIsSet(value: opcode, bit: 20); |
1527 | |
1528 | // if d == 15 || n == 15 || m == 15 then UNPREDICTABLE; |
1529 | if ((d == 15) || (n == 15) || (m == 15)) |
1530 | return false; |
1531 | |
1532 | // if ArchVersion() < 6 && d == n then UNPREDICTABLE; |
1533 | if ((ArchVersion() < ARMv6) && (d == n)) |
1534 | return false; |
1535 | |
1536 | break; |
1537 | |
1538 | default: |
1539 | return false; |
1540 | } |
1541 | |
1542 | bool success = false; |
1543 | |
1544 | // operand1 = SInt(R[n]); // operand1 = UInt(R[n]) produces the same final |
1545 | // results |
1546 | uint64_t operand1 = |
1547 | ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n, fail_value: 0, success_ptr: &success); |
1548 | if (!success) |
1549 | return false; |
1550 | |
1551 | // operand2 = SInt(R[m]); // operand2 = UInt(R[m]) produces the same final |
1552 | // results |
1553 | uint64_t operand2 = |
1554 | ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + m, fail_value: 0, success_ptr: &success); |
1555 | if (!success) |
1556 | return false; |
1557 | |
1558 | // result = operand1 * operand2; |
1559 | uint64_t result = operand1 * operand2; |
1560 | |
1561 | // R[d] = result<31:0>; |
1562 | std::optional<RegisterInfo> op1_reg = |
1563 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n); |
1564 | std::optional<RegisterInfo> op2_reg = |
1565 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + m); |
1566 | |
1567 | EmulateInstruction::Context context; |
1568 | context.type = eContextArithmetic; |
1569 | context.SetRegisterRegisterOperands(op1_reg: *op1_reg, op2_reg: *op2_reg); |
1570 | |
1571 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + d, |
1572 | reg_value: (0x0000ffff & result))) |
1573 | return false; |
1574 | |
1575 | // if setflags then |
1576 | if (setflags) { |
1577 | // APSR.N = result<31>; |
1578 | // APSR.Z = IsZeroBit(result); |
1579 | m_new_inst_cpsr = m_opcode_cpsr; |
1580 | SetBit32(bits&: m_new_inst_cpsr, CPSR_N_POS, val: Bit32(bits: result, bit: 31)); |
1581 | SetBit32(bits&: m_new_inst_cpsr, CPSR_Z_POS, val: result == 0 ? 1 : 0); |
1582 | if (m_new_inst_cpsr != m_opcode_cpsr) { |
1583 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindGeneric, |
1584 | LLDB_REGNUM_GENERIC_FLAGS, reg_value: m_new_inst_cpsr)) |
1585 | return false; |
1586 | } |
1587 | |
1588 | // if ArchVersion() == 4 then |
1589 | // APSR.C = bit UNKNOWN; |
1590 | } |
1591 | } |
1592 | return true; |
1593 | } |
1594 | |
1595 | // Bitwise NOT (immediate) writes the bitwise inverse of an immediate value to |
1596 | // the destination register. It can optionally update the condition flags based |
1597 | // on the value. |
1598 | bool EmulateInstructionARM::EmulateMVNImm(const uint32_t opcode, |
1599 | const ARMEncoding encoding) { |
1600 | #if 0 |
1601 | // ARM pseudo code... |
1602 | if (ConditionPassed()) |
1603 | { |
1604 | EncodingSpecificOperations(); |
1605 | result = NOT(imm32); |
1606 | if d == 15 then // Can only occur for ARM encoding |
1607 | ALUWritePC(result); // setflags is always FALSE here |
1608 | else |
1609 | R[d] = result; |
1610 | if setflags then |
1611 | APSR.N = result<31>; |
1612 | APSR.Z = IsZeroBit(result); |
1613 | APSR.C = carry; |
1614 | // APSR.V unchanged |
1615 | } |
1616 | #endif |
1617 | |
1618 | if (ConditionPassed(opcode)) { |
1619 | uint32_t Rd; // the destination register |
1620 | uint32_t imm32; // the output after ThumbExpandImm_C or ARMExpandImm_C |
1621 | uint32_t carry; // the carry bit after ThumbExpandImm_C or ARMExpandImm_C |
1622 | bool setflags; |
1623 | switch (encoding) { |
1624 | case eEncodingT1: |
1625 | Rd = Bits32(bits: opcode, msbit: 11, lsbit: 8); |
1626 | setflags = BitIsSet(value: opcode, bit: 20); |
1627 | imm32 = ThumbExpandImm_C(opcode, APSR_C, carry_out&: carry); |
1628 | break; |
1629 | case eEncodingA1: |
1630 | Rd = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
1631 | setflags = BitIsSet(value: opcode, bit: 20); |
1632 | imm32 = ARMExpandImm_C(opcode, APSR_C, carry_out&: carry); |
1633 | |
1634 | // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related |
1635 | // instructions; |
1636 | if (Rd == 15 && setflags) |
1637 | return EmulateSUBSPcLrEtc(opcode, encoding); |
1638 | break; |
1639 | default: |
1640 | return false; |
1641 | } |
1642 | uint32_t result = ~imm32; |
1643 | |
1644 | // The context specifies that an immediate is to be moved into Rd. |
1645 | EmulateInstruction::Context context; |
1646 | context.type = EmulateInstruction::eContextImmediate; |
1647 | context.SetNoArgs(); |
1648 | |
1649 | if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry)) |
1650 | return false; |
1651 | } |
1652 | return true; |
1653 | } |
1654 | |
1655 | // Bitwise NOT (register) writes the bitwise inverse of a register value to the |
1656 | // destination register. It can optionally update the condition flags based on |
1657 | // the result. |
1658 | bool EmulateInstructionARM::EmulateMVNReg(const uint32_t opcode, |
1659 | const ARMEncoding encoding) { |
1660 | #if 0 |
1661 | // ARM pseudo code... |
1662 | if (ConditionPassed()) |
1663 | { |
1664 | EncodingSpecificOperations(); |
1665 | (shifted, carry) = Shift_C(R[m], shift_t, shift_n, APSR.C); |
1666 | result = NOT(shifted); |
1667 | if d == 15 then // Can only occur for ARM encoding |
1668 | ALUWritePC(result); // setflags is always FALSE here |
1669 | else |
1670 | R[d] = result; |
1671 | if setflags then |
1672 | APSR.N = result<31>; |
1673 | APSR.Z = IsZeroBit(result); |
1674 | APSR.C = carry; |
1675 | // APSR.V unchanged |
1676 | } |
1677 | #endif |
1678 | |
1679 | if (ConditionPassed(opcode)) { |
1680 | uint32_t Rm; // the source register |
1681 | uint32_t Rd; // the destination register |
1682 | ARM_ShifterType shift_t; |
1683 | uint32_t shift_n; // the shift applied to the value read from Rm |
1684 | bool setflags; |
1685 | uint32_t carry; // the carry bit after the shift operation |
1686 | switch (encoding) { |
1687 | case eEncodingT1: |
1688 | Rd = Bits32(bits: opcode, msbit: 2, lsbit: 0); |
1689 | Rm = Bits32(bits: opcode, msbit: 5, lsbit: 3); |
1690 | setflags = !InITBlock(); |
1691 | shift_t = SRType_LSL; |
1692 | shift_n = 0; |
1693 | if (InITBlock()) |
1694 | return false; |
1695 | break; |
1696 | case eEncodingT2: |
1697 | Rd = Bits32(bits: opcode, msbit: 11, lsbit: 8); |
1698 | Rm = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
1699 | setflags = BitIsSet(value: opcode, bit: 20); |
1700 | shift_n = DecodeImmShiftThumb(opcode, shift_t); |
1701 | // if (BadReg(d) || BadReg(m)) then UNPREDICTABLE; |
1702 | if (BadReg(n: Rd) || BadReg(n: Rm)) |
1703 | return false; |
1704 | break; |
1705 | case eEncodingA1: |
1706 | Rd = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
1707 | Rm = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
1708 | setflags = BitIsSet(value: opcode, bit: 20); |
1709 | shift_n = DecodeImmShiftARM(opcode, shift_t); |
1710 | break; |
1711 | default: |
1712 | return false; |
1713 | } |
1714 | bool success = false; |
1715 | uint32_t value = ReadCoreReg(regnum: Rm, success: &success); |
1716 | if (!success) |
1717 | return false; |
1718 | |
1719 | uint32_t shifted = |
1720 | Shift_C(value, type: shift_t, amount: shift_n, APSR_C, carry_out&: carry, success: &success); |
1721 | if (!success) |
1722 | return false; |
1723 | uint32_t result = ~shifted; |
1724 | |
1725 | // The context specifies that an immediate is to be moved into Rd. |
1726 | EmulateInstruction::Context context; |
1727 | context.type = EmulateInstruction::eContextImmediate; |
1728 | context.SetNoArgs(); |
1729 | |
1730 | if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry)) |
1731 | return false; |
1732 | } |
1733 | return true; |
1734 | } |
1735 | |
1736 | // PC relative immediate load into register, possibly followed by ADD (SP plus |
1737 | // register). |
1738 | // LDR (literal) |
1739 | bool EmulateInstructionARM::EmulateLDRRtPCRelative(const uint32_t opcode, |
1740 | const ARMEncoding encoding) { |
1741 | #if 0 |
1742 | // ARM pseudo code... |
1743 | if (ConditionPassed()) |
1744 | { |
1745 | EncodingSpecificOperations(); NullCheckIfThumbEE(15); |
1746 | base = Align(PC,4); |
1747 | address = if add then (base + imm32) else (base - imm32); |
1748 | data = MemU[address,4]; |
1749 | if t == 15 then |
1750 | if address<1:0> == '00' then LoadWritePC(data); else UNPREDICTABLE; |
1751 | elsif UnalignedSupport() || address<1:0> = '00' then |
1752 | R[t] = data; |
1753 | else // Can only apply before ARMv7 |
1754 | if CurrentInstrSet() == InstrSet_ARM then |
1755 | R[t] = ROR(data, 8*UInt(address<1:0>)); |
1756 | else |
1757 | R[t] = bits(32) UNKNOWN; |
1758 | } |
1759 | #endif |
1760 | |
1761 | if (ConditionPassed(opcode)) { |
1762 | bool success = false; |
1763 | const uint32_t pc = ReadCoreReg(PC_REG, success: &success); |
1764 | if (!success) |
1765 | return false; |
1766 | |
1767 | // PC relative immediate load context |
1768 | EmulateInstruction::Context context; |
1769 | context.type = EmulateInstruction::eContextRegisterPlusOffset; |
1770 | std::optional<RegisterInfo> pc_reg = |
1771 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_pc); |
1772 | context.SetRegisterPlusOffset(base_reg: *pc_reg, signed_offset: 0); |
1773 | |
1774 | uint32_t Rt; // the destination register |
1775 | uint32_t imm32; // immediate offset from the PC |
1776 | bool add; // +imm32 or -imm32? |
1777 | addr_t base; // the base address |
1778 | addr_t address; // the PC relative address |
1779 | uint32_t data; // the literal data value from the PC relative load |
1780 | switch (encoding) { |
1781 | case eEncodingT1: |
1782 | Rt = Bits32(bits: opcode, msbit: 10, lsbit: 8); |
1783 | imm32 = Bits32(bits: opcode, msbit: 7, lsbit: 0) << 2; // imm32 = ZeroExtend(imm8:'00', 32); |
1784 | add = true; |
1785 | break; |
1786 | case eEncodingT2: |
1787 | Rt = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
1788 | imm32 = Bits32(bits: opcode, msbit: 11, lsbit: 0) << 2; // imm32 = ZeroExtend(imm12, 32); |
1789 | add = BitIsSet(value: opcode, bit: 23); |
1790 | if (Rt == 15 && InITBlock() && !LastInITBlock()) |
1791 | return false; |
1792 | break; |
1793 | default: |
1794 | return false; |
1795 | } |
1796 | |
1797 | base = Align(val: pc, alignment: 4); |
1798 | if (add) |
1799 | address = base + imm32; |
1800 | else |
1801 | address = base - imm32; |
1802 | |
1803 | context.SetRegisterPlusOffset(base_reg: *pc_reg, signed_offset: address - base); |
1804 | data = MemURead(context, address, size: 4, fail_value: 0, success_ptr: &success); |
1805 | if (!success) |
1806 | return false; |
1807 | |
1808 | if (Rt == 15) { |
1809 | if (Bits32(bits: address, msbit: 1, lsbit: 0) == 0) { |
1810 | // In ARMv5T and above, this is an interworking branch. |
1811 | if (!LoadWritePC(context, addr: data)) |
1812 | return false; |
1813 | } else |
1814 | return false; |
1815 | } else if (UnalignedSupport() || Bits32(bits: address, msbit: 1, lsbit: 0) == 0) { |
1816 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + Rt, |
1817 | reg_value: data)) |
1818 | return false; |
1819 | } else // We don't handle ARM for now. |
1820 | return false; |
1821 | } |
1822 | return true; |
1823 | } |
1824 | |
1825 | // An add operation to adjust the SP. |
1826 | // ADD (SP plus immediate) |
1827 | bool EmulateInstructionARM::EmulateADDSPImm(const uint32_t opcode, |
1828 | const ARMEncoding encoding) { |
1829 | #if 0 |
1830 | // ARM pseudo code... |
1831 | if (ConditionPassed()) |
1832 | { |
1833 | EncodingSpecificOperations(); |
1834 | (result, carry, overflow) = AddWithCarry(SP, imm32, '0'); |
1835 | if d == 15 then // Can only occur for ARM encoding |
1836 | ALUWritePC(result); // setflags is always FALSE here |
1837 | else |
1838 | R[d] = result; |
1839 | if setflags then |
1840 | APSR.N = result<31>; |
1841 | APSR.Z = IsZeroBit(result); |
1842 | APSR.C = carry; |
1843 | APSR.V = overflow; |
1844 | } |
1845 | #endif |
1846 | |
1847 | bool success = false; |
1848 | |
1849 | if (ConditionPassed(opcode)) { |
1850 | const addr_t sp = ReadCoreReg(SP_REG, success: &success); |
1851 | if (!success) |
1852 | return false; |
1853 | uint32_t imm32; // the immediate operand |
1854 | uint32_t d; |
1855 | bool setflags; |
1856 | switch (encoding) { |
1857 | case eEncodingT1: |
1858 | // d = UInt(Rd); setflags = FALSE; imm32 = ZeroExtend(imm8:'00', 32); |
1859 | d = Bits32(bits: opcode, msbit: 10, lsbit: 8); |
1860 | imm32 = (Bits32(bits: opcode, msbit: 7, lsbit: 0) << 2); |
1861 | setflags = false; |
1862 | break; |
1863 | |
1864 | case eEncodingT2: |
1865 | // d = 13; setflags = FALSE; imm32 = ZeroExtend(imm7:'00', 32); |
1866 | d = 13; |
1867 | imm32 = ThumbImm7Scaled(opcode); // imm32 = ZeroExtend(imm7:'00', 32) |
1868 | setflags = false; |
1869 | break; |
1870 | |
1871 | case eEncodingT3: |
1872 | // d = UInt(Rd); setflags = (S == "1"); imm32 = |
1873 | // ThumbExpandImm(i:imm3:imm8); |
1874 | d = Bits32(bits: opcode, msbit: 11, lsbit: 8); |
1875 | imm32 = ThumbExpandImm(opcode); |
1876 | setflags = Bit32(bits: opcode, bit: 20); |
1877 | |
1878 | // if Rd == "1111" && S == "1" then SEE CMN (immediate); |
1879 | if (d == 15 && setflags == 1) |
1880 | return false; // CMN (immediate) not yet supported |
1881 | |
1882 | // if d == 15 && S == "0" then UNPREDICTABLE; |
1883 | if (d == 15 && setflags == 0) |
1884 | return false; |
1885 | break; |
1886 | |
1887 | case eEncodingT4: { |
1888 | // if Rn == '1111' then SEE ADR; |
1889 | // d = UInt(Rd); setflags = FALSE; imm32 = ZeroExtend(i:imm3:imm8, 32); |
1890 | d = Bits32(bits: opcode, msbit: 11, lsbit: 8); |
1891 | setflags = false; |
1892 | uint32_t i = Bit32(bits: opcode, bit: 26); |
1893 | uint32_t imm3 = Bits32(bits: opcode, msbit: 14, lsbit: 12); |
1894 | uint32_t imm8 = Bits32(bits: opcode, msbit: 7, lsbit: 0); |
1895 | imm32 = (i << 11) | (imm3 << 8) | imm8; |
1896 | |
1897 | // if d == 15 then UNPREDICTABLE; |
1898 | if (d == 15) |
1899 | return false; |
1900 | } break; |
1901 | |
1902 | default: |
1903 | return false; |
1904 | } |
1905 | // (result, carry, overflow) = AddWithCarry(R[n], imm32, '0'); |
1906 | AddWithCarryResult res = AddWithCarry(x: sp, y: imm32, carry_in: 0); |
1907 | |
1908 | EmulateInstruction::Context context; |
1909 | if (d == 13) |
1910 | context.type = EmulateInstruction::eContextAdjustStackPointer; |
1911 | else |
1912 | context.type = EmulateInstruction::eContextRegisterPlusOffset; |
1913 | |
1914 | std::optional<RegisterInfo> sp_reg = |
1915 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_sp); |
1916 | context.SetRegisterPlusOffset(base_reg: *sp_reg, signed_offset: res.result - sp); |
1917 | |
1918 | if (d == 15) { |
1919 | if (!ALUWritePC(context, addr: res.result)) |
1920 | return false; |
1921 | } else { |
1922 | // R[d] = result; |
1923 | // if setflags then |
1924 | // APSR.N = result<31>; |
1925 | // APSR.Z = IsZeroBit(result); |
1926 | // APSR.C = carry; |
1927 | // APSR.V = overflow; |
1928 | if (!WriteCoreRegOptionalFlags(context, result: res.result, Rd: d, setflags, |
1929 | carry: res.carry_out, overflow: res.overflow)) |
1930 | return false; |
1931 | } |
1932 | } |
1933 | return true; |
1934 | } |
1935 | |
1936 | // An add operation to adjust the SP. |
1937 | // ADD (SP plus register) |
1938 | bool EmulateInstructionARM::EmulateADDSPRm(const uint32_t opcode, |
1939 | const ARMEncoding encoding) { |
1940 | #if 0 |
1941 | // ARM pseudo code... |
1942 | if (ConditionPassed()) |
1943 | { |
1944 | EncodingSpecificOperations(); |
1945 | shifted = Shift(R[m], shift_t, shift_n, APSR.C); |
1946 | (result, carry, overflow) = AddWithCarry(SP, shifted, '0'); |
1947 | if d == 15 then |
1948 | ALUWritePC(result); // setflags is always FALSE here |
1949 | else |
1950 | R[d] = result; |
1951 | if setflags then |
1952 | APSR.N = result<31>; |
1953 | APSR.Z = IsZeroBit(result); |
1954 | APSR.C = carry; |
1955 | APSR.V = overflow; |
1956 | } |
1957 | #endif |
1958 | |
1959 | bool success = false; |
1960 | |
1961 | if (ConditionPassed(opcode)) { |
1962 | const addr_t sp = ReadCoreReg(SP_REG, success: &success); |
1963 | if (!success) |
1964 | return false; |
1965 | uint32_t Rm; // the second operand |
1966 | switch (encoding) { |
1967 | case eEncodingT2: |
1968 | Rm = Bits32(bits: opcode, msbit: 6, lsbit: 3); |
1969 | break; |
1970 | default: |
1971 | return false; |
1972 | } |
1973 | int32_t reg_value = ReadCoreReg(regnum: Rm, success: &success); |
1974 | if (!success) |
1975 | return false; |
1976 | |
1977 | addr_t addr = (int32_t)sp + reg_value; // the adjusted stack pointer value |
1978 | |
1979 | EmulateInstruction::Context context; |
1980 | context.type = eContextArithmetic; |
1981 | std::optional<RegisterInfo> sp_reg = |
1982 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_sp); |
1983 | std::optional<RegisterInfo> other_reg = |
1984 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + Rm); |
1985 | context.SetRegisterRegisterOperands(op1_reg: *sp_reg, op2_reg: *other_reg); |
1986 | |
1987 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindGeneric, |
1988 | LLDB_REGNUM_GENERIC_SP, reg_value: addr)) |
1989 | return false; |
1990 | } |
1991 | return true; |
1992 | } |
1993 | |
1994 | // Branch with Link and Exchange Instruction Sets (immediate) calls a |
1995 | // subroutine at a PC-relative address, and changes instruction set from ARM to |
1996 | // Thumb, or from Thumb to ARM. |
1997 | // BLX (immediate) |
1998 | bool EmulateInstructionARM::EmulateBLXImmediate(const uint32_t opcode, |
1999 | const ARMEncoding encoding) { |
2000 | #if 0 |
2001 | // ARM pseudo code... |
2002 | if (ConditionPassed()) |
2003 | { |
2004 | EncodingSpecificOperations(); |
2005 | if CurrentInstrSet() == InstrSet_ARM then |
2006 | LR = PC - 4; |
2007 | else |
2008 | LR = PC<31:1> : '1'; |
2009 | if targetInstrSet == InstrSet_ARM then |
2010 | targetAddress = Align(PC,4) + imm32; |
2011 | else |
2012 | targetAddress = PC + imm32; |
2013 | SelectInstrSet(targetInstrSet); |
2014 | BranchWritePC(targetAddress); |
2015 | } |
2016 | #endif |
2017 | |
2018 | bool success = true; |
2019 | |
2020 | if (ConditionPassed(opcode)) { |
2021 | EmulateInstruction::Context context; |
2022 | context.type = EmulateInstruction::eContextRelativeBranchImmediate; |
2023 | const uint32_t pc = ReadCoreReg(PC_REG, success: &success); |
2024 | if (!success) |
2025 | return false; |
2026 | addr_t lr; // next instruction address |
2027 | addr_t target; // target address |
2028 | int32_t imm32; // PC-relative offset |
2029 | switch (encoding) { |
2030 | case eEncodingT1: { |
2031 | lr = pc | 1u; // return address |
2032 | uint32_t S = Bit32(bits: opcode, bit: 26); |
2033 | uint32_t imm10 = Bits32(bits: opcode, msbit: 25, lsbit: 16); |
2034 | uint32_t J1 = Bit32(bits: opcode, bit: 13); |
2035 | uint32_t J2 = Bit32(bits: opcode, bit: 11); |
2036 | uint32_t imm11 = Bits32(bits: opcode, msbit: 10, lsbit: 0); |
2037 | uint32_t I1 = !(J1 ^ S); |
2038 | uint32_t I2 = !(J2 ^ S); |
2039 | uint32_t imm25 = |
2040 | (S << 24) | (I1 << 23) | (I2 << 22) | (imm10 << 12) | (imm11 << 1); |
2041 | imm32 = llvm::SignExtend32<25>(X: imm25); |
2042 | target = pc + imm32; |
2043 | SelectInstrSet(arm_or_thumb: eModeThumb); |
2044 | context.SetISAAndImmediateSigned(isa: eModeThumb, data: 4 + imm32); |
2045 | if (InITBlock() && !LastInITBlock()) |
2046 | return false; |
2047 | break; |
2048 | } |
2049 | case eEncodingT2: { |
2050 | lr = pc | 1u; // return address |
2051 | uint32_t S = Bit32(bits: opcode, bit: 26); |
2052 | uint32_t imm10H = Bits32(bits: opcode, msbit: 25, lsbit: 16); |
2053 | uint32_t J1 = Bit32(bits: opcode, bit: 13); |
2054 | uint32_t J2 = Bit32(bits: opcode, bit: 11); |
2055 | uint32_t imm10L = Bits32(bits: opcode, msbit: 10, lsbit: 1); |
2056 | uint32_t I1 = !(J1 ^ S); |
2057 | uint32_t I2 = !(J2 ^ S); |
2058 | uint32_t imm25 = |
2059 | (S << 24) | (I1 << 23) | (I2 << 22) | (imm10H << 12) | (imm10L << 2); |
2060 | imm32 = llvm::SignExtend32<25>(X: imm25); |
2061 | target = Align(val: pc, alignment: 4) + imm32; |
2062 | SelectInstrSet(arm_or_thumb: eModeARM); |
2063 | context.SetISAAndImmediateSigned(isa: eModeARM, data: 4 + imm32); |
2064 | if (InITBlock() && !LastInITBlock()) |
2065 | return false; |
2066 | break; |
2067 | } |
2068 | case eEncodingA1: |
2069 | lr = pc - 4; // return address |
2070 | imm32 = llvm::SignExtend32<26>(X: Bits32(bits: opcode, msbit: 23, lsbit: 0) << 2); |
2071 | target = Align(val: pc, alignment: 4) + imm32; |
2072 | SelectInstrSet(arm_or_thumb: eModeARM); |
2073 | context.SetISAAndImmediateSigned(isa: eModeARM, data: 8 + imm32); |
2074 | break; |
2075 | case eEncodingA2: |
2076 | lr = pc - 4; // return address |
2077 | imm32 = llvm::SignExtend32<26>(X: Bits32(bits: opcode, msbit: 23, lsbit: 0) << 2 | |
2078 | Bits32(bits: opcode, msbit: 24, lsbit: 24) << 1); |
2079 | target = pc + imm32; |
2080 | SelectInstrSet(arm_or_thumb: eModeThumb); |
2081 | context.SetISAAndImmediateSigned(isa: eModeThumb, data: 8 + imm32); |
2082 | break; |
2083 | default: |
2084 | return false; |
2085 | } |
2086 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindGeneric, |
2087 | LLDB_REGNUM_GENERIC_RA, reg_value: lr)) |
2088 | return false; |
2089 | if (!BranchWritePC(context, addr: target)) |
2090 | return false; |
2091 | if (m_opcode_cpsr != m_new_inst_cpsr) |
2092 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindGeneric, |
2093 | LLDB_REGNUM_GENERIC_FLAGS, reg_value: m_new_inst_cpsr)) |
2094 | return false; |
2095 | } |
2096 | return true; |
2097 | } |
2098 | |
2099 | // Branch with Link and Exchange (register) calls a subroutine at an address |
2100 | // and instruction set specified by a register. |
2101 | // BLX (register) |
2102 | bool EmulateInstructionARM::EmulateBLXRm(const uint32_t opcode, |
2103 | const ARMEncoding encoding) { |
2104 | #if 0 |
2105 | // ARM pseudo code... |
2106 | if (ConditionPassed()) |
2107 | { |
2108 | EncodingSpecificOperations(); |
2109 | target = R[m]; |
2110 | if CurrentInstrSet() == InstrSet_ARM then |
2111 | next_instr_addr = PC - 4; |
2112 | LR = next_instr_addr; |
2113 | else |
2114 | next_instr_addr = PC - 2; |
2115 | LR = next_instr_addr<31:1> : '1'; |
2116 | BXWritePC(target); |
2117 | } |
2118 | #endif |
2119 | |
2120 | bool success = false; |
2121 | |
2122 | if (ConditionPassed(opcode)) { |
2123 | EmulateInstruction::Context context; |
2124 | context.type = EmulateInstruction::eContextAbsoluteBranchRegister; |
2125 | const uint32_t pc = ReadCoreReg(PC_REG, success: &success); |
2126 | addr_t lr; // next instruction address |
2127 | if (!success) |
2128 | return false; |
2129 | uint32_t Rm; // the register with the target address |
2130 | switch (encoding) { |
2131 | case eEncodingT1: |
2132 | lr = (pc - 2) | 1u; // return address |
2133 | Rm = Bits32(bits: opcode, msbit: 6, lsbit: 3); |
2134 | // if m == 15 then UNPREDICTABLE; |
2135 | if (Rm == 15) |
2136 | return false; |
2137 | if (InITBlock() && !LastInITBlock()) |
2138 | return false; |
2139 | break; |
2140 | case eEncodingA1: |
2141 | lr = pc - 4; // return address |
2142 | Rm = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
2143 | // if m == 15 then UNPREDICTABLE; |
2144 | if (Rm == 15) |
2145 | return false; |
2146 | break; |
2147 | default: |
2148 | return false; |
2149 | } |
2150 | addr_t target = ReadCoreReg(regnum: Rm, success: &success); |
2151 | if (!success) |
2152 | return false; |
2153 | std::optional<RegisterInfo> dwarf_reg = |
2154 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + Rm); |
2155 | context.SetRegister(*dwarf_reg); |
2156 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindGeneric, |
2157 | LLDB_REGNUM_GENERIC_RA, reg_value: lr)) |
2158 | return false; |
2159 | if (!BXWritePC(context, addr: target)) |
2160 | return false; |
2161 | } |
2162 | return true; |
2163 | } |
2164 | |
2165 | // Branch and Exchange causes a branch to an address and instruction set |
2166 | // specified by a register. |
2167 | bool EmulateInstructionARM::EmulateBXRm(const uint32_t opcode, |
2168 | const ARMEncoding encoding) { |
2169 | #if 0 |
2170 | // ARM pseudo code... |
2171 | if (ConditionPassed()) |
2172 | { |
2173 | EncodingSpecificOperations(); |
2174 | BXWritePC(R[m]); |
2175 | } |
2176 | #endif |
2177 | |
2178 | if (ConditionPassed(opcode)) { |
2179 | EmulateInstruction::Context context; |
2180 | context.type = EmulateInstruction::eContextAbsoluteBranchRegister; |
2181 | uint32_t Rm; // the register with the target address |
2182 | switch (encoding) { |
2183 | case eEncodingT1: |
2184 | Rm = Bits32(bits: opcode, msbit: 6, lsbit: 3); |
2185 | if (InITBlock() && !LastInITBlock()) |
2186 | return false; |
2187 | break; |
2188 | case eEncodingA1: |
2189 | Rm = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
2190 | break; |
2191 | default: |
2192 | return false; |
2193 | } |
2194 | bool success = false; |
2195 | addr_t target = ReadCoreReg(regnum: Rm, success: &success); |
2196 | if (!success) |
2197 | return false; |
2198 | |
2199 | std::optional<RegisterInfo> dwarf_reg = |
2200 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + Rm); |
2201 | context.SetRegister(*dwarf_reg); |
2202 | if (!BXWritePC(context, addr: target)) |
2203 | return false; |
2204 | } |
2205 | return true; |
2206 | } |
2207 | |
2208 | // Branch and Exchange Jazelle attempts to change to Jazelle state. If the |
2209 | // attempt fails, it branches to an address and instruction set specified by a |
2210 | // register as though it were a BX instruction. |
2211 | // |
2212 | // TODO: Emulate Jazelle architecture? |
2213 | // We currently assume that switching to Jazelle state fails, thus |
2214 | // treating BXJ as a BX operation. |
2215 | bool EmulateInstructionARM::EmulateBXJRm(const uint32_t opcode, |
2216 | const ARMEncoding encoding) { |
2217 | #if 0 |
2218 | // ARM pseudo code... |
2219 | if (ConditionPassed()) |
2220 | { |
2221 | EncodingSpecificOperations(); |
2222 | if JMCR.JE == '0' || CurrentInstrSet() == InstrSet_ThumbEE then |
2223 | BXWritePC(R[m]); |
2224 | else |
2225 | if JazelleAcceptsExecution() then |
2226 | SwitchToJazelleExecution(); |
2227 | else |
2228 | SUBARCHITECTURE_DEFINED handler call; |
2229 | } |
2230 | #endif |
2231 | |
2232 | if (ConditionPassed(opcode)) { |
2233 | EmulateInstruction::Context context; |
2234 | context.type = EmulateInstruction::eContextAbsoluteBranchRegister; |
2235 | uint32_t Rm; // the register with the target address |
2236 | switch (encoding) { |
2237 | case eEncodingT1: |
2238 | Rm = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
2239 | if (BadReg(n: Rm)) |
2240 | return false; |
2241 | if (InITBlock() && !LastInITBlock()) |
2242 | return false; |
2243 | break; |
2244 | case eEncodingA1: |
2245 | Rm = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
2246 | if (Rm == 15) |
2247 | return false; |
2248 | break; |
2249 | default: |
2250 | return false; |
2251 | } |
2252 | bool success = false; |
2253 | addr_t target = ReadCoreReg(regnum: Rm, success: &success); |
2254 | if (!success) |
2255 | return false; |
2256 | |
2257 | std::optional<RegisterInfo> dwarf_reg = |
2258 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + Rm); |
2259 | context.SetRegister(*dwarf_reg); |
2260 | if (!BXWritePC(context, addr: target)) |
2261 | return false; |
2262 | } |
2263 | return true; |
2264 | } |
2265 | |
2266 | // Set r7 to point to some ip offset. |
2267 | // SUB (immediate) |
2268 | bool EmulateInstructionARM::EmulateSUBR7IPImm(const uint32_t opcode, |
2269 | const ARMEncoding encoding) { |
2270 | #if 0 |
2271 | // ARM pseudo code... |
2272 | if (ConditionPassed()) |
2273 | { |
2274 | EncodingSpecificOperations(); |
2275 | (result, carry, overflow) = AddWithCarry(SP, NOT(imm32), '1'); |
2276 | if d == 15 then // Can only occur for ARM encoding |
2277 | ALUWritePC(result); // setflags is always FALSE here |
2278 | else |
2279 | R[d] = result; |
2280 | if setflags then |
2281 | APSR.N = result<31>; |
2282 | APSR.Z = IsZeroBit(result); |
2283 | APSR.C = carry; |
2284 | APSR.V = overflow; |
2285 | } |
2286 | #endif |
2287 | |
2288 | if (ConditionPassed(opcode)) { |
2289 | bool success = false; |
2290 | const addr_t ip = ReadCoreReg(regnum: 12, success: &success); |
2291 | if (!success) |
2292 | return false; |
2293 | uint32_t imm32; |
2294 | switch (encoding) { |
2295 | case eEncodingA1: |
2296 | imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12) |
2297 | break; |
2298 | default: |
2299 | return false; |
2300 | } |
2301 | addr_t ip_offset = imm32; |
2302 | addr_t addr = ip - ip_offset; // the adjusted ip value |
2303 | |
2304 | EmulateInstruction::Context context; |
2305 | context.type = EmulateInstruction::eContextRegisterPlusOffset; |
2306 | std::optional<RegisterInfo> dwarf_reg = |
2307 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r12); |
2308 | context.SetRegisterPlusOffset(base_reg: *dwarf_reg, signed_offset: -ip_offset); |
2309 | |
2310 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r7, reg_value: addr)) |
2311 | return false; |
2312 | } |
2313 | return true; |
2314 | } |
2315 | |
2316 | // Set ip to point to some stack offset. |
2317 | // SUB (SP minus immediate) |
2318 | bool EmulateInstructionARM::EmulateSUBIPSPImm(const uint32_t opcode, |
2319 | const ARMEncoding encoding) { |
2320 | #if 0 |
2321 | // ARM pseudo code... |
2322 | if (ConditionPassed()) |
2323 | { |
2324 | EncodingSpecificOperations(); |
2325 | (result, carry, overflow) = AddWithCarry(SP, NOT(imm32), '1'); |
2326 | if d == 15 then // Can only occur for ARM encoding |
2327 | ALUWritePC(result); // setflags is always FALSE here |
2328 | else |
2329 | R[d] = result; |
2330 | if setflags then |
2331 | APSR.N = result<31>; |
2332 | APSR.Z = IsZeroBit(result); |
2333 | APSR.C = carry; |
2334 | APSR.V = overflow; |
2335 | } |
2336 | #endif |
2337 | |
2338 | if (ConditionPassed(opcode)) { |
2339 | bool success = false; |
2340 | const addr_t sp = ReadCoreReg(SP_REG, success: &success); |
2341 | if (!success) |
2342 | return false; |
2343 | uint32_t imm32; |
2344 | switch (encoding) { |
2345 | case eEncodingA1: |
2346 | imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12) |
2347 | break; |
2348 | default: |
2349 | return false; |
2350 | } |
2351 | addr_t sp_offset = imm32; |
2352 | addr_t addr = sp - sp_offset; // the adjusted stack pointer value |
2353 | |
2354 | EmulateInstruction::Context context; |
2355 | context.type = EmulateInstruction::eContextRegisterPlusOffset; |
2356 | std::optional<RegisterInfo> dwarf_reg = |
2357 | GetRegisterInfo(reg_kind: eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP); |
2358 | context.SetRegisterPlusOffset(base_reg: *dwarf_reg, signed_offset: -sp_offset); |
2359 | |
2360 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r12, reg_value: addr)) |
2361 | return false; |
2362 | } |
2363 | return true; |
2364 | } |
2365 | |
2366 | // This instruction subtracts an immediate value from the SP value, and writes |
2367 | // the result to the destination register. |
2368 | // |
2369 | // If Rd == 13 => A sub operation to adjust the SP -- allocate space for local |
2370 | // storage. |
2371 | bool EmulateInstructionARM::EmulateSUBSPImm(const uint32_t opcode, |
2372 | const ARMEncoding encoding) { |
2373 | #if 0 |
2374 | // ARM pseudo code... |
2375 | if (ConditionPassed()) |
2376 | { |
2377 | EncodingSpecificOperations(); |
2378 | (result, carry, overflow) = AddWithCarry(SP, NOT(imm32), '1'); |
2379 | if d == 15 then // Can only occur for ARM encoding |
2380 | ALUWritePC(result); // setflags is always FALSE here |
2381 | else |
2382 | R[d] = result; |
2383 | if setflags then |
2384 | APSR.N = result<31>; |
2385 | APSR.Z = IsZeroBit(result); |
2386 | APSR.C = carry; |
2387 | APSR.V = overflow; |
2388 | } |
2389 | #endif |
2390 | |
2391 | bool success = false; |
2392 | if (ConditionPassed(opcode)) { |
2393 | const addr_t sp = ReadCoreReg(SP_REG, success: &success); |
2394 | if (!success) |
2395 | return false; |
2396 | |
2397 | uint32_t Rd; |
2398 | bool setflags; |
2399 | uint32_t imm32; |
2400 | switch (encoding) { |
2401 | case eEncodingT1: |
2402 | Rd = 13; |
2403 | setflags = false; |
2404 | imm32 = ThumbImm7Scaled(opcode); // imm32 = ZeroExtend(imm7:'00', 32) |
2405 | break; |
2406 | case eEncodingT2: |
2407 | Rd = Bits32(bits: opcode, msbit: 11, lsbit: 8); |
2408 | setflags = BitIsSet(value: opcode, bit: 20); |
2409 | imm32 = ThumbExpandImm(opcode); // imm32 = ThumbExpandImm(i:imm3:imm8) |
2410 | if (Rd == 15 && setflags) |
2411 | return EmulateCMPImm(opcode, encoding: eEncodingT2); |
2412 | if (Rd == 15 && !setflags) |
2413 | return false; |
2414 | break; |
2415 | case eEncodingT3: |
2416 | Rd = Bits32(bits: opcode, msbit: 11, lsbit: 8); |
2417 | setflags = false; |
2418 | imm32 = ThumbImm12(opcode); // imm32 = ZeroExtend(i:imm3:imm8, 32) |
2419 | if (Rd == 15) |
2420 | return false; |
2421 | break; |
2422 | case eEncodingA1: |
2423 | Rd = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
2424 | setflags = BitIsSet(value: opcode, bit: 20); |
2425 | imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12) |
2426 | |
2427 | // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related |
2428 | // instructions; |
2429 | if (Rd == 15 && setflags) |
2430 | return EmulateSUBSPcLrEtc(opcode, encoding); |
2431 | break; |
2432 | default: |
2433 | return false; |
2434 | } |
2435 | AddWithCarryResult res = AddWithCarry(x: sp, y: ~imm32, carry_in: 1); |
2436 | |
2437 | EmulateInstruction::Context context; |
2438 | if (Rd == 13) { |
2439 | uint64_t imm64 = imm32; // Need to expand it to 64 bits before attempting |
2440 | // to negate it, or the wrong |
2441 | // value gets passed down to context.SetImmediateSigned. |
2442 | context.type = EmulateInstruction::eContextAdjustStackPointer; |
2443 | context.SetImmediateSigned(-imm64); // the stack pointer offset |
2444 | } else { |
2445 | context.type = EmulateInstruction::eContextImmediate; |
2446 | context.SetNoArgs(); |
2447 | } |
2448 | |
2449 | if (!WriteCoreRegOptionalFlags(context, result: res.result, Rd, setflags, |
2450 | carry: res.carry_out, overflow: res.overflow)) |
2451 | return false; |
2452 | } |
2453 | return true; |
2454 | } |
2455 | |
2456 | // A store operation to the stack that also updates the SP. |
2457 | bool EmulateInstructionARM::EmulateSTRRtSP(const uint32_t opcode, |
2458 | const ARMEncoding encoding) { |
2459 | #if 0 |
2460 | // ARM pseudo code... |
2461 | if (ConditionPassed()) |
2462 | { |
2463 | EncodingSpecificOperations(); |
2464 | offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); |
2465 | address = if index then offset_addr else R[n]; |
2466 | MemU[address,4] = if t == 15 then PCStoreValue() else R[t]; |
2467 | if wback then R[n] = offset_addr; |
2468 | } |
2469 | #endif |
2470 | |
2471 | bool success = false; |
2472 | if (ConditionPassed(opcode)) { |
2473 | const uint32_t addr_byte_size = GetAddressByteSize(); |
2474 | const addr_t sp = ReadCoreReg(SP_REG, success: &success); |
2475 | if (!success) |
2476 | return false; |
2477 | uint32_t Rt; // the source register |
2478 | uint32_t imm12; |
2479 | uint32_t |
2480 | Rn; // This function assumes Rn is the SP, but we should verify that. |
2481 | |
2482 | bool index; |
2483 | bool add; |
2484 | bool wback; |
2485 | switch (encoding) { |
2486 | case eEncodingA1: |
2487 | Rt = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
2488 | imm12 = Bits32(bits: opcode, msbit: 11, lsbit: 0); |
2489 | Rn = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
2490 | |
2491 | if (Rn != 13) // 13 is the SP reg on ARM. Verify that Rn == SP. |
2492 | return false; |
2493 | |
2494 | index = BitIsSet(value: opcode, bit: 24); |
2495 | add = BitIsSet(value: opcode, bit: 23); |
2496 | wback = (BitIsClear(value: opcode, bit: 24) || BitIsSet(value: opcode, bit: 21)); |
2497 | |
2498 | if (wback && ((Rn == 15) || (Rn == Rt))) |
2499 | return false; |
2500 | break; |
2501 | default: |
2502 | return false; |
2503 | } |
2504 | addr_t offset_addr; |
2505 | if (add) |
2506 | offset_addr = sp + imm12; |
2507 | else |
2508 | offset_addr = sp - imm12; |
2509 | |
2510 | addr_t addr; |
2511 | if (index) |
2512 | addr = offset_addr; |
2513 | else |
2514 | addr = sp; |
2515 | |
2516 | EmulateInstruction::Context context; |
2517 | context.type = EmulateInstruction::eContextPushRegisterOnStack; |
2518 | std::optional<RegisterInfo> sp_reg = |
2519 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_sp); |
2520 | std::optional<RegisterInfo> dwarf_reg = |
2521 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + Rt); |
2522 | |
2523 | context.SetRegisterToRegisterPlusOffset(data_reg: *dwarf_reg, base_reg: *sp_reg, offset: addr - sp); |
2524 | if (Rt != 15) { |
2525 | uint32_t reg_value = ReadCoreReg(regnum: Rt, success: &success); |
2526 | if (!success) |
2527 | return false; |
2528 | if (!MemUWrite(context, address: addr, data_val: reg_value, size: addr_byte_size)) |
2529 | return false; |
2530 | } else { |
2531 | const uint32_t pc = ReadCoreReg(PC_REG, success: &success); |
2532 | if (!success) |
2533 | return false; |
2534 | if (!MemUWrite(context, address: addr, data_val: pc, size: addr_byte_size)) |
2535 | return false; |
2536 | } |
2537 | |
2538 | if (wback) { |
2539 | context.type = EmulateInstruction::eContextAdjustStackPointer; |
2540 | context.SetImmediateSigned(addr - sp); |
2541 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindGeneric, |
2542 | LLDB_REGNUM_GENERIC_SP, reg_value: offset_addr)) |
2543 | return false; |
2544 | } |
2545 | } |
2546 | return true; |
2547 | } |
2548 | |
2549 | // Vector Push stores multiple extension registers to the stack. It also |
2550 | // updates SP to point to the start of the stored data. |
2551 | bool EmulateInstructionARM::EmulateVPUSH(const uint32_t opcode, |
2552 | const ARMEncoding encoding) { |
2553 | #if 0 |
2554 | // ARM pseudo code... |
2555 | if (ConditionPassed()) |
2556 | { |
2557 | EncodingSpecificOperations(); CheckVFPEnabled(TRUE); NullCheckIfThumbEE(13); |
2558 | address = SP - imm32; |
2559 | SP = SP - imm32; |
2560 | if single_regs then |
2561 | for r = 0 to regs-1 |
2562 | MemA[address,4] = S[d+r]; address = address+4; |
2563 | else |
2564 | for r = 0 to regs-1 |
2565 | // Store as two word-aligned words in the correct order for |
2566 | // current endianness. |
2567 | MemA[address,4] = if BigEndian() then D[d+r]<63:32> else D[d+r]<31:0>; |
2568 | MemA[address+4,4] = if BigEndian() then D[d+r]<31:0> else D[d+r]<63:32>; |
2569 | address = address+8; |
2570 | } |
2571 | #endif |
2572 | |
2573 | bool success = false; |
2574 | if (ConditionPassed(opcode)) { |
2575 | const uint32_t addr_byte_size = GetAddressByteSize(); |
2576 | const addr_t sp = ReadCoreReg(SP_REG, success: &success); |
2577 | if (!success) |
2578 | return false; |
2579 | bool single_regs; |
2580 | uint32_t d; // UInt(D:Vd) or UInt(Vd:D) starting register |
2581 | uint32_t imm32; // stack offset |
2582 | uint32_t regs; // number of registers |
2583 | switch (encoding) { |
2584 | case eEncodingT1: |
2585 | case eEncodingA1: |
2586 | single_regs = false; |
2587 | d = Bit32(bits: opcode, bit: 22) << 4 | Bits32(bits: opcode, msbit: 15, lsbit: 12); |
2588 | imm32 = Bits32(bits: opcode, msbit: 7, lsbit: 0) * addr_byte_size; |
2589 | // If UInt(imm8) is odd, see "FSTMX". |
2590 | regs = Bits32(bits: opcode, msbit: 7, lsbit: 0) / 2; |
2591 | // if regs == 0 || regs > 16 || (d+regs) > 32 then UNPREDICTABLE; |
2592 | if (regs == 0 || regs > 16 || (d + regs) > 32) |
2593 | return false; |
2594 | break; |
2595 | case eEncodingT2: |
2596 | case eEncodingA2: |
2597 | single_regs = true; |
2598 | d = Bits32(bits: opcode, msbit: 15, lsbit: 12) << 1 | Bit32(bits: opcode, bit: 22); |
2599 | imm32 = Bits32(bits: opcode, msbit: 7, lsbit: 0) * addr_byte_size; |
2600 | regs = Bits32(bits: opcode, msbit: 7, lsbit: 0); |
2601 | // if regs == 0 || regs > 16 || (d+regs) > 32 then UNPREDICTABLE; |
2602 | if (regs == 0 || regs > 16 || (d + regs) > 32) |
2603 | return false; |
2604 | break; |
2605 | default: |
2606 | return false; |
2607 | } |
2608 | uint32_t start_reg = single_regs ? dwarf_s0 : dwarf_d0; |
2609 | uint32_t reg_byte_size = single_regs ? addr_byte_size : addr_byte_size * 2; |
2610 | addr_t sp_offset = imm32; |
2611 | addr_t addr = sp - sp_offset; |
2612 | uint32_t i; |
2613 | |
2614 | EmulateInstruction::Context context; |
2615 | context.type = EmulateInstruction::eContextPushRegisterOnStack; |
2616 | |
2617 | std::optional<RegisterInfo> sp_reg = |
2618 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_sp); |
2619 | for (i = 0; i < regs; ++i) { |
2620 | std::optional<RegisterInfo> dwarf_reg = |
2621 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: start_reg + d + i); |
2622 | context.SetRegisterToRegisterPlusOffset(data_reg: *dwarf_reg, base_reg: *sp_reg, offset: addr - sp); |
2623 | // uint64_t to accommodate 64-bit registers. |
2624 | uint64_t reg_value = ReadRegisterUnsigned(reg_info: *dwarf_reg, fail_value: 0, success_ptr: &success); |
2625 | if (!success) |
2626 | return false; |
2627 | if (!MemAWrite(context, address: addr, data_val: reg_value, size: reg_byte_size)) |
2628 | return false; |
2629 | addr += reg_byte_size; |
2630 | } |
2631 | |
2632 | context.type = EmulateInstruction::eContextAdjustStackPointer; |
2633 | context.SetImmediateSigned(-sp_offset); |
2634 | |
2635 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindGeneric, |
2636 | LLDB_REGNUM_GENERIC_SP, reg_value: sp - sp_offset)) |
2637 | return false; |
2638 | } |
2639 | return true; |
2640 | } |
2641 | |
2642 | // Vector Pop loads multiple extension registers from the stack. It also |
2643 | // updates SP to point just above the loaded data. |
2644 | bool EmulateInstructionARM::EmulateVPOP(const uint32_t opcode, |
2645 | const ARMEncoding encoding) { |
2646 | #if 0 |
2647 | // ARM pseudo code... |
2648 | if (ConditionPassed()) |
2649 | { |
2650 | EncodingSpecificOperations(); CheckVFPEnabled(TRUE); NullCheckIfThumbEE(13); |
2651 | address = SP; |
2652 | SP = SP + imm32; |
2653 | if single_regs then |
2654 | for r = 0 to regs-1 |
2655 | S[d+r] = MemA[address,4]; address = address+4; |
2656 | else |
2657 | for r = 0 to regs-1 |
2658 | word1 = MemA[address,4]; word2 = MemA[address+4,4]; address = address+8; |
2659 | // Combine the word-aligned words in the correct order for |
2660 | // current endianness. |
2661 | D[d+r] = if BigEndian() then word1:word2 else word2:word1; |
2662 | } |
2663 | #endif |
2664 | |
2665 | bool success = false; |
2666 | if (ConditionPassed(opcode)) { |
2667 | const uint32_t addr_byte_size = GetAddressByteSize(); |
2668 | const addr_t sp = ReadCoreReg(SP_REG, success: &success); |
2669 | if (!success) |
2670 | return false; |
2671 | bool single_regs; |
2672 | uint32_t d; // UInt(D:Vd) or UInt(Vd:D) starting register |
2673 | uint32_t imm32; // stack offset |
2674 | uint32_t regs; // number of registers |
2675 | switch (encoding) { |
2676 | case eEncodingT1: |
2677 | case eEncodingA1: |
2678 | single_regs = false; |
2679 | d = Bit32(bits: opcode, bit: 22) << 4 | Bits32(bits: opcode, msbit: 15, lsbit: 12); |
2680 | imm32 = Bits32(bits: opcode, msbit: 7, lsbit: 0) * addr_byte_size; |
2681 | // If UInt(imm8) is odd, see "FLDMX". |
2682 | regs = Bits32(bits: opcode, msbit: 7, lsbit: 0) / 2; |
2683 | // if regs == 0 || regs > 16 || (d+regs) > 32 then UNPREDICTABLE; |
2684 | if (regs == 0 || regs > 16 || (d + regs) > 32) |
2685 | return false; |
2686 | break; |
2687 | case eEncodingT2: |
2688 | case eEncodingA2: |
2689 | single_regs = true; |
2690 | d = Bits32(bits: opcode, msbit: 15, lsbit: 12) << 1 | Bit32(bits: opcode, bit: 22); |
2691 | imm32 = Bits32(bits: opcode, msbit: 7, lsbit: 0) * addr_byte_size; |
2692 | regs = Bits32(bits: opcode, msbit: 7, lsbit: 0); |
2693 | // if regs == 0 || regs > 16 || (d+regs) > 32 then UNPREDICTABLE; |
2694 | if (regs == 0 || regs > 16 || (d + regs) > 32) |
2695 | return false; |
2696 | break; |
2697 | default: |
2698 | return false; |
2699 | } |
2700 | uint32_t start_reg = single_regs ? dwarf_s0 : dwarf_d0; |
2701 | uint32_t reg_byte_size = single_regs ? addr_byte_size : addr_byte_size * 2; |
2702 | addr_t sp_offset = imm32; |
2703 | addr_t addr = sp; |
2704 | uint32_t i; |
2705 | uint64_t data; // uint64_t to accommodate 64-bit registers. |
2706 | |
2707 | EmulateInstruction::Context context; |
2708 | context.type = EmulateInstruction::eContextPopRegisterOffStack; |
2709 | |
2710 | for (i = 0; i < regs; ++i) { |
2711 | std::optional<RegisterInfo> dwarf_reg = |
2712 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: start_reg + d + i); |
2713 | context.SetAddress(addr); |
2714 | data = MemARead(context, address: addr, size: reg_byte_size, fail_value: 0, success_ptr: &success); |
2715 | if (!success) |
2716 | return false; |
2717 | if (!WriteRegisterUnsigned(context, reg_info: *dwarf_reg, reg_value: data)) |
2718 | return false; |
2719 | addr += reg_byte_size; |
2720 | } |
2721 | |
2722 | context.type = EmulateInstruction::eContextAdjustStackPointer; |
2723 | context.SetImmediateSigned(sp_offset); |
2724 | |
2725 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindGeneric, |
2726 | LLDB_REGNUM_GENERIC_SP, reg_value: sp + sp_offset)) |
2727 | return false; |
2728 | } |
2729 | return true; |
2730 | } |
2731 | |
2732 | // SVC (previously SWI) |
2733 | bool EmulateInstructionARM::EmulateSVC(const uint32_t opcode, |
2734 | const ARMEncoding encoding) { |
2735 | #if 0 |
2736 | // ARM pseudo code... |
2737 | if (ConditionPassed()) |
2738 | { |
2739 | EncodingSpecificOperations(); |
2740 | CallSupervisor(); |
2741 | } |
2742 | #endif |
2743 | |
2744 | bool success = false; |
2745 | |
2746 | if (ConditionPassed(opcode)) { |
2747 | const uint32_t pc = ReadCoreReg(PC_REG, success: &success); |
2748 | addr_t lr; // next instruction address |
2749 | if (!success) |
2750 | return false; |
2751 | uint32_t imm32; // the immediate constant |
2752 | uint32_t mode; // ARM or Thumb mode |
2753 | switch (encoding) { |
2754 | case eEncodingT1: |
2755 | lr = (pc + 2) | 1u; // return address |
2756 | imm32 = Bits32(bits: opcode, msbit: 7, lsbit: 0); |
2757 | mode = eModeThumb; |
2758 | break; |
2759 | case eEncodingA1: |
2760 | lr = pc + 4; // return address |
2761 | imm32 = Bits32(bits: opcode, msbit: 23, lsbit: 0); |
2762 | mode = eModeARM; |
2763 | break; |
2764 | default: |
2765 | return false; |
2766 | } |
2767 | |
2768 | EmulateInstruction::Context context; |
2769 | context.type = EmulateInstruction::eContextSupervisorCall; |
2770 | context.SetISAAndImmediate(isa: mode, data: imm32); |
2771 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindGeneric, |
2772 | LLDB_REGNUM_GENERIC_RA, reg_value: lr)) |
2773 | return false; |
2774 | } |
2775 | return true; |
2776 | } |
2777 | |
2778 | // If Then makes up to four following instructions (the IT block) conditional. |
2779 | bool EmulateInstructionARM::EmulateIT(const uint32_t opcode, |
2780 | const ARMEncoding encoding) { |
2781 | #if 0 |
2782 | // ARM pseudo code... |
2783 | EncodingSpecificOperations(); |
2784 | ITSTATE.IT<7:0> = firstcond:mask; |
2785 | #endif |
2786 | |
2787 | m_it_session.InitIT(bits7_0: Bits32(bits: opcode, msbit: 7, lsbit: 0)); |
2788 | return true; |
2789 | } |
2790 | |
2791 | bool EmulateInstructionARM::EmulateNop(const uint32_t opcode, |
2792 | const ARMEncoding encoding) { |
2793 | // NOP, nothing to do... |
2794 | return true; |
2795 | } |
2796 | |
2797 | // Branch causes a branch to a target address. |
2798 | bool EmulateInstructionARM::EmulateB(const uint32_t opcode, |
2799 | const ARMEncoding encoding) { |
2800 | #if 0 |
2801 | // ARM pseudo code... |
2802 | if (ConditionPassed()) |
2803 | { |
2804 | EncodingSpecificOperations(); |
2805 | BranchWritePC(PC + imm32); |
2806 | } |
2807 | #endif |
2808 | |
2809 | bool success = false; |
2810 | |
2811 | if (ConditionPassed(opcode)) { |
2812 | EmulateInstruction::Context context; |
2813 | context.type = EmulateInstruction::eContextRelativeBranchImmediate; |
2814 | const uint32_t pc = ReadCoreReg(PC_REG, success: &success); |
2815 | if (!success) |
2816 | return false; |
2817 | addr_t target; // target address |
2818 | int32_t imm32; // PC-relative offset |
2819 | switch (encoding) { |
2820 | case eEncodingT1: |
2821 | // The 'cond' field is handled in EmulateInstructionARM::CurrentCond(). |
2822 | imm32 = llvm::SignExtend32<9>(X: Bits32(bits: opcode, msbit: 7, lsbit: 0) << 1); |
2823 | target = pc + imm32; |
2824 | context.SetISAAndImmediateSigned(isa: eModeThumb, data: 4 + imm32); |
2825 | break; |
2826 | case eEncodingT2: |
2827 | imm32 = llvm::SignExtend32<12>(X: Bits32(bits: opcode, msbit: 10, lsbit: 0) << 1); |
2828 | target = pc + imm32; |
2829 | context.SetISAAndImmediateSigned(isa: eModeThumb, data: 4 + imm32); |
2830 | break; |
2831 | case eEncodingT3: |
2832 | // The 'cond' field is handled in EmulateInstructionARM::CurrentCond(). |
2833 | { |
2834 | if (Bits32(bits: opcode, msbit: 25, lsbit: 23) == 7) |
2835 | return false; // See Branches and miscellaneous control on page |
2836 | // A6-235. |
2837 | |
2838 | uint32_t S = Bit32(bits: opcode, bit: 26); |
2839 | uint32_t imm6 = Bits32(bits: opcode, msbit: 21, lsbit: 16); |
2840 | uint32_t J1 = Bit32(bits: opcode, bit: 13); |
2841 | uint32_t J2 = Bit32(bits: opcode, bit: 11); |
2842 | uint32_t imm11 = Bits32(bits: opcode, msbit: 10, lsbit: 0); |
2843 | uint32_t imm21 = |
2844 | (S << 20) | (J2 << 19) | (J1 << 18) | (imm6 << 12) | (imm11 << 1); |
2845 | imm32 = llvm::SignExtend32<21>(X: imm21); |
2846 | target = pc + imm32; |
2847 | context.SetISAAndImmediateSigned(isa: eModeThumb, data: 4 + imm32); |
2848 | break; |
2849 | } |
2850 | case eEncodingT4: { |
2851 | uint32_t S = Bit32(bits: opcode, bit: 26); |
2852 | uint32_t imm10 = Bits32(bits: opcode, msbit: 25, lsbit: 16); |
2853 | uint32_t J1 = Bit32(bits: opcode, bit: 13); |
2854 | uint32_t J2 = Bit32(bits: opcode, bit: 11); |
2855 | uint32_t imm11 = Bits32(bits: opcode, msbit: 10, lsbit: 0); |
2856 | uint32_t I1 = !(J1 ^ S); |
2857 | uint32_t I2 = !(J2 ^ S); |
2858 | uint32_t imm25 = |
2859 | (S << 24) | (I1 << 23) | (I2 << 22) | (imm10 << 12) | (imm11 << 1); |
2860 | imm32 = llvm::SignExtend32<25>(X: imm25); |
2861 | target = pc + imm32; |
2862 | context.SetISAAndImmediateSigned(isa: eModeThumb, data: 4 + imm32); |
2863 | break; |
2864 | } |
2865 | case eEncodingA1: |
2866 | imm32 = llvm::SignExtend32<26>(X: Bits32(bits: opcode, msbit: 23, lsbit: 0) << 2); |
2867 | target = pc + imm32; |
2868 | context.SetISAAndImmediateSigned(isa: eModeARM, data: 8 + imm32); |
2869 | break; |
2870 | default: |
2871 | return false; |
2872 | } |
2873 | if (!BranchWritePC(context, addr: target)) |
2874 | return false; |
2875 | } |
2876 | return true; |
2877 | } |
2878 | |
2879 | // Compare and Branch on Nonzero and Compare and Branch on Zero compare the |
2880 | // value in a register with zero and conditionally branch forward a constant |
2881 | // value. They do not affect the condition flags. CBNZ, CBZ |
2882 | bool EmulateInstructionARM::EmulateCB(const uint32_t opcode, |
2883 | const ARMEncoding encoding) { |
2884 | #if 0 |
2885 | // ARM pseudo code... |
2886 | EncodingSpecificOperations(); |
2887 | if nonzero ^ IsZero(R[n]) then |
2888 | BranchWritePC(PC + imm32); |
2889 | #endif |
2890 | |
2891 | bool success = false; |
2892 | |
2893 | // Read the register value from the operand register Rn. |
2894 | uint32_t reg_val = ReadCoreReg(regnum: Bits32(bits: opcode, msbit: 2, lsbit: 0), success: &success); |
2895 | if (!success) |
2896 | return false; |
2897 | |
2898 | EmulateInstruction::Context context; |
2899 | context.type = EmulateInstruction::eContextRelativeBranchImmediate; |
2900 | const uint32_t pc = ReadCoreReg(PC_REG, success: &success); |
2901 | if (!success) |
2902 | return false; |
2903 | |
2904 | addr_t target; // target address |
2905 | uint32_t imm32; // PC-relative offset to branch forward |
2906 | bool nonzero; |
2907 | switch (encoding) { |
2908 | case eEncodingT1: |
2909 | imm32 = Bit32(bits: opcode, bit: 9) << 6 | Bits32(bits: opcode, msbit: 7, lsbit: 3) << 1; |
2910 | nonzero = BitIsSet(value: opcode, bit: 11); |
2911 | target = pc + imm32; |
2912 | context.SetISAAndImmediateSigned(isa: eModeThumb, data: 4 + imm32); |
2913 | break; |
2914 | default: |
2915 | return false; |
2916 | } |
2917 | if (m_ignore_conditions || (nonzero ^ (reg_val == 0))) |
2918 | if (!BranchWritePC(context, addr: target)) |
2919 | return false; |
2920 | |
2921 | return true; |
2922 | } |
2923 | |
2924 | // Table Branch Byte causes a PC-relative forward branch using a table of |
2925 | // single byte offsets. |
2926 | // A base register provides a pointer to the table, and a second register |
2927 | // supplies an index into the table. |
2928 | // The branch length is twice the value of the byte returned from the table. |
2929 | // |
2930 | // Table Branch Halfword causes a PC-relative forward branch using a table of |
2931 | // single halfword offsets. |
2932 | // A base register provides a pointer to the table, and a second register |
2933 | // supplies an index into the table. |
2934 | // The branch length is twice the value of the halfword returned from the |
2935 | // table. TBB, TBH |
2936 | bool EmulateInstructionARM::EmulateTB(const uint32_t opcode, |
2937 | const ARMEncoding encoding) { |
2938 | #if 0 |
2939 | // ARM pseudo code... |
2940 | EncodingSpecificOperations(); NullCheckIfThumbEE(n); |
2941 | if is_tbh then |
2942 | halfwords = UInt(MemU[R[n]+LSL(R[m],1), 2]); |
2943 | else |
2944 | halfwords = UInt(MemU[R[n]+R[m], 1]); |
2945 | BranchWritePC(PC + 2*halfwords); |
2946 | #endif |
2947 | |
2948 | bool success = false; |
2949 | |
2950 | if (ConditionPassed(opcode)) { |
2951 | uint32_t Rn; // the base register which contains the address of the table of |
2952 | // branch lengths |
2953 | uint32_t Rm; // the index register which contains an integer pointing to a |
2954 | // byte/halfword in the table |
2955 | bool is_tbh; // true if table branch halfword |
2956 | switch (encoding) { |
2957 | case eEncodingT1: |
2958 | Rn = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
2959 | Rm = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
2960 | is_tbh = BitIsSet(value: opcode, bit: 4); |
2961 | if (Rn == 13 || BadReg(n: Rm)) |
2962 | return false; |
2963 | if (InITBlock() && !LastInITBlock()) |
2964 | return false; |
2965 | break; |
2966 | default: |
2967 | return false; |
2968 | } |
2969 | |
2970 | // Read the address of the table from the operand register Rn. The PC can |
2971 | // be used, in which case the table immediately follows this instruction. |
2972 | uint32_t base = ReadCoreReg(regnum: Rn, success: &success); |
2973 | if (!success) |
2974 | return false; |
2975 | |
2976 | // the table index |
2977 | uint32_t index = ReadCoreReg(regnum: Rm, success: &success); |
2978 | if (!success) |
2979 | return false; |
2980 | |
2981 | // the offsetted table address |
2982 | addr_t addr = base + (is_tbh ? index * 2 : index); |
2983 | |
2984 | // PC-relative offset to branch forward |
2985 | EmulateInstruction::Context context; |
2986 | context.type = EmulateInstruction::eContextTableBranchReadMemory; |
2987 | uint32_t offset = MemURead(context, address: addr, size: is_tbh ? 2 : 1, fail_value: 0, success_ptr: &success) * 2; |
2988 | if (!success) |
2989 | return false; |
2990 | |
2991 | const uint32_t pc = ReadCoreReg(PC_REG, success: &success); |
2992 | if (!success) |
2993 | return false; |
2994 | |
2995 | // target address |
2996 | addr_t target = pc + offset; |
2997 | context.type = EmulateInstruction::eContextRelativeBranchImmediate; |
2998 | context.SetISAAndImmediateSigned(isa: eModeThumb, data: 4 + offset); |
2999 | |
3000 | if (!BranchWritePC(context, addr: target)) |
3001 | return false; |
3002 | } |
3003 | |
3004 | return true; |
3005 | } |
3006 | |
3007 | // This instruction adds an immediate value to a register value, and writes the |
3008 | // result to the destination register. It can optionally update the condition |
3009 | // flags based on the result. |
3010 | bool EmulateInstructionARM::EmulateADDImmThumb(const uint32_t opcode, |
3011 | const ARMEncoding encoding) { |
3012 | #if 0 |
3013 | if ConditionPassed() then |
3014 | EncodingSpecificOperations(); |
3015 | (result, carry, overflow) = AddWithCarry(R[n], imm32, '0'); |
3016 | R[d] = result; |
3017 | if setflags then |
3018 | APSR.N = result<31>; |
3019 | APSR.Z = IsZeroBit(result); |
3020 | APSR.C = carry; |
3021 | APSR.V = overflow; |
3022 | #endif |
3023 | |
3024 | bool success = false; |
3025 | |
3026 | if (ConditionPassed(opcode)) { |
3027 | uint32_t d; |
3028 | uint32_t n; |
3029 | bool setflags; |
3030 | uint32_t imm32; |
3031 | uint32_t carry_out; |
3032 | |
3033 | // EncodingSpecificOperations(); |
3034 | switch (encoding) { |
3035 | case eEncodingT1: |
3036 | // d = UInt(Rd); n = UInt(Rn); setflags = !InITBlock(); imm32 = |
3037 | // ZeroExtend(imm3, 32); |
3038 | d = Bits32(bits: opcode, msbit: 2, lsbit: 0); |
3039 | n = Bits32(bits: opcode, msbit: 5, lsbit: 3); |
3040 | setflags = !InITBlock(); |
3041 | imm32 = Bits32(bits: opcode, msbit: 8, lsbit: 6); |
3042 | |
3043 | break; |
3044 | |
3045 | case eEncodingT2: |
3046 | // d = UInt(Rdn); n = UInt(Rdn); setflags = !InITBlock(); imm32 = |
3047 | // ZeroExtend(imm8, 32); |
3048 | d = Bits32(bits: opcode, msbit: 10, lsbit: 8); |
3049 | n = Bits32(bits: opcode, msbit: 10, lsbit: 8); |
3050 | setflags = !InITBlock(); |
3051 | imm32 = Bits32(bits: opcode, msbit: 7, lsbit: 0); |
3052 | |
3053 | break; |
3054 | |
3055 | case eEncodingT3: |
3056 | // if Rd == '1111' && S == '1' then SEE CMN (immediate); |
3057 | // d = UInt(Rd); n = UInt(Rn); setflags = (S == '1'); imm32 = |
3058 | // ThumbExpandImm(i:imm3:imm8); |
3059 | d = Bits32(bits: opcode, msbit: 11, lsbit: 8); |
3060 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
3061 | setflags = BitIsSet(value: opcode, bit: 20); |
3062 | imm32 = ThumbExpandImm_C(opcode, APSR_C, carry_out); |
3063 | |
3064 | // if Rn == '1101' then SEE ADD (SP plus immediate); |
3065 | if (n == 13) |
3066 | return EmulateADDSPImm(opcode, encoding: eEncodingT3); |
3067 | |
3068 | // if BadReg(d) || n == 15 then UNPREDICTABLE; |
3069 | if (BadReg(n: d) || (n == 15)) |
3070 | return false; |
3071 | |
3072 | break; |
3073 | |
3074 | case eEncodingT4: { |
3075 | // if Rn == '1111' then SEE ADR; |
3076 | // d = UInt(Rd); n = UInt(Rn); setflags = FALSE; imm32 = |
3077 | // ZeroExtend(i:imm3:imm8, 32); |
3078 | d = Bits32(bits: opcode, msbit: 11, lsbit: 8); |
3079 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
3080 | setflags = false; |
3081 | uint32_t i = Bit32(bits: opcode, bit: 26); |
3082 | uint32_t imm3 = Bits32(bits: opcode, msbit: 14, lsbit: 12); |
3083 | uint32_t imm8 = Bits32(bits: opcode, msbit: 7, lsbit: 0); |
3084 | imm32 = (i << 11) | (imm3 << 8) | imm8; |
3085 | |
3086 | // if Rn == '1101' then SEE ADD (SP plus immediate); |
3087 | if (n == 13) |
3088 | return EmulateADDSPImm(opcode, encoding: eEncodingT4); |
3089 | |
3090 | // if BadReg(d) then UNPREDICTABLE; |
3091 | if (BadReg(n: d)) |
3092 | return false; |
3093 | |
3094 | break; |
3095 | } |
3096 | |
3097 | default: |
3098 | return false; |
3099 | } |
3100 | |
3101 | uint64_t Rn = |
3102 | ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n, fail_value: 0, success_ptr: &success); |
3103 | if (!success) |
3104 | return false; |
3105 | |
3106 | //(result, carry, overflow) = AddWithCarry(R[n], imm32, '0'); |
3107 | AddWithCarryResult res = AddWithCarry(x: Rn, y: imm32, carry_in: 0); |
3108 | |
3109 | std::optional<RegisterInfo> reg_n = |
3110 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n); |
3111 | EmulateInstruction::Context context; |
3112 | context.type = eContextArithmetic; |
3113 | context.SetRegisterPlusOffset(base_reg: *reg_n, signed_offset: imm32); |
3114 | |
3115 | // R[d] = result; |
3116 | // if setflags then |
3117 | // APSR.N = result<31>; |
3118 | // APSR.Z = IsZeroBit(result); |
3119 | // APSR.C = carry; |
3120 | // APSR.V = overflow; |
3121 | if (!WriteCoreRegOptionalFlags(context, result: res.result, Rd: d, setflags, |
3122 | carry: res.carry_out, overflow: res.overflow)) |
3123 | return false; |
3124 | } |
3125 | return true; |
3126 | } |
3127 | |
3128 | // This instruction adds an immediate value to a register value, and writes the |
3129 | // result to the destination register. It can optionally update the condition |
3130 | // flags based on the result. |
3131 | bool EmulateInstructionARM::EmulateADDImmARM(const uint32_t opcode, |
3132 | const ARMEncoding encoding) { |
3133 | #if 0 |
3134 | // ARM pseudo code... |
3135 | if ConditionPassed() then |
3136 | EncodingSpecificOperations(); |
3137 | (result, carry, overflow) = AddWithCarry(R[n], imm32, '0'); |
3138 | if d == 15 then |
3139 | ALUWritePC(result); // setflags is always FALSE here |
3140 | else |
3141 | R[d] = result; |
3142 | if setflags then |
3143 | APSR.N = result<31>; |
3144 | APSR.Z = IsZeroBit(result); |
3145 | APSR.C = carry; |
3146 | APSR.V = overflow; |
3147 | #endif |
3148 | |
3149 | bool success = false; |
3150 | |
3151 | if (ConditionPassed(opcode)) { |
3152 | uint32_t Rd, Rn; |
3153 | uint32_t |
3154 | imm32; // the immediate value to be added to the value obtained from Rn |
3155 | bool setflags; |
3156 | switch (encoding) { |
3157 | case eEncodingA1: |
3158 | Rd = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
3159 | Rn = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
3160 | setflags = BitIsSet(value: opcode, bit: 20); |
3161 | imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12) |
3162 | break; |
3163 | default: |
3164 | return false; |
3165 | } |
3166 | |
3167 | // Read the first operand. |
3168 | uint32_t val1 = ReadCoreReg(regnum: Rn, success: &success); |
3169 | if (!success) |
3170 | return false; |
3171 | |
3172 | AddWithCarryResult res = AddWithCarry(x: val1, y: imm32, carry_in: 0); |
3173 | |
3174 | EmulateInstruction::Context context; |
3175 | if (Rd == 13) |
3176 | context.type = EmulateInstruction::eContextAdjustStackPointer; |
3177 | else if (Rd == GetFramePointerRegisterNumber()) |
3178 | context.type = EmulateInstruction::eContextSetFramePointer; |
3179 | else |
3180 | context.type = EmulateInstruction::eContextRegisterPlusOffset; |
3181 | |
3182 | std::optional<RegisterInfo> dwarf_reg = |
3183 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: Rn); |
3184 | context.SetRegisterPlusOffset(base_reg: *dwarf_reg, signed_offset: imm32); |
3185 | |
3186 | if (!WriteCoreRegOptionalFlags(context, result: res.result, Rd, setflags, |
3187 | carry: res.carry_out, overflow: res.overflow)) |
3188 | return false; |
3189 | } |
3190 | return true; |
3191 | } |
3192 | |
3193 | // This instruction adds a register value and an optionally-shifted register |
3194 | // value, and writes the result to the destination register. It can optionally |
3195 | // update the condition flags based on the result. |
3196 | bool EmulateInstructionARM::EmulateADDReg(const uint32_t opcode, |
3197 | const ARMEncoding encoding) { |
3198 | #if 0 |
3199 | // ARM pseudo code... |
3200 | if ConditionPassed() then |
3201 | EncodingSpecificOperations(); |
3202 | shifted = Shift(R[m], shift_t, shift_n, APSR.C); |
3203 | (result, carry, overflow) = AddWithCarry(R[n], shifted, '0'); |
3204 | if d == 15 then |
3205 | ALUWritePC(result); // setflags is always FALSE here |
3206 | else |
3207 | R[d] = result; |
3208 | if setflags then |
3209 | APSR.N = result<31>; |
3210 | APSR.Z = IsZeroBit(result); |
3211 | APSR.C = carry; |
3212 | APSR.V = overflow; |
3213 | #endif |
3214 | |
3215 | bool success = false; |
3216 | |
3217 | if (ConditionPassed(opcode)) { |
3218 | uint32_t Rd, Rn, Rm; |
3219 | ARM_ShifterType shift_t; |
3220 | uint32_t shift_n; // the shift applied to the value read from Rm |
3221 | bool setflags; |
3222 | switch (encoding) { |
3223 | case eEncodingT1: |
3224 | Rd = Bits32(bits: opcode, msbit: 2, lsbit: 0); |
3225 | Rn = Bits32(bits: opcode, msbit: 5, lsbit: 3); |
3226 | Rm = Bits32(bits: opcode, msbit: 8, lsbit: 6); |
3227 | setflags = !InITBlock(); |
3228 | shift_t = SRType_LSL; |
3229 | shift_n = 0; |
3230 | break; |
3231 | case eEncodingT2: |
3232 | Rd = Rn = Bit32(bits: opcode, bit: 7) << 3 | Bits32(bits: opcode, msbit: 2, lsbit: 0); |
3233 | Rm = Bits32(bits: opcode, msbit: 6, lsbit: 3); |
3234 | setflags = false; |
3235 | shift_t = SRType_LSL; |
3236 | shift_n = 0; |
3237 | if (Rn == 15 && Rm == 15) |
3238 | return false; |
3239 | if (Rd == 15 && InITBlock() && !LastInITBlock()) |
3240 | return false; |
3241 | break; |
3242 | case eEncodingA1: |
3243 | Rd = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
3244 | Rn = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
3245 | Rm = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
3246 | setflags = BitIsSet(value: opcode, bit: 20); |
3247 | shift_n = DecodeImmShiftARM(opcode, shift_t); |
3248 | break; |
3249 | default: |
3250 | return false; |
3251 | } |
3252 | |
3253 | // Read the first operand. |
3254 | uint32_t val1 = ReadCoreReg(regnum: Rn, success: &success); |
3255 | if (!success) |
3256 | return false; |
3257 | |
3258 | // Read the second operand. |
3259 | uint32_t val2 = ReadCoreReg(regnum: Rm, success: &success); |
3260 | if (!success) |
3261 | return false; |
3262 | |
3263 | uint32_t shifted = Shift(value: val2, type: shift_t, amount: shift_n, APSR_C, success: &success); |
3264 | if (!success) |
3265 | return false; |
3266 | AddWithCarryResult res = AddWithCarry(x: val1, y: shifted, carry_in: 0); |
3267 | |
3268 | EmulateInstruction::Context context; |
3269 | context.type = eContextArithmetic; |
3270 | std::optional<RegisterInfo> op1_reg = |
3271 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + Rn); |
3272 | std::optional<RegisterInfo> op2_reg = |
3273 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + Rm); |
3274 | context.SetRegisterRegisterOperands(op1_reg: *op1_reg, op2_reg: *op2_reg); |
3275 | |
3276 | if (!WriteCoreRegOptionalFlags(context, result: res.result, Rd, setflags, |
3277 | carry: res.carry_out, overflow: res.overflow)) |
3278 | return false; |
3279 | } |
3280 | return true; |
3281 | } |
3282 | |
3283 | // Compare Negative (immediate) adds a register value and an immediate value. |
3284 | // It updates the condition flags based on the result, and discards the result. |
3285 | bool EmulateInstructionARM::EmulateCMNImm(const uint32_t opcode, |
3286 | const ARMEncoding encoding) { |
3287 | #if 0 |
3288 | // ARM pseudo code... |
3289 | if ConditionPassed() then |
3290 | EncodingSpecificOperations(); |
3291 | (result, carry, overflow) = AddWithCarry(R[n], imm32, '0'); |
3292 | APSR.N = result<31>; |
3293 | APSR.Z = IsZeroBit(result); |
3294 | APSR.C = carry; |
3295 | APSR.V = overflow; |
3296 | #endif |
3297 | |
3298 | bool success = false; |
3299 | |
3300 | uint32_t Rn; // the first operand |
3301 | uint32_t imm32; // the immediate value to be compared with |
3302 | switch (encoding) { |
3303 | case eEncodingT1: |
3304 | Rn = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
3305 | imm32 = ThumbExpandImm(opcode); // imm32 = ThumbExpandImm(i:imm3:imm8) |
3306 | if (Rn == 15) |
3307 | return false; |
3308 | break; |
3309 | case eEncodingA1: |
3310 | Rn = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
3311 | imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12) |
3312 | break; |
3313 | default: |
3314 | return false; |
3315 | } |
3316 | // Read the register value from the operand register Rn. |
3317 | uint32_t reg_val = ReadCoreReg(regnum: Rn, success: &success); |
3318 | if (!success) |
3319 | return false; |
3320 | |
3321 | AddWithCarryResult res = AddWithCarry(x: reg_val, y: imm32, carry_in: 0); |
3322 | |
3323 | EmulateInstruction::Context context; |
3324 | context.type = EmulateInstruction::eContextImmediate; |
3325 | context.SetNoArgs(); |
3326 | return WriteFlags(context, result: res.result, carry: res.carry_out, overflow: res.overflow); |
3327 | } |
3328 | |
3329 | // Compare Negative (register) adds a register value and an optionally-shifted |
3330 | // register value. It updates the condition flags based on the result, and |
3331 | // discards the result. |
3332 | bool EmulateInstructionARM::EmulateCMNReg(const uint32_t opcode, |
3333 | const ARMEncoding encoding) { |
3334 | #if 0 |
3335 | // ARM pseudo code... |
3336 | if ConditionPassed() then |
3337 | EncodingSpecificOperations(); |
3338 | shifted = Shift(R[m], shift_t, shift_n, APSR.C); |
3339 | (result, carry, overflow) = AddWithCarry(R[n], shifted, '0'); |
3340 | APSR.N = result<31>; |
3341 | APSR.Z = IsZeroBit(result); |
3342 | APSR.C = carry; |
3343 | APSR.V = overflow; |
3344 | #endif |
3345 | |
3346 | bool success = false; |
3347 | |
3348 | uint32_t Rn; // the first operand |
3349 | uint32_t Rm; // the second operand |
3350 | ARM_ShifterType shift_t; |
3351 | uint32_t shift_n; // the shift applied to the value read from Rm |
3352 | switch (encoding) { |
3353 | case eEncodingT1: |
3354 | Rn = Bits32(bits: opcode, msbit: 2, lsbit: 0); |
3355 | Rm = Bits32(bits: opcode, msbit: 5, lsbit: 3); |
3356 | shift_t = SRType_LSL; |
3357 | shift_n = 0; |
3358 | break; |
3359 | case eEncodingT2: |
3360 | Rn = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
3361 | Rm = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
3362 | shift_n = DecodeImmShiftThumb(opcode, shift_t); |
3363 | // if n == 15 || BadReg(m) then UNPREDICTABLE; |
3364 | if (Rn == 15 || BadReg(n: Rm)) |
3365 | return false; |
3366 | break; |
3367 | case eEncodingA1: |
3368 | Rn = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
3369 | Rm = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
3370 | shift_n = DecodeImmShiftARM(opcode, shift_t); |
3371 | break; |
3372 | default: |
3373 | return false; |
3374 | } |
3375 | // Read the register value from register Rn. |
3376 | uint32_t val1 = ReadCoreReg(regnum: Rn, success: &success); |
3377 | if (!success) |
3378 | return false; |
3379 | |
3380 | // Read the register value from register Rm. |
3381 | uint32_t val2 = ReadCoreReg(regnum: Rm, success: &success); |
3382 | if (!success) |
3383 | return false; |
3384 | |
3385 | uint32_t shifted = Shift(value: val2, type: shift_t, amount: shift_n, APSR_C, success: &success); |
3386 | if (!success) |
3387 | return false; |
3388 | AddWithCarryResult res = AddWithCarry(x: val1, y: shifted, carry_in: 0); |
3389 | |
3390 | EmulateInstruction::Context context; |
3391 | context.type = EmulateInstruction::eContextImmediate; |
3392 | context.SetNoArgs(); |
3393 | return WriteFlags(context, result: res.result, carry: res.carry_out, overflow: res.overflow); |
3394 | } |
3395 | |
3396 | // Compare (immediate) subtracts an immediate value from a register value. It |
3397 | // updates the condition flags based on the result, and discards the result. |
3398 | bool EmulateInstructionARM::EmulateCMPImm(const uint32_t opcode, |
3399 | const ARMEncoding encoding) { |
3400 | #if 0 |
3401 | // ARM pseudo code... |
3402 | if ConditionPassed() then |
3403 | EncodingSpecificOperations(); |
3404 | (result, carry, overflow) = AddWithCarry(R[n], NOT(imm32), '1'); |
3405 | APSR.N = result<31>; |
3406 | APSR.Z = IsZeroBit(result); |
3407 | APSR.C = carry; |
3408 | APSR.V = overflow; |
3409 | #endif |
3410 | |
3411 | bool success = false; |
3412 | |
3413 | uint32_t Rn; // the first operand |
3414 | uint32_t imm32; // the immediate value to be compared with |
3415 | switch (encoding) { |
3416 | case eEncodingT1: |
3417 | Rn = Bits32(bits: opcode, msbit: 10, lsbit: 8); |
3418 | imm32 = Bits32(bits: opcode, msbit: 7, lsbit: 0); |
3419 | break; |
3420 | case eEncodingT2: |
3421 | Rn = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
3422 | imm32 = ThumbExpandImm(opcode); // imm32 = ThumbExpandImm(i:imm3:imm8) |
3423 | if (Rn == 15) |
3424 | return false; |
3425 | break; |
3426 | case eEncodingA1: |
3427 | Rn = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
3428 | imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12) |
3429 | break; |
3430 | default: |
3431 | return false; |
3432 | } |
3433 | // Read the register value from the operand register Rn. |
3434 | uint32_t reg_val = ReadCoreReg(regnum: Rn, success: &success); |
3435 | if (!success) |
3436 | return false; |
3437 | |
3438 | AddWithCarryResult res = AddWithCarry(x: reg_val, y: ~imm32, carry_in: 1); |
3439 | |
3440 | EmulateInstruction::Context context; |
3441 | context.type = EmulateInstruction::eContextImmediate; |
3442 | context.SetNoArgs(); |
3443 | return WriteFlags(context, result: res.result, carry: res.carry_out, overflow: res.overflow); |
3444 | } |
3445 | |
3446 | // Compare (register) subtracts an optionally-shifted register value from a |
3447 | // register value. It updates the condition flags based on the result, and |
3448 | // discards the result. |
3449 | bool EmulateInstructionARM::EmulateCMPReg(const uint32_t opcode, |
3450 | const ARMEncoding encoding) { |
3451 | #if 0 |
3452 | // ARM pseudo code... |
3453 | if ConditionPassed() then |
3454 | EncodingSpecificOperations(); |
3455 | shifted = Shift(R[m], shift_t, shift_n, APSR.C); |
3456 | (result, carry, overflow) = AddWithCarry(R[n], NOT(shifted), '1'); |
3457 | APSR.N = result<31>; |
3458 | APSR.Z = IsZeroBit(result); |
3459 | APSR.C = carry; |
3460 | APSR.V = overflow; |
3461 | #endif |
3462 | |
3463 | bool success = false; |
3464 | |
3465 | uint32_t Rn; // the first operand |
3466 | uint32_t Rm; // the second operand |
3467 | ARM_ShifterType shift_t; |
3468 | uint32_t shift_n; // the shift applied to the value read from Rm |
3469 | switch (encoding) { |
3470 | case eEncodingT1: |
3471 | Rn = Bits32(bits: opcode, msbit: 2, lsbit: 0); |
3472 | Rm = Bits32(bits: opcode, msbit: 5, lsbit: 3); |
3473 | shift_t = SRType_LSL; |
3474 | shift_n = 0; |
3475 | break; |
3476 | case eEncodingT2: |
3477 | Rn = Bit32(bits: opcode, bit: 7) << 3 | Bits32(bits: opcode, msbit: 2, lsbit: 0); |
3478 | Rm = Bits32(bits: opcode, msbit: 6, lsbit: 3); |
3479 | shift_t = SRType_LSL; |
3480 | shift_n = 0; |
3481 | if (Rn < 8 && Rm < 8) |
3482 | return false; |
3483 | if (Rn == 15 || Rm == 15) |
3484 | return false; |
3485 | break; |
3486 | case eEncodingT3: |
3487 | Rn = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
3488 | Rm = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
3489 | shift_n = DecodeImmShiftThumb(opcode, shift_t); |
3490 | if (Rn == 15 || BadReg(n: Rm)) |
3491 | return false; |
3492 | break; |
3493 | case eEncodingA1: |
3494 | Rn = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
3495 | Rm = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
3496 | shift_n = DecodeImmShiftARM(opcode, shift_t); |
3497 | break; |
3498 | default: |
3499 | return false; |
3500 | } |
3501 | // Read the register value from register Rn. |
3502 | uint32_t val1 = ReadCoreReg(regnum: Rn, success: &success); |
3503 | if (!success) |
3504 | return false; |
3505 | |
3506 | // Read the register value from register Rm. |
3507 | uint32_t val2 = ReadCoreReg(regnum: Rm, success: &success); |
3508 | if (!success) |
3509 | return false; |
3510 | |
3511 | uint32_t shifted = Shift(value: val2, type: shift_t, amount: shift_n, APSR_C, success: &success); |
3512 | if (!success) |
3513 | return false; |
3514 | AddWithCarryResult res = AddWithCarry(x: val1, y: ~shifted, carry_in: 1); |
3515 | |
3516 | EmulateInstruction::Context context; |
3517 | context.type = EmulateInstruction::eContextImmediate; |
3518 | context.SetNoArgs(); |
3519 | return WriteFlags(context, result: res.result, carry: res.carry_out, overflow: res.overflow); |
3520 | } |
3521 | |
3522 | // Arithmetic Shift Right (immediate) shifts a register value right by an |
3523 | // immediate number of bits, shifting in copies of its sign bit, and writes the |
3524 | // result to the destination register. It can optionally update the condition |
3525 | // flags based on the result. |
3526 | bool EmulateInstructionARM::EmulateASRImm(const uint32_t opcode, |
3527 | const ARMEncoding encoding) { |
3528 | #if 0 |
3529 | // ARM pseudo code... |
3530 | if ConditionPassed() then |
3531 | EncodingSpecificOperations(); |
3532 | (result, carry) = Shift_C(R[m], SRType_ASR, shift_n, APSR.C); |
3533 | if d == 15 then // Can only occur for ARM encoding |
3534 | ALUWritePC(result); // setflags is always FALSE here |
3535 | else |
3536 | R[d] = result; |
3537 | if setflags then |
3538 | APSR.N = result<31>; |
3539 | APSR.Z = IsZeroBit(result); |
3540 | APSR.C = carry; |
3541 | // APSR.V unchanged |
3542 | #endif |
3543 | |
3544 | return EmulateShiftImm(opcode, encoding, shift_type: SRType_ASR); |
3545 | } |
3546 | |
3547 | // Arithmetic Shift Right (register) shifts a register value right by a |
3548 | // variable number of bits, shifting in copies of its sign bit, and writes the |
3549 | // result to the destination register. The variable number of bits is read from |
3550 | // the bottom byte of a register. It can optionally update the condition flags |
3551 | // based on the result. |
3552 | bool EmulateInstructionARM::EmulateASRReg(const uint32_t opcode, |
3553 | const ARMEncoding encoding) { |
3554 | #if 0 |
3555 | // ARM pseudo code... |
3556 | if ConditionPassed() then |
3557 | EncodingSpecificOperations(); |
3558 | shift_n = UInt(R[m]<7:0>); |
3559 | (result, carry) = Shift_C(R[m], SRType_ASR, shift_n, APSR.C); |
3560 | R[d] = result; |
3561 | if setflags then |
3562 | APSR.N = result<31>; |
3563 | APSR.Z = IsZeroBit(result); |
3564 | APSR.C = carry; |
3565 | // APSR.V unchanged |
3566 | #endif |
3567 | |
3568 | return EmulateShiftReg(opcode, encoding, shift_type: SRType_ASR); |
3569 | } |
3570 | |
3571 | // Logical Shift Left (immediate) shifts a register value left by an immediate |
3572 | // number of bits, shifting in zeros, and writes the result to the destination |
3573 | // register. It can optionally update the condition flags based on the result. |
3574 | bool EmulateInstructionARM::EmulateLSLImm(const uint32_t opcode, |
3575 | const ARMEncoding encoding) { |
3576 | #if 0 |
3577 | // ARM pseudo code... |
3578 | if ConditionPassed() then |
3579 | EncodingSpecificOperations(); |
3580 | (result, carry) = Shift_C(R[m], SRType_LSL, shift_n, APSR.C); |
3581 | if d == 15 then // Can only occur for ARM encoding |
3582 | ALUWritePC(result); // setflags is always FALSE here |
3583 | else |
3584 | R[d] = result; |
3585 | if setflags then |
3586 | APSR.N = result<31>; |
3587 | APSR.Z = IsZeroBit(result); |
3588 | APSR.C = carry; |
3589 | // APSR.V unchanged |
3590 | #endif |
3591 | |
3592 | return EmulateShiftImm(opcode, encoding, shift_type: SRType_LSL); |
3593 | } |
3594 | |
3595 | // Logical Shift Left (register) shifts a register value left by a variable |
3596 | // number of bits, shifting in zeros, and writes the result to the destination |
3597 | // register. The variable number of bits is read from the bottom byte of a |
3598 | // register. It can optionally update the condition flags based on the result. |
3599 | bool EmulateInstructionARM::EmulateLSLReg(const uint32_t opcode, |
3600 | const ARMEncoding encoding) { |
3601 | #if 0 |
3602 | // ARM pseudo code... |
3603 | if ConditionPassed() then |
3604 | EncodingSpecificOperations(); |
3605 | shift_n = UInt(R[m]<7:0>); |
3606 | (result, carry) = Shift_C(R[m], SRType_LSL, shift_n, APSR.C); |
3607 | R[d] = result; |
3608 | if setflags then |
3609 | APSR.N = result<31>; |
3610 | APSR.Z = IsZeroBit(result); |
3611 | APSR.C = carry; |
3612 | // APSR.V unchanged |
3613 | #endif |
3614 | |
3615 | return EmulateShiftReg(opcode, encoding, shift_type: SRType_LSL); |
3616 | } |
3617 | |
3618 | // Logical Shift Right (immediate) shifts a register value right by an |
3619 | // immediate number of bits, shifting in zeros, and writes the result to the |
3620 | // destination register. It can optionally update the condition flags based on |
3621 | // the result. |
3622 | bool EmulateInstructionARM::EmulateLSRImm(const uint32_t opcode, |
3623 | const ARMEncoding encoding) { |
3624 | #if 0 |
3625 | // ARM pseudo code... |
3626 | if ConditionPassed() then |
3627 | EncodingSpecificOperations(); |
3628 | (result, carry) = Shift_C(R[m], SRType_LSR, shift_n, APSR.C); |
3629 | if d == 15 then // Can only occur for ARM encoding |
3630 | ALUWritePC(result); // setflags is always FALSE here |
3631 | else |
3632 | R[d] = result; |
3633 | if setflags then |
3634 | APSR.N = result<31>; |
3635 | APSR.Z = IsZeroBit(result); |
3636 | APSR.C = carry; |
3637 | // APSR.V unchanged |
3638 | #endif |
3639 | |
3640 | return EmulateShiftImm(opcode, encoding, shift_type: SRType_LSR); |
3641 | } |
3642 | |
3643 | // Logical Shift Right (register) shifts a register value right by a variable |
3644 | // number of bits, shifting in zeros, and writes the result to the destination |
3645 | // register. The variable number of bits is read from the bottom byte of a |
3646 | // register. It can optionally update the condition flags based on the result. |
3647 | bool EmulateInstructionARM::EmulateLSRReg(const uint32_t opcode, |
3648 | const ARMEncoding encoding) { |
3649 | #if 0 |
3650 | // ARM pseudo code... |
3651 | if ConditionPassed() then |
3652 | EncodingSpecificOperations(); |
3653 | shift_n = UInt(R[m]<7:0>); |
3654 | (result, carry) = Shift_C(R[m], SRType_LSR, shift_n, APSR.C); |
3655 | R[d] = result; |
3656 | if setflags then |
3657 | APSR.N = result<31>; |
3658 | APSR.Z = IsZeroBit(result); |
3659 | APSR.C = carry; |
3660 | // APSR.V unchanged |
3661 | #endif |
3662 | |
3663 | return EmulateShiftReg(opcode, encoding, shift_type: SRType_LSR); |
3664 | } |
3665 | |
3666 | // Rotate Right (immediate) provides the value of the contents of a register |
3667 | // rotated by a constant value. The bits that are rotated off the right end are |
3668 | // inserted into the vacated bit positions on the left. It can optionally |
3669 | // update the condition flags based on the result. |
3670 | bool EmulateInstructionARM::EmulateRORImm(const uint32_t opcode, |
3671 | const ARMEncoding encoding) { |
3672 | #if 0 |
3673 | // ARM pseudo code... |
3674 | if ConditionPassed() then |
3675 | EncodingSpecificOperations(); |
3676 | (result, carry) = Shift_C(R[m], SRType_ROR, shift_n, APSR.C); |
3677 | if d == 15 then // Can only occur for ARM encoding |
3678 | ALUWritePC(result); // setflags is always FALSE here |
3679 | else |
3680 | R[d] = result; |
3681 | if setflags then |
3682 | APSR.N = result<31>; |
3683 | APSR.Z = IsZeroBit(result); |
3684 | APSR.C = carry; |
3685 | // APSR.V unchanged |
3686 | #endif |
3687 | |
3688 | return EmulateShiftImm(opcode, encoding, shift_type: SRType_ROR); |
3689 | } |
3690 | |
3691 | // Rotate Right (register) provides the value of the contents of a register |
3692 | // rotated by a variable number of bits. The bits that are rotated off the |
3693 | // right end are inserted into the vacated bit positions on the left. The |
3694 | // variable number of bits is read from the bottom byte of a register. It can |
3695 | // optionally update the condition flags based on the result. |
3696 | bool EmulateInstructionARM::EmulateRORReg(const uint32_t opcode, |
3697 | const ARMEncoding encoding) { |
3698 | #if 0 |
3699 | // ARM pseudo code... |
3700 | if ConditionPassed() then |
3701 | EncodingSpecificOperations(); |
3702 | shift_n = UInt(R[m]<7:0>); |
3703 | (result, carry) = Shift_C(R[m], SRType_ROR, shift_n, APSR.C); |
3704 | R[d] = result; |
3705 | if setflags then |
3706 | APSR.N = result<31>; |
3707 | APSR.Z = IsZeroBit(result); |
3708 | APSR.C = carry; |
3709 | // APSR.V unchanged |
3710 | #endif |
3711 | |
3712 | return EmulateShiftReg(opcode, encoding, shift_type: SRType_ROR); |
3713 | } |
3714 | |
3715 | // Rotate Right with Extend provides the value of the contents of a register |
3716 | // shifted right by one place, with the carry flag shifted into bit [31]. |
3717 | // |
3718 | // RRX can optionally update the condition flags based on the result. |
3719 | // In that case, bit [0] is shifted into the carry flag. |
3720 | bool EmulateInstructionARM::EmulateRRX(const uint32_t opcode, |
3721 | const ARMEncoding encoding) { |
3722 | #if 0 |
3723 | // ARM pseudo code... |
3724 | if ConditionPassed() then |
3725 | EncodingSpecificOperations(); |
3726 | (result, carry) = Shift_C(R[m], SRType_RRX, 1, APSR.C); |
3727 | if d == 15 then // Can only occur for ARM encoding |
3728 | ALUWritePC(result); // setflags is always FALSE here |
3729 | else |
3730 | R[d] = result; |
3731 | if setflags then |
3732 | APSR.N = result<31>; |
3733 | APSR.Z = IsZeroBit(result); |
3734 | APSR.C = carry; |
3735 | // APSR.V unchanged |
3736 | #endif |
3737 | |
3738 | return EmulateShiftImm(opcode, encoding, shift_type: SRType_RRX); |
3739 | } |
3740 | |
3741 | bool EmulateInstructionARM::EmulateShiftImm(const uint32_t opcode, |
3742 | const ARMEncoding encoding, |
3743 | ARM_ShifterType shift_type) { |
3744 | // assert(shift_type == SRType_ASR |
3745 | // || shift_type == SRType_LSL |
3746 | // || shift_type == SRType_LSR |
3747 | // || shift_type == SRType_ROR |
3748 | // || shift_type == SRType_RRX); |
3749 | |
3750 | bool success = false; |
3751 | |
3752 | if (ConditionPassed(opcode)) { |
3753 | uint32_t Rd; // the destination register |
3754 | uint32_t Rm; // the first operand register |
3755 | uint32_t imm5; // encoding for the shift amount |
3756 | uint32_t carry; // the carry bit after the shift operation |
3757 | bool setflags; |
3758 | |
3759 | // Special case handling! |
3760 | // A8.6.139 ROR (immediate) -- Encoding T1 |
3761 | ARMEncoding use_encoding = encoding; |
3762 | if (shift_type == SRType_ROR && use_encoding == eEncodingT1) { |
3763 | // Morph the T1 encoding from the ARM Architecture Manual into T2 |
3764 | // encoding to have the same decoding of bit fields as the other Thumb2 |
3765 | // shift operations. |
3766 | use_encoding = eEncodingT2; |
3767 | } |
3768 | |
3769 | switch (use_encoding) { |
3770 | case eEncodingT1: |
3771 | Rd = Bits32(bits: opcode, msbit: 2, lsbit: 0); |
3772 | Rm = Bits32(bits: opcode, msbit: 5, lsbit: 3); |
3773 | setflags = !InITBlock(); |
3774 | imm5 = Bits32(bits: opcode, msbit: 10, lsbit: 6); |
3775 | break; |
3776 | case eEncodingT2: |
3777 | // A8.6.141 RRX |
3778 | // There's no imm form of RRX instructions. |
3779 | if (shift_type == SRType_RRX) |
3780 | return false; |
3781 | |
3782 | Rd = Bits32(bits: opcode, msbit: 11, lsbit: 8); |
3783 | Rm = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
3784 | setflags = BitIsSet(value: opcode, bit: 20); |
3785 | imm5 = Bits32(bits: opcode, msbit: 14, lsbit: 12) << 2 | Bits32(bits: opcode, msbit: 7, lsbit: 6); |
3786 | if (BadReg(n: Rd) || BadReg(n: Rm)) |
3787 | return false; |
3788 | break; |
3789 | case eEncodingA1: |
3790 | Rd = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
3791 | Rm = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
3792 | setflags = BitIsSet(value: opcode, bit: 20); |
3793 | imm5 = Bits32(bits: opcode, msbit: 11, lsbit: 7); |
3794 | break; |
3795 | default: |
3796 | return false; |
3797 | } |
3798 | |
3799 | // A8.6.139 ROR (immediate) |
3800 | if (shift_type == SRType_ROR && imm5 == 0) |
3801 | shift_type = SRType_RRX; |
3802 | |
3803 | // Get the first operand. |
3804 | uint32_t value = ReadCoreReg(regnum: Rm, success: &success); |
3805 | if (!success) |
3806 | return false; |
3807 | |
3808 | // Decode the shift amount if not RRX. |
3809 | uint32_t amt = |
3810 | (shift_type == SRType_RRX ? 1 : DecodeImmShift(shift_t: shift_type, imm5)); |
3811 | |
3812 | uint32_t result = Shift_C(value, type: shift_type, amount: amt, APSR_C, carry_out&: carry, success: &success); |
3813 | if (!success) |
3814 | return false; |
3815 | |
3816 | // The context specifies that an immediate is to be moved into Rd. |
3817 | EmulateInstruction::Context context; |
3818 | context.type = EmulateInstruction::eContextImmediate; |
3819 | context.SetNoArgs(); |
3820 | |
3821 | if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry)) |
3822 | return false; |
3823 | } |
3824 | return true; |
3825 | } |
3826 | |
3827 | bool EmulateInstructionARM::EmulateShiftReg(const uint32_t opcode, |
3828 | const ARMEncoding encoding, |
3829 | ARM_ShifterType shift_type) { |
3830 | // assert(shift_type == SRType_ASR |
3831 | // || shift_type == SRType_LSL |
3832 | // || shift_type == SRType_LSR |
3833 | // || shift_type == SRType_ROR); |
3834 | |
3835 | bool success = false; |
3836 | |
3837 | if (ConditionPassed(opcode)) { |
3838 | uint32_t Rd; // the destination register |
3839 | uint32_t Rn; // the first operand register |
3840 | uint32_t |
3841 | Rm; // the register whose bottom byte contains the amount to shift by |
3842 | uint32_t carry; // the carry bit after the shift operation |
3843 | bool setflags; |
3844 | switch (encoding) { |
3845 | case eEncodingT1: |
3846 | Rd = Bits32(bits: opcode, msbit: 2, lsbit: 0); |
3847 | Rn = Rd; |
3848 | Rm = Bits32(bits: opcode, msbit: 5, lsbit: 3); |
3849 | setflags = !InITBlock(); |
3850 | break; |
3851 | case eEncodingT2: |
3852 | Rd = Bits32(bits: opcode, msbit: 11, lsbit: 8); |
3853 | Rn = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
3854 | Rm = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
3855 | setflags = BitIsSet(value: opcode, bit: 20); |
3856 | if (BadReg(n: Rd) || BadReg(n: Rn) || BadReg(n: Rm)) |
3857 | return false; |
3858 | break; |
3859 | case eEncodingA1: |
3860 | Rd = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
3861 | Rn = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
3862 | Rm = Bits32(bits: opcode, msbit: 11, lsbit: 8); |
3863 | setflags = BitIsSet(value: opcode, bit: 20); |
3864 | if (Rd == 15 || Rn == 15 || Rm == 15) |
3865 | return false; |
3866 | break; |
3867 | default: |
3868 | return false; |
3869 | } |
3870 | |
3871 | // Get the first operand. |
3872 | uint32_t value = ReadCoreReg(regnum: Rn, success: &success); |
3873 | if (!success) |
3874 | return false; |
3875 | // Get the Rm register content. |
3876 | uint32_t val = ReadCoreReg(regnum: Rm, success: &success); |
3877 | if (!success) |
3878 | return false; |
3879 | |
3880 | // Get the shift amount. |
3881 | uint32_t amt = Bits32(bits: val, msbit: 7, lsbit: 0); |
3882 | |
3883 | uint32_t result = Shift_C(value, type: shift_type, amount: amt, APSR_C, carry_out&: carry, success: &success); |
3884 | if (!success) |
3885 | return false; |
3886 | |
3887 | // The context specifies that an immediate is to be moved into Rd. |
3888 | EmulateInstruction::Context context; |
3889 | context.type = EmulateInstruction::eContextImmediate; |
3890 | context.SetNoArgs(); |
3891 | |
3892 | if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry)) |
3893 | return false; |
3894 | } |
3895 | return true; |
3896 | } |
3897 | |
3898 | // LDM loads multiple registers from consecutive memory locations, using an |
3899 | // address from a base register. Optionally the address just above the highest |
3900 | // of those locations can be written back to the base register. |
3901 | bool EmulateInstructionARM::EmulateLDM(const uint32_t opcode, |
3902 | const ARMEncoding encoding) { |
3903 | #if 0 |
3904 | // ARM pseudo code... |
3905 | if ConditionPassed() |
3906 | EncodingSpecificOperations(); NullCheckIfThumbEE (n); |
3907 | address = R[n]; |
3908 | |
3909 | for i = 0 to 14 |
3910 | if registers<i> == '1' then |
3911 | R[i] = MemA[address, 4]; address = address + 4; |
3912 | if registers<15> == '1' then |
3913 | LoadWritePC (MemA[address, 4]); |
3914 | |
3915 | if wback && registers<n> == '0' then R[n] = R[n] + 4 * BitCount (registers); |
3916 | if wback && registers<n> == '1' then R[n] = bits(32) UNKNOWN; // Only possible for encoding A1 |
3917 | |
3918 | #endif |
3919 | |
3920 | bool success = false; |
3921 | if (ConditionPassed(opcode)) { |
3922 | uint32_t n; |
3923 | uint32_t registers = 0; |
3924 | bool wback; |
3925 | const uint32_t addr_byte_size = GetAddressByteSize(); |
3926 | switch (encoding) { |
3927 | case eEncodingT1: |
3928 | // n = UInt(Rn); registers = '00000000':register_list; wback = |
3929 | // (registers<n> == '0'); |
3930 | n = Bits32(bits: opcode, msbit: 10, lsbit: 8); |
3931 | registers = Bits32(bits: opcode, msbit: 7, lsbit: 0); |
3932 | registers = registers & 0x00ff; // Make sure the top 8 bits are zeros. |
3933 | wback = BitIsClear(value: registers, bit: n); |
3934 | // if BitCount(registers) < 1 then UNPREDICTABLE; |
3935 | if (BitCount(x: registers) < 1) |
3936 | return false; |
3937 | break; |
3938 | case eEncodingT2: |
3939 | // if W == '1' && Rn == '1101' then SEE POP; |
3940 | // n = UInt(Rn); registers = P:M:'0':register_list; wback = (W == '1'); |
3941 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
3942 | registers = Bits32(bits: opcode, msbit: 15, lsbit: 0); |
3943 | registers = registers & 0xdfff; // Make sure bit 13 is zero. |
3944 | wback = BitIsSet(value: opcode, bit: 21); |
3945 | |
3946 | // if n == 15 || BitCount(registers) < 2 || (P == '1' && M == '1') then |
3947 | // UNPREDICTABLE; |
3948 | if ((n == 15) || (BitCount(x: registers) < 2) || |
3949 | (BitIsSet(value: opcode, bit: 14) && BitIsSet(value: opcode, bit: 15))) |
3950 | return false; |
3951 | |
3952 | // if registers<15> == '1' && InITBlock() && !LastInITBlock() then |
3953 | // UNPREDICTABLE; |
3954 | if (BitIsSet(value: registers, bit: 15) && InITBlock() && !LastInITBlock()) |
3955 | return false; |
3956 | |
3957 | // if wback && registers<n> == '1' then UNPREDICTABLE; |
3958 | if (wback && BitIsSet(value: registers, bit: n)) |
3959 | return false; |
3960 | break; |
3961 | |
3962 | case eEncodingA1: |
3963 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
3964 | registers = Bits32(bits: opcode, msbit: 15, lsbit: 0); |
3965 | wback = BitIsSet(value: opcode, bit: 21); |
3966 | if ((n == 15) || (BitCount(x: registers) < 1)) |
3967 | return false; |
3968 | break; |
3969 | default: |
3970 | return false; |
3971 | } |
3972 | |
3973 | int32_t offset = 0; |
3974 | const addr_t base_address = |
3975 | ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n, fail_value: 0, success_ptr: &success); |
3976 | if (!success) |
3977 | return false; |
3978 | |
3979 | EmulateInstruction::Context context; |
3980 | context.type = EmulateInstruction::eContextRegisterPlusOffset; |
3981 | std::optional<RegisterInfo> dwarf_reg = |
3982 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n); |
3983 | context.SetRegisterPlusOffset(base_reg: *dwarf_reg, signed_offset: offset); |
3984 | |
3985 | for (int i = 0; i < 14; ++i) { |
3986 | if (BitIsSet(value: registers, bit: i)) { |
3987 | context.type = EmulateInstruction::eContextRegisterPlusOffset; |
3988 | context.SetRegisterPlusOffset(base_reg: *dwarf_reg, signed_offset: offset); |
3989 | if (wback && (n == 13)) // Pop Instruction |
3990 | { |
3991 | context.type = EmulateInstruction::eContextPopRegisterOffStack; |
3992 | context.SetAddress(base_address + offset); |
3993 | } |
3994 | |
3995 | // R[i] = MemA [address, 4]; address = address + 4; |
3996 | uint32_t data = MemARead(context, address: base_address + offset, size: addr_byte_size, |
3997 | fail_value: 0, success_ptr: &success); |
3998 | if (!success) |
3999 | return false; |
4000 | |
4001 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + i, |
4002 | reg_value: data)) |
4003 | return false; |
4004 | |
4005 | offset += addr_byte_size; |
4006 | } |
4007 | } |
4008 | |
4009 | if (BitIsSet(value: registers, bit: 15)) { |
4010 | // LoadWritePC (MemA [address, 4]); |
4011 | context.type = EmulateInstruction::eContextRegisterPlusOffset; |
4012 | context.SetRegisterPlusOffset(base_reg: *dwarf_reg, signed_offset: offset); |
4013 | uint32_t data = |
4014 | MemARead(context, address: base_address + offset, size: addr_byte_size, fail_value: 0, success_ptr: &success); |
4015 | if (!success) |
4016 | return false; |
4017 | // In ARMv5T and above, this is an interworking branch. |
4018 | if (!LoadWritePC(context, addr: data)) |
4019 | return false; |
4020 | } |
4021 | |
4022 | if (wback && BitIsClear(value: registers, bit: n)) { |
4023 | // R[n] = R[n] + 4 * BitCount (registers) |
4024 | int32_t offset = addr_byte_size * BitCount(x: registers); |
4025 | context.type = EmulateInstruction::eContextAdjustBaseRegister; |
4026 | context.SetRegisterPlusOffset(base_reg: *dwarf_reg, signed_offset: offset); |
4027 | |
4028 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n, |
4029 | reg_value: base_address + offset)) |
4030 | return false; |
4031 | } |
4032 | if (wback && BitIsSet(value: registers, bit: n)) |
4033 | // R[n] bits(32) UNKNOWN; |
4034 | return WriteBits32Unknown(n); |
4035 | } |
4036 | return true; |
4037 | } |
4038 | |
4039 | // LDMDA loads multiple registers from consecutive memory locations using an |
4040 | // address from a base register. |
4041 | // The consecutive memory locations end at this address and the address just |
4042 | // below the lowest of those locations can optionally be written back to the |
4043 | // base register. |
4044 | bool EmulateInstructionARM::EmulateLDMDA(const uint32_t opcode, |
4045 | const ARMEncoding encoding) { |
4046 | #if 0 |
4047 | // ARM pseudo code... |
4048 | if ConditionPassed() then |
4049 | EncodingSpecificOperations(); |
4050 | address = R[n] - 4*BitCount(registers) + 4; |
4051 | |
4052 | for i = 0 to 14 |
4053 | if registers<i> == '1' then |
4054 | R[i] = MemA[address,4]; address = address + 4; |
4055 | |
4056 | if registers<15> == '1' then |
4057 | LoadWritePC(MemA[address,4]); |
4058 | |
4059 | if wback && registers<n> == '0' then R[n] = R[n] - 4*BitCount(registers); |
4060 | if wback && registers<n> == '1' then R[n] = bits(32) UNKNOWN; |
4061 | #endif |
4062 | |
4063 | bool success = false; |
4064 | |
4065 | if (ConditionPassed(opcode)) { |
4066 | uint32_t n; |
4067 | uint32_t registers = 0; |
4068 | bool wback; |
4069 | const uint32_t addr_byte_size = GetAddressByteSize(); |
4070 | |
4071 | // EncodingSpecificOperations(); |
4072 | switch (encoding) { |
4073 | case eEncodingA1: |
4074 | // n = UInt(Rn); registers = register_list; wback = (W == '1'); |
4075 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
4076 | registers = Bits32(bits: opcode, msbit: 15, lsbit: 0); |
4077 | wback = BitIsSet(value: opcode, bit: 21); |
4078 | |
4079 | // if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE; |
4080 | if ((n == 15) || (BitCount(x: registers) < 1)) |
4081 | return false; |
4082 | |
4083 | break; |
4084 | |
4085 | default: |
4086 | return false; |
4087 | } |
4088 | // address = R[n] - 4*BitCount(registers) + 4; |
4089 | |
4090 | int32_t offset = 0; |
4091 | addr_t Rn = ReadCoreReg(regnum: n, success: &success); |
4092 | |
4093 | if (!success) |
4094 | return false; |
4095 | |
4096 | addr_t address = |
4097 | Rn - (addr_byte_size * BitCount(x: registers)) + addr_byte_size; |
4098 | |
4099 | EmulateInstruction::Context context; |
4100 | context.type = EmulateInstruction::eContextRegisterPlusOffset; |
4101 | std::optional<RegisterInfo> dwarf_reg = |
4102 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n); |
4103 | context.SetRegisterPlusOffset(base_reg: *dwarf_reg, signed_offset: offset); |
4104 | |
4105 | // for i = 0 to 14 |
4106 | for (int i = 0; i < 14; ++i) { |
4107 | // if registers<i> == '1' then |
4108 | if (BitIsSet(value: registers, bit: i)) { |
4109 | // R[i] = MemA[address,4]; address = address + 4; |
4110 | context.SetRegisterPlusOffset(base_reg: *dwarf_reg, signed_offset: Rn - (address + offset)); |
4111 | uint32_t data = |
4112 | MemARead(context, address: address + offset, size: addr_byte_size, fail_value: 0, success_ptr: &success); |
4113 | if (!success) |
4114 | return false; |
4115 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + i, |
4116 | reg_value: data)) |
4117 | return false; |
4118 | offset += addr_byte_size; |
4119 | } |
4120 | } |
4121 | |
4122 | // if registers<15> == '1' then |
4123 | // LoadWritePC(MemA[address,4]); |
4124 | if (BitIsSet(value: registers, bit: 15)) { |
4125 | context.SetRegisterPlusOffset(base_reg: *dwarf_reg, signed_offset: offset); |
4126 | uint32_t data = |
4127 | MemARead(context, address: address + offset, size: addr_byte_size, fail_value: 0, success_ptr: &success); |
4128 | if (!success) |
4129 | return false; |
4130 | // In ARMv5T and above, this is an interworking branch. |
4131 | if (!LoadWritePC(context, addr: data)) |
4132 | return false; |
4133 | } |
4134 | |
4135 | // if wback && registers<n> == '0' then R[n] = R[n] - 4*BitCount(registers); |
4136 | if (wback && BitIsClear(value: registers, bit: n)) { |
4137 | |
4138 | offset = (addr_byte_size * BitCount(x: registers)) * -1; |
4139 | context.type = EmulateInstruction::eContextAdjustBaseRegister; |
4140 | context.SetImmediateSigned(offset); |
4141 | addr_t addr = Rn + offset; |
4142 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n, |
4143 | reg_value: addr)) |
4144 | return false; |
4145 | } |
4146 | |
4147 | // if wback && registers<n> == '1' then R[n] = bits(32) UNKNOWN; |
4148 | if (wback && BitIsSet(value: registers, bit: n)) |
4149 | return WriteBits32Unknown(n); |
4150 | } |
4151 | return true; |
4152 | } |
4153 | |
4154 | // LDMDB loads multiple registers from consecutive memory locations using an |
4155 | // address from a base register. The |
4156 | // consecutive memory locations end just below this address, and the address of |
4157 | // the lowest of those locations can be optionally written back to the base |
4158 | // register. |
4159 | bool EmulateInstructionARM::EmulateLDMDB(const uint32_t opcode, |
4160 | const ARMEncoding encoding) { |
4161 | #if 0 |
4162 | // ARM pseudo code... |
4163 | if ConditionPassed() then |
4164 | EncodingSpecificOperations(); NullCheckIfThumbEE(n); |
4165 | address = R[n] - 4*BitCount(registers); |
4166 | |
4167 | for i = 0 to 14 |
4168 | if registers<i> == '1' then |
4169 | R[i] = MemA[address,4]; address = address + 4; |
4170 | if registers<15> == '1' then |
4171 | LoadWritePC(MemA[address,4]); |
4172 | |
4173 | if wback && registers<n> == '0' then R[n] = R[n] - 4*BitCount(registers); |
4174 | if wback && registers<n> == '1' then R[n] = bits(32) UNKNOWN; // Only possible for encoding A1 |
4175 | #endif |
4176 | |
4177 | bool success = false; |
4178 | |
4179 | if (ConditionPassed(opcode)) { |
4180 | uint32_t n; |
4181 | uint32_t registers = 0; |
4182 | bool wback; |
4183 | const uint32_t addr_byte_size = GetAddressByteSize(); |
4184 | switch (encoding) { |
4185 | case eEncodingT1: |
4186 | // n = UInt(Rn); registers = P:M:'0':register_list; wback = (W == '1'); |
4187 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
4188 | registers = Bits32(bits: opcode, msbit: 15, lsbit: 0); |
4189 | registers = registers & 0xdfff; // Make sure bit 13 is a zero. |
4190 | wback = BitIsSet(value: opcode, bit: 21); |
4191 | |
4192 | // if n == 15 || BitCount(registers) < 2 || (P == '1' && M == '1') then |
4193 | // UNPREDICTABLE; |
4194 | if ((n == 15) || (BitCount(x: registers) < 2) || |
4195 | (BitIsSet(value: opcode, bit: 14) && BitIsSet(value: opcode, bit: 15))) |
4196 | return false; |
4197 | |
4198 | // if registers<15> == '1' && InITBlock() && !LastInITBlock() then |
4199 | // UNPREDICTABLE; |
4200 | if (BitIsSet(value: registers, bit: 15) && InITBlock() && !LastInITBlock()) |
4201 | return false; |
4202 | |
4203 | // if wback && registers<n> == '1' then UNPREDICTABLE; |
4204 | if (wback && BitIsSet(value: registers, bit: n)) |
4205 | return false; |
4206 | |
4207 | break; |
4208 | |
4209 | case eEncodingA1: |
4210 | // n = UInt(Rn); registers = register_list; wback = (W == '1'); |
4211 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
4212 | registers = Bits32(bits: opcode, msbit: 15, lsbit: 0); |
4213 | wback = BitIsSet(value: opcode, bit: 21); |
4214 | |
4215 | // if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE; |
4216 | if ((n == 15) || (BitCount(x: registers) < 1)) |
4217 | return false; |
4218 | |
4219 | break; |
4220 | |
4221 | default: |
4222 | return false; |
4223 | } |
4224 | |
4225 | // address = R[n] - 4*BitCount(registers); |
4226 | |
4227 | int32_t offset = 0; |
4228 | addr_t Rn = |
4229 | ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n, fail_value: 0, success_ptr: &success); |
4230 | |
4231 | if (!success) |
4232 | return false; |
4233 | |
4234 | addr_t address = Rn - (addr_byte_size * BitCount(x: registers)); |
4235 | EmulateInstruction::Context context; |
4236 | context.type = EmulateInstruction::eContextRegisterPlusOffset; |
4237 | std::optional<RegisterInfo> dwarf_reg = |
4238 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n); |
4239 | context.SetRegisterPlusOffset(base_reg: *dwarf_reg, signed_offset: Rn - address); |
4240 | |
4241 | for (int i = 0; i < 14; ++i) { |
4242 | if (BitIsSet(value: registers, bit: i)) { |
4243 | // R[i] = MemA[address,4]; address = address + 4; |
4244 | context.SetRegisterPlusOffset(base_reg: *dwarf_reg, signed_offset: Rn - (address + offset)); |
4245 | uint32_t data = |
4246 | MemARead(context, address: address + offset, size: addr_byte_size, fail_value: 0, success_ptr: &success); |
4247 | if (!success) |
4248 | return false; |
4249 | |
4250 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + i, |
4251 | reg_value: data)) |
4252 | return false; |
4253 | |
4254 | offset += addr_byte_size; |
4255 | } |
4256 | } |
4257 | |
4258 | // if registers<15> == '1' then |
4259 | // LoadWritePC(MemA[address,4]); |
4260 | if (BitIsSet(value: registers, bit: 15)) { |
4261 | context.SetRegisterPlusOffset(base_reg: *dwarf_reg, signed_offset: offset); |
4262 | uint32_t data = |
4263 | MemARead(context, address: address + offset, size: addr_byte_size, fail_value: 0, success_ptr: &success); |
4264 | if (!success) |
4265 | return false; |
4266 | // In ARMv5T and above, this is an interworking branch. |
4267 | if (!LoadWritePC(context, addr: data)) |
4268 | return false; |
4269 | } |
4270 | |
4271 | // if wback && registers<n> == '0' then R[n] = R[n] - 4*BitCount(registers); |
4272 | if (wback && BitIsClear(value: registers, bit: n)) { |
4273 | |
4274 | offset = (addr_byte_size * BitCount(x: registers)) * -1; |
4275 | context.type = EmulateInstruction::eContextAdjustBaseRegister; |
4276 | context.SetImmediateSigned(offset); |
4277 | addr_t addr = Rn + offset; |
4278 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n, |
4279 | reg_value: addr)) |
4280 | return false; |
4281 | } |
4282 | |
4283 | // if wback && registers<n> == '1' then R[n] = bits(32) UNKNOWN; // Only |
4284 | // possible for encoding A1 |
4285 | if (wback && BitIsSet(value: registers, bit: n)) |
4286 | return WriteBits32Unknown(n); |
4287 | } |
4288 | return true; |
4289 | } |
4290 | |
4291 | // LDMIB loads multiple registers from consecutive memory locations using an |
4292 | // address from a base register. The |
4293 | // consecutive memory locations start just above this address, and thea ddress |
4294 | // of the last of those locations can optinoally be written back to the base |
4295 | // register. |
4296 | bool EmulateInstructionARM::EmulateLDMIB(const uint32_t opcode, |
4297 | const ARMEncoding encoding) { |
4298 | #if 0 |
4299 | if ConditionPassed() then |
4300 | EncodingSpecificOperations(); |
4301 | address = R[n] + 4; |
4302 | |
4303 | for i = 0 to 14 |
4304 | if registers<i> == '1' then |
4305 | R[i] = MemA[address,4]; address = address + 4; |
4306 | if registers<15> == '1' then |
4307 | LoadWritePC(MemA[address,4]); |
4308 | |
4309 | if wback && registers<n> == '0' then R[n] = R[n] + 4*BitCount(registers); |
4310 | if wback && registers<n> == '1' then R[n] = bits(32) UNKNOWN; |
4311 | #endif |
4312 | |
4313 | bool success = false; |
4314 | |
4315 | if (ConditionPassed(opcode)) { |
4316 | uint32_t n; |
4317 | uint32_t registers = 0; |
4318 | bool wback; |
4319 | const uint32_t addr_byte_size = GetAddressByteSize(); |
4320 | switch (encoding) { |
4321 | case eEncodingA1: |
4322 | // n = UInt(Rn); registers = register_list; wback = (W == '1'); |
4323 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
4324 | registers = Bits32(bits: opcode, msbit: 15, lsbit: 0); |
4325 | wback = BitIsSet(value: opcode, bit: 21); |
4326 | |
4327 | // if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE; |
4328 | if ((n == 15) || (BitCount(x: registers) < 1)) |
4329 | return false; |
4330 | |
4331 | break; |
4332 | default: |
4333 | return false; |
4334 | } |
4335 | // address = R[n] + 4; |
4336 | |
4337 | int32_t offset = 0; |
4338 | addr_t Rn = |
4339 | ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n, fail_value: 0, success_ptr: &success); |
4340 | |
4341 | if (!success) |
4342 | return false; |
4343 | |
4344 | addr_t address = Rn + addr_byte_size; |
4345 | |
4346 | EmulateInstruction::Context context; |
4347 | context.type = EmulateInstruction::eContextRegisterPlusOffset; |
4348 | std::optional<RegisterInfo> dwarf_reg = |
4349 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n); |
4350 | context.SetRegisterPlusOffset(base_reg: *dwarf_reg, signed_offset: offset); |
4351 | |
4352 | for (int i = 0; i < 14; ++i) { |
4353 | if (BitIsSet(value: registers, bit: i)) { |
4354 | // R[i] = MemA[address,4]; address = address + 4; |
4355 | |
4356 | context.SetRegisterPlusOffset(base_reg: *dwarf_reg, signed_offset: offset + addr_byte_size); |
4357 | uint32_t data = |
4358 | MemARead(context, address: address + offset, size: addr_byte_size, fail_value: 0, success_ptr: &success); |
4359 | if (!success) |
4360 | return false; |
4361 | |
4362 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + i, |
4363 | reg_value: data)) |
4364 | return false; |
4365 | |
4366 | offset += addr_byte_size; |
4367 | } |
4368 | } |
4369 | |
4370 | // if registers<15> == '1' then |
4371 | // LoadWritePC(MemA[address,4]); |
4372 | if (BitIsSet(value: registers, bit: 15)) { |
4373 | context.SetRegisterPlusOffset(base_reg: *dwarf_reg, signed_offset: offset); |
4374 | uint32_t data = |
4375 | MemARead(context, address: address + offset, size: addr_byte_size, fail_value: 0, success_ptr: &success); |
4376 | if (!success) |
4377 | return false; |
4378 | // In ARMv5T and above, this is an interworking branch. |
4379 | if (!LoadWritePC(context, addr: data)) |
4380 | return false; |
4381 | } |
4382 | |
4383 | // if wback && registers<n> == '0' then R[n] = R[n] + 4*BitCount(registers); |
4384 | if (wback && BitIsClear(value: registers, bit: n)) { |
4385 | |
4386 | offset = addr_byte_size * BitCount(x: registers); |
4387 | context.type = EmulateInstruction::eContextAdjustBaseRegister; |
4388 | context.SetImmediateSigned(offset); |
4389 | addr_t addr = Rn + offset; |
4390 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n, |
4391 | reg_value: addr)) |
4392 | return false; |
4393 | } |
4394 | |
4395 | // if wback && registers<n> == '1' then R[n] = bits(32) UNKNOWN; // Only |
4396 | // possible for encoding A1 |
4397 | if (wback && BitIsSet(value: registers, bit: n)) |
4398 | return WriteBits32Unknown(n); |
4399 | } |
4400 | return true; |
4401 | } |
4402 | |
4403 | // Load Register (immediate) calculates an address from a base register value |
4404 | // and an immediate offset, loads a word from memory, and writes to a register. |
4405 | // LDR (immediate, Thumb) |
4406 | bool EmulateInstructionARM::EmulateLDRRtRnImm(const uint32_t opcode, |
4407 | const ARMEncoding encoding) { |
4408 | #if 0 |
4409 | // ARM pseudo code... |
4410 | if (ConditionPassed()) |
4411 | { |
4412 | EncodingSpecificOperations(); NullCheckIfThumbEE(15); |
4413 | offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); |
4414 | address = if index then offset_addr else R[n]; |
4415 | data = MemU[address,4]; |
4416 | if wback then R[n] = offset_addr; |
4417 | if t == 15 then |
4418 | if address<1:0> == '00' then LoadWritePC(data); else UNPREDICTABLE; |
4419 | elsif UnalignedSupport() || address<1:0> = '00' then |
4420 | R[t] = data; |
4421 | else R[t] = bits(32) UNKNOWN; // Can only apply before ARMv7 |
4422 | } |
4423 | #endif |
4424 | |
4425 | bool success = false; |
4426 | |
4427 | if (ConditionPassed(opcode)) { |
4428 | uint32_t Rt; // the destination register |
4429 | uint32_t Rn; // the base register |
4430 | uint32_t imm32; // the immediate offset used to form the address |
4431 | addr_t offset_addr; // the offset address |
4432 | addr_t address; // the calculated address |
4433 | uint32_t data; // the literal data value from memory load |
4434 | bool add, index, wback; |
4435 | switch (encoding) { |
4436 | case eEncodingT1: |
4437 | Rt = Bits32(bits: opcode, msbit: 2, lsbit: 0); |
4438 | Rn = Bits32(bits: opcode, msbit: 5, lsbit: 3); |
4439 | imm32 = Bits32(bits: opcode, msbit: 10, lsbit: 6) << 2; // imm32 = ZeroExtend(imm5:'00', 32); |
4440 | // index = TRUE; add = TRUE; wback = FALSE |
4441 | add = true; |
4442 | index = true; |
4443 | wback = false; |
4444 | |
4445 | break; |
4446 | |
4447 | case eEncodingT2: |
4448 | // t = UInt(Rt); n = 13; imm32 = ZeroExtend(imm8:'00', 32); |
4449 | Rt = Bits32(bits: opcode, msbit: 10, lsbit: 8); |
4450 | Rn = 13; |
4451 | imm32 = Bits32(bits: opcode, msbit: 7, lsbit: 0) << 2; |
4452 | |
4453 | // index = TRUE; add = TRUE; wback = FALSE; |
4454 | index = true; |
4455 | add = true; |
4456 | wback = false; |
4457 | |
4458 | break; |
4459 | |
4460 | case eEncodingT3: |
4461 | // if Rn == '1111' then SEE LDR (literal); |
4462 | // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm12, 32); |
4463 | Rt = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
4464 | Rn = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
4465 | imm32 = Bits32(bits: opcode, msbit: 11, lsbit: 0); |
4466 | |
4467 | // index = TRUE; add = TRUE; wback = FALSE; |
4468 | index = true; |
4469 | add = true; |
4470 | wback = false; |
4471 | |
4472 | // if t == 15 && InITBlock() && !LastInITBlock() then UNPREDICTABLE; |
4473 | if ((Rt == 15) && InITBlock() && !LastInITBlock()) |
4474 | return false; |
4475 | |
4476 | break; |
4477 | |
4478 | case eEncodingT4: |
4479 | // if Rn == '1111' then SEE LDR (literal); |
4480 | // if P == '1' && U == '1' && W == '0' then SEE LDRT; |
4481 | // if Rn == '1101' && P == '0' && U == '1' && W == '1' && imm8 == |
4482 | // '00000100' then SEE POP; |
4483 | // if P == '0' && W == '0' then UNDEFINED; |
4484 | if (BitIsClear(value: opcode, bit: 10) && BitIsClear(value: opcode, bit: 8)) |
4485 | return false; |
4486 | |
4487 | // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm8, 32); |
4488 | Rt = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
4489 | Rn = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
4490 | imm32 = Bits32(bits: opcode, msbit: 7, lsbit: 0); |
4491 | |
4492 | // index = (P == '1'); add = (U == '1'); wback = (W == '1'); |
4493 | index = BitIsSet(value: opcode, bit: 10); |
4494 | add = BitIsSet(value: opcode, bit: 9); |
4495 | wback = BitIsSet(value: opcode, bit: 8); |
4496 | |
4497 | // if (wback && n == t) || (t == 15 && InITBlock() && !LastInITBlock()) |
4498 | // then UNPREDICTABLE; |
4499 | if ((wback && (Rn == Rt)) || |
4500 | ((Rt == 15) && InITBlock() && !LastInITBlock())) |
4501 | return false; |
4502 | |
4503 | break; |
4504 | |
4505 | default: |
4506 | return false; |
4507 | } |
4508 | uint32_t base = ReadCoreReg(regnum: Rn, success: &success); |
4509 | if (!success) |
4510 | return false; |
4511 | if (add) |
4512 | offset_addr = base + imm32; |
4513 | else |
4514 | offset_addr = base - imm32; |
4515 | |
4516 | address = (index ? offset_addr : base); |
4517 | |
4518 | std::optional<RegisterInfo> base_reg = |
4519 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + Rn); |
4520 | if (wback) { |
4521 | EmulateInstruction::Context ctx; |
4522 | if (Rn == 13) { |
4523 | ctx.type = eContextAdjustStackPointer; |
4524 | ctx.SetImmediateSigned((int32_t)(offset_addr - base)); |
4525 | } else if (Rn == GetFramePointerRegisterNumber()) { |
4526 | ctx.type = eContextSetFramePointer; |
4527 | ctx.SetRegisterPlusOffset(base_reg: *base_reg, signed_offset: (int32_t)(offset_addr - base)); |
4528 | } else { |
4529 | ctx.type = EmulateInstruction::eContextAdjustBaseRegister; |
4530 | ctx.SetRegisterPlusOffset(base_reg: *base_reg, signed_offset: (int32_t)(offset_addr - base)); |
4531 | } |
4532 | |
4533 | if (!WriteRegisterUnsigned(context: ctx, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + Rn, |
4534 | reg_value: offset_addr)) |
4535 | return false; |
4536 | } |
4537 | |
4538 | // Prepare to write to the Rt register. |
4539 | EmulateInstruction::Context context; |
4540 | context.type = EmulateInstruction::eContextRegisterLoad; |
4541 | context.SetRegisterPlusOffset(base_reg: *base_reg, signed_offset: (int32_t)(offset_addr - base)); |
4542 | |
4543 | // Read memory from the address. |
4544 | data = MemURead(context, address, size: 4, fail_value: 0, success_ptr: &success); |
4545 | if (!success) |
4546 | return false; |
4547 | |
4548 | if (Rt == 15) { |
4549 | if (Bits32(bits: address, msbit: 1, lsbit: 0) == 0) { |
4550 | if (!LoadWritePC(context, addr: data)) |
4551 | return false; |
4552 | } else |
4553 | return false; |
4554 | } else if (UnalignedSupport() || Bits32(bits: address, msbit: 1, lsbit: 0) == 0) { |
4555 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + Rt, |
4556 | reg_value: data)) |
4557 | return false; |
4558 | } else |
4559 | WriteBits32Unknown(n: Rt); |
4560 | } |
4561 | return true; |
4562 | } |
4563 | |
4564 | // STM (Store Multiple Increment After) stores multiple registers to consecutive |
4565 | // memory locations using an address |
4566 | // from a base register. The consecutive memory locations start at this |
4567 | // address, and the address just above the last of those locations can |
4568 | // optionally be written back to the base register. |
4569 | bool EmulateInstructionARM::EmulateSTM(const uint32_t opcode, |
4570 | const ARMEncoding encoding) { |
4571 | #if 0 |
4572 | if ConditionPassed() then |
4573 | EncodingSpecificOperations(); NullCheckIfThumbEE(n); |
4574 | address = R[n]; |
4575 | |
4576 | for i = 0 to 14 |
4577 | if registers<i> == '1' then |
4578 | if i == n && wback && i != LowestSetBit(registers) then |
4579 | MemA[address,4] = bits(32) UNKNOWN; // Only possible for encodings T1 and A1 |
4580 | else |
4581 | MemA[address,4] = R[i]; |
4582 | address = address + 4; |
4583 | |
4584 | if registers<15> == '1' then // Only possible for encoding A1 |
4585 | MemA[address,4] = PCStoreValue(); |
4586 | if wback then R[n] = R[n] + 4*BitCount(registers); |
4587 | #endif |
4588 | |
4589 | bool success = false; |
4590 | |
4591 | if (ConditionPassed(opcode)) { |
4592 | uint32_t n; |
4593 | uint32_t registers = 0; |
4594 | bool wback; |
4595 | const uint32_t addr_byte_size = GetAddressByteSize(); |
4596 | |
4597 | // EncodingSpecificOperations(); NullCheckIfThumbEE(n); |
4598 | switch (encoding) { |
4599 | case eEncodingT1: |
4600 | // n = UInt(Rn); registers = '00000000':register_list; wback = TRUE; |
4601 | n = Bits32(bits: opcode, msbit: 10, lsbit: 8); |
4602 | registers = Bits32(bits: opcode, msbit: 7, lsbit: 0); |
4603 | registers = registers & 0x00ff; // Make sure the top 8 bits are zeros. |
4604 | wback = true; |
4605 | |
4606 | // if BitCount(registers) < 1 then UNPREDICTABLE; |
4607 | if (BitCount(x: registers) < 1) |
4608 | return false; |
4609 | |
4610 | break; |
4611 | |
4612 | case eEncodingT2: |
4613 | // n = UInt(Rn); registers = '0':M:'0':register_list; wback = (W == '1'); |
4614 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
4615 | registers = Bits32(bits: opcode, msbit: 15, lsbit: 0); |
4616 | registers = registers & 0x5fff; // Make sure bits 15 & 13 are zeros. |
4617 | wback = BitIsSet(value: opcode, bit: 21); |
4618 | |
4619 | // if n == 15 || BitCount(registers) < 2 then UNPREDICTABLE; |
4620 | if ((n == 15) || (BitCount(x: registers) < 2)) |
4621 | return false; |
4622 | |
4623 | // if wback && registers<n> == '1' then UNPREDICTABLE; |
4624 | if (wback && BitIsSet(value: registers, bit: n)) |
4625 | return false; |
4626 | |
4627 | break; |
4628 | |
4629 | case eEncodingA1: |
4630 | // n = UInt(Rn); registers = register_list; wback = (W == '1'); |
4631 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
4632 | registers = Bits32(bits: opcode, msbit: 15, lsbit: 0); |
4633 | wback = BitIsSet(value: opcode, bit: 21); |
4634 | |
4635 | // if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE; |
4636 | if ((n == 15) || (BitCount(x: registers) < 1)) |
4637 | return false; |
4638 | |
4639 | break; |
4640 | |
4641 | default: |
4642 | return false; |
4643 | } |
4644 | |
4645 | // address = R[n]; |
4646 | int32_t offset = 0; |
4647 | const addr_t address = |
4648 | ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n, fail_value: 0, success_ptr: &success); |
4649 | if (!success) |
4650 | return false; |
4651 | |
4652 | EmulateInstruction::Context context; |
4653 | context.type = EmulateInstruction::eContextRegisterStore; |
4654 | std::optional<RegisterInfo> base_reg = |
4655 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n); |
4656 | |
4657 | // for i = 0 to 14 |
4658 | uint32_t lowest_set_bit = 14; |
4659 | for (uint32_t i = 0; i < 14; ++i) { |
4660 | // if registers<i> == '1' then |
4661 | if (BitIsSet(value: registers, bit: i)) { |
4662 | if (i < lowest_set_bit) |
4663 | lowest_set_bit = i; |
4664 | // if i == n && wback && i != LowestSetBit(registers) then |
4665 | if ((i == n) && wback && (i != lowest_set_bit)) |
4666 | // MemA[address,4] = bits(32) UNKNOWN; // Only possible for encodings |
4667 | // T1 and A1 |
4668 | WriteBits32UnknownToMemory(address: address + offset); |
4669 | else { |
4670 | // MemA[address,4] = R[i]; |
4671 | uint32_t data = ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + i, |
4672 | fail_value: 0, success_ptr: &success); |
4673 | if (!success) |
4674 | return false; |
4675 | |
4676 | std::optional<RegisterInfo> data_reg = |
4677 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + i); |
4678 | context.SetRegisterToRegisterPlusOffset(data_reg: *data_reg, base_reg: *base_reg, offset); |
4679 | if (!MemAWrite(context, address: address + offset, data_val: data, size: addr_byte_size)) |
4680 | return false; |
4681 | } |
4682 | |
4683 | // address = address + 4; |
4684 | offset += addr_byte_size; |
4685 | } |
4686 | } |
4687 | |
4688 | // if registers<15> == '1' then // Only possible for encoding A1 |
4689 | // MemA[address,4] = PCStoreValue(); |
4690 | if (BitIsSet(value: registers, bit: 15)) { |
4691 | std::optional<RegisterInfo> pc_reg = |
4692 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_pc); |
4693 | context.SetRegisterPlusOffset(base_reg: *pc_reg, signed_offset: 8); |
4694 | const uint32_t pc = ReadCoreReg(PC_REG, success: &success); |
4695 | if (!success) |
4696 | return false; |
4697 | |
4698 | if (!MemAWrite(context, address: address + offset, data_val: pc, size: addr_byte_size)) |
4699 | return false; |
4700 | } |
4701 | |
4702 | // if wback then R[n] = R[n] + 4*BitCount(registers); |
4703 | if (wback) { |
4704 | offset = addr_byte_size * BitCount(x: registers); |
4705 | context.type = EmulateInstruction::eContextAdjustBaseRegister; |
4706 | context.SetImmediateSigned(offset); |
4707 | addr_t data = address + offset; |
4708 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n, |
4709 | reg_value: data)) |
4710 | return false; |
4711 | } |
4712 | } |
4713 | return true; |
4714 | } |
4715 | |
4716 | // STMDA (Store Multiple Decrement After) stores multiple registers to |
4717 | // consecutive memory locations using an address from a base register. The |
4718 | // consecutive memory locations end at this address, and the address just below |
4719 | // the lowest of those locations can optionally be written back to the base |
4720 | // register. |
4721 | bool EmulateInstructionARM::EmulateSTMDA(const uint32_t opcode, |
4722 | const ARMEncoding encoding) { |
4723 | #if 0 |
4724 | if ConditionPassed() then |
4725 | EncodingSpecificOperations(); |
4726 | address = R[n] - 4*BitCount(registers) + 4; |
4727 | |
4728 | for i = 0 to 14 |
4729 | if registers<i> == '1' then |
4730 | if i == n && wback && i != LowestSetBit(registers) then |
4731 | MemA[address,4] = bits(32) UNKNOWN; |
4732 | else |
4733 | MemA[address,4] = R[i]; |
4734 | address = address + 4; |
4735 | |
4736 | if registers<15> == '1' then |
4737 | MemA[address,4] = PCStoreValue(); |
4738 | |
4739 | if wback then R[n] = R[n] - 4*BitCount(registers); |
4740 | #endif |
4741 | |
4742 | bool success = false; |
4743 | |
4744 | if (ConditionPassed(opcode)) { |
4745 | uint32_t n; |
4746 | uint32_t registers = 0; |
4747 | bool wback; |
4748 | const uint32_t addr_byte_size = GetAddressByteSize(); |
4749 | |
4750 | // EncodingSpecificOperations(); |
4751 | switch (encoding) { |
4752 | case eEncodingA1: |
4753 | // n = UInt(Rn); registers = register_list; wback = (W == '1'); |
4754 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
4755 | registers = Bits32(bits: opcode, msbit: 15, lsbit: 0); |
4756 | wback = BitIsSet(value: opcode, bit: 21); |
4757 | |
4758 | // if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE; |
4759 | if ((n == 15) || (BitCount(x: registers) < 1)) |
4760 | return false; |
4761 | break; |
4762 | default: |
4763 | return false; |
4764 | } |
4765 | |
4766 | // address = R[n] - 4*BitCount(registers) + 4; |
4767 | int32_t offset = 0; |
4768 | addr_t Rn = ReadCoreReg(regnum: n, success: &success); |
4769 | if (!success) |
4770 | return false; |
4771 | |
4772 | addr_t address = Rn - (addr_byte_size * BitCount(x: registers)) + 4; |
4773 | |
4774 | EmulateInstruction::Context context; |
4775 | context.type = EmulateInstruction::eContextRegisterStore; |
4776 | std::optional<RegisterInfo> base_reg = |
4777 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n); |
4778 | |
4779 | // for i = 0 to 14 |
4780 | uint32_t lowest_bit_set = 14; |
4781 | for (uint32_t i = 0; i < 14; ++i) { |
4782 | // if registers<i> == '1' then |
4783 | if (BitIsSet(value: registers, bit: i)) { |
4784 | if (i < lowest_bit_set) |
4785 | lowest_bit_set = i; |
4786 | // if i == n && wback && i != LowestSetBit(registers) then |
4787 | if ((i == n) && wback && (i != lowest_bit_set)) |
4788 | // MemA[address,4] = bits(32) UNKNOWN; |
4789 | WriteBits32UnknownToMemory(address: address + offset); |
4790 | else { |
4791 | // MemA[address,4] = R[i]; |
4792 | uint32_t data = ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + i, |
4793 | fail_value: 0, success_ptr: &success); |
4794 | if (!success) |
4795 | return false; |
4796 | |
4797 | std::optional<RegisterInfo> data_reg = |
4798 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + i); |
4799 | context.SetRegisterToRegisterPlusOffset(data_reg: *data_reg, base_reg: *base_reg, |
4800 | offset: Rn - (address + offset)); |
4801 | if (!MemAWrite(context, address: address + offset, data_val: data, size: addr_byte_size)) |
4802 | return false; |
4803 | } |
4804 | |
4805 | // address = address + 4; |
4806 | offset += addr_byte_size; |
4807 | } |
4808 | } |
4809 | |
4810 | // if registers<15> == '1' then |
4811 | // MemA[address,4] = PCStoreValue(); |
4812 | if (BitIsSet(value: registers, bit: 15)) { |
4813 | std::optional<RegisterInfo> pc_reg = |
4814 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_pc); |
4815 | context.SetRegisterPlusOffset(base_reg: *pc_reg, signed_offset: 8); |
4816 | const uint32_t pc = ReadCoreReg(PC_REG, success: &success); |
4817 | if (!success) |
4818 | return false; |
4819 | |
4820 | if (!MemAWrite(context, address: address + offset, data_val: pc, size: addr_byte_size)) |
4821 | return false; |
4822 | } |
4823 | |
4824 | // if wback then R[n] = R[n] - 4*BitCount(registers); |
4825 | if (wback) { |
4826 | offset = (addr_byte_size * BitCount(x: registers)) * -1; |
4827 | context.type = EmulateInstruction::eContextAdjustBaseRegister; |
4828 | context.SetImmediateSigned(offset); |
4829 | addr_t data = Rn + offset; |
4830 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n, |
4831 | reg_value: data)) |
4832 | return false; |
4833 | } |
4834 | } |
4835 | return true; |
4836 | } |
4837 | |
4838 | // STMDB (Store Multiple Decrement Before) stores multiple registers to |
4839 | // consecutive memory locations using an address from a base register. The |
4840 | // consecutive memory locations end just below this address, and the address of |
4841 | // the first of those locations can optionally be written back to the base |
4842 | // register. |
4843 | bool EmulateInstructionARM::EmulateSTMDB(const uint32_t opcode, |
4844 | const ARMEncoding encoding) { |
4845 | #if 0 |
4846 | if ConditionPassed() then |
4847 | EncodingSpecificOperations(); NullCheckIfThumbEE(n); |
4848 | address = R[n] - 4*BitCount(registers); |
4849 | |
4850 | for i = 0 to 14 |
4851 | if registers<i> == '1' then |
4852 | if i == n && wback && i != LowestSetBit(registers) then |
4853 | MemA[address,4] = bits(32) UNKNOWN; // Only possible for encoding A1 |
4854 | else |
4855 | MemA[address,4] = R[i]; |
4856 | address = address + 4; |
4857 | |
4858 | if registers<15> == '1' then // Only possible for encoding A1 |
4859 | MemA[address,4] = PCStoreValue(); |
4860 | |
4861 | if wback then R[n] = R[n] - 4*BitCount(registers); |
4862 | #endif |
4863 | |
4864 | bool success = false; |
4865 | |
4866 | if (ConditionPassed(opcode)) { |
4867 | uint32_t n; |
4868 | uint32_t registers = 0; |
4869 | bool wback; |
4870 | const uint32_t addr_byte_size = GetAddressByteSize(); |
4871 | |
4872 | // EncodingSpecificOperations(); NullCheckIfThumbEE(n); |
4873 | switch (encoding) { |
4874 | case eEncodingT1: |
4875 | // if W == '1' && Rn == '1101' then SEE PUSH; |
4876 | if ((BitIsSet(value: opcode, bit: 21)) && (Bits32(bits: opcode, msbit: 19, lsbit: 16) == 13)) { |
4877 | // See PUSH |
4878 | } |
4879 | // n = UInt(Rn); registers = '0':M:'0':register_list; wback = (W == '1'); |
4880 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
4881 | registers = Bits32(bits: opcode, msbit: 15, lsbit: 0); |
4882 | registers = registers & 0x5fff; // Make sure bits 15 & 13 are zeros. |
4883 | wback = BitIsSet(value: opcode, bit: 21); |
4884 | // if n == 15 || BitCount(registers) < 2 then UNPREDICTABLE; |
4885 | if ((n == 15) || BitCount(x: registers) < 2) |
4886 | return false; |
4887 | // if wback && registers<n> == '1' then UNPREDICTABLE; |
4888 | if (wback && BitIsSet(value: registers, bit: n)) |
4889 | return false; |
4890 | break; |
4891 | |
4892 | case eEncodingA1: |
4893 | // if W == '1' && Rn == '1101' && BitCount(register_list) >= 2 then SEE |
4894 | // PUSH; |
4895 | if (BitIsSet(value: opcode, bit: 21) && (Bits32(bits: opcode, msbit: 19, lsbit: 16) == 13) && |
4896 | BitCount(x: Bits32(bits: opcode, msbit: 15, lsbit: 0)) >= 2) { |
4897 | // See Push |
4898 | } |
4899 | // n = UInt(Rn); registers = register_list; wback = (W == '1'); |
4900 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
4901 | registers = Bits32(bits: opcode, msbit: 15, lsbit: 0); |
4902 | wback = BitIsSet(value: opcode, bit: 21); |
4903 | // if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE; |
4904 | if ((n == 15) || BitCount(x: registers) < 1) |
4905 | return false; |
4906 | break; |
4907 | |
4908 | default: |
4909 | return false; |
4910 | } |
4911 | |
4912 | // address = R[n] - 4*BitCount(registers); |
4913 | |
4914 | int32_t offset = 0; |
4915 | addr_t Rn = |
4916 | ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n, fail_value: 0, success_ptr: &success); |
4917 | if (!success) |
4918 | return false; |
4919 | |
4920 | addr_t address = Rn - (addr_byte_size * BitCount(x: registers)); |
4921 | |
4922 | EmulateInstruction::Context context; |
4923 | context.type = EmulateInstruction::eContextRegisterStore; |
4924 | std::optional<RegisterInfo> base_reg = |
4925 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n); |
4926 | |
4927 | // for i = 0 to 14 |
4928 | uint32_t lowest_set_bit = 14; |
4929 | for (uint32_t i = 0; i < 14; ++i) { |
4930 | // if registers<i> == '1' then |
4931 | if (BitIsSet(value: registers, bit: i)) { |
4932 | if (i < lowest_set_bit) |
4933 | lowest_set_bit = i; |
4934 | // if i == n && wback && i != LowestSetBit(registers) then |
4935 | if ((i == n) && wback && (i != lowest_set_bit)) |
4936 | // MemA[address,4] = bits(32) UNKNOWN; // Only possible for encoding |
4937 | // A1 |
4938 | WriteBits32UnknownToMemory(address: address + offset); |
4939 | else { |
4940 | // MemA[address,4] = R[i]; |
4941 | uint32_t data = ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + i, |
4942 | fail_value: 0, success_ptr: &success); |
4943 | if (!success) |
4944 | return false; |
4945 | |
4946 | std::optional<RegisterInfo> data_reg = |
4947 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + i); |
4948 | context.SetRegisterToRegisterPlusOffset(data_reg: *data_reg, base_reg: *base_reg, |
4949 | offset: Rn - (address + offset)); |
4950 | if (!MemAWrite(context, address: address + offset, data_val: data, size: addr_byte_size)) |
4951 | return false; |
4952 | } |
4953 | |
4954 | // address = address + 4; |
4955 | offset += addr_byte_size; |
4956 | } |
4957 | } |
4958 | |
4959 | // if registers<15> == '1' then // Only possible for encoding A1 |
4960 | // MemA[address,4] = PCStoreValue(); |
4961 | if (BitIsSet(value: registers, bit: 15)) { |
4962 | std::optional<RegisterInfo> pc_reg = |
4963 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_pc); |
4964 | context.SetRegisterPlusOffset(base_reg: *pc_reg, signed_offset: 8); |
4965 | const uint32_t pc = ReadCoreReg(PC_REG, success: &success); |
4966 | if (!success) |
4967 | return false; |
4968 | |
4969 | if (!MemAWrite(context, address: address + offset, data_val: pc, size: addr_byte_size)) |
4970 | return false; |
4971 | } |
4972 | |
4973 | // if wback then R[n] = R[n] - 4*BitCount(registers); |
4974 | if (wback) { |
4975 | offset = (addr_byte_size * BitCount(x: registers)) * -1; |
4976 | context.type = EmulateInstruction::eContextAdjustBaseRegister; |
4977 | context.SetImmediateSigned(offset); |
4978 | addr_t data = Rn + offset; |
4979 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n, |
4980 | reg_value: data)) |
4981 | return false; |
4982 | } |
4983 | } |
4984 | return true; |
4985 | } |
4986 | |
4987 | // STMIB (Store Multiple Increment Before) stores multiple registers to |
4988 | // consecutive memory locations using an address from a base register. The |
4989 | // consecutive memory locations start just above this address, and the address |
4990 | // of the last of those locations can optionally be written back to the base |
4991 | // register. |
4992 | bool EmulateInstructionARM::EmulateSTMIB(const uint32_t opcode, |
4993 | const ARMEncoding encoding) { |
4994 | #if 0 |
4995 | if ConditionPassed() then |
4996 | EncodingSpecificOperations(); |
4997 | address = R[n] + 4; |
4998 | |
4999 | for i = 0 to 14 |
5000 | if registers<i> == '1' then |
5001 | if i == n && wback && i != LowestSetBit(registers) then |
5002 | MemA[address,4] = bits(32) UNKNOWN; |
5003 | else |
5004 | MemA[address,4] = R[i]; |
5005 | address = address + 4; |
5006 | |
5007 | if registers<15> == '1' then |
5008 | MemA[address,4] = PCStoreValue(); |
5009 | |
5010 | if wback then R[n] = R[n] + 4*BitCount(registers); |
5011 | #endif |
5012 | |
5013 | bool success = false; |
5014 | |
5015 | if (ConditionPassed(opcode)) { |
5016 | uint32_t n; |
5017 | uint32_t registers = 0; |
5018 | bool wback; |
5019 | const uint32_t addr_byte_size = GetAddressByteSize(); |
5020 | |
5021 | // EncodingSpecificOperations(); |
5022 | switch (encoding) { |
5023 | case eEncodingA1: |
5024 | // n = UInt(Rn); registers = register_list; wback = (W == '1'); |
5025 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
5026 | registers = Bits32(bits: opcode, msbit: 15, lsbit: 0); |
5027 | wback = BitIsSet(value: opcode, bit: 21); |
5028 | |
5029 | // if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE; |
5030 | if ((n == 15) && (BitCount(x: registers) < 1)) |
5031 | return false; |
5032 | break; |
5033 | default: |
5034 | return false; |
5035 | } |
5036 | // address = R[n] + 4; |
5037 | |
5038 | int32_t offset = 0; |
5039 | addr_t Rn = ReadCoreReg(regnum: n, success: &success); |
5040 | if (!success) |
5041 | return false; |
5042 | |
5043 | addr_t address = Rn + addr_byte_size; |
5044 | |
5045 | EmulateInstruction::Context context; |
5046 | context.type = EmulateInstruction::eContextRegisterStore; |
5047 | std::optional<RegisterInfo> base_reg = |
5048 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n); |
5049 | |
5050 | uint32_t lowest_set_bit = 14; |
5051 | // for i = 0 to 14 |
5052 | for (uint32_t i = 0; i < 14; ++i) { |
5053 | // if registers<i> == '1' then |
5054 | if (BitIsSet(value: registers, bit: i)) { |
5055 | if (i < lowest_set_bit) |
5056 | lowest_set_bit = i; |
5057 | // if i == n && wback && i != LowestSetBit(registers) then |
5058 | if ((i == n) && wback && (i != lowest_set_bit)) |
5059 | // MemA[address,4] = bits(32) UNKNOWN; |
5060 | WriteBits32UnknownToMemory(address: address + offset); |
5061 | // else |
5062 | else { |
5063 | // MemA[address,4] = R[i]; |
5064 | uint32_t data = ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + i, |
5065 | fail_value: 0, success_ptr: &success); |
5066 | if (!success) |
5067 | return false; |
5068 | |
5069 | std::optional<RegisterInfo> data_reg = |
5070 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + i); |
5071 | context.SetRegisterToRegisterPlusOffset(data_reg: *data_reg, base_reg: *base_reg, |
5072 | offset: offset + addr_byte_size); |
5073 | if (!MemAWrite(context, address: address + offset, data_val: data, size: addr_byte_size)) |
5074 | return false; |
5075 | } |
5076 | |
5077 | // address = address + 4; |
5078 | offset += addr_byte_size; |
5079 | } |
5080 | } |
5081 | |
5082 | // if registers<15> == '1' then |
5083 | // MemA[address,4] = PCStoreValue(); |
5084 | if (BitIsSet(value: registers, bit: 15)) { |
5085 | std::optional<RegisterInfo> pc_reg = |
5086 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_pc); |
5087 | context.SetRegisterPlusOffset(base_reg: *pc_reg, signed_offset: 8); |
5088 | const uint32_t pc = ReadCoreReg(PC_REG, success: &success); |
5089 | if (!success) |
5090 | return false; |
5091 | |
5092 | if (!MemAWrite(context, address: address + offset, data_val: pc, size: addr_byte_size)) |
5093 | return false; |
5094 | } |
5095 | |
5096 | // if wback then R[n] = R[n] + 4*BitCount(registers); |
5097 | if (wback) { |
5098 | offset = addr_byte_size * BitCount(x: registers); |
5099 | context.type = EmulateInstruction::eContextAdjustBaseRegister; |
5100 | context.SetImmediateSigned(offset); |
5101 | addr_t data = Rn + offset; |
5102 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n, |
5103 | reg_value: data)) |
5104 | return false; |
5105 | } |
5106 | } |
5107 | return true; |
5108 | } |
5109 | |
5110 | // STR (store immediate) calculates an address from a base register value and an |
5111 | // immediate offset, and stores a word |
5112 | // from a register to memory. It can use offset, post-indexed, or pre-indexed |
5113 | // addressing. |
5114 | bool EmulateInstructionARM::EmulateSTRThumb(const uint32_t opcode, |
5115 | const ARMEncoding encoding) { |
5116 | #if 0 |
5117 | if ConditionPassed() then |
5118 | EncodingSpecificOperations(); NullCheckIfThumbEE(n); |
5119 | offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); |
5120 | address = if index then offset_addr else R[n]; |
5121 | if UnalignedSupport() || address<1:0> == '00' then |
5122 | MemU[address,4] = R[t]; |
5123 | else // Can only occur before ARMv7 |
5124 | MemU[address,4] = bits(32) UNKNOWN; |
5125 | if wback then R[n] = offset_addr; |
5126 | #endif |
5127 | |
5128 | bool success = false; |
5129 | |
5130 | if (ConditionPassed(opcode)) { |
5131 | const uint32_t addr_byte_size = GetAddressByteSize(); |
5132 | |
5133 | uint32_t t; |
5134 | uint32_t n; |
5135 | uint32_t imm32; |
5136 | bool index; |
5137 | bool add; |
5138 | bool wback; |
5139 | // EncodingSpecificOperations (); NullCheckIfThumbEE(n); |
5140 | switch (encoding) { |
5141 | case eEncodingT1: |
5142 | // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm5:'00', 32); |
5143 | t = Bits32(bits: opcode, msbit: 2, lsbit: 0); |
5144 | n = Bits32(bits: opcode, msbit: 5, lsbit: 3); |
5145 | imm32 = Bits32(bits: opcode, msbit: 10, lsbit: 6) << 2; |
5146 | |
5147 | // index = TRUE; add = TRUE; wback = FALSE; |
5148 | index = true; |
5149 | add = false; |
5150 | wback = false; |
5151 | break; |
5152 | |
5153 | case eEncodingT2: |
5154 | // t = UInt(Rt); n = 13; imm32 = ZeroExtend(imm8:'00', 32); |
5155 | t = Bits32(bits: opcode, msbit: 10, lsbit: 8); |
5156 | n = 13; |
5157 | imm32 = Bits32(bits: opcode, msbit: 7, lsbit: 0) << 2; |
5158 | |
5159 | // index = TRUE; add = TRUE; wback = FALSE; |
5160 | index = true; |
5161 | add = true; |
5162 | wback = false; |
5163 | break; |
5164 | |
5165 | case eEncodingT3: |
5166 | // if Rn == '1111' then UNDEFINED; |
5167 | if (Bits32(bits: opcode, msbit: 19, lsbit: 16) == 15) |
5168 | return false; |
5169 | |
5170 | // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm12, 32); |
5171 | t = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
5172 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
5173 | imm32 = Bits32(bits: opcode, msbit: 11, lsbit: 0); |
5174 | |
5175 | // index = TRUE; add = TRUE; wback = FALSE; |
5176 | index = true; |
5177 | add = true; |
5178 | wback = false; |
5179 | |
5180 | // if t == 15 then UNPREDICTABLE; |
5181 | if (t == 15) |
5182 | return false; |
5183 | break; |
5184 | |
5185 | case eEncodingT4: |
5186 | // if P == '1' && U == '1' && W == '0' then SEE STRT; |
5187 | // if Rn == '1101' && P == '1' && U == '0' && W == '1' && imm8 == |
5188 | // '00000100' then SEE PUSH; |
5189 | // if Rn == '1111' || (P == '0' && W == '0') then UNDEFINED; |
5190 | if ((Bits32(bits: opcode, msbit: 19, lsbit: 16) == 15) || |
5191 | (BitIsClear(value: opcode, bit: 10) && BitIsClear(value: opcode, bit: 8))) |
5192 | return false; |
5193 | |
5194 | // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm8, 32); |
5195 | t = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
5196 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
5197 | imm32 = Bits32(bits: opcode, msbit: 7, lsbit: 0); |
5198 | |
5199 | // index = (P == '1'); add = (U == '1'); wback = (W == '1'); |
5200 | index = BitIsSet(value: opcode, bit: 10); |
5201 | add = BitIsSet(value: opcode, bit: 9); |
5202 | wback = BitIsSet(value: opcode, bit: 8); |
5203 | |
5204 | // if t == 15 || (wback && n == t) then UNPREDICTABLE; |
5205 | if ((t == 15) || (wback && (n == t))) |
5206 | return false; |
5207 | break; |
5208 | |
5209 | default: |
5210 | return false; |
5211 | } |
5212 | |
5213 | addr_t offset_addr; |
5214 | addr_t address; |
5215 | |
5216 | // offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); |
5217 | uint32_t base_address = ReadCoreReg(regnum: n, success: &success); |
5218 | if (!success) |
5219 | return false; |
5220 | |
5221 | if (add) |
5222 | offset_addr = base_address + imm32; |
5223 | else |
5224 | offset_addr = base_address - imm32; |
5225 | |
5226 | // address = if index then offset_addr else R[n]; |
5227 | if (index) |
5228 | address = offset_addr; |
5229 | else |
5230 | address = base_address; |
5231 | |
5232 | EmulateInstruction::Context context; |
5233 | if (n == 13) |
5234 | context.type = eContextPushRegisterOnStack; |
5235 | else |
5236 | context.type = eContextRegisterStore; |
5237 | |
5238 | std::optional<RegisterInfo> base_reg = |
5239 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n); |
5240 | |
5241 | // if UnalignedSupport() || address<1:0> == '00' then |
5242 | if (UnalignedSupport() || |
5243 | (BitIsClear(value: address, bit: 1) && BitIsClear(value: address, bit: 0))) { |
5244 | // MemU[address,4] = R[t]; |
5245 | uint32_t data = |
5246 | ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + t, fail_value: 0, success_ptr: &success); |
5247 | if (!success) |
5248 | return false; |
5249 | |
5250 | std::optional<RegisterInfo> data_reg = |
5251 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + t); |
5252 | int32_t offset = address - base_address; |
5253 | context.SetRegisterToRegisterPlusOffset(data_reg: *data_reg, base_reg: *base_reg, offset); |
5254 | if (!MemUWrite(context, address, data_val: data, size: addr_byte_size)) |
5255 | return false; |
5256 | } else { |
5257 | // MemU[address,4] = bits(32) UNKNOWN; |
5258 | WriteBits32UnknownToMemory(address); |
5259 | } |
5260 | |
5261 | // if wback then R[n] = offset_addr; |
5262 | if (wback) { |
5263 | if (n == 13) |
5264 | context.type = eContextAdjustStackPointer; |
5265 | else |
5266 | context.type = eContextAdjustBaseRegister; |
5267 | context.SetAddress(offset_addr); |
5268 | |
5269 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n, |
5270 | reg_value: offset_addr)) |
5271 | return false; |
5272 | } |
5273 | } |
5274 | return true; |
5275 | } |
5276 | |
5277 | // STR (Store Register) calculates an address from a base register value and an |
5278 | // offset register value, stores a |
5279 | // word from a register to memory. The offset register value can optionally |
5280 | // be shifted. |
5281 | bool EmulateInstructionARM::EmulateSTRRegister(const uint32_t opcode, |
5282 | const ARMEncoding encoding) { |
5283 | #if 0 |
5284 | if ConditionPassed() then |
5285 | EncodingSpecificOperations(); NullCheckIfThumbEE(n); |
5286 | offset = Shift(R[m], shift_t, shift_n, APSR.C); |
5287 | offset_addr = if add then (R[n] + offset) else (R[n] - offset); |
5288 | address = if index then offset_addr else R[n]; |
5289 | if t == 15 then // Only possible for encoding A1 |
5290 | data = PCStoreValue(); |
5291 | else |
5292 | data = R[t]; |
5293 | if UnalignedSupport() || address<1:0> == '00' || CurrentInstrSet() == InstrSet_ARM then |
5294 | MemU[address,4] = data; |
5295 | else // Can only occur before ARMv7 |
5296 | MemU[address,4] = bits(32) UNKNOWN; |
5297 | if wback then R[n] = offset_addr; |
5298 | #endif |
5299 | |
5300 | bool success = false; |
5301 | |
5302 | if (ConditionPassed(opcode)) { |
5303 | const uint32_t addr_byte_size = GetAddressByteSize(); |
5304 | |
5305 | uint32_t t; |
5306 | uint32_t n; |
5307 | uint32_t m; |
5308 | ARM_ShifterType shift_t; |
5309 | uint32_t shift_n; |
5310 | bool index; |
5311 | bool add; |
5312 | bool wback; |
5313 | |
5314 | // EncodingSpecificOperations (); NullCheckIfThumbEE(n); |
5315 | switch (encoding) { |
5316 | case eEncodingT1: |
5317 | // if CurrentInstrSet() == InstrSet_ThumbEE then SEE "Modified operation |
5318 | // in ThumbEE"; |
5319 | // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); |
5320 | t = Bits32(bits: opcode, msbit: 2, lsbit: 0); |
5321 | n = Bits32(bits: opcode, msbit: 5, lsbit: 3); |
5322 | m = Bits32(bits: opcode, msbit: 8, lsbit: 6); |
5323 | |
5324 | // index = TRUE; add = TRUE; wback = FALSE; |
5325 | index = true; |
5326 | add = true; |
5327 | wback = false; |
5328 | |
5329 | // (shift_t, shift_n) = (SRType_LSL, 0); |
5330 | shift_t = SRType_LSL; |
5331 | shift_n = 0; |
5332 | break; |
5333 | |
5334 | case eEncodingT2: |
5335 | // if Rn == '1111' then UNDEFINED; |
5336 | if (Bits32(bits: opcode, msbit: 19, lsbit: 16) == 15) |
5337 | return false; |
5338 | |
5339 | // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); |
5340 | t = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
5341 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
5342 | m = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
5343 | |
5344 | // index = TRUE; add = TRUE; wback = FALSE; |
5345 | index = true; |
5346 | add = true; |
5347 | wback = false; |
5348 | |
5349 | // (shift_t, shift_n) = (SRType_LSL, UInt(imm2)); |
5350 | shift_t = SRType_LSL; |
5351 | shift_n = Bits32(bits: opcode, msbit: 5, lsbit: 4); |
5352 | |
5353 | // if t == 15 || BadReg(m) then UNPREDICTABLE; |
5354 | if ((t == 15) || (BadReg(n: m))) |
5355 | return false; |
5356 | break; |
5357 | |
5358 | case eEncodingA1: { |
5359 | // if P == '0' && W == '1' then SEE STRT; |
5360 | // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); |
5361 | t = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
5362 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
5363 | m = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
5364 | |
5365 | // index = (P == '1'); add = (U == '1'); wback = (P == '0') || |
5366 | // (W == '1'); |
5367 | index = BitIsSet(value: opcode, bit: 24); |
5368 | add = BitIsSet(value: opcode, bit: 23); |
5369 | wback = (BitIsClear(value: opcode, bit: 24) || BitIsSet(value: opcode, bit: 21)); |
5370 | |
5371 | // (shift_t, shift_n) = DecodeImmShift(type, imm5); |
5372 | uint32_t typ = Bits32(bits: opcode, msbit: 6, lsbit: 5); |
5373 | uint32_t imm5 = Bits32(bits: opcode, msbit: 11, lsbit: 7); |
5374 | shift_n = DecodeImmShift(type: typ, imm5, shift_t); |
5375 | |
5376 | // if m == 15 then UNPREDICTABLE; |
5377 | if (m == 15) |
5378 | return false; |
5379 | |
5380 | // if wback && (n == 15 || n == t) then UNPREDICTABLE; |
5381 | if (wback && ((n == 15) || (n == t))) |
5382 | return false; |
5383 | |
5384 | break; |
5385 | } |
5386 | default: |
5387 | return false; |
5388 | } |
5389 | |
5390 | addr_t offset_addr; |
5391 | addr_t address; |
5392 | int32_t offset = 0; |
5393 | |
5394 | addr_t base_address = |
5395 | ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n, fail_value: 0, success_ptr: &success); |
5396 | if (!success) |
5397 | return false; |
5398 | |
5399 | uint32_t Rm_data = |
5400 | ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + m, fail_value: 0, success_ptr: &success); |
5401 | if (!success) |
5402 | return false; |
5403 | |
5404 | // offset = Shift(R[m], shift_t, shift_n, APSR.C); |
5405 | offset = Shift(value: Rm_data, type: shift_t, amount: shift_n, APSR_C, success: &success); |
5406 | if (!success) |
5407 | return false; |
5408 | |
5409 | // offset_addr = if add then (R[n] + offset) else (R[n] - offset); |
5410 | if (add) |
5411 | offset_addr = base_address + offset; |
5412 | else |
5413 | offset_addr = base_address - offset; |
5414 | |
5415 | // address = if index then offset_addr else R[n]; |
5416 | if (index) |
5417 | address = offset_addr; |
5418 | else |
5419 | address = base_address; |
5420 | |
5421 | uint32_t data; |
5422 | // if t == 15 then // Only possible for encoding A1 |
5423 | if (t == 15) |
5424 | // data = PCStoreValue(); |
5425 | data = ReadCoreReg(PC_REG, success: &success); |
5426 | else |
5427 | // data = R[t]; |
5428 | data = |
5429 | ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + t, fail_value: 0, success_ptr: &success); |
5430 | |
5431 | if (!success) |
5432 | return false; |
5433 | |
5434 | EmulateInstruction::Context context; |
5435 | context.type = eContextRegisterStore; |
5436 | |
5437 | // if UnalignedSupport() || address<1:0> == '00' || CurrentInstrSet() == |
5438 | // InstrSet_ARM then |
5439 | if (UnalignedSupport() || |
5440 | (BitIsClear(value: address, bit: 1) && BitIsClear(value: address, bit: 0)) || |
5441 | CurrentInstrSet() == eModeARM) { |
5442 | // MemU[address,4] = data; |
5443 | |
5444 | std::optional<RegisterInfo> base_reg = |
5445 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n); |
5446 | std::optional<RegisterInfo> data_reg = |
5447 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + t); |
5448 | |
5449 | context.SetRegisterToRegisterPlusOffset(data_reg: *data_reg, base_reg: *base_reg, |
5450 | offset: address - base_address); |
5451 | if (!MemUWrite(context, address, data_val: data, size: addr_byte_size)) |
5452 | return false; |
5453 | |
5454 | } else |
5455 | // MemU[address,4] = bits(32) UNKNOWN; |
5456 | WriteBits32UnknownToMemory(address); |
5457 | |
5458 | // if wback then R[n] = offset_addr; |
5459 | if (wback) { |
5460 | context.type = eContextRegisterLoad; |
5461 | context.SetAddress(offset_addr); |
5462 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n, |
5463 | reg_value: offset_addr)) |
5464 | return false; |
5465 | } |
5466 | } |
5467 | return true; |
5468 | } |
5469 | |
5470 | bool EmulateInstructionARM::EmulateSTRBThumb(const uint32_t opcode, |
5471 | const ARMEncoding encoding) { |
5472 | #if 0 |
5473 | if ConditionPassed() then |
5474 | EncodingSpecificOperations(); NullCheckIfThumbEE(n); |
5475 | offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); |
5476 | address = if index then offset_addr else R[n]; |
5477 | MemU[address,1] = R[t]<7:0>; |
5478 | if wback then R[n] = offset_addr; |
5479 | #endif |
5480 | |
5481 | bool success = false; |
5482 | |
5483 | if (ConditionPassed(opcode)) { |
5484 | uint32_t t; |
5485 | uint32_t n; |
5486 | uint32_t imm32; |
5487 | bool index; |
5488 | bool add; |
5489 | bool wback; |
5490 | // EncodingSpecificOperations(); NullCheckIfThumbEE(n); |
5491 | switch (encoding) { |
5492 | case eEncodingT1: |
5493 | // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm5, 32); |
5494 | t = Bits32(bits: opcode, msbit: 2, lsbit: 0); |
5495 | n = Bits32(bits: opcode, msbit: 5, lsbit: 3); |
5496 | imm32 = Bits32(bits: opcode, msbit: 10, lsbit: 6); |
5497 | |
5498 | // index = TRUE; add = TRUE; wback = FALSE; |
5499 | index = true; |
5500 | add = true; |
5501 | wback = false; |
5502 | break; |
5503 | |
5504 | case eEncodingT2: |
5505 | // if Rn == '1111' then UNDEFINED; |
5506 | if (Bits32(bits: opcode, msbit: 19, lsbit: 16) == 15) |
5507 | return false; |
5508 | |
5509 | // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm12, 32); |
5510 | t = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
5511 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
5512 | imm32 = Bits32(bits: opcode, msbit: 11, lsbit: 0); |
5513 | |
5514 | // index = TRUE; add = TRUE; wback = FALSE; |
5515 | index = true; |
5516 | add = true; |
5517 | wback = false; |
5518 | |
5519 | // if BadReg(t) then UNPREDICTABLE; |
5520 | if (BadReg(n: t)) |
5521 | return false; |
5522 | break; |
5523 | |
5524 | case eEncodingT3: |
5525 | // if P == '1' && U == '1' && W == '0' then SEE STRBT; |
5526 | // if Rn == '1111' || (P == '0' && W == '0') then UNDEFINED; |
5527 | if (Bits32(bits: opcode, msbit: 19, lsbit: 16) == 15) |
5528 | return false; |
5529 | |
5530 | // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm8, 32); |
5531 | t = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
5532 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
5533 | imm32 = Bits32(bits: opcode, msbit: 7, lsbit: 0); |
5534 | |
5535 | // index = (P == '1'); add = (U == '1'); wback = (W == '1'); |
5536 | index = BitIsSet(value: opcode, bit: 10); |
5537 | add = BitIsSet(value: opcode, bit: 9); |
5538 | wback = BitIsSet(value: opcode, bit: 8); |
5539 | |
5540 | // if BadReg(t) || (wback && n == t) then UNPREDICTABLE |
5541 | if ((BadReg(n: t)) || (wback && (n == t))) |
5542 | return false; |
5543 | break; |
5544 | |
5545 | default: |
5546 | return false; |
5547 | } |
5548 | |
5549 | addr_t offset_addr; |
5550 | addr_t address; |
5551 | addr_t base_address = |
5552 | ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n, fail_value: 0, success_ptr: &success); |
5553 | if (!success) |
5554 | return false; |
5555 | |
5556 | // offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); |
5557 | if (add) |
5558 | offset_addr = base_address + imm32; |
5559 | else |
5560 | offset_addr = base_address - imm32; |
5561 | |
5562 | // address = if index then offset_addr else R[n]; |
5563 | if (index) |
5564 | address = offset_addr; |
5565 | else |
5566 | address = base_address; |
5567 | |
5568 | // MemU[address,1] = R[t]<7:0> |
5569 | std::optional<RegisterInfo> base_reg = |
5570 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n); |
5571 | std::optional<RegisterInfo> data_reg = |
5572 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + t); |
5573 | |
5574 | EmulateInstruction::Context context; |
5575 | context.type = eContextRegisterStore; |
5576 | context.SetRegisterToRegisterPlusOffset(data_reg: *data_reg, base_reg: *base_reg, |
5577 | offset: address - base_address); |
5578 | |
5579 | uint32_t data = |
5580 | ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + t, fail_value: 0, success_ptr: &success); |
5581 | if (!success) |
5582 | return false; |
5583 | |
5584 | data = Bits32(bits: data, msbit: 7, lsbit: 0); |
5585 | |
5586 | if (!MemUWrite(context, address, data_val: data, size: 1)) |
5587 | return false; |
5588 | |
5589 | // if wback then R[n] = offset_addr; |
5590 | if (wback) { |
5591 | context.type = eContextRegisterLoad; |
5592 | context.SetAddress(offset_addr); |
5593 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n, |
5594 | reg_value: offset_addr)) |
5595 | return false; |
5596 | } |
5597 | } |
5598 | |
5599 | return true; |
5600 | } |
5601 | |
5602 | // STRH (register) calculates an address from a base register value and an |
5603 | // offset register value, and stores a |
5604 | // halfword from a register to memory. The offset register value can be |
5605 | // shifted left by 0, 1, 2, or 3 bits. |
5606 | bool EmulateInstructionARM::EmulateSTRHRegister(const uint32_t opcode, |
5607 | const ARMEncoding encoding) { |
5608 | #if 0 |
5609 | if ConditionPassed() then |
5610 | EncodingSpecificOperations(); NullCheckIfThumbEE(n); |
5611 | offset = Shift(R[m], shift_t, shift_n, APSR.C); |
5612 | offset_addr = if add then (R[n] + offset) else (R[n] - offset); |
5613 | address = if index then offset_addr else R[n]; |
5614 | if UnalignedSupport() || address<0> == '0' then |
5615 | MemU[address,2] = R[t]<15:0>; |
5616 | else // Can only occur before ARMv7 |
5617 | MemU[address,2] = bits(16) UNKNOWN; |
5618 | if wback then R[n] = offset_addr; |
5619 | #endif |
5620 | |
5621 | bool success = false; |
5622 | |
5623 | if (ConditionPassed(opcode)) { |
5624 | uint32_t t; |
5625 | uint32_t n; |
5626 | uint32_t m; |
5627 | bool index; |
5628 | bool add; |
5629 | bool wback; |
5630 | ARM_ShifterType shift_t; |
5631 | uint32_t shift_n; |
5632 | |
5633 | // EncodingSpecificOperations(); NullCheckIfThumbEE(n); |
5634 | switch (encoding) { |
5635 | case eEncodingT1: |
5636 | // if CurrentInstrSet() == InstrSet_ThumbEE then SEE "Modified operation |
5637 | // in ThumbEE"; |
5638 | // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); |
5639 | t = Bits32(bits: opcode, msbit: 2, lsbit: 0); |
5640 | n = Bits32(bits: opcode, msbit: 5, lsbit: 3); |
5641 | m = Bits32(bits: opcode, msbit: 8, lsbit: 6); |
5642 | |
5643 | // index = TRUE; add = TRUE; wback = FALSE; |
5644 | index = true; |
5645 | add = true; |
5646 | wback = false; |
5647 | |
5648 | // (shift_t, shift_n) = (SRType_LSL, 0); |
5649 | shift_t = SRType_LSL; |
5650 | shift_n = 0; |
5651 | |
5652 | break; |
5653 | |
5654 | case eEncodingT2: |
5655 | // if Rn == '1111' then UNDEFINED; |
5656 | // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); |
5657 | t = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
5658 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
5659 | m = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
5660 | if (n == 15) |
5661 | return false; |
5662 | |
5663 | // index = TRUE; add = TRUE; wback = FALSE; |
5664 | index = true; |
5665 | add = true; |
5666 | wback = false; |
5667 | |
5668 | // (shift_t, shift_n) = (SRType_LSL, UInt(imm2)); |
5669 | shift_t = SRType_LSL; |
5670 | shift_n = Bits32(bits: opcode, msbit: 5, lsbit: 4); |
5671 | |
5672 | // if BadReg(t) || BadReg(m) then UNPREDICTABLE; |
5673 | if (BadReg(n: t) || BadReg(n: m)) |
5674 | return false; |
5675 | |
5676 | break; |
5677 | |
5678 | case eEncodingA1: |
5679 | // if P == '0' && W == '1' then SEE STRHT; |
5680 | // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); |
5681 | t = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
5682 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
5683 | m = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
5684 | |
5685 | // index = (P == '1'); add = (U == '1'); wback = (P == '0') || |
5686 | // (W == '1'); |
5687 | index = BitIsSet(value: opcode, bit: 24); |
5688 | add = BitIsSet(value: opcode, bit: 23); |
5689 | wback = (BitIsClear(value: opcode, bit: 24) || BitIsSet(value: opcode, bit: 21)); |
5690 | |
5691 | // (shift_t, shift_n) = (SRType_LSL, 0); |
5692 | shift_t = SRType_LSL; |
5693 | shift_n = 0; |
5694 | |
5695 | // if t == 15 || m == 15 then UNPREDICTABLE; |
5696 | if ((t == 15) || (m == 15)) |
5697 | return false; |
5698 | |
5699 | // if wback && (n == 15 || n == t) then UNPREDICTABLE; |
5700 | if (wback && ((n == 15) || (n == t))) |
5701 | return false; |
5702 | |
5703 | break; |
5704 | |
5705 | default: |
5706 | return false; |
5707 | } |
5708 | |
5709 | uint32_t Rm = ReadCoreReg(regnum: m, success: &success); |
5710 | if (!success) |
5711 | return false; |
5712 | |
5713 | uint32_t Rn = ReadCoreReg(regnum: n, success: &success); |
5714 | if (!success) |
5715 | return false; |
5716 | |
5717 | // offset = Shift(R[m], shift_t, shift_n, APSR.C); |
5718 | uint32_t offset = Shift(value: Rm, type: shift_t, amount: shift_n, APSR_C, success: &success); |
5719 | if (!success) |
5720 | return false; |
5721 | |
5722 | // offset_addr = if add then (R[n] + offset) else (R[n] - offset); |
5723 | addr_t offset_addr; |
5724 | if (add) |
5725 | offset_addr = Rn + offset; |
5726 | else |
5727 | offset_addr = Rn - offset; |
5728 | |
5729 | // address = if index then offset_addr else R[n]; |
5730 | addr_t address; |
5731 | if (index) |
5732 | address = offset_addr; |
5733 | else |
5734 | address = Rn; |
5735 | |
5736 | EmulateInstruction::Context context; |
5737 | context.type = eContextRegisterStore; |
5738 | |
5739 | // if UnalignedSupport() || address<0> == '0' then |
5740 | if (UnalignedSupport() || BitIsClear(value: address, bit: 0)) { |
5741 | // MemU[address,2] = R[t]<15:0>; |
5742 | uint32_t Rt = ReadCoreReg(regnum: t, success: &success); |
5743 | if (!success) |
5744 | return false; |
5745 | |
5746 | EmulateInstruction::Context context; |
5747 | context.type = eContextRegisterStore; |
5748 | std::optional<RegisterInfo> base_reg = |
5749 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n); |
5750 | std::optional<RegisterInfo> offset_reg = |
5751 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + m); |
5752 | std::optional<RegisterInfo> data_reg = |
5753 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + t); |
5754 | context.SetRegisterToRegisterPlusIndirectOffset(base_reg: *base_reg, offset_reg: *offset_reg, |
5755 | data_reg: *data_reg); |
5756 | |
5757 | if (!MemUWrite(context, address, data_val: Bits32(bits: Rt, msbit: 15, lsbit: 0), size: 2)) |
5758 | return false; |
5759 | } else // Can only occur before ARMv7 |
5760 | { |
5761 | // MemU[address,2] = bits(16) UNKNOWN; |
5762 | } |
5763 | |
5764 | // if wback then R[n] = offset_addr; |
5765 | if (wback) { |
5766 | context.type = eContextAdjustBaseRegister; |
5767 | context.SetAddress(offset_addr); |
5768 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n, |
5769 | reg_value: offset_addr)) |
5770 | return false; |
5771 | } |
5772 | } |
5773 | |
5774 | return true; |
5775 | } |
5776 | |
5777 | // Add with Carry (immediate) adds an immediate value and the carry flag value |
5778 | // to a register value, and writes the result to the destination register. It |
5779 | // can optionally update the condition flags based on the result. |
5780 | bool EmulateInstructionARM::EmulateADCImm(const uint32_t opcode, |
5781 | const ARMEncoding encoding) { |
5782 | #if 0 |
5783 | // ARM pseudo code... |
5784 | if ConditionPassed() then |
5785 | EncodingSpecificOperations(); |
5786 | (result, carry, overflow) = AddWithCarry(R[n], imm32, APSR.C); |
5787 | if d == 15 then // Can only occur for ARM encoding |
5788 | ALUWritePC(result); // setflags is always FALSE here |
5789 | else |
5790 | R[d] = result; |
5791 | if setflags then |
5792 | APSR.N = result<31>; |
5793 | APSR.Z = IsZeroBit(result); |
5794 | APSR.C = carry; |
5795 | APSR.V = overflow; |
5796 | #endif |
5797 | |
5798 | bool success = false; |
5799 | |
5800 | if (ConditionPassed(opcode)) { |
5801 | uint32_t Rd, Rn; |
5802 | uint32_t |
5803 | imm32; // the immediate value to be added to the value obtained from Rn |
5804 | bool setflags; |
5805 | switch (encoding) { |
5806 | case eEncodingT1: |
5807 | Rd = Bits32(bits: opcode, msbit: 11, lsbit: 8); |
5808 | Rn = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
5809 | setflags = BitIsSet(value: opcode, bit: 20); |
5810 | imm32 = ThumbExpandImm(opcode); // imm32 = ThumbExpandImm(i:imm3:imm8) |
5811 | if (BadReg(n: Rd) || BadReg(n: Rn)) |
5812 | return false; |
5813 | break; |
5814 | case eEncodingA1: |
5815 | Rd = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
5816 | Rn = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
5817 | setflags = BitIsSet(value: opcode, bit: 20); |
5818 | imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12) |
5819 | |
5820 | if (Rd == 15 && setflags) |
5821 | return EmulateSUBSPcLrEtc(opcode, encoding); |
5822 | break; |
5823 | default: |
5824 | return false; |
5825 | } |
5826 | |
5827 | // Read the first operand. |
5828 | int32_t val1 = ReadCoreReg(regnum: Rn, success: &success); |
5829 | if (!success) |
5830 | return false; |
5831 | |
5832 | AddWithCarryResult res = AddWithCarry(x: val1, y: imm32, APSR_C); |
5833 | |
5834 | EmulateInstruction::Context context; |
5835 | context.type = EmulateInstruction::eContextImmediate; |
5836 | context.SetNoArgs(); |
5837 | |
5838 | if (!WriteCoreRegOptionalFlags(context, result: res.result, Rd, setflags, |
5839 | carry: res.carry_out, overflow: res.overflow)) |
5840 | return false; |
5841 | } |
5842 | return true; |
5843 | } |
5844 | |
5845 | // Add with Carry (register) adds a register value, the carry flag value, and |
5846 | // an optionally-shifted register value, and writes the result to the |
5847 | // destination register. It can optionally update the condition flags based on |
5848 | // the result. |
5849 | bool EmulateInstructionARM::EmulateADCReg(const uint32_t opcode, |
5850 | const ARMEncoding encoding) { |
5851 | #if 0 |
5852 | // ARM pseudo code... |
5853 | if ConditionPassed() then |
5854 | EncodingSpecificOperations(); |
5855 | shifted = Shift(R[m], shift_t, shift_n, APSR.C); |
5856 | (result, carry, overflow) = AddWithCarry(R[n], shifted, APSR.C); |
5857 | if d == 15 then // Can only occur for ARM encoding |
5858 | ALUWritePC(result); // setflags is always FALSE here |
5859 | else |
5860 | R[d] = result; |
5861 | if setflags then |
5862 | APSR.N = result<31>; |
5863 | APSR.Z = IsZeroBit(result); |
5864 | APSR.C = carry; |
5865 | APSR.V = overflow; |
5866 | #endif |
5867 | |
5868 | bool success = false; |
5869 | |
5870 | if (ConditionPassed(opcode)) { |
5871 | uint32_t Rd, Rn, Rm; |
5872 | ARM_ShifterType shift_t; |
5873 | uint32_t shift_n; // the shift applied to the value read from Rm |
5874 | bool setflags; |
5875 | switch (encoding) { |
5876 | case eEncodingT1: |
5877 | Rd = Rn = Bits32(bits: opcode, msbit: 2, lsbit: 0); |
5878 | Rm = Bits32(bits: opcode, msbit: 5, lsbit: 3); |
5879 | setflags = !InITBlock(); |
5880 | shift_t = SRType_LSL; |
5881 | shift_n = 0; |
5882 | break; |
5883 | case eEncodingT2: |
5884 | Rd = Bits32(bits: opcode, msbit: 11, lsbit: 8); |
5885 | Rn = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
5886 | Rm = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
5887 | setflags = BitIsSet(value: opcode, bit: 20); |
5888 | shift_n = DecodeImmShiftThumb(opcode, shift_t); |
5889 | if (BadReg(n: Rd) || BadReg(n: Rn) || BadReg(n: Rm)) |
5890 | return false; |
5891 | break; |
5892 | case eEncodingA1: |
5893 | Rd = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
5894 | Rn = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
5895 | Rm = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
5896 | setflags = BitIsSet(value: opcode, bit: 20); |
5897 | shift_n = DecodeImmShiftARM(opcode, shift_t); |
5898 | |
5899 | if (Rd == 15 && setflags) |
5900 | return EmulateSUBSPcLrEtc(opcode, encoding); |
5901 | break; |
5902 | default: |
5903 | return false; |
5904 | } |
5905 | |
5906 | // Read the first operand. |
5907 | int32_t val1 = ReadCoreReg(regnum: Rn, success: &success); |
5908 | if (!success) |
5909 | return false; |
5910 | |
5911 | // Read the second operand. |
5912 | int32_t val2 = ReadCoreReg(regnum: Rm, success: &success); |
5913 | if (!success) |
5914 | return false; |
5915 | |
5916 | uint32_t shifted = Shift(value: val2, type: shift_t, amount: shift_n, APSR_C, success: &success); |
5917 | if (!success) |
5918 | return false; |
5919 | AddWithCarryResult res = AddWithCarry(x: val1, y: shifted, APSR_C); |
5920 | |
5921 | EmulateInstruction::Context context; |
5922 | context.type = EmulateInstruction::eContextImmediate; |
5923 | context.SetNoArgs(); |
5924 | |
5925 | if (!WriteCoreRegOptionalFlags(context, result: res.result, Rd, setflags, |
5926 | carry: res.carry_out, overflow: res.overflow)) |
5927 | return false; |
5928 | } |
5929 | return true; |
5930 | } |
5931 | |
5932 | // This instruction adds an immediate value to the PC value to form a PC- |
5933 | // relative address, and writes the result to the destination register. |
5934 | bool EmulateInstructionARM::EmulateADR(const uint32_t opcode, |
5935 | const ARMEncoding encoding) { |
5936 | #if 0 |
5937 | // ARM pseudo code... |
5938 | if ConditionPassed() then |
5939 | EncodingSpecificOperations(); |
5940 | result = if add then (Align(PC,4) + imm32) else (Align(PC,4) - imm32); |
5941 | if d == 15 then // Can only occur for ARM encodings |
5942 | ALUWritePC(result); |
5943 | else |
5944 | R[d] = result; |
5945 | #endif |
5946 | |
5947 | bool success = false; |
5948 | |
5949 | if (ConditionPassed(opcode)) { |
5950 | uint32_t Rd; |
5951 | uint32_t imm32; // the immediate value to be added/subtracted to/from the PC |
5952 | bool add; |
5953 | switch (encoding) { |
5954 | case eEncodingT1: |
5955 | Rd = Bits32(bits: opcode, msbit: 10, lsbit: 8); |
5956 | imm32 = ThumbImm8Scaled(opcode); // imm32 = ZeroExtend(imm8:'00', 32) |
5957 | add = true; |
5958 | break; |
5959 | case eEncodingT2: |
5960 | case eEncodingT3: |
5961 | Rd = Bits32(bits: opcode, msbit: 11, lsbit: 8); |
5962 | imm32 = ThumbImm12(opcode); // imm32 = ZeroExtend(i:imm3:imm8, 32) |
5963 | add = (Bits32(bits: opcode, msbit: 24, lsbit: 21) == 0); // 0b0000 => ADD; 0b0101 => SUB |
5964 | if (BadReg(n: Rd)) |
5965 | return false; |
5966 | break; |
5967 | case eEncodingA1: |
5968 | case eEncodingA2: |
5969 | Rd = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
5970 | imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12) |
5971 | add = (Bits32(bits: opcode, msbit: 24, lsbit: 21) == 0x4); // 0b0100 => ADD; 0b0010 => SUB |
5972 | break; |
5973 | default: |
5974 | return false; |
5975 | } |
5976 | |
5977 | // Read the PC value. |
5978 | uint32_t pc = ReadCoreReg(PC_REG, success: &success); |
5979 | if (!success) |
5980 | return false; |
5981 | |
5982 | uint32_t result = (add ? Align(val: pc, alignment: 4) + imm32 : Align(val: pc, alignment: 4) - imm32); |
5983 | |
5984 | EmulateInstruction::Context context; |
5985 | context.type = EmulateInstruction::eContextImmediate; |
5986 | context.SetNoArgs(); |
5987 | |
5988 | if (!WriteCoreReg(context, result, Rd)) |
5989 | return false; |
5990 | } |
5991 | return true; |
5992 | } |
5993 | |
5994 | // This instruction performs a bitwise AND of a register value and an immediate |
5995 | // value, and writes the result to the destination register. It can optionally |
5996 | // update the condition flags based on the result. |
5997 | bool EmulateInstructionARM::EmulateANDImm(const uint32_t opcode, |
5998 | const ARMEncoding encoding) { |
5999 | #if 0 |
6000 | // ARM pseudo code... |
6001 | if ConditionPassed() then |
6002 | EncodingSpecificOperations(); |
6003 | result = R[n] AND imm32; |
6004 | if d == 15 then // Can only occur for ARM encoding |
6005 | ALUWritePC(result); // setflags is always FALSE here |
6006 | else |
6007 | R[d] = result; |
6008 | if setflags then |
6009 | APSR.N = result<31>; |
6010 | APSR.Z = IsZeroBit(result); |
6011 | APSR.C = carry; |
6012 | // APSR.V unchanged |
6013 | #endif |
6014 | |
6015 | bool success = false; |
6016 | |
6017 | if (ConditionPassed(opcode)) { |
6018 | uint32_t Rd, Rn; |
6019 | uint32_t |
6020 | imm32; // the immediate value to be ANDed to the value obtained from Rn |
6021 | bool setflags; |
6022 | uint32_t carry; // the carry bit after ARM/Thumb Expand operation |
6023 | switch (encoding) { |
6024 | case eEncodingT1: |
6025 | Rd = Bits32(bits: opcode, msbit: 11, lsbit: 8); |
6026 | Rn = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
6027 | setflags = BitIsSet(value: opcode, bit: 20); |
6028 | imm32 = ThumbExpandImm_C( |
6029 | opcode, APSR_C, |
6030 | carry_out&: carry); // (imm32, carry) = ThumbExpandImm(i:imm3:imm8, APSR.C) |
6031 | // if Rd == '1111' && S == '1' then SEE TST (immediate); |
6032 | if (Rd == 15 && setflags) |
6033 | return EmulateTSTImm(opcode, encoding: eEncodingT1); |
6034 | if (Rd == 13 || (Rd == 15 && !setflags) || BadReg(n: Rn)) |
6035 | return false; |
6036 | break; |
6037 | case eEncodingA1: |
6038 | Rd = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
6039 | Rn = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
6040 | setflags = BitIsSet(value: opcode, bit: 20); |
6041 | imm32 = |
6042 | ARMExpandImm_C(opcode, APSR_C, |
6043 | carry_out&: carry); // (imm32, carry) = ARMExpandImm(imm12, APSR.C) |
6044 | |
6045 | if (Rd == 15 && setflags) |
6046 | return EmulateSUBSPcLrEtc(opcode, encoding); |
6047 | break; |
6048 | default: |
6049 | return false; |
6050 | } |
6051 | |
6052 | // Read the first operand. |
6053 | uint32_t val1 = ReadCoreReg(regnum: Rn, success: &success); |
6054 | if (!success) |
6055 | return false; |
6056 | |
6057 | uint32_t result = val1 & imm32; |
6058 | |
6059 | EmulateInstruction::Context context; |
6060 | context.type = EmulateInstruction::eContextImmediate; |
6061 | context.SetNoArgs(); |
6062 | |
6063 | if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry)) |
6064 | return false; |
6065 | } |
6066 | return true; |
6067 | } |
6068 | |
6069 | // This instruction performs a bitwise AND of a register value and an |
6070 | // optionally-shifted register value, and writes the result to the destination |
6071 | // register. It can optionally update the condition flags based on the result. |
6072 | bool EmulateInstructionARM::EmulateANDReg(const uint32_t opcode, |
6073 | const ARMEncoding encoding) { |
6074 | #if 0 |
6075 | // ARM pseudo code... |
6076 | if ConditionPassed() then |
6077 | EncodingSpecificOperations(); |
6078 | (shifted, carry) = Shift_C(R[m], shift_t, shift_n, APSR.C); |
6079 | result = R[n] AND shifted; |
6080 | if d == 15 then // Can only occur for ARM encoding |
6081 | ALUWritePC(result); // setflags is always FALSE here |
6082 | else |
6083 | R[d] = result; |
6084 | if setflags then |
6085 | APSR.N = result<31>; |
6086 | APSR.Z = IsZeroBit(result); |
6087 | APSR.C = carry; |
6088 | // APSR.V unchanged |
6089 | #endif |
6090 | |
6091 | bool success = false; |
6092 | |
6093 | if (ConditionPassed(opcode)) { |
6094 | uint32_t Rd, Rn, Rm; |
6095 | ARM_ShifterType shift_t; |
6096 | uint32_t shift_n; // the shift applied to the value read from Rm |
6097 | bool setflags; |
6098 | uint32_t carry; |
6099 | switch (encoding) { |
6100 | case eEncodingT1: |
6101 | Rd = Rn = Bits32(bits: opcode, msbit: 2, lsbit: 0); |
6102 | Rm = Bits32(bits: opcode, msbit: 5, lsbit: 3); |
6103 | setflags = !InITBlock(); |
6104 | shift_t = SRType_LSL; |
6105 | shift_n = 0; |
6106 | break; |
6107 | case eEncodingT2: |
6108 | Rd = Bits32(bits: opcode, msbit: 11, lsbit: 8); |
6109 | Rn = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
6110 | Rm = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
6111 | setflags = BitIsSet(value: opcode, bit: 20); |
6112 | shift_n = DecodeImmShiftThumb(opcode, shift_t); |
6113 | // if Rd == '1111' && S == '1' then SEE TST (register); |
6114 | if (Rd == 15 && setflags) |
6115 | return EmulateTSTReg(opcode, encoding: eEncodingT2); |
6116 | if (Rd == 13 || (Rd == 15 && !setflags) || BadReg(n: Rn) || BadReg(n: Rm)) |
6117 | return false; |
6118 | break; |
6119 | case eEncodingA1: |
6120 | Rd = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
6121 | Rn = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
6122 | Rm = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
6123 | setflags = BitIsSet(value: opcode, bit: 20); |
6124 | shift_n = DecodeImmShiftARM(opcode, shift_t); |
6125 | |
6126 | if (Rd == 15 && setflags) |
6127 | return EmulateSUBSPcLrEtc(opcode, encoding); |
6128 | break; |
6129 | default: |
6130 | return false; |
6131 | } |
6132 | |
6133 | // Read the first operand. |
6134 | uint32_t val1 = ReadCoreReg(regnum: Rn, success: &success); |
6135 | if (!success) |
6136 | return false; |
6137 | |
6138 | // Read the second operand. |
6139 | uint32_t val2 = ReadCoreReg(regnum: Rm, success: &success); |
6140 | if (!success) |
6141 | return false; |
6142 | |
6143 | uint32_t shifted = Shift_C(value: val2, type: shift_t, amount: shift_n, APSR_C, carry_out&: carry, success: &success); |
6144 | if (!success) |
6145 | return false; |
6146 | uint32_t result = val1 & shifted; |
6147 | |
6148 | EmulateInstruction::Context context; |
6149 | context.type = EmulateInstruction::eContextImmediate; |
6150 | context.SetNoArgs(); |
6151 | |
6152 | if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry)) |
6153 | return false; |
6154 | } |
6155 | return true; |
6156 | } |
6157 | |
6158 | // Bitwise Bit Clear (immediate) performs a bitwise AND of a register value and |
6159 | // the complement of an immediate value, and writes the result to the |
6160 | // destination register. It can optionally update the condition flags based on |
6161 | // the result. |
6162 | bool EmulateInstructionARM::EmulateBICImm(const uint32_t opcode, |
6163 | const ARMEncoding encoding) { |
6164 | #if 0 |
6165 | // ARM pseudo code... |
6166 | if ConditionPassed() then |
6167 | EncodingSpecificOperations(); |
6168 | result = R[n] AND NOT(imm32); |
6169 | if d == 15 then // Can only occur for ARM encoding |
6170 | ALUWritePC(result); // setflags is always FALSE here |
6171 | else |
6172 | R[d] = result; |
6173 | if setflags then |
6174 | APSR.N = result<31>; |
6175 | APSR.Z = IsZeroBit(result); |
6176 | APSR.C = carry; |
6177 | // APSR.V unchanged |
6178 | #endif |
6179 | |
6180 | bool success = false; |
6181 | |
6182 | if (ConditionPassed(opcode)) { |
6183 | uint32_t Rd, Rn; |
6184 | uint32_t imm32; // the immediate value to be bitwise inverted and ANDed to |
6185 | // the value obtained from Rn |
6186 | bool setflags; |
6187 | uint32_t carry; // the carry bit after ARM/Thumb Expand operation |
6188 | switch (encoding) { |
6189 | case eEncodingT1: |
6190 | Rd = Bits32(bits: opcode, msbit: 11, lsbit: 8); |
6191 | Rn = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
6192 | setflags = BitIsSet(value: opcode, bit: 20); |
6193 | imm32 = ThumbExpandImm_C( |
6194 | opcode, APSR_C, |
6195 | carry_out&: carry); // (imm32, carry) = ThumbExpandImm(i:imm3:imm8, APSR.C) |
6196 | if (BadReg(n: Rd) || BadReg(n: Rn)) |
6197 | return false; |
6198 | break; |
6199 | case eEncodingA1: |
6200 | Rd = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
6201 | Rn = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
6202 | setflags = BitIsSet(value: opcode, bit: 20); |
6203 | imm32 = |
6204 | ARMExpandImm_C(opcode, APSR_C, |
6205 | carry_out&: carry); // (imm32, carry) = ARMExpandImm(imm12, APSR.C) |
6206 | |
6207 | // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related |
6208 | // instructions; |
6209 | if (Rd == 15 && setflags) |
6210 | return EmulateSUBSPcLrEtc(opcode, encoding); |
6211 | break; |
6212 | default: |
6213 | return false; |
6214 | } |
6215 | |
6216 | // Read the first operand. |
6217 | uint32_t val1 = ReadCoreReg(regnum: Rn, success: &success); |
6218 | if (!success) |
6219 | return false; |
6220 | |
6221 | uint32_t result = val1 & ~imm32; |
6222 | |
6223 | EmulateInstruction::Context context; |
6224 | context.type = EmulateInstruction::eContextImmediate; |
6225 | context.SetNoArgs(); |
6226 | |
6227 | if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry)) |
6228 | return false; |
6229 | } |
6230 | return true; |
6231 | } |
6232 | |
6233 | // Bitwise Bit Clear (register) performs a bitwise AND of a register value and |
6234 | // the complement of an optionally-shifted register value, and writes the |
6235 | // result to the destination register. It can optionally update the condition |
6236 | // flags based on the result. |
6237 | bool EmulateInstructionARM::EmulateBICReg(const uint32_t opcode, |
6238 | const ARMEncoding encoding) { |
6239 | #if 0 |
6240 | // ARM pseudo code... |
6241 | if ConditionPassed() then |
6242 | EncodingSpecificOperations(); |
6243 | (shifted, carry) = Shift_C(R[m], shift_t, shift_n, APSR.C); |
6244 | result = R[n] AND NOT(shifted); |
6245 | if d == 15 then // Can only occur for ARM encoding |
6246 | ALUWritePC(result); // setflags is always FALSE here |
6247 | else |
6248 | R[d] = result; |
6249 | if setflags then |
6250 | APSR.N = result<31>; |
6251 | APSR.Z = IsZeroBit(result); |
6252 | APSR.C = carry; |
6253 | // APSR.V unchanged |
6254 | #endif |
6255 | |
6256 | bool success = false; |
6257 | |
6258 | if (ConditionPassed(opcode)) { |
6259 | uint32_t Rd, Rn, Rm; |
6260 | ARM_ShifterType shift_t; |
6261 | uint32_t shift_n; // the shift applied to the value read from Rm |
6262 | bool setflags; |
6263 | uint32_t carry; |
6264 | switch (encoding) { |
6265 | case eEncodingT1: |
6266 | Rd = Rn = Bits32(bits: opcode, msbit: 2, lsbit: 0); |
6267 | Rm = Bits32(bits: opcode, msbit: 5, lsbit: 3); |
6268 | setflags = !InITBlock(); |
6269 | shift_t = SRType_LSL; |
6270 | shift_n = 0; |
6271 | break; |
6272 | case eEncodingT2: |
6273 | Rd = Bits32(bits: opcode, msbit: 11, lsbit: 8); |
6274 | Rn = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
6275 | Rm = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
6276 | setflags = BitIsSet(value: opcode, bit: 20); |
6277 | shift_n = DecodeImmShiftThumb(opcode, shift_t); |
6278 | if (BadReg(n: Rd) || BadReg(n: Rn) || BadReg(n: Rm)) |
6279 | return false; |
6280 | break; |
6281 | case eEncodingA1: |
6282 | Rd = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
6283 | Rn = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
6284 | Rm = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
6285 | setflags = BitIsSet(value: opcode, bit: 20); |
6286 | shift_n = DecodeImmShiftARM(opcode, shift_t); |
6287 | |
6288 | // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related |
6289 | // instructions; |
6290 | if (Rd == 15 && setflags) |
6291 | return EmulateSUBSPcLrEtc(opcode, encoding); |
6292 | break; |
6293 | default: |
6294 | return false; |
6295 | } |
6296 | |
6297 | // Read the first operand. |
6298 | uint32_t val1 = ReadCoreReg(regnum: Rn, success: &success); |
6299 | if (!success) |
6300 | return false; |
6301 | |
6302 | // Read the second operand. |
6303 | uint32_t val2 = ReadCoreReg(regnum: Rm, success: &success); |
6304 | if (!success) |
6305 | return false; |
6306 | |
6307 | uint32_t shifted = Shift_C(value: val2, type: shift_t, amount: shift_n, APSR_C, carry_out&: carry, success: &success); |
6308 | if (!success) |
6309 | return false; |
6310 | uint32_t result = val1 & ~shifted; |
6311 | |
6312 | EmulateInstruction::Context context; |
6313 | context.type = EmulateInstruction::eContextImmediate; |
6314 | context.SetNoArgs(); |
6315 | |
6316 | if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry)) |
6317 | return false; |
6318 | } |
6319 | return true; |
6320 | } |
6321 | |
6322 | // LDR (immediate, ARM) calculates an address from a base register value and an |
6323 | // immediate offset, loads a word |
6324 | // from memory, and writes it to a register. It can use offset, post-indexed, |
6325 | // or pre-indexed addressing. |
6326 | bool EmulateInstructionARM::EmulateLDRImmediateARM(const uint32_t opcode, |
6327 | const ARMEncoding encoding) { |
6328 | #if 0 |
6329 | if ConditionPassed() then |
6330 | EncodingSpecificOperations(); |
6331 | offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); |
6332 | address = if index then offset_addr else R[n]; |
6333 | data = MemU[address,4]; |
6334 | if wback then R[n] = offset_addr; |
6335 | if t == 15 then |
6336 | if address<1:0> == '00' then LoadWritePC(data); else UNPREDICTABLE; |
6337 | elsif UnalignedSupport() || address<1:0> = '00' then |
6338 | R[t] = data; |
6339 | else // Can only apply before ARMv7 |
6340 | R[t] = ROR(data, 8*UInt(address<1:0>)); |
6341 | #endif |
6342 | |
6343 | bool success = false; |
6344 | |
6345 | if (ConditionPassed(opcode)) { |
6346 | const uint32_t addr_byte_size = GetAddressByteSize(); |
6347 | |
6348 | uint32_t t; |
6349 | uint32_t n; |
6350 | uint32_t imm32; |
6351 | bool index; |
6352 | bool add; |
6353 | bool wback; |
6354 | |
6355 | switch (encoding) { |
6356 | case eEncodingA1: |
6357 | // if Rn == '1111' then SEE LDR (literal); |
6358 | // if P == '0' && W == '1' then SEE LDRT; |
6359 | // if Rn == '1101' && P == '0' && U == '1' && W == '0' && imm12 == |
6360 | // '000000000100' then SEE POP; |
6361 | // t == UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm12, 32); |
6362 | t = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
6363 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
6364 | imm32 = Bits32(bits: opcode, msbit: 11, lsbit: 0); |
6365 | |
6366 | // index = (P == '1'); add = (U == '1'); wback = (P == '0') || |
6367 | // (W == '1'); |
6368 | index = BitIsSet(value: opcode, bit: 24); |
6369 | add = BitIsSet(value: opcode, bit: 23); |
6370 | wback = (BitIsClear(value: opcode, bit: 24) || BitIsSet(value: opcode, bit: 21)); |
6371 | |
6372 | // if wback && n == t then UNPREDICTABLE; |
6373 | if (wback && (n == t)) |
6374 | return false; |
6375 | |
6376 | break; |
6377 | |
6378 | default: |
6379 | return false; |
6380 | } |
6381 | |
6382 | addr_t address; |
6383 | addr_t offset_addr; |
6384 | addr_t base_address = ReadCoreReg(regnum: n, success: &success); |
6385 | if (!success) |
6386 | return false; |
6387 | |
6388 | // offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); |
6389 | if (add) |
6390 | offset_addr = base_address + imm32; |
6391 | else |
6392 | offset_addr = base_address - imm32; |
6393 | |
6394 | // address = if index then offset_addr else R[n]; |
6395 | if (index) |
6396 | address = offset_addr; |
6397 | else |
6398 | address = base_address; |
6399 | |
6400 | // data = MemU[address,4]; |
6401 | |
6402 | std::optional<RegisterInfo> base_reg = |
6403 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n); |
6404 | EmulateInstruction::Context context; |
6405 | context.type = eContextRegisterLoad; |
6406 | context.SetRegisterPlusOffset(base_reg: *base_reg, signed_offset: address - base_address); |
6407 | |
6408 | uint64_t data = MemURead(context, address, size: addr_byte_size, fail_value: 0, success_ptr: &success); |
6409 | if (!success) |
6410 | return false; |
6411 | |
6412 | // if wback then R[n] = offset_addr; |
6413 | if (wback) { |
6414 | context.type = eContextAdjustBaseRegister; |
6415 | context.SetAddress(offset_addr); |
6416 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n, |
6417 | reg_value: offset_addr)) |
6418 | return false; |
6419 | } |
6420 | |
6421 | // if t == 15 then |
6422 | if (t == 15) { |
6423 | // if address<1:0> == '00' then LoadWritePC(data); else UNPREDICTABLE; |
6424 | if (BitIsClear(value: address, bit: 1) && BitIsClear(value: address, bit: 0)) { |
6425 | // LoadWritePC (data); |
6426 | context.type = eContextRegisterLoad; |
6427 | context.SetRegisterPlusOffset(base_reg: *base_reg, signed_offset: address - base_address); |
6428 | LoadWritePC(context, addr: data); |
6429 | } else |
6430 | return false; |
6431 | } |
6432 | // elsif UnalignedSupport() || address<1:0> = '00' then |
6433 | else if (UnalignedSupport() || |
6434 | (BitIsClear(value: address, bit: 1) && BitIsClear(value: address, bit: 0))) { |
6435 | // R[t] = data; |
6436 | context.type = eContextRegisterLoad; |
6437 | context.SetRegisterPlusOffset(base_reg: *base_reg, signed_offset: address - base_address); |
6438 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + t, |
6439 | reg_value: data)) |
6440 | return false; |
6441 | } |
6442 | // else // Can only apply before ARMv7 |
6443 | else { |
6444 | // R[t] = ROR(data, 8*UInt(address<1:0>)); |
6445 | data = ROR(value: data, amount: Bits32(bits: address, msbit: 1, lsbit: 0), success: &success); |
6446 | if (!success) |
6447 | return false; |
6448 | context.type = eContextRegisterLoad; |
6449 | context.SetImmediate(data); |
6450 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + t, |
6451 | reg_value: data)) |
6452 | return false; |
6453 | } |
6454 | } |
6455 | return true; |
6456 | } |
6457 | |
6458 | // LDR (register) calculates an address from a base register value and an offset |
6459 | // register value, loads a word |
6460 | // from memory, and writes it to a register. The offset register value can |
6461 | // optionally be shifted. |
6462 | bool EmulateInstructionARM::EmulateLDRRegister(const uint32_t opcode, |
6463 | const ARMEncoding encoding) { |
6464 | #if 0 |
6465 | if ConditionPassed() then |
6466 | EncodingSpecificOperations(); NullCheckIfThumbEE(n); |
6467 | offset = Shift(R[m], shift_t, shift_n, APSR.C); |
6468 | offset_addr = if add then (R[n] + offset) else (R[n] - offset); |
6469 | address = if index then offset_addr else R[n]; |
6470 | data = MemU[address,4]; |
6471 | if wback then R[n] = offset_addr; |
6472 | if t == 15 then |
6473 | if address<1:0> == '00' then LoadWritePC(data); else UNPREDICTABLE; |
6474 | elsif UnalignedSupport() || address<1:0> = '00' then |
6475 | R[t] = data; |
6476 | else // Can only apply before ARMv7 |
6477 | if CurrentInstrSet() == InstrSet_ARM then |
6478 | R[t] = ROR(data, 8*UInt(address<1:0>)); |
6479 | else |
6480 | R[t] = bits(32) UNKNOWN; |
6481 | #endif |
6482 | |
6483 | bool success = false; |
6484 | |
6485 | if (ConditionPassed(opcode)) { |
6486 | const uint32_t addr_byte_size = GetAddressByteSize(); |
6487 | |
6488 | uint32_t t; |
6489 | uint32_t n; |
6490 | uint32_t m; |
6491 | bool index; |
6492 | bool add; |
6493 | bool wback; |
6494 | ARM_ShifterType shift_t; |
6495 | uint32_t shift_n; |
6496 | |
6497 | switch (encoding) { |
6498 | case eEncodingT1: |
6499 | // if CurrentInstrSet() == InstrSet_ThumbEE then SEE "Modified operation |
6500 | // in ThumbEE"; |
6501 | // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); |
6502 | t = Bits32(bits: opcode, msbit: 2, lsbit: 0); |
6503 | n = Bits32(bits: opcode, msbit: 5, lsbit: 3); |
6504 | m = Bits32(bits: opcode, msbit: 8, lsbit: 6); |
6505 | |
6506 | // index = TRUE; add = TRUE; wback = FALSE; |
6507 | index = true; |
6508 | add = true; |
6509 | wback = false; |
6510 | |
6511 | // (shift_t, shift_n) = (SRType_LSL, 0); |
6512 | shift_t = SRType_LSL; |
6513 | shift_n = 0; |
6514 | |
6515 | break; |
6516 | |
6517 | case eEncodingT2: |
6518 | // if Rn == '1111' then SEE LDR (literal); |
6519 | // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); |
6520 | t = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
6521 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
6522 | m = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
6523 | |
6524 | // index = TRUE; add = TRUE; wback = FALSE; |
6525 | index = true; |
6526 | add = true; |
6527 | wback = false; |
6528 | |
6529 | // (shift_t, shift_n) = (SRType_LSL, UInt(imm2)); |
6530 | shift_t = SRType_LSL; |
6531 | shift_n = Bits32(bits: opcode, msbit: 5, lsbit: 4); |
6532 | |
6533 | // if BadReg(m) then UNPREDICTABLE; |
6534 | if (BadReg(n: m)) |
6535 | return false; |
6536 | |
6537 | // if t == 15 && InITBlock() && !LastInITBlock() then UNPREDICTABLE; |
6538 | if ((t == 15) && InITBlock() && !LastInITBlock()) |
6539 | return false; |
6540 | |
6541 | break; |
6542 | |
6543 | case eEncodingA1: { |
6544 | // if P == '0' && W == '1' then SEE LDRT; |
6545 | // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); |
6546 | t = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
6547 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
6548 | m = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
6549 | |
6550 | // index = (P == '1'); add = (U == '1'); wback = (P == '0') || |
6551 | // (W == '1'); |
6552 | index = BitIsSet(value: opcode, bit: 24); |
6553 | add = BitIsSet(value: opcode, bit: 23); |
6554 | wback = (BitIsClear(value: opcode, bit: 24) || BitIsSet(value: opcode, bit: 21)); |
6555 | |
6556 | // (shift_t, shift_n) = DecodeImmShift(type, imm5); |
6557 | uint32_t type = Bits32(bits: opcode, msbit: 6, lsbit: 5); |
6558 | uint32_t imm5 = Bits32(bits: opcode, msbit: 11, lsbit: 7); |
6559 | shift_n = DecodeImmShift(type, imm5, shift_t); |
6560 | |
6561 | // if m == 15 then UNPREDICTABLE; |
6562 | if (m == 15) |
6563 | return false; |
6564 | |
6565 | // if wback && (n == 15 || n == t) then UNPREDICTABLE; |
6566 | if (wback && ((n == 15) || (n == t))) |
6567 | return false; |
6568 | } break; |
6569 | |
6570 | default: |
6571 | return false; |
6572 | } |
6573 | |
6574 | uint32_t Rm = |
6575 | ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + m, fail_value: 0, success_ptr: &success); |
6576 | if (!success) |
6577 | return false; |
6578 | |
6579 | uint32_t Rn = |
6580 | ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n, fail_value: 0, success_ptr: &success); |
6581 | if (!success) |
6582 | return false; |
6583 | |
6584 | addr_t offset_addr; |
6585 | addr_t address; |
6586 | |
6587 | // offset = Shift(R[m], shift_t, shift_n, APSR.C); -- Note "The APSR is |
6588 | // an application level alias for the CPSR". |
6589 | addr_t offset = |
6590 | Shift(value: Rm, type: shift_t, amount: shift_n, carry_in: Bit32(bits: m_opcode_cpsr, APSR_C), success: &success); |
6591 | if (!success) |
6592 | return false; |
6593 | |
6594 | // offset_addr = if add then (R[n] + offset) else (R[n] - offset); |
6595 | if (add) |
6596 | offset_addr = Rn + offset; |
6597 | else |
6598 | offset_addr = Rn - offset; |
6599 | |
6600 | // address = if index then offset_addr else R[n]; |
6601 | if (index) |
6602 | address = offset_addr; |
6603 | else |
6604 | address = Rn; |
6605 | |
6606 | // data = MemU[address,4]; |
6607 | std::optional<RegisterInfo> base_reg = |
6608 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n); |
6609 | EmulateInstruction::Context context; |
6610 | context.type = eContextRegisterLoad; |
6611 | context.SetRegisterPlusOffset(base_reg: *base_reg, signed_offset: address - Rn); |
6612 | |
6613 | uint64_t data = MemURead(context, address, size: addr_byte_size, fail_value: 0, success_ptr: &success); |
6614 | if (!success) |
6615 | return false; |
6616 | |
6617 | // if wback then R[n] = offset_addr; |
6618 | if (wback) { |
6619 | context.type = eContextAdjustBaseRegister; |
6620 | context.SetAddress(offset_addr); |
6621 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n, |
6622 | reg_value: offset_addr)) |
6623 | return false; |
6624 | } |
6625 | |
6626 | // if t == 15 then |
6627 | if (t == 15) { |
6628 | // if address<1:0> == '00' then LoadWritePC(data); else UNPREDICTABLE; |
6629 | if (BitIsClear(value: address, bit: 1) && BitIsClear(value: address, bit: 0)) { |
6630 | context.type = eContextRegisterLoad; |
6631 | context.SetRegisterPlusOffset(base_reg: *base_reg, signed_offset: address - Rn); |
6632 | LoadWritePC(context, addr: data); |
6633 | } else |
6634 | return false; |
6635 | } |
6636 | // elsif UnalignedSupport() || address<1:0> = '00' then |
6637 | else if (UnalignedSupport() || |
6638 | (BitIsClear(value: address, bit: 1) && BitIsClear(value: address, bit: 0))) { |
6639 | // R[t] = data; |
6640 | context.type = eContextRegisterLoad; |
6641 | context.SetRegisterPlusOffset(base_reg: *base_reg, signed_offset: address - Rn); |
6642 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + t, |
6643 | reg_value: data)) |
6644 | return false; |
6645 | } else // Can only apply before ARMv7 |
6646 | { |
6647 | // if CurrentInstrSet() == InstrSet_ARM then |
6648 | if (CurrentInstrSet() == eModeARM) { |
6649 | // R[t] = ROR(data, 8*UInt(address<1:0>)); |
6650 | data = ROR(value: data, amount: Bits32(bits: address, msbit: 1, lsbit: 0), success: &success); |
6651 | if (!success) |
6652 | return false; |
6653 | context.type = eContextRegisterLoad; |
6654 | context.SetImmediate(data); |
6655 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + t, |
6656 | reg_value: data)) |
6657 | return false; |
6658 | } else { |
6659 | // R[t] = bits(32) UNKNOWN; |
6660 | WriteBits32Unknown(n: t); |
6661 | } |
6662 | } |
6663 | } |
6664 | return true; |
6665 | } |
6666 | |
6667 | // LDRB (immediate, Thumb) |
6668 | bool EmulateInstructionARM::EmulateLDRBImmediate(const uint32_t opcode, |
6669 | const ARMEncoding encoding) { |
6670 | #if 0 |
6671 | if ConditionPassed() then |
6672 | EncodingSpecificOperations(); NullCheckIfThumbEE(n); |
6673 | offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); |
6674 | address = if index then offset_addr else R[n]; |
6675 | R[t] = ZeroExtend(MemU[address,1], 32); |
6676 | if wback then R[n] = offset_addr; |
6677 | #endif |
6678 | |
6679 | bool success = false; |
6680 | |
6681 | if (ConditionPassed(opcode)) { |
6682 | uint32_t t; |
6683 | uint32_t n; |
6684 | uint32_t imm32; |
6685 | bool index; |
6686 | bool add; |
6687 | bool wback; |
6688 | |
6689 | // EncodingSpecificOperations(); NullCheckIfThumbEE(n); |
6690 | switch (encoding) { |
6691 | case eEncodingT1: |
6692 | // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm5, 32); |
6693 | t = Bits32(bits: opcode, msbit: 2, lsbit: 0); |
6694 | n = Bits32(bits: opcode, msbit: 5, lsbit: 3); |
6695 | imm32 = Bits32(bits: opcode, msbit: 10, lsbit: 6); |
6696 | |
6697 | // index = TRUE; add = TRUE; wback = FALSE; |
6698 | index = true; |
6699 | add = true; |
6700 | wback = false; |
6701 | |
6702 | break; |
6703 | |
6704 | case eEncodingT2: |
6705 | // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm12, 32); |
6706 | t = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
6707 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
6708 | imm32 = Bits32(bits: opcode, msbit: 11, lsbit: 0); |
6709 | |
6710 | // index = TRUE; add = TRUE; wback = FALSE; |
6711 | index = true; |
6712 | add = true; |
6713 | wback = false; |
6714 | |
6715 | // if Rt == '1111' then SEE PLD; |
6716 | if (t == 15) |
6717 | return false; // PLD is not implemented yet |
6718 | |
6719 | // if Rn == '1111' then SEE LDRB (literal); |
6720 | if (n == 15) |
6721 | return EmulateLDRBLiteral(opcode, encoding: eEncodingT1); |
6722 | |
6723 | // if t == 13 then UNPREDICTABLE; |
6724 | if (t == 13) |
6725 | return false; |
6726 | |
6727 | break; |
6728 | |
6729 | case eEncodingT3: |
6730 | // if P == '1' && U == '1' && W == '0' then SEE LDRBT; |
6731 | // if P == '0' && W == '0' then UNDEFINED; |
6732 | if (BitIsClear(value: opcode, bit: 10) && BitIsClear(value: opcode, bit: 8)) |
6733 | return false; |
6734 | |
6735 | // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm8, 32); |
6736 | t = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
6737 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
6738 | imm32 = Bits32(bits: opcode, msbit: 7, lsbit: 0); |
6739 | |
6740 | // index = (P == '1'); add = (U == '1'); wback = (W == '1'); |
6741 | index = BitIsSet(value: opcode, bit: 10); |
6742 | add = BitIsSet(value: opcode, bit: 9); |
6743 | wback = BitIsSet(value: opcode, bit: 8); |
6744 | |
6745 | // if Rt == '1111' && P == '1' && U == '0' && W == '0' then SEE PLD; |
6746 | if (t == 15) |
6747 | return false; // PLD is not implemented yet |
6748 | |
6749 | // if Rn == '1111' then SEE LDRB (literal); |
6750 | if (n == 15) |
6751 | return EmulateLDRBLiteral(opcode, encoding: eEncodingT1); |
6752 | |
6753 | // if BadReg(t) || (wback && n == t) then UNPREDICTABLE; |
6754 | if (BadReg(n: t) || (wback && (n == t))) |
6755 | return false; |
6756 | |
6757 | break; |
6758 | |
6759 | default: |
6760 | return false; |
6761 | } |
6762 | |
6763 | uint32_t Rn = |
6764 | ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n, fail_value: 0, success_ptr: &success); |
6765 | if (!success) |
6766 | return false; |
6767 | |
6768 | addr_t address; |
6769 | addr_t offset_addr; |
6770 | |
6771 | // offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); |
6772 | if (add) |
6773 | offset_addr = Rn + imm32; |
6774 | else |
6775 | offset_addr = Rn - imm32; |
6776 | |
6777 | // address = if index then offset_addr else R[n]; |
6778 | if (index) |
6779 | address = offset_addr; |
6780 | else |
6781 | address = Rn; |
6782 | |
6783 | // R[t] = ZeroExtend(MemU[address,1], 32); |
6784 | std::optional<RegisterInfo> base_reg = |
6785 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n); |
6786 | std::optional<RegisterInfo> data_reg = |
6787 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + t); |
6788 | |
6789 | EmulateInstruction::Context context; |
6790 | context.type = eContextRegisterLoad; |
6791 | context.SetRegisterToRegisterPlusOffset(data_reg: *data_reg, base_reg: *base_reg, offset: address - Rn); |
6792 | |
6793 | uint64_t data = MemURead(context, address, size: 1, fail_value: 0, success_ptr: &success); |
6794 | if (!success) |
6795 | return false; |
6796 | |
6797 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + t, reg_value: data)) |
6798 | return false; |
6799 | |
6800 | // if wback then R[n] = offset_addr; |
6801 | if (wback) { |
6802 | context.type = eContextAdjustBaseRegister; |
6803 | context.SetAddress(offset_addr); |
6804 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n, |
6805 | reg_value: offset_addr)) |
6806 | return false; |
6807 | } |
6808 | } |
6809 | return true; |
6810 | } |
6811 | |
6812 | // LDRB (literal) calculates an address from the PC value and an immediate |
6813 | // offset, loads a byte from memory, |
6814 | // zero-extends it to form a 32-bit word and writes it to a register. |
6815 | bool EmulateInstructionARM::EmulateLDRBLiteral(const uint32_t opcode, |
6816 | const ARMEncoding encoding) { |
6817 | #if 0 |
6818 | if ConditionPassed() then |
6819 | EncodingSpecificOperations(); NullCheckIfThumbEE(15); |
6820 | base = Align(PC,4); |
6821 | address = if add then (base + imm32) else (base - imm32); |
6822 | R[t] = ZeroExtend(MemU[address,1], 32); |
6823 | #endif |
6824 | |
6825 | bool success = false; |
6826 | |
6827 | if (ConditionPassed(opcode)) { |
6828 | uint32_t t; |
6829 | uint32_t imm32; |
6830 | bool add; |
6831 | switch (encoding) { |
6832 | case eEncodingT1: |
6833 | // t = UInt(Rt); imm32 = ZeroExtend(imm12, 32); add = (U == '1'); |
6834 | t = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
6835 | imm32 = Bits32(bits: opcode, msbit: 11, lsbit: 0); |
6836 | add = BitIsSet(value: opcode, bit: 23); |
6837 | |
6838 | // if Rt == '1111' then SEE PLD; |
6839 | if (t == 15) |
6840 | return false; // PLD is not implemented yet |
6841 | |
6842 | // if t == 13 then UNPREDICTABLE; |
6843 | if (t == 13) |
6844 | return false; |
6845 | |
6846 | break; |
6847 | |
6848 | case eEncodingA1: |
6849 | // t == UInt(Rt); imm32 = ZeroExtend(imm12, 32); add = (U == '1'); |
6850 | t = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
6851 | imm32 = Bits32(bits: opcode, msbit: 11, lsbit: 0); |
6852 | add = BitIsSet(value: opcode, bit: 23); |
6853 | |
6854 | // if t == 15 then UNPREDICTABLE; |
6855 | if (t == 15) |
6856 | return false; |
6857 | break; |
6858 | |
6859 | default: |
6860 | return false; |
6861 | } |
6862 | |
6863 | // base = Align(PC,4); |
6864 | uint32_t pc_val = ReadCoreReg(PC_REG, success: &success); |
6865 | if (!success) |
6866 | return false; |
6867 | |
6868 | uint32_t base = AlignPC(pc_val); |
6869 | |
6870 | addr_t address; |
6871 | // address = if add then (base + imm32) else (base - imm32); |
6872 | if (add) |
6873 | address = base + imm32; |
6874 | else |
6875 | address = base - imm32; |
6876 | |
6877 | // R[t] = ZeroExtend(MemU[address,1], 32); |
6878 | EmulateInstruction::Context context; |
6879 | context.type = eContextRelativeBranchImmediate; |
6880 | context.SetImmediate(address - base); |
6881 | |
6882 | uint64_t data = MemURead(context, address, size: 1, fail_value: 0, success_ptr: &success); |
6883 | if (!success) |
6884 | return false; |
6885 | |
6886 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + t, reg_value: data)) |
6887 | return false; |
6888 | } |
6889 | return true; |
6890 | } |
6891 | |
6892 | // LDRB (register) calculates an address from a base register value and an |
6893 | // offset rigister value, loads a byte from memory, zero-extends it to form a |
6894 | // 32-bit word, and writes it to a register. The offset register value can |
6895 | // optionally be shifted. |
6896 | bool EmulateInstructionARM::EmulateLDRBRegister(const uint32_t opcode, |
6897 | const ARMEncoding encoding) { |
6898 | #if 0 |
6899 | if ConditionPassed() then |
6900 | EncodingSpecificOperations(); NullCheckIfThumbEE(n); |
6901 | offset = Shift(R[m], shift_t, shift_n, APSR.C); |
6902 | offset_addr = if add then (R[n] + offset) else (R[n] - offset); |
6903 | address = if index then offset_addr else R[n]; |
6904 | R[t] = ZeroExtend(MemU[address,1],32); |
6905 | if wback then R[n] = offset_addr; |
6906 | #endif |
6907 | |
6908 | bool success = false; |
6909 | |
6910 | if (ConditionPassed(opcode)) { |
6911 | uint32_t t; |
6912 | uint32_t n; |
6913 | uint32_t m; |
6914 | bool index; |
6915 | bool add; |
6916 | bool wback; |
6917 | ARM_ShifterType shift_t; |
6918 | uint32_t shift_n; |
6919 | |
6920 | // EncodingSpecificOperations(); NullCheckIfThumbEE(n); |
6921 | switch (encoding) { |
6922 | case eEncodingT1: |
6923 | // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); |
6924 | t = Bits32(bits: opcode, msbit: 2, lsbit: 0); |
6925 | n = Bits32(bits: opcode, msbit: 5, lsbit: 3); |
6926 | m = Bits32(bits: opcode, msbit: 8, lsbit: 6); |
6927 | |
6928 | // index = TRUE; add = TRUE; wback = FALSE; |
6929 | index = true; |
6930 | add = true; |
6931 | wback = false; |
6932 | |
6933 | // (shift_t, shift_n) = (SRType_LSL, 0); |
6934 | shift_t = SRType_LSL; |
6935 | shift_n = 0; |
6936 | break; |
6937 | |
6938 | case eEncodingT2: |
6939 | // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); |
6940 | t = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
6941 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
6942 | m = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
6943 | |
6944 | // index = TRUE; add = TRUE; wback = FALSE; |
6945 | index = true; |
6946 | add = true; |
6947 | wback = false; |
6948 | |
6949 | // (shift_t, shift_n) = (SRType_LSL, UInt(imm2)); |
6950 | shift_t = SRType_LSL; |
6951 | shift_n = Bits32(bits: opcode, msbit: 5, lsbit: 4); |
6952 | |
6953 | // if Rt == '1111' then SEE PLD; |
6954 | if (t == 15) |
6955 | return false; // PLD is not implemented yet |
6956 | |
6957 | // if Rn == '1111' then SEE LDRB (literal); |
6958 | if (n == 15) |
6959 | return EmulateLDRBLiteral(opcode, encoding: eEncodingT1); |
6960 | |
6961 | // if t == 13 || BadReg(m) then UNPREDICTABLE; |
6962 | if ((t == 13) || BadReg(n: m)) |
6963 | return false; |
6964 | break; |
6965 | |
6966 | case eEncodingA1: { |
6967 | // if P == '0' && W == '1' then SEE LDRBT; |
6968 | // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); |
6969 | t = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
6970 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
6971 | m = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
6972 | |
6973 | // index = (P == '1'); add = (U == '1'); wback = (P == '0') || |
6974 | // (W == '1'); |
6975 | index = BitIsSet(value: opcode, bit: 24); |
6976 | add = BitIsSet(value: opcode, bit: 23); |
6977 | wback = (BitIsClear(value: opcode, bit: 24) || BitIsSet(value: opcode, bit: 21)); |
6978 | |
6979 | // (shift_t, shift_n) = DecodeImmShift(type, imm5); |
6980 | uint32_t type = Bits32(bits: opcode, msbit: 6, lsbit: 5); |
6981 | uint32_t imm5 = Bits32(bits: opcode, msbit: 11, lsbit: 7); |
6982 | shift_n = DecodeImmShift(type, imm5, shift_t); |
6983 | |
6984 | // if t == 15 || m == 15 then UNPREDICTABLE; |
6985 | if ((t == 15) || (m == 15)) |
6986 | return false; |
6987 | |
6988 | // if wback && (n == 15 || n == t) then UNPREDICTABLE; |
6989 | if (wback && ((n == 15) || (n == t))) |
6990 | return false; |
6991 | } break; |
6992 | |
6993 | default: |
6994 | return false; |
6995 | } |
6996 | |
6997 | addr_t offset_addr; |
6998 | addr_t address; |
6999 | |
7000 | // offset = Shift(R[m], shift_t, shift_n, APSR.C); |
7001 | uint32_t Rm = |
7002 | ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + m, fail_value: 0, success_ptr: &success); |
7003 | if (!success) |
7004 | return false; |
7005 | |
7006 | addr_t offset = Shift(value: Rm, type: shift_t, amount: shift_n, APSR_C, success: &success); |
7007 | if (!success) |
7008 | return false; |
7009 | |
7010 | // offset_addr = if add then (R[n] + offset) else (R[n] - offset); |
7011 | uint32_t Rn = |
7012 | ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n, fail_value: 0, success_ptr: &success); |
7013 | if (!success) |
7014 | return false; |
7015 | |
7016 | if (add) |
7017 | offset_addr = Rn + offset; |
7018 | else |
7019 | offset_addr = Rn - offset; |
7020 | |
7021 | // address = if index then offset_addr else R[n]; |
7022 | if (index) |
7023 | address = offset_addr; |
7024 | else |
7025 | address = Rn; |
7026 | |
7027 | // R[t] = ZeroExtend(MemU[address,1],32); |
7028 | std::optional<RegisterInfo> base_reg = |
7029 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n); |
7030 | |
7031 | EmulateInstruction::Context context; |
7032 | context.type = eContextRegisterLoad; |
7033 | context.SetRegisterPlusOffset(base_reg: *base_reg, signed_offset: address - Rn); |
7034 | |
7035 | uint64_t data = MemURead(context, address, size: 1, fail_value: 0, success_ptr: &success); |
7036 | if (!success) |
7037 | return false; |
7038 | |
7039 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + t, reg_value: data)) |
7040 | return false; |
7041 | |
7042 | // if wback then R[n] = offset_addr; |
7043 | if (wback) { |
7044 | context.type = eContextAdjustBaseRegister; |
7045 | context.SetAddress(offset_addr); |
7046 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n, |
7047 | reg_value: offset_addr)) |
7048 | return false; |
7049 | } |
7050 | } |
7051 | return true; |
7052 | } |
7053 | |
7054 | // LDRH (immediate, Thumb) calculates an address from a base register value and |
7055 | // an immediate offset, loads a |
7056 | // halfword from memory, zero-extends it to form a 32-bit word, and writes it |
7057 | // to a register. It can use offset, post-indexed, or pre-indexed addressing. |
7058 | bool EmulateInstructionARM::EmulateLDRHImmediate(const uint32_t opcode, |
7059 | const ARMEncoding encoding) { |
7060 | #if 0 |
7061 | if ConditionPassed() then |
7062 | EncodingSpecificOperations(); NullCheckIfThumbEE(n); |
7063 | offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); |
7064 | address = if index then offset_addr else R[n]; |
7065 | data = MemU[address,2]; |
7066 | if wback then R[n] = offset_addr; |
7067 | if UnalignedSupport() || address<0> = '0' then |
7068 | R[t] = ZeroExtend(data, 32); |
7069 | else // Can only apply before ARMv7 |
7070 | R[t] = bits(32) UNKNOWN; |
7071 | #endif |
7072 | |
7073 | bool success = false; |
7074 | |
7075 | if (ConditionPassed(opcode)) { |
7076 | uint32_t t; |
7077 | uint32_t n; |
7078 | uint32_t imm32; |
7079 | bool index; |
7080 | bool add; |
7081 | bool wback; |
7082 | |
7083 | // EncodingSpecificOperations(); NullCheckIfThumbEE(n); |
7084 | switch (encoding) { |
7085 | case eEncodingT1: |
7086 | // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm5:'0', 32); |
7087 | t = Bits32(bits: opcode, msbit: 2, lsbit: 0); |
7088 | n = Bits32(bits: opcode, msbit: 5, lsbit: 3); |
7089 | imm32 = Bits32(bits: opcode, msbit: 10, lsbit: 6) << 1; |
7090 | |
7091 | // index = TRUE; add = TRUE; wback = FALSE; |
7092 | index = true; |
7093 | add = true; |
7094 | wback = false; |
7095 | |
7096 | break; |
7097 | |
7098 | case eEncodingT2: |
7099 | // if Rt == '1111' then SEE "Unallocated memory hints"; |
7100 | // if Rn == '1111' then SEE LDRH (literal); |
7101 | // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm12, 32); |
7102 | t = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
7103 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
7104 | imm32 = Bits32(bits: opcode, msbit: 11, lsbit: 0); |
7105 | |
7106 | // index = TRUE; add = TRUE; wback = FALSE; |
7107 | index = true; |
7108 | add = true; |
7109 | wback = false; |
7110 | |
7111 | // if t == 13 then UNPREDICTABLE; |
7112 | if (t == 13) |
7113 | return false; |
7114 | break; |
7115 | |
7116 | case eEncodingT3: |
7117 | // if Rn == '1111' then SEE LDRH (literal); |
7118 | // if Rt == '1111' && P == '1' && U == '0' && W == '0' then SEE |
7119 | // "Unallocated memory hints"; |
7120 | // if P == '1' && U == '1' && W == '0' then SEE LDRHT; |
7121 | // if P == '0' && W == '0' then UNDEFINED; |
7122 | if (BitIsClear(value: opcode, bit: 10) && BitIsClear(value: opcode, bit: 8)) |
7123 | return false; |
7124 | |
7125 | // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm8, 32); |
7126 | t = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
7127 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
7128 | imm32 = Bits32(bits: opcode, msbit: 7, lsbit: 0); |
7129 | |
7130 | // index = (P == '1'); add = (U == '1'); wback = (W == '1'); |
7131 | index = BitIsSet(value: opcode, bit: 10); |
7132 | add = BitIsSet(value: opcode, bit: 9); |
7133 | wback = BitIsSet(value: opcode, bit: 8); |
7134 | |
7135 | // if BadReg(t) || (wback && n == t) then UNPREDICTABLE; |
7136 | if (BadReg(n: t) || (wback && (n == t))) |
7137 | return false; |
7138 | break; |
7139 | |
7140 | default: |
7141 | return false; |
7142 | } |
7143 | |
7144 | // offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); |
7145 | uint32_t Rn = |
7146 | ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n, fail_value: 0, success_ptr: &success); |
7147 | if (!success) |
7148 | return false; |
7149 | |
7150 | addr_t offset_addr; |
7151 | addr_t address; |
7152 | |
7153 | if (add) |
7154 | offset_addr = Rn + imm32; |
7155 | else |
7156 | offset_addr = Rn - imm32; |
7157 | |
7158 | // address = if index then offset_addr else R[n]; |
7159 | if (index) |
7160 | address = offset_addr; |
7161 | else |
7162 | address = Rn; |
7163 | |
7164 | // data = MemU[address,2]; |
7165 | std::optional<RegisterInfo> base_reg = |
7166 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n); |
7167 | |
7168 | EmulateInstruction::Context context; |
7169 | context.type = eContextRegisterLoad; |
7170 | context.SetRegisterPlusOffset(base_reg: *base_reg, signed_offset: address - Rn); |
7171 | |
7172 | uint64_t data = MemURead(context, address, size: 2, fail_value: 0, success_ptr: &success); |
7173 | if (!success) |
7174 | return false; |
7175 | |
7176 | // if wback then R[n] = offset_addr; |
7177 | if (wback) { |
7178 | context.type = eContextAdjustBaseRegister; |
7179 | context.SetAddress(offset_addr); |
7180 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n, |
7181 | reg_value: offset_addr)) |
7182 | return false; |
7183 | } |
7184 | |
7185 | // if UnalignedSupport() || address<0> = '0' then |
7186 | if (UnalignedSupport() || BitIsClear(value: address, bit: 0)) { |
7187 | // R[t] = ZeroExtend(data, 32); |
7188 | context.type = eContextRegisterLoad; |
7189 | context.SetRegisterPlusOffset(base_reg: *base_reg, signed_offset: address - Rn); |
7190 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + t, |
7191 | reg_value: data)) |
7192 | return false; |
7193 | } else // Can only apply before ARMv7 |
7194 | { |
7195 | // R[t] = bits(32) UNKNOWN; |
7196 | WriteBits32Unknown(n: t); |
7197 | } |
7198 | } |
7199 | return true; |
7200 | } |
7201 | |
7202 | // LDRH (literal) calculates an address from the PC value and an immediate |
7203 | // offset, loads a halfword from memory, |
7204 | // zero-extends it to form a 32-bit word, and writes it to a register. |
7205 | bool EmulateInstructionARM::EmulateLDRHLiteral(const uint32_t opcode, |
7206 | const ARMEncoding encoding) { |
7207 | #if 0 |
7208 | if ConditionPassed() then |
7209 | EncodingSpecificOperations(); NullCheckIfThumbEE(15); |
7210 | base = Align(PC,4); |
7211 | address = if add then (base + imm32) else (base - imm32); |
7212 | data = MemU[address,2]; |
7213 | if UnalignedSupport() || address<0> = '0' then |
7214 | R[t] = ZeroExtend(data, 32); |
7215 | else // Can only apply before ARMv7 |
7216 | R[t] = bits(32) UNKNOWN; |
7217 | #endif |
7218 | |
7219 | bool success = false; |
7220 | |
7221 | if (ConditionPassed(opcode)) { |
7222 | uint32_t t; |
7223 | uint32_t imm32; |
7224 | bool add; |
7225 | |
7226 | // EncodingSpecificOperations(); NullCheckIfThumbEE(15); |
7227 | switch (encoding) { |
7228 | case eEncodingT1: |
7229 | // if Rt == '1111' then SEE "Unallocated memory hints"; |
7230 | // t = UInt(Rt); imm32 = ZeroExtend(imm12, 32); add = (U == '1'); |
7231 | t = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
7232 | imm32 = Bits32(bits: opcode, msbit: 11, lsbit: 0); |
7233 | add = BitIsSet(value: opcode, bit: 23); |
7234 | |
7235 | // if t == 13 then UNPREDICTABLE; |
7236 | if (t == 13) |
7237 | return false; |
7238 | |
7239 | break; |
7240 | |
7241 | case eEncodingA1: { |
7242 | uint32_t imm4H = Bits32(bits: opcode, msbit: 11, lsbit: 8); |
7243 | uint32_t imm4L = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
7244 | |
7245 | // t == UInt(Rt); imm32 = ZeroExtend(imm4H:imm4L, 32); add = (U == '1'); |
7246 | t = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
7247 | imm32 = (imm4H << 4) | imm4L; |
7248 | add = BitIsSet(value: opcode, bit: 23); |
7249 | |
7250 | // if t == 15 then UNPREDICTABLE; |
7251 | if (t == 15) |
7252 | return false; |
7253 | break; |
7254 | } |
7255 | |
7256 | default: |
7257 | return false; |
7258 | } |
7259 | |
7260 | // base = Align(PC,4); |
7261 | uint64_t pc_value = ReadCoreReg(PC_REG, success: &success); |
7262 | if (!success) |
7263 | return false; |
7264 | |
7265 | addr_t base = AlignPC(pc_value); |
7266 | addr_t address; |
7267 | |
7268 | // address = if add then (base + imm32) else (base - imm32); |
7269 | if (add) |
7270 | address = base + imm32; |
7271 | else |
7272 | address = base - imm32; |
7273 | |
7274 | // data = MemU[address,2]; |
7275 | std::optional<RegisterInfo> base_reg = |
7276 | GetRegisterInfo(reg_kind: eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); |
7277 | |
7278 | EmulateInstruction::Context context; |
7279 | context.type = eContextRegisterLoad; |
7280 | context.SetRegisterPlusOffset(base_reg: *base_reg, signed_offset: address - base); |
7281 | |
7282 | uint64_t data = MemURead(context, address, size: 2, fail_value: 0, success_ptr: &success); |
7283 | if (!success) |
7284 | return false; |
7285 | |
7286 | // if UnalignedSupport() || address<0> = '0' then |
7287 | if (UnalignedSupport() || BitIsClear(value: address, bit: 0)) { |
7288 | // R[t] = ZeroExtend(data, 32); |
7289 | context.type = eContextRegisterLoad; |
7290 | context.SetRegisterPlusOffset(base_reg: *base_reg, signed_offset: address - base); |
7291 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + t, |
7292 | reg_value: data)) |
7293 | return false; |
7294 | |
7295 | } else // Can only apply before ARMv7 |
7296 | { |
7297 | // R[t] = bits(32) UNKNOWN; |
7298 | WriteBits32Unknown(n: t); |
7299 | } |
7300 | } |
7301 | return true; |
7302 | } |
7303 | |
7304 | // LDRH (literal) calculates an address from a base register value and an offset |
7305 | // register value, loads a halfword |
7306 | // from memory, zero-extends it to form a 32-bit word, and writes it to a |
7307 | // register. The offset register value can be shifted left by 0, 1, 2, or 3 |
7308 | // bits. |
7309 | bool EmulateInstructionARM::EmulateLDRHRegister(const uint32_t opcode, |
7310 | const ARMEncoding encoding) { |
7311 | #if 0 |
7312 | if ConditionPassed() then |
7313 | EncodingSpecificOperations(); NullCheckIfThumbEE(n); |
7314 | offset = Shift(R[m], shift_t, shift_n, APSR.C); |
7315 | offset_addr = if add then (R[n] + offset) else (R[n] - offset); |
7316 | address = if index then offset_addr else R[n]; |
7317 | data = MemU[address,2]; |
7318 | if wback then R[n] = offset_addr; |
7319 | if UnalignedSupport() || address<0> = '0' then |
7320 | R[t] = ZeroExtend(data, 32); |
7321 | else // Can only apply before ARMv7 |
7322 | R[t] = bits(32) UNKNOWN; |
7323 | #endif |
7324 | |
7325 | bool success = false; |
7326 | |
7327 | if (ConditionPassed(opcode)) { |
7328 | uint32_t t; |
7329 | uint32_t n; |
7330 | uint32_t m; |
7331 | bool index; |
7332 | bool add; |
7333 | bool wback; |
7334 | ARM_ShifterType shift_t; |
7335 | uint32_t shift_n; |
7336 | |
7337 | // EncodingSpecificOperations(); NullCheckIfThumbEE(n); |
7338 | switch (encoding) { |
7339 | case eEncodingT1: |
7340 | // if CurrentInstrSet() == InstrSet_ThumbEE then SEE "Modified operation |
7341 | // in ThumbEE"; |
7342 | // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); |
7343 | t = Bits32(bits: opcode, msbit: 2, lsbit: 0); |
7344 | n = Bits32(bits: opcode, msbit: 5, lsbit: 3); |
7345 | m = Bits32(bits: opcode, msbit: 8, lsbit: 6); |
7346 | |
7347 | // index = TRUE; add = TRUE; wback = FALSE; |
7348 | index = true; |
7349 | add = true; |
7350 | wback = false; |
7351 | |
7352 | // (shift_t, shift_n) = (SRType_LSL, 0); |
7353 | shift_t = SRType_LSL; |
7354 | shift_n = 0; |
7355 | |
7356 | break; |
7357 | |
7358 | case eEncodingT2: |
7359 | // if Rn == '1111' then SEE LDRH (literal); |
7360 | // if Rt == '1111' then SEE "Unallocated memory hints"; |
7361 | // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); |
7362 | t = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
7363 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
7364 | m = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
7365 | |
7366 | // index = TRUE; add = TRUE; wback = FALSE; |
7367 | index = true; |
7368 | add = true; |
7369 | wback = false; |
7370 | |
7371 | // (shift_t, shift_n) = (SRType_LSL, UInt(imm2)); |
7372 | shift_t = SRType_LSL; |
7373 | shift_n = Bits32(bits: opcode, msbit: 5, lsbit: 4); |
7374 | |
7375 | // if t == 13 || BadReg(m) then UNPREDICTABLE; |
7376 | if ((t == 13) || BadReg(n: m)) |
7377 | return false; |
7378 | break; |
7379 | |
7380 | case eEncodingA1: |
7381 | // if P == '0' && W == '1' then SEE LDRHT; |
7382 | // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); |
7383 | t = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
7384 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
7385 | m = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
7386 | |
7387 | // index = (P == '1'); add = (U == '1'); wback = (P == '0') || |
7388 | // (W == '1'); |
7389 | index = BitIsSet(value: opcode, bit: 24); |
7390 | add = BitIsSet(value: opcode, bit: 23); |
7391 | wback = (BitIsClear(value: opcode, bit: 24) || BitIsSet(value: opcode, bit: 21)); |
7392 | |
7393 | // (shift_t, shift_n) = (SRType_LSL, 0); |
7394 | shift_t = SRType_LSL; |
7395 | shift_n = 0; |
7396 | |
7397 | // if t == 15 || m == 15 then UNPREDICTABLE; |
7398 | if ((t == 15) || (m == 15)) |
7399 | return false; |
7400 | |
7401 | // if wback && (n == 15 || n == t) then UNPREDICTABLE; |
7402 | if (wback && ((n == 15) || (n == t))) |
7403 | return false; |
7404 | |
7405 | break; |
7406 | |
7407 | default: |
7408 | return false; |
7409 | } |
7410 | |
7411 | // offset = Shift(R[m], shift_t, shift_n, APSR.C); |
7412 | |
7413 | uint64_t Rm = |
7414 | ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + m, fail_value: 0, success_ptr: &success); |
7415 | if (!success) |
7416 | return false; |
7417 | |
7418 | addr_t offset = Shift(value: Rm, type: shift_t, amount: shift_n, APSR_C, success: &success); |
7419 | if (!success) |
7420 | return false; |
7421 | |
7422 | addr_t offset_addr; |
7423 | addr_t address; |
7424 | |
7425 | // offset_addr = if add then (R[n] + offset) else (R[n] - offset); |
7426 | uint64_t Rn = |
7427 | ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n, fail_value: 0, success_ptr: &success); |
7428 | if (!success) |
7429 | return false; |
7430 | |
7431 | if (add) |
7432 | offset_addr = Rn + offset; |
7433 | else |
7434 | offset_addr = Rn - offset; |
7435 | |
7436 | // address = if index then offset_addr else R[n]; |
7437 | if (index) |
7438 | address = offset_addr; |
7439 | else |
7440 | address = Rn; |
7441 | |
7442 | // data = MemU[address,2]; |
7443 | std::optional<RegisterInfo> base_reg = |
7444 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n); |
7445 | std::optional<RegisterInfo> offset_reg = |
7446 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + m); |
7447 | |
7448 | EmulateInstruction::Context context; |
7449 | context.type = eContextRegisterLoad; |
7450 | context.SetRegisterPlusIndirectOffset(base_reg: *base_reg, offset_reg: *offset_reg); |
7451 | uint64_t data = MemURead(context, address, size: 2, fail_value: 0, success_ptr: &success); |
7452 | if (!success) |
7453 | return false; |
7454 | |
7455 | // if wback then R[n] = offset_addr; |
7456 | if (wback) { |
7457 | context.type = eContextAdjustBaseRegister; |
7458 | context.SetAddress(offset_addr); |
7459 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n, |
7460 | reg_value: offset_addr)) |
7461 | return false; |
7462 | } |
7463 | |
7464 | // if UnalignedSupport() || address<0> = '0' then |
7465 | if (UnalignedSupport() || BitIsClear(value: address, bit: 0)) { |
7466 | // R[t] = ZeroExtend(data, 32); |
7467 | context.type = eContextRegisterLoad; |
7468 | context.SetRegisterPlusIndirectOffset(base_reg: *base_reg, offset_reg: *offset_reg); |
7469 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + t, |
7470 | reg_value: data)) |
7471 | return false; |
7472 | } else // Can only apply before ARMv7 |
7473 | { |
7474 | // R[t] = bits(32) UNKNOWN; |
7475 | WriteBits32Unknown(n: t); |
7476 | } |
7477 | } |
7478 | return true; |
7479 | } |
7480 | |
7481 | // LDRSB (immediate) calculates an address from a base register value and an |
7482 | // immediate offset, loads a byte from |
7483 | // memory, sign-extends it to form a 32-bit word, and writes it to a register. |
7484 | // It can use offset, post-indexed, or pre-indexed addressing. |
7485 | bool EmulateInstructionARM::EmulateLDRSBImmediate(const uint32_t opcode, |
7486 | const ARMEncoding encoding) { |
7487 | #if 0 |
7488 | if ConditionPassed() then |
7489 | EncodingSpecificOperations(); NullCheckIfThumbEE(n); |
7490 | offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); |
7491 | address = if index then offset_addr else R[n]; |
7492 | R[t] = SignExtend(MemU[address,1], 32); |
7493 | if wback then R[n] = offset_addr; |
7494 | #endif |
7495 | |
7496 | bool success = false; |
7497 | |
7498 | if (ConditionPassed(opcode)) { |
7499 | uint32_t t; |
7500 | uint32_t n; |
7501 | uint32_t imm32; |
7502 | bool index; |
7503 | bool add; |
7504 | bool wback; |
7505 | |
7506 | // EncodingSpecificOperations(); NullCheckIfThumbEE(n); |
7507 | switch (encoding) { |
7508 | case eEncodingT1: |
7509 | // if Rt == '1111' then SEE PLI; |
7510 | // if Rn == '1111' then SEE LDRSB (literal); |
7511 | // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm12, 32); |
7512 | t = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
7513 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
7514 | imm32 = Bits32(bits: opcode, msbit: 11, lsbit: 0); |
7515 | |
7516 | // index = TRUE; add = TRUE; wback = FALSE; |
7517 | index = true; |
7518 | add = true; |
7519 | wback = false; |
7520 | |
7521 | // if t == 13 then UNPREDICTABLE; |
7522 | if (t == 13) |
7523 | return false; |
7524 | |
7525 | break; |
7526 | |
7527 | case eEncodingT2: |
7528 | // if Rt == '1111' && P == '1' && U == '0' && W == '0' then SEE PLI; |
7529 | // if Rn == '1111' then SEE LDRSB (literal); |
7530 | // if P == '1' && U == '1' && W == '0' then SEE LDRSBT; |
7531 | // if P == '0' && W == '0' then UNDEFINED; |
7532 | if (BitIsClear(value: opcode, bit: 10) && BitIsClear(value: opcode, bit: 8)) |
7533 | return false; |
7534 | |
7535 | // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm8, 32); |
7536 | t = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
7537 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
7538 | imm32 = Bits32(bits: opcode, msbit: 7, lsbit: 0); |
7539 | |
7540 | // index = (P == '1'); add = (U == '1'); wback = (W == '1'); |
7541 | index = BitIsSet(value: opcode, bit: 10); |
7542 | add = BitIsSet(value: opcode, bit: 9); |
7543 | wback = BitIsSet(value: opcode, bit: 8); |
7544 | |
7545 | // if BadReg(t) || (wback && n == t) then UNPREDICTABLE; |
7546 | if (((t == 13) || |
7547 | ((t == 15) && (BitIsClear(value: opcode, bit: 10) || BitIsSet(value: opcode, bit: 9) || |
7548 | BitIsSet(value: opcode, bit: 8)))) || |
7549 | (wback && (n == t))) |
7550 | return false; |
7551 | |
7552 | break; |
7553 | |
7554 | case eEncodingA1: { |
7555 | // if Rn == '1111' then SEE LDRSB (literal); |
7556 | // if P == '0' && W == '1' then SEE LDRSBT; |
7557 | // t == UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm4H:imm4L, 32); |
7558 | t = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
7559 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
7560 | |
7561 | uint32_t imm4H = Bits32(bits: opcode, msbit: 11, lsbit: 8); |
7562 | uint32_t imm4L = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
7563 | imm32 = (imm4H << 4) | imm4L; |
7564 | |
7565 | // index = (P == '1'); add = (U == '1'); wback = (P == '0') || |
7566 | // (W == '1'); |
7567 | index = BitIsSet(value: opcode, bit: 24); |
7568 | add = BitIsSet(value: opcode, bit: 23); |
7569 | wback = (BitIsClear(value: opcode, bit: 24) || BitIsSet(value: opcode, bit: 21)); |
7570 | |
7571 | // if t == 15 || (wback && n == t) then UNPREDICTABLE; |
7572 | if ((t == 15) || (wback && (n == t))) |
7573 | return false; |
7574 | |
7575 | break; |
7576 | } |
7577 | |
7578 | default: |
7579 | return false; |
7580 | } |
7581 | |
7582 | uint64_t Rn = ReadCoreReg(regnum: n, success: &success); |
7583 | if (!success) |
7584 | return false; |
7585 | |
7586 | addr_t offset_addr; |
7587 | addr_t address; |
7588 | |
7589 | // offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); |
7590 | if (add) |
7591 | offset_addr = Rn + imm32; |
7592 | else |
7593 | offset_addr = Rn - imm32; |
7594 | |
7595 | // address = if index then offset_addr else R[n]; |
7596 | if (index) |
7597 | address = offset_addr; |
7598 | else |
7599 | address = Rn; |
7600 | |
7601 | // R[t] = SignExtend(MemU[address,1], 32); |
7602 | std::optional<RegisterInfo> base_reg = |
7603 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n); |
7604 | |
7605 | EmulateInstruction::Context context; |
7606 | context.type = eContextRegisterLoad; |
7607 | context.SetRegisterPlusOffset(base_reg: *base_reg, signed_offset: address - Rn); |
7608 | |
7609 | uint64_t unsigned_data = MemURead(context, address, size: 1, fail_value: 0, success_ptr: &success); |
7610 | if (!success) |
7611 | return false; |
7612 | |
7613 | int64_t signed_data = llvm::SignExtend64<8>(x: unsigned_data); |
7614 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + t, |
7615 | reg_value: (uint64_t)signed_data)) |
7616 | return false; |
7617 | |
7618 | // if wback then R[n] = offset_addr; |
7619 | if (wback) { |
7620 | context.type = eContextAdjustBaseRegister; |
7621 | context.SetAddress(offset_addr); |
7622 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n, |
7623 | reg_value: offset_addr)) |
7624 | return false; |
7625 | } |
7626 | } |
7627 | |
7628 | return true; |
7629 | } |
7630 | |
7631 | // LDRSB (literal) calculates an address from the PC value and an immediate |
7632 | // offset, loads a byte from memory, |
7633 | // sign-extends it to form a 32-bit word, and writes tit to a register. |
7634 | bool EmulateInstructionARM::EmulateLDRSBLiteral(const uint32_t opcode, |
7635 | const ARMEncoding encoding) { |
7636 | #if 0 |
7637 | if ConditionPassed() then |
7638 | EncodingSpecificOperations(); NullCheckIfThumbEE(15); |
7639 | base = Align(PC,4); |
7640 | address = if add then (base + imm32) else (base - imm32); |
7641 | R[t] = SignExtend(MemU[address,1], 32); |
7642 | #endif |
7643 | |
7644 | bool success = false; |
7645 | |
7646 | if (ConditionPassed(opcode)) { |
7647 | uint32_t t; |
7648 | uint32_t imm32; |
7649 | bool add; |
7650 | |
7651 | // EncodingSpecificOperations(); NullCheckIfThumbEE(15); |
7652 | switch (encoding) { |
7653 | case eEncodingT1: |
7654 | // if Rt == '1111' then SEE PLI; |
7655 | // t = UInt(Rt); imm32 = ZeroExtend(imm12, 32); add = (U == '1'); |
7656 | t = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
7657 | imm32 = Bits32(bits: opcode, msbit: 11, lsbit: 0); |
7658 | add = BitIsSet(value: opcode, bit: 23); |
7659 | |
7660 | // if t == 13 then UNPREDICTABLE; |
7661 | if (t == 13) |
7662 | return false; |
7663 | |
7664 | break; |
7665 | |
7666 | case eEncodingA1: { |
7667 | // t == UInt(Rt); imm32 = ZeroExtend(imm4H:imm4L, 32); add = (U == '1'); |
7668 | t = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
7669 | uint32_t imm4H = Bits32(bits: opcode, msbit: 11, lsbit: 8); |
7670 | uint32_t imm4L = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
7671 | imm32 = (imm4H << 4) | imm4L; |
7672 | add = BitIsSet(value: opcode, bit: 23); |
7673 | |
7674 | // if t == 15 then UNPREDICTABLE; |
7675 | if (t == 15) |
7676 | return false; |
7677 | |
7678 | break; |
7679 | } |
7680 | |
7681 | default: |
7682 | return false; |
7683 | } |
7684 | |
7685 | // base = Align(PC,4); |
7686 | uint64_t pc_value = ReadCoreReg(PC_REG, success: &success); |
7687 | if (!success) |
7688 | return false; |
7689 | uint64_t base = AlignPC(pc_value); |
7690 | |
7691 | // address = if add then (base + imm32) else (base - imm32); |
7692 | addr_t address; |
7693 | if (add) |
7694 | address = base + imm32; |
7695 | else |
7696 | address = base - imm32; |
7697 | |
7698 | // R[t] = SignExtend(MemU[address,1], 32); |
7699 | std::optional<RegisterInfo> base_reg = |
7700 | GetRegisterInfo(reg_kind: eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); |
7701 | |
7702 | EmulateInstruction::Context context; |
7703 | context.type = eContextRegisterLoad; |
7704 | context.SetRegisterPlusOffset(base_reg: *base_reg, signed_offset: address - base); |
7705 | |
7706 | uint64_t unsigned_data = MemURead(context, address, size: 1, fail_value: 0, success_ptr: &success); |
7707 | if (!success) |
7708 | return false; |
7709 | |
7710 | int64_t signed_data = llvm::SignExtend64<8>(x: unsigned_data); |
7711 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + t, |
7712 | reg_value: (uint64_t)signed_data)) |
7713 | return false; |
7714 | } |
7715 | return true; |
7716 | } |
7717 | |
7718 | // LDRSB (register) calculates an address from a base register value and an |
7719 | // offset register value, loadsa byte from |
7720 | // memory, sign-extends it to form a 32-bit word, and writes it to a register. |
7721 | // The offset register value can be shifted left by 0, 1, 2, or 3 bits. |
7722 | bool EmulateInstructionARM::EmulateLDRSBRegister(const uint32_t opcode, |
7723 | const ARMEncoding encoding) { |
7724 | #if 0 |
7725 | if ConditionPassed() then |
7726 | EncodingSpecificOperations(); NullCheckIfThumbEE(n); |
7727 | offset = Shift(R[m], shift_t, shift_n, APSR.C); |
7728 | offset_addr = if add then (R[n] + offset) else (R[n] - offset); |
7729 | address = if index then offset_addr else R[n]; |
7730 | R[t] = SignExtend(MemU[address,1], 32); |
7731 | if wback then R[n] = offset_addr; |
7732 | #endif |
7733 | |
7734 | bool success = false; |
7735 | |
7736 | if (ConditionPassed(opcode)) { |
7737 | uint32_t t; |
7738 | uint32_t n; |
7739 | uint32_t m; |
7740 | bool index; |
7741 | bool add; |
7742 | bool wback; |
7743 | ARM_ShifterType shift_t; |
7744 | uint32_t shift_n; |
7745 | |
7746 | // EncodingSpecificOperations(); NullCheckIfThumbEE(n); |
7747 | switch (encoding) { |
7748 | case eEncodingT1: |
7749 | // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); |
7750 | t = Bits32(bits: opcode, msbit: 2, lsbit: 0); |
7751 | n = Bits32(bits: opcode, msbit: 5, lsbit: 3); |
7752 | m = Bits32(bits: opcode, msbit: 8, lsbit: 6); |
7753 | |
7754 | // index = TRUE; add = TRUE; wback = FALSE; |
7755 | index = true; |
7756 | add = true; |
7757 | wback = false; |
7758 | |
7759 | // (shift_t, shift_n) = (SRType_LSL, 0); |
7760 | shift_t = SRType_LSL; |
7761 | shift_n = 0; |
7762 | |
7763 | break; |
7764 | |
7765 | case eEncodingT2: |
7766 | // if Rt == '1111' then SEE PLI; |
7767 | // if Rn == '1111' then SEE LDRSB (literal); |
7768 | // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); |
7769 | t = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
7770 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
7771 | m = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
7772 | |
7773 | // index = TRUE; add = TRUE; wback = FALSE; |
7774 | index = true; |
7775 | add = true; |
7776 | wback = false; |
7777 | |
7778 | // (shift_t, shift_n) = (SRType_LSL, UInt(imm2)); |
7779 | shift_t = SRType_LSL; |
7780 | shift_n = Bits32(bits: opcode, msbit: 5, lsbit: 4); |
7781 | |
7782 | // if t == 13 || BadReg(m) then UNPREDICTABLE; |
7783 | if ((t == 13) || BadReg(n: m)) |
7784 | return false; |
7785 | break; |
7786 | |
7787 | case eEncodingA1: |
7788 | // if P == '0' && W == '1' then SEE LDRSBT; |
7789 | // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); |
7790 | t = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
7791 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
7792 | m = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
7793 | |
7794 | // index = (P == '1'); add = (U == '1'); wback = (P == '0') || |
7795 | // (W == '1'); |
7796 | index = BitIsSet(value: opcode, bit: 24); |
7797 | add = BitIsSet(value: opcode, bit: 23); |
7798 | wback = BitIsClear(value: opcode, bit: 24) || BitIsSet(value: opcode, bit: 21); |
7799 | |
7800 | // (shift_t, shift_n) = (SRType_LSL, 0); |
7801 | shift_t = SRType_LSL; |
7802 | shift_n = 0; |
7803 | |
7804 | // if t == 15 || m == 15 then UNPREDICTABLE; |
7805 | if ((t == 15) || (m == 15)) |
7806 | return false; |
7807 | |
7808 | // if wback && (n == 15 || n == t) then UNPREDICTABLE; |
7809 | if (wback && ((n == 15) || (n == t))) |
7810 | return false; |
7811 | break; |
7812 | |
7813 | default: |
7814 | return false; |
7815 | } |
7816 | |
7817 | uint64_t Rm = |
7818 | ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + m, fail_value: 0, success_ptr: &success); |
7819 | if (!success) |
7820 | return false; |
7821 | |
7822 | // offset = Shift(R[m], shift_t, shift_n, APSR.C); |
7823 | addr_t offset = Shift(value: Rm, type: shift_t, amount: shift_n, APSR_C, success: &success); |
7824 | if (!success) |
7825 | return false; |
7826 | |
7827 | addr_t offset_addr; |
7828 | addr_t address; |
7829 | |
7830 | // offset_addr = if add then (R[n] + offset) else (R[n] - offset); |
7831 | uint64_t Rn = |
7832 | ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n, fail_value: 0, success_ptr: &success); |
7833 | if (!success) |
7834 | return false; |
7835 | |
7836 | if (add) |
7837 | offset_addr = Rn + offset; |
7838 | else |
7839 | offset_addr = Rn - offset; |
7840 | |
7841 | // address = if index then offset_addr else R[n]; |
7842 | if (index) |
7843 | address = offset_addr; |
7844 | else |
7845 | address = Rn; |
7846 | |
7847 | // R[t] = SignExtend(MemU[address,1], 32); |
7848 | std::optional<RegisterInfo> base_reg = |
7849 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n); |
7850 | std::optional<RegisterInfo> offset_reg = |
7851 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + m); |
7852 | |
7853 | EmulateInstruction::Context context; |
7854 | context.type = eContextRegisterLoad; |
7855 | context.SetRegisterPlusIndirectOffset(base_reg: *base_reg, offset_reg: *offset_reg); |
7856 | |
7857 | uint64_t unsigned_data = MemURead(context, address, size: 1, fail_value: 0, success_ptr: &success); |
7858 | if (!success) |
7859 | return false; |
7860 | |
7861 | int64_t signed_data = llvm::SignExtend64<8>(x: unsigned_data); |
7862 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + t, |
7863 | reg_value: (uint64_t)signed_data)) |
7864 | return false; |
7865 | |
7866 | // if wback then R[n] = offset_addr; |
7867 | if (wback) { |
7868 | context.type = eContextAdjustBaseRegister; |
7869 | context.SetAddress(offset_addr); |
7870 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n, |
7871 | reg_value: offset_addr)) |
7872 | return false; |
7873 | } |
7874 | } |
7875 | return true; |
7876 | } |
7877 | |
7878 | // LDRSH (immediate) calculates an address from a base register value and an |
7879 | // immediate offset, loads a halfword from |
7880 | // memory, sign-extends it to form a 32-bit word, and writes it to a register. |
7881 | // It can use offset, post-indexed, or pre-indexed addressing. |
7882 | bool EmulateInstructionARM::EmulateLDRSHImmediate(const uint32_t opcode, |
7883 | const ARMEncoding encoding) { |
7884 | #if 0 |
7885 | if ConditionPassed() then |
7886 | EncodingSpecificOperations(); NullCheckIfThumbEE(n); |
7887 | offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); |
7888 | address = if index then offset_addr else R[n]; |
7889 | data = MemU[address,2]; |
7890 | if wback then R[n] = offset_addr; |
7891 | if UnalignedSupport() || address<0> = '0' then |
7892 | R[t] = SignExtend(data, 32); |
7893 | else // Can only apply before ARMv7 |
7894 | R[t] = bits(32) UNKNOWN; |
7895 | #endif |
7896 | |
7897 | bool success = false; |
7898 | |
7899 | if (ConditionPassed(opcode)) { |
7900 | uint32_t t; |
7901 | uint32_t n; |
7902 | uint32_t imm32; |
7903 | bool index; |
7904 | bool add; |
7905 | bool wback; |
7906 | |
7907 | // EncodingSpecificOperations(); NullCheckIfThumbEE(n); |
7908 | switch (encoding) { |
7909 | case eEncodingT1: |
7910 | // if Rn == '1111' then SEE LDRSH (literal); |
7911 | // if Rt == '1111' then SEE "Unallocated memory hints"; |
7912 | // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm12, 32); |
7913 | t = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
7914 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
7915 | imm32 = Bits32(bits: opcode, msbit: 11, lsbit: 0); |
7916 | |
7917 | // index = TRUE; add = TRUE; wback = FALSE; |
7918 | index = true; |
7919 | add = true; |
7920 | wback = false; |
7921 | |
7922 | // if t == 13 then UNPREDICTABLE; |
7923 | if (t == 13) |
7924 | return false; |
7925 | |
7926 | break; |
7927 | |
7928 | case eEncodingT2: |
7929 | // if Rn == '1111' then SEE LDRSH (literal); |
7930 | // if Rt == '1111' && P == '1' && U == '0' && W == '0' then SEE |
7931 | // "Unallocated memory hints"; |
7932 | // if P == '1' && U == '1' && W == '0' then SEE LDRSHT; |
7933 | // if P == '0' && W == '0' then UNDEFINED; |
7934 | if (BitIsClear(value: opcode, bit: 10) && BitIsClear(value: opcode, bit: 8)) |
7935 | return false; |
7936 | |
7937 | // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm8, 32); |
7938 | t = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
7939 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
7940 | imm32 = Bits32(bits: opcode, msbit: 7, lsbit: 0); |
7941 | |
7942 | // index = (P == '1'); add = (U == '1'); wback = (W == '1'); |
7943 | index = BitIsSet(value: opcode, bit: 10); |
7944 | add = BitIsSet(value: opcode, bit: 9); |
7945 | wback = BitIsSet(value: opcode, bit: 8); |
7946 | |
7947 | // if BadReg(t) || (wback && n == t) then UNPREDICTABLE; |
7948 | if (BadReg(n: t) || (wback && (n == t))) |
7949 | return false; |
7950 | |
7951 | break; |
7952 | |
7953 | case eEncodingA1: { |
7954 | // if Rn == '1111' then SEE LDRSH (literal); |
7955 | // if P == '0' && W == '1' then SEE LDRSHT; |
7956 | // t == UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm4H:imm4L, 32); |
7957 | t = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
7958 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
7959 | uint32_t imm4H = Bits32(bits: opcode, msbit: 11, lsbit: 8); |
7960 | uint32_t imm4L = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
7961 | imm32 = (imm4H << 4) | imm4L; |
7962 | |
7963 | // index = (P == '1'); add = (U == '1'); wback = (P == '0') || |
7964 | // (W == '1'); |
7965 | index = BitIsSet(value: opcode, bit: 24); |
7966 | add = BitIsSet(value: opcode, bit: 23); |
7967 | wback = BitIsClear(value: opcode, bit: 24) || BitIsSet(value: opcode, bit: 21); |
7968 | |
7969 | // if t == 15 || (wback && n == t) then UNPREDICTABLE; |
7970 | if ((t == 15) || (wback && (n == t))) |
7971 | return false; |
7972 | |
7973 | break; |
7974 | } |
7975 | |
7976 | default: |
7977 | return false; |
7978 | } |
7979 | |
7980 | // offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); |
7981 | uint64_t Rn = |
7982 | ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n, fail_value: 0, success_ptr: &success); |
7983 | if (!success) |
7984 | return false; |
7985 | |
7986 | addr_t offset_addr; |
7987 | if (add) |
7988 | offset_addr = Rn + imm32; |
7989 | else |
7990 | offset_addr = Rn - imm32; |
7991 | |
7992 | // address = if index then offset_addr else R[n]; |
7993 | addr_t address; |
7994 | if (index) |
7995 | address = offset_addr; |
7996 | else |
7997 | address = Rn; |
7998 | |
7999 | // data = MemU[address,2]; |
8000 | std::optional<RegisterInfo> base_reg = |
8001 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n); |
8002 | |
8003 | EmulateInstruction::Context context; |
8004 | context.type = eContextRegisterLoad; |
8005 | context.SetRegisterPlusOffset(base_reg: *base_reg, signed_offset: address - Rn); |
8006 | |
8007 | uint64_t data = MemURead(context, address, size: 2, fail_value: 0, success_ptr: &success); |
8008 | if (!success) |
8009 | return false; |
8010 | |
8011 | // if wback then R[n] = offset_addr; |
8012 | if (wback) { |
8013 | context.type = eContextAdjustBaseRegister; |
8014 | context.SetAddress(offset_addr); |
8015 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n, |
8016 | reg_value: offset_addr)) |
8017 | return false; |
8018 | } |
8019 | |
8020 | // if UnalignedSupport() || address<0> = '0' then |
8021 | if (UnalignedSupport() || BitIsClear(value: address, bit: 0)) { |
8022 | // R[t] = SignExtend(data, 32); |
8023 | int64_t signed_data = llvm::SignExtend64<16>(x: data); |
8024 | context.type = eContextRegisterLoad; |
8025 | context.SetRegisterPlusOffset(base_reg: *base_reg, signed_offset: address - Rn); |
8026 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + t, |
8027 | reg_value: (uint64_t)signed_data)) |
8028 | return false; |
8029 | } else // Can only apply before ARMv7 |
8030 | { |
8031 | // R[t] = bits(32) UNKNOWN; |
8032 | WriteBits32Unknown(n: t); |
8033 | } |
8034 | } |
8035 | return true; |
8036 | } |
8037 | |
8038 | // LDRSH (literal) calculates an address from the PC value and an immediate |
8039 | // offset, loads a halfword from memory, |
8040 | // sign-extends it to from a 32-bit word, and writes it to a register. |
8041 | bool EmulateInstructionARM::EmulateLDRSHLiteral(const uint32_t opcode, |
8042 | const ARMEncoding encoding) { |
8043 | #if 0 |
8044 | if ConditionPassed() then |
8045 | EncodingSpecificOperations(); NullCheckIfThumbEE(15); |
8046 | base = Align(PC,4); |
8047 | address = if add then (base + imm32) else (base - imm32); |
8048 | data = MemU[address,2]; |
8049 | if UnalignedSupport() || address<0> = '0' then |
8050 | R[t] = SignExtend(data, 32); |
8051 | else // Can only apply before ARMv7 |
8052 | R[t] = bits(32) UNKNOWN; |
8053 | #endif |
8054 | |
8055 | bool success = false; |
8056 | |
8057 | if (ConditionPassed(opcode)) { |
8058 | uint32_t t; |
8059 | uint32_t imm32; |
8060 | bool add; |
8061 | |
8062 | // EncodingSpecificOperations(); NullCheckIfThumbEE(15); |
8063 | switch (encoding) { |
8064 | case eEncodingT1: |
8065 | // if Rt == '1111' then SEE "Unallocated memory hints"; |
8066 | // t = UInt(Rt); imm32 = ZeroExtend(imm12, 32); add = (U == '1'); |
8067 | t = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
8068 | imm32 = Bits32(bits: opcode, msbit: 11, lsbit: 0); |
8069 | add = BitIsSet(value: opcode, bit: 23); |
8070 | |
8071 | // if t == 13 then UNPREDICTABLE; |
8072 | if (t == 13) |
8073 | return false; |
8074 | |
8075 | break; |
8076 | |
8077 | case eEncodingA1: { |
8078 | // t == UInt(Rt); imm32 = ZeroExtend(imm4H:imm4L, 32); add = (U == '1'); |
8079 | t = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
8080 | uint32_t imm4H = Bits32(bits: opcode, msbit: 11, lsbit: 8); |
8081 | uint32_t imm4L = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
8082 | imm32 = (imm4H << 4) | imm4L; |
8083 | add = BitIsSet(value: opcode, bit: 23); |
8084 | |
8085 | // if t == 15 then UNPREDICTABLE; |
8086 | if (t == 15) |
8087 | return false; |
8088 | |
8089 | break; |
8090 | } |
8091 | default: |
8092 | return false; |
8093 | } |
8094 | |
8095 | // base = Align(PC,4); |
8096 | uint64_t pc_value = ReadCoreReg(PC_REG, success: &success); |
8097 | if (!success) |
8098 | return false; |
8099 | |
8100 | uint64_t base = AlignPC(pc_value); |
8101 | |
8102 | addr_t address; |
8103 | // address = if add then (base + imm32) else (base - imm32); |
8104 | if (add) |
8105 | address = base + imm32; |
8106 | else |
8107 | address = base - imm32; |
8108 | |
8109 | // data = MemU[address,2]; |
8110 | std::optional<RegisterInfo> base_reg = |
8111 | GetRegisterInfo(reg_kind: eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); |
8112 | |
8113 | EmulateInstruction::Context context; |
8114 | context.type = eContextRegisterLoad; |
8115 | context.SetRegisterPlusOffset(base_reg: *base_reg, signed_offset: imm32); |
8116 | |
8117 | uint64_t data = MemURead(context, address, size: 2, fail_value: 0, success_ptr: &success); |
8118 | if (!success) |
8119 | return false; |
8120 | |
8121 | // if UnalignedSupport() || address<0> = '0' then |
8122 | if (UnalignedSupport() || BitIsClear(value: address, bit: 0)) { |
8123 | // R[t] = SignExtend(data, 32); |
8124 | int64_t signed_data = llvm::SignExtend64<16>(x: data); |
8125 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + t, |
8126 | reg_value: (uint64_t)signed_data)) |
8127 | return false; |
8128 | } else // Can only apply before ARMv7 |
8129 | { |
8130 | // R[t] = bits(32) UNKNOWN; |
8131 | WriteBits32Unknown(n: t); |
8132 | } |
8133 | } |
8134 | return true; |
8135 | } |
8136 | |
8137 | // LDRSH (register) calculates an address from a base register value and an |
8138 | // offset register value, loads a halfword |
8139 | // from memory, sign-extends it to form a 32-bit word, and writes it to a |
8140 | // register. The offset register value can be shifted left by 0, 1, 2, or 3 |
8141 | // bits. |
8142 | bool EmulateInstructionARM::EmulateLDRSHRegister(const uint32_t opcode, |
8143 | const ARMEncoding encoding) { |
8144 | #if 0 |
8145 | if ConditionPassed() then |
8146 | EncodingSpecificOperations(); NullCheckIfThumbEE(n); |
8147 | offset = Shift(R[m], shift_t, shift_n, APSR.C); |
8148 | offset_addr = if add then (R[n] + offset) else (R[n] - offset); |
8149 | address = if index then offset_addr else R[n]; |
8150 | data = MemU[address,2]; |
8151 | if wback then R[n] = offset_addr; |
8152 | if UnalignedSupport() || address<0> = '0' then |
8153 | R[t] = SignExtend(data, 32); |
8154 | else // Can only apply before ARMv7 |
8155 | R[t] = bits(32) UNKNOWN; |
8156 | #endif |
8157 | |
8158 | bool success = false; |
8159 | |
8160 | if (ConditionPassed(opcode)) { |
8161 | uint32_t t; |
8162 | uint32_t n; |
8163 | uint32_t m; |
8164 | bool index; |
8165 | bool add; |
8166 | bool wback; |
8167 | ARM_ShifterType shift_t; |
8168 | uint32_t shift_n; |
8169 | |
8170 | // EncodingSpecificOperations(); NullCheckIfThumbEE(n); |
8171 | switch (encoding) { |
8172 | case eEncodingT1: |
8173 | // if CurrentInstrSet() == InstrSet_ThumbEE then SEE "Modified operation |
8174 | // in ThumbEE"; |
8175 | // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); |
8176 | t = Bits32(bits: opcode, msbit: 2, lsbit: 0); |
8177 | n = Bits32(bits: opcode, msbit: 5, lsbit: 3); |
8178 | m = Bits32(bits: opcode, msbit: 8, lsbit: 6); |
8179 | |
8180 | // index = TRUE; add = TRUE; wback = FALSE; |
8181 | index = true; |
8182 | add = true; |
8183 | wback = false; |
8184 | |
8185 | // (shift_t, shift_n) = (SRType_LSL, 0); |
8186 | shift_t = SRType_LSL; |
8187 | shift_n = 0; |
8188 | |
8189 | break; |
8190 | |
8191 | case eEncodingT2: |
8192 | // if Rn == '1111' then SEE LDRSH (literal); |
8193 | // if Rt == '1111' then SEE "Unallocated memory hints"; |
8194 | // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); |
8195 | t = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
8196 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
8197 | m = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
8198 | |
8199 | // index = TRUE; add = TRUE; wback = FALSE; |
8200 | index = true; |
8201 | add = true; |
8202 | wback = false; |
8203 | |
8204 | // (shift_t, shift_n) = (SRType_LSL, UInt(imm2)); |
8205 | shift_t = SRType_LSL; |
8206 | shift_n = Bits32(bits: opcode, msbit: 5, lsbit: 4); |
8207 | |
8208 | // if t == 13 || BadReg(m) then UNPREDICTABLE; |
8209 | if ((t == 13) || BadReg(n: m)) |
8210 | return false; |
8211 | |
8212 | break; |
8213 | |
8214 | case eEncodingA1: |
8215 | // if P == '0' && W == '1' then SEE LDRSHT; |
8216 | // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); |
8217 | t = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
8218 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
8219 | m = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
8220 | |
8221 | // index = (P == '1'); add = (U == '1'); wback = (P == '0') || |
8222 | // (W == '1'); |
8223 | index = BitIsSet(value: opcode, bit: 24); |
8224 | add = BitIsSet(value: opcode, bit: 23); |
8225 | wback = BitIsClear(value: opcode, bit: 24) || BitIsSet(value: opcode, bit: 21); |
8226 | |
8227 | // (shift_t, shift_n) = (SRType_LSL, 0); |
8228 | shift_t = SRType_LSL; |
8229 | shift_n = 0; |
8230 | |
8231 | // if t == 15 || m == 15 then UNPREDICTABLE; |
8232 | if ((t == 15) || (m == 15)) |
8233 | return false; |
8234 | |
8235 | // if wback && (n == 15 || n == t) then UNPREDICTABLE; |
8236 | if (wback && ((n == 15) || (n == t))) |
8237 | return false; |
8238 | |
8239 | break; |
8240 | |
8241 | default: |
8242 | return false; |
8243 | } |
8244 | |
8245 | uint64_t Rm = |
8246 | ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + m, fail_value: 0, success_ptr: &success); |
8247 | if (!success) |
8248 | return false; |
8249 | |
8250 | uint64_t Rn = |
8251 | ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n, fail_value: 0, success_ptr: &success); |
8252 | if (!success) |
8253 | return false; |
8254 | |
8255 | // offset = Shift(R[m], shift_t, shift_n, APSR.C); |
8256 | addr_t offset = Shift(value: Rm, type: shift_t, amount: shift_n, APSR_C, success: &success); |
8257 | if (!success) |
8258 | return false; |
8259 | |
8260 | addr_t offset_addr; |
8261 | addr_t address; |
8262 | |
8263 | // offset_addr = if add then (R[n] + offset) else (R[n] - offset); |
8264 | if (add) |
8265 | offset_addr = Rn + offset; |
8266 | else |
8267 | offset_addr = Rn - offset; |
8268 | |
8269 | // address = if index then offset_addr else R[n]; |
8270 | if (index) |
8271 | address = offset_addr; |
8272 | else |
8273 | address = Rn; |
8274 | |
8275 | // data = MemU[address,2]; |
8276 | std::optional<RegisterInfo> base_reg = |
8277 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n); |
8278 | std::optional<RegisterInfo> offset_reg = |
8279 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + m); |
8280 | |
8281 | EmulateInstruction::Context context; |
8282 | context.type = eContextRegisterLoad; |
8283 | context.SetRegisterPlusIndirectOffset(base_reg: *base_reg, offset_reg: *offset_reg); |
8284 | |
8285 | uint64_t data = MemURead(context, address, size: 2, fail_value: 0, success_ptr: &success); |
8286 | if (!success) |
8287 | return false; |
8288 | |
8289 | // if wback then R[n] = offset_addr; |
8290 | if (wback) { |
8291 | context.type = eContextAdjustBaseRegister; |
8292 | context.SetAddress(offset_addr); |
8293 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n, |
8294 | reg_value: offset_addr)) |
8295 | return false; |
8296 | } |
8297 | |
8298 | // if UnalignedSupport() || address<0> = '0' then |
8299 | if (UnalignedSupport() || BitIsClear(value: address, bit: 0)) { |
8300 | // R[t] = SignExtend(data, 32); |
8301 | context.type = eContextRegisterLoad; |
8302 | context.SetRegisterPlusIndirectOffset(base_reg: *base_reg, offset_reg: *offset_reg); |
8303 | |
8304 | int64_t signed_data = llvm::SignExtend64<16>(x: data); |
8305 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + t, |
8306 | reg_value: (uint64_t)signed_data)) |
8307 | return false; |
8308 | } else // Can only apply before ARMv7 |
8309 | { |
8310 | // R[t] = bits(32) UNKNOWN; |
8311 | WriteBits32Unknown(n: t); |
8312 | } |
8313 | } |
8314 | return true; |
8315 | } |
8316 | |
8317 | // SXTB extracts an 8-bit value from a register, sign-extends it to 32 bits, and |
8318 | // writes the result to the destination |
8319 | // register. You can specifiy a rotation by 0, 8, 16, or 24 bits before |
8320 | // extracting the 8-bit value. |
8321 | bool EmulateInstructionARM::EmulateSXTB(const uint32_t opcode, |
8322 | const ARMEncoding encoding) { |
8323 | #if 0 |
8324 | if ConditionPassed() then |
8325 | EncodingSpecificOperations(); |
8326 | rotated = ROR(R[m], rotation); |
8327 | R[d] = SignExtend(rotated<7:0>, 32); |
8328 | #endif |
8329 | |
8330 | bool success = false; |
8331 | |
8332 | if (ConditionPassed(opcode)) { |
8333 | uint32_t d; |
8334 | uint32_t m; |
8335 | uint32_t rotation; |
8336 | |
8337 | // EncodingSpecificOperations(); |
8338 | switch (encoding) { |
8339 | case eEncodingT1: |
8340 | // d = UInt(Rd); m = UInt(Rm); rotation = 0; |
8341 | d = Bits32(bits: opcode, msbit: 2, lsbit: 0); |
8342 | m = Bits32(bits: opcode, msbit: 5, lsbit: 3); |
8343 | rotation = 0; |
8344 | |
8345 | break; |
8346 | |
8347 | case eEncodingT2: |
8348 | // d = UInt(Rd); m = UInt(Rm); rotation = UInt(rotate:'000'); |
8349 | d = Bits32(bits: opcode, msbit: 11, lsbit: 8); |
8350 | m = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
8351 | rotation = Bits32(bits: opcode, msbit: 5, lsbit: 4) << 3; |
8352 | |
8353 | // if BadReg(d) || BadReg(m) then UNPREDICTABLE; |
8354 | if (BadReg(n: d) || BadReg(n: m)) |
8355 | return false; |
8356 | |
8357 | break; |
8358 | |
8359 | case eEncodingA1: |
8360 | // d = UInt(Rd); m = UInt(Rm); rotation = UInt(rotate:'000'); |
8361 | d = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
8362 | m = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
8363 | rotation = Bits32(bits: opcode, msbit: 11, lsbit: 10) << 3; |
8364 | |
8365 | // if d == 15 || m == 15 then UNPREDICTABLE; |
8366 | if ((d == 15) || (m == 15)) |
8367 | return false; |
8368 | |
8369 | break; |
8370 | |
8371 | default: |
8372 | return false; |
8373 | } |
8374 | |
8375 | uint64_t Rm = |
8376 | ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + m, fail_value: 0, success_ptr: &success); |
8377 | if (!success) |
8378 | return false; |
8379 | |
8380 | // rotated = ROR(R[m], rotation); |
8381 | uint64_t rotated = ROR(value: Rm, amount: rotation, success: &success); |
8382 | if (!success) |
8383 | return false; |
8384 | |
8385 | // R[d] = SignExtend(rotated<7:0>, 32); |
8386 | int64_t data = llvm::SignExtend64<8>(x: rotated); |
8387 | |
8388 | std::optional<RegisterInfo> source_reg = |
8389 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + m); |
8390 | |
8391 | EmulateInstruction::Context context; |
8392 | context.type = eContextRegisterLoad; |
8393 | context.SetRegister(*source_reg); |
8394 | |
8395 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + d, |
8396 | reg_value: (uint64_t)data)) |
8397 | return false; |
8398 | } |
8399 | return true; |
8400 | } |
8401 | |
8402 | // SXTH extracts a 16-bit value from a register, sign-extends it to 32 bits, and |
8403 | // writes the result to the destination |
8404 | // register. You can specify a rotation by 0, 8, 16, or 24 bits before |
8405 | // extracting the 16-bit value. |
8406 | bool EmulateInstructionARM::EmulateSXTH(const uint32_t opcode, |
8407 | const ARMEncoding encoding) { |
8408 | #if 0 |
8409 | if ConditionPassed() then |
8410 | EncodingSpecificOperations(); |
8411 | rotated = ROR(R[m], rotation); |
8412 | R[d] = SignExtend(rotated<15:0>, 32); |
8413 | #endif |
8414 | |
8415 | bool success = false; |
8416 | |
8417 | if (ConditionPassed(opcode)) { |
8418 | uint32_t d; |
8419 | uint32_t m; |
8420 | uint32_t rotation; |
8421 | |
8422 | // EncodingSpecificOperations(); |
8423 | switch (encoding) { |
8424 | case eEncodingT1: |
8425 | // d = UInt(Rd); m = UInt(Rm); rotation = 0; |
8426 | d = Bits32(bits: opcode, msbit: 2, lsbit: 0); |
8427 | m = Bits32(bits: opcode, msbit: 5, lsbit: 3); |
8428 | rotation = 0; |
8429 | |
8430 | break; |
8431 | |
8432 | case eEncodingT2: |
8433 | // d = UInt(Rd); m = UInt(Rm); rotation = UInt(rotate:'000'); |
8434 | d = Bits32(bits: opcode, msbit: 11, lsbit: 8); |
8435 | m = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
8436 | rotation = Bits32(bits: opcode, msbit: 5, lsbit: 4) << 3; |
8437 | |
8438 | // if BadReg(d) || BadReg(m) then UNPREDICTABLE; |
8439 | if (BadReg(n: d) || BadReg(n: m)) |
8440 | return false; |
8441 | |
8442 | break; |
8443 | |
8444 | case eEncodingA1: |
8445 | // d = UInt(Rd); m = UInt(Rm); rotation = UInt(rotate:'000'); |
8446 | d = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
8447 | m = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
8448 | rotation = Bits32(bits: opcode, msbit: 11, lsbit: 10) << 3; |
8449 | |
8450 | // if d == 15 || m == 15 then UNPREDICTABLE; |
8451 | if ((d == 15) || (m == 15)) |
8452 | return false; |
8453 | |
8454 | break; |
8455 | |
8456 | default: |
8457 | return false; |
8458 | } |
8459 | |
8460 | uint64_t Rm = |
8461 | ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + m, fail_value: 0, success_ptr: &success); |
8462 | if (!success) |
8463 | return false; |
8464 | |
8465 | // rotated = ROR(R[m], rotation); |
8466 | uint64_t rotated = ROR(value: Rm, amount: rotation, success: &success); |
8467 | if (!success) |
8468 | return false; |
8469 | |
8470 | // R[d] = SignExtend(rotated<15:0>, 32); |
8471 | std::optional<RegisterInfo> source_reg = |
8472 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + m); |
8473 | |
8474 | EmulateInstruction::Context context; |
8475 | context.type = eContextRegisterLoad; |
8476 | context.SetRegister(*source_reg); |
8477 | |
8478 | int64_t data = llvm::SignExtend64<16>(x: rotated); |
8479 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + d, |
8480 | reg_value: (uint64_t)data)) |
8481 | return false; |
8482 | } |
8483 | |
8484 | return true; |
8485 | } |
8486 | |
8487 | // UXTB extracts an 8-bit value from a register, zero-extends it to 32 bits, and |
8488 | // writes the result to the destination |
8489 | // register. You can specify a rotation by 0, 8, 16, or 24 bits before |
8490 | // extracting the 8-bit value. |
8491 | bool EmulateInstructionARM::EmulateUXTB(const uint32_t opcode, |
8492 | const ARMEncoding encoding) { |
8493 | #if 0 |
8494 | if ConditionPassed() then |
8495 | EncodingSpecificOperations(); |
8496 | rotated = ROR(R[m], rotation); |
8497 | R[d] = ZeroExtend(rotated<7:0>, 32); |
8498 | #endif |
8499 | |
8500 | bool success = false; |
8501 | |
8502 | if (ConditionPassed(opcode)) { |
8503 | uint32_t d; |
8504 | uint32_t m; |
8505 | uint32_t rotation; |
8506 | |
8507 | // EncodingSpecificOperations(); |
8508 | switch (encoding) { |
8509 | case eEncodingT1: |
8510 | // d = UInt(Rd); m = UInt(Rm); rotation = 0; |
8511 | d = Bits32(bits: opcode, msbit: 2, lsbit: 0); |
8512 | m = Bits32(bits: opcode, msbit: 5, lsbit: 3); |
8513 | rotation = 0; |
8514 | |
8515 | break; |
8516 | |
8517 | case eEncodingT2: |
8518 | // d = UInt(Rd); m = UInt(Rm); rotation = UInt(rotate:'000'); |
8519 | d = Bits32(bits: opcode, msbit: 11, lsbit: 8); |
8520 | m = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
8521 | rotation = Bits32(bits: opcode, msbit: 5, lsbit: 4) << 3; |
8522 | |
8523 | // if BadReg(d) || BadReg(m) then UNPREDICTABLE; |
8524 | if (BadReg(n: d) || BadReg(n: m)) |
8525 | return false; |
8526 | |
8527 | break; |
8528 | |
8529 | case eEncodingA1: |
8530 | // d = UInt(Rd); m = UInt(Rm); rotation = UInt(rotate:'000'); |
8531 | d = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
8532 | m = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
8533 | rotation = Bits32(bits: opcode, msbit: 11, lsbit: 10) << 3; |
8534 | |
8535 | // if d == 15 || m == 15 then UNPREDICTABLE; |
8536 | if ((d == 15) || (m == 15)) |
8537 | return false; |
8538 | |
8539 | break; |
8540 | |
8541 | default: |
8542 | return false; |
8543 | } |
8544 | |
8545 | uint64_t Rm = |
8546 | ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + m, fail_value: 0, success_ptr: &success); |
8547 | if (!success) |
8548 | return false; |
8549 | |
8550 | // rotated = ROR(R[m], rotation); |
8551 | uint64_t rotated = ROR(value: Rm, amount: rotation, success: &success); |
8552 | if (!success) |
8553 | return false; |
8554 | |
8555 | // R[d] = ZeroExtend(rotated<7:0>, 32); |
8556 | std::optional<RegisterInfo> source_reg = |
8557 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + m); |
8558 | |
8559 | EmulateInstruction::Context context; |
8560 | context.type = eContextRegisterLoad; |
8561 | context.SetRegister(*source_reg); |
8562 | |
8563 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + d, |
8564 | reg_value: Bits32(bits: rotated, msbit: 7, lsbit: 0))) |
8565 | return false; |
8566 | } |
8567 | return true; |
8568 | } |
8569 | |
8570 | // UXTH extracts a 16-bit value from a register, zero-extends it to 32 bits, and |
8571 | // writes the result to the destination |
8572 | // register. You can specify a rotation by 0, 8, 16, or 24 bits before |
8573 | // extracting the 16-bit value. |
8574 | bool EmulateInstructionARM::EmulateUXTH(const uint32_t opcode, |
8575 | const ARMEncoding encoding) { |
8576 | #if 0 |
8577 | if ConditionPassed() then |
8578 | EncodingSpecificOperations(); |
8579 | rotated = ROR(R[m], rotation); |
8580 | R[d] = ZeroExtend(rotated<15:0>, 32); |
8581 | #endif |
8582 | |
8583 | bool success = false; |
8584 | |
8585 | if (ConditionPassed(opcode)) { |
8586 | uint32_t d; |
8587 | uint32_t m; |
8588 | uint32_t rotation; |
8589 | |
8590 | switch (encoding) { |
8591 | case eEncodingT1: |
8592 | // d = UInt(Rd); m = UInt(Rm); rotation = 0; |
8593 | d = Bits32(bits: opcode, msbit: 2, lsbit: 0); |
8594 | m = Bits32(bits: opcode, msbit: 5, lsbit: 3); |
8595 | rotation = 0; |
8596 | |
8597 | break; |
8598 | |
8599 | case eEncodingT2: |
8600 | // d = UInt(Rd); m = UInt(Rm); rotation = UInt(rotate:'000'); |
8601 | d = Bits32(bits: opcode, msbit: 11, lsbit: 8); |
8602 | m = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
8603 | rotation = Bits32(bits: opcode, msbit: 5, lsbit: 4) << 3; |
8604 | |
8605 | // if BadReg(d) || BadReg(m) then UNPREDICTABLE; |
8606 | if (BadReg(n: d) || BadReg(n: m)) |
8607 | return false; |
8608 | |
8609 | break; |
8610 | |
8611 | case eEncodingA1: |
8612 | // d = UInt(Rd); m = UInt(Rm); rotation = UInt(rotate:'000'); |
8613 | d = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
8614 | m = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
8615 | rotation = Bits32(bits: opcode, msbit: 11, lsbit: 10) << 3; |
8616 | |
8617 | // if d == 15 || m == 15 then UNPREDICTABLE; |
8618 | if ((d == 15) || (m == 15)) |
8619 | return false; |
8620 | |
8621 | break; |
8622 | |
8623 | default: |
8624 | return false; |
8625 | } |
8626 | |
8627 | uint64_t Rm = |
8628 | ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + m, fail_value: 0, success_ptr: &success); |
8629 | if (!success) |
8630 | return false; |
8631 | |
8632 | // rotated = ROR(R[m], rotation); |
8633 | uint64_t rotated = ROR(value: Rm, amount: rotation, success: &success); |
8634 | if (!success) |
8635 | return false; |
8636 | |
8637 | // R[d] = ZeroExtend(rotated<15:0>, 32); |
8638 | std::optional<RegisterInfo> source_reg = |
8639 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + m); |
8640 | |
8641 | EmulateInstruction::Context context; |
8642 | context.type = eContextRegisterLoad; |
8643 | context.SetRegister(*source_reg); |
8644 | |
8645 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + d, |
8646 | reg_value: Bits32(bits: rotated, msbit: 15, lsbit: 0))) |
8647 | return false; |
8648 | } |
8649 | return true; |
8650 | } |
8651 | |
8652 | // RFE (Return From Exception) loads the PC and the CPSR from the word at the |
8653 | // specified address and the following |
8654 | // word respectively. |
8655 | bool EmulateInstructionARM::EmulateRFE(const uint32_t opcode, |
8656 | const ARMEncoding encoding) { |
8657 | #if 0 |
8658 | if ConditionPassed() then |
8659 | EncodingSpecificOperations(); |
8660 | if !CurrentModeIsPrivileged() || CurrentInstrSet() == InstrSet_ThumbEE then |
8661 | UNPREDICTABLE; |
8662 | else |
8663 | address = if increment then R[n] else R[n]-8; |
8664 | if wordhigher then address = address+4; |
8665 | CPSRWriteByInstr(MemA[address+4,4], '1111', TRUE); |
8666 | BranchWritePC(MemA[address,4]); |
8667 | if wback then R[n] = if increment then R[n]+8 else R[n]-8; |
8668 | #endif |
8669 | |
8670 | bool success = false; |
8671 | |
8672 | if (ConditionPassed(opcode)) { |
8673 | uint32_t n; |
8674 | bool wback; |
8675 | bool increment; |
8676 | bool wordhigher; |
8677 | |
8678 | // EncodingSpecificOperations(); |
8679 | switch (encoding) { |
8680 | case eEncodingT1: |
8681 | // n = UInt(Rn); wback = (W == '1'); increment = FALSE; wordhigher = |
8682 | // FALSE; |
8683 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
8684 | wback = BitIsSet(value: opcode, bit: 21); |
8685 | increment = false; |
8686 | wordhigher = false; |
8687 | |
8688 | // if n == 15 then UNPREDICTABLE; |
8689 | if (n == 15) |
8690 | return false; |
8691 | |
8692 | // if InITBlock() && !LastInITBlock() then UNPREDICTABLE; |
8693 | if (InITBlock() && !LastInITBlock()) |
8694 | return false; |
8695 | |
8696 | break; |
8697 | |
8698 | case eEncodingT2: |
8699 | // n = UInt(Rn); wback = (W == '1'); increment = TRUE; wordhigher = FALSE; |
8700 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
8701 | wback = BitIsSet(value: opcode, bit: 21); |
8702 | increment = true; |
8703 | wordhigher = false; |
8704 | |
8705 | // if n == 15 then UNPREDICTABLE; |
8706 | if (n == 15) |
8707 | return false; |
8708 | |
8709 | // if InITBlock() && !LastInITBlock() then UNPREDICTABLE; |
8710 | if (InITBlock() && !LastInITBlock()) |
8711 | return false; |
8712 | |
8713 | break; |
8714 | |
8715 | case eEncodingA1: |
8716 | // n = UInt(Rn); |
8717 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
8718 | |
8719 | // wback = (W == '1'); inc = (U == '1'); wordhigher = (P == U); |
8720 | wback = BitIsSet(value: opcode, bit: 21); |
8721 | increment = BitIsSet(value: opcode, bit: 23); |
8722 | wordhigher = (Bit32(bits: opcode, bit: 24) == Bit32(bits: opcode, bit: 23)); |
8723 | |
8724 | // if n == 15 then UNPREDICTABLE; |
8725 | if (n == 15) |
8726 | return false; |
8727 | |
8728 | break; |
8729 | |
8730 | default: |
8731 | return false; |
8732 | } |
8733 | |
8734 | // if !CurrentModeIsPrivileged() || CurrentInstrSet() == InstrSet_ThumbEE |
8735 | // then |
8736 | if (!CurrentModeIsPrivileged()) |
8737 | // UNPREDICTABLE; |
8738 | return false; |
8739 | else { |
8740 | uint64_t Rn = |
8741 | ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n, fail_value: 0, success_ptr: &success); |
8742 | if (!success) |
8743 | return false; |
8744 | |
8745 | addr_t address; |
8746 | // address = if increment then R[n] else R[n]-8; |
8747 | if (increment) |
8748 | address = Rn; |
8749 | else |
8750 | address = Rn - 8; |
8751 | |
8752 | // if wordhigher then address = address+4; |
8753 | if (wordhigher) |
8754 | address = address + 4; |
8755 | |
8756 | // CPSRWriteByInstr(MemA[address+4,4], '1111', TRUE); |
8757 | std::optional<RegisterInfo> base_reg = |
8758 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n); |
8759 | |
8760 | EmulateInstruction::Context context; |
8761 | context.type = eContextReturnFromException; |
8762 | context.SetRegisterPlusOffset(base_reg: *base_reg, signed_offset: address - Rn); |
8763 | |
8764 | uint64_t data = MemARead(context, address: address + 4, size: 4, fail_value: 0, success_ptr: &success); |
8765 | if (!success) |
8766 | return false; |
8767 | |
8768 | CPSRWriteByInstr(value: data, bytemask: 15, affect_execstate: true); |
8769 | |
8770 | // BranchWritePC(MemA[address,4]); |
8771 | uint64_t data2 = MemARead(context, address, size: 4, fail_value: 0, success_ptr: &success); |
8772 | if (!success) |
8773 | return false; |
8774 | |
8775 | BranchWritePC(context, addr: data2); |
8776 | |
8777 | // if wback then R[n] = if increment then R[n]+8 else R[n]-8; |
8778 | if (wback) { |
8779 | context.type = eContextAdjustBaseRegister; |
8780 | if (increment) { |
8781 | context.SetOffset(8); |
8782 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n, |
8783 | reg_value: Rn + 8)) |
8784 | return false; |
8785 | } else { |
8786 | context.SetOffset(-8); |
8787 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n, |
8788 | reg_value: Rn - 8)) |
8789 | return false; |
8790 | } |
8791 | } // if wback |
8792 | } |
8793 | } // if ConditionPassed() |
8794 | return true; |
8795 | } |
8796 | |
8797 | // Bitwise Exclusive OR (immediate) performs a bitwise exclusive OR of a |
8798 | // register value and an immediate value, and writes the result to the |
8799 | // destination register. It can optionally update the condition flags based on |
8800 | // the result. |
8801 | bool EmulateInstructionARM::EmulateEORImm(const uint32_t opcode, |
8802 | const ARMEncoding encoding) { |
8803 | #if 0 |
8804 | // ARM pseudo code... |
8805 | if ConditionPassed() then |
8806 | EncodingSpecificOperations(); |
8807 | result = R[n] EOR imm32; |
8808 | if d == 15 then // Can only occur for ARM encoding |
8809 | ALUWritePC(result); // setflags is always FALSE here |
8810 | else |
8811 | R[d] = result; |
8812 | if setflags then |
8813 | APSR.N = result<31>; |
8814 | APSR.Z = IsZeroBit(result); |
8815 | APSR.C = carry; |
8816 | // APSR.V unchanged |
8817 | #endif |
8818 | |
8819 | bool success = false; |
8820 | |
8821 | if (ConditionPassed(opcode)) { |
8822 | uint32_t Rd, Rn; |
8823 | uint32_t |
8824 | imm32; // the immediate value to be ORed to the value obtained from Rn |
8825 | bool setflags; |
8826 | uint32_t carry; // the carry bit after ARM/Thumb Expand operation |
8827 | switch (encoding) { |
8828 | case eEncodingT1: |
8829 | Rd = Bits32(bits: opcode, msbit: 11, lsbit: 8); |
8830 | Rn = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
8831 | setflags = BitIsSet(value: opcode, bit: 20); |
8832 | imm32 = ThumbExpandImm_C( |
8833 | opcode, APSR_C, |
8834 | carry_out&: carry); // (imm32, carry) = ThumbExpandImm(i:imm3:imm8, APSR.C) |
8835 | // if Rd == '1111' && S == '1' then SEE TEQ (immediate); |
8836 | if (Rd == 15 && setflags) |
8837 | return EmulateTEQImm(opcode, encoding: eEncodingT1); |
8838 | if (Rd == 13 || (Rd == 15 && !setflags) || BadReg(n: Rn)) |
8839 | return false; |
8840 | break; |
8841 | case eEncodingA1: |
8842 | Rd = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
8843 | Rn = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
8844 | setflags = BitIsSet(value: opcode, bit: 20); |
8845 | imm32 = |
8846 | ARMExpandImm_C(opcode, APSR_C, |
8847 | carry_out&: carry); // (imm32, carry) = ARMExpandImm(imm12, APSR.C) |
8848 | |
8849 | // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related |
8850 | // instructions; |
8851 | if (Rd == 15 && setflags) |
8852 | return EmulateSUBSPcLrEtc(opcode, encoding); |
8853 | break; |
8854 | default: |
8855 | return false; |
8856 | } |
8857 | |
8858 | // Read the first operand. |
8859 | uint32_t val1 = ReadCoreReg(regnum: Rn, success: &success); |
8860 | if (!success) |
8861 | return false; |
8862 | |
8863 | uint32_t result = val1 ^ imm32; |
8864 | |
8865 | EmulateInstruction::Context context; |
8866 | context.type = EmulateInstruction::eContextImmediate; |
8867 | context.SetNoArgs(); |
8868 | |
8869 | if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry)) |
8870 | return false; |
8871 | } |
8872 | return true; |
8873 | } |
8874 | |
8875 | // Bitwise Exclusive OR (register) performs a bitwise exclusive OR of a |
8876 | // register value and an optionally-shifted register value, and writes the |
8877 | // result to the destination register. It can optionally update the condition |
8878 | // flags based on the result. |
8879 | bool EmulateInstructionARM::EmulateEORReg(const uint32_t opcode, |
8880 | const ARMEncoding encoding) { |
8881 | #if 0 |
8882 | // ARM pseudo code... |
8883 | if ConditionPassed() then |
8884 | EncodingSpecificOperations(); |
8885 | (shifted, carry) = Shift_C(R[m], shift_t, shift_n, APSR.C); |
8886 | result = R[n] EOR shifted; |
8887 | if d == 15 then // Can only occur for ARM encoding |
8888 | ALUWritePC(result); // setflags is always FALSE here |
8889 | else |
8890 | R[d] = result; |
8891 | if setflags then |
8892 | APSR.N = result<31>; |
8893 | APSR.Z = IsZeroBit(result); |
8894 | APSR.C = carry; |
8895 | // APSR.V unchanged |
8896 | #endif |
8897 | |
8898 | bool success = false; |
8899 | |
8900 | if (ConditionPassed(opcode)) { |
8901 | uint32_t Rd, Rn, Rm; |
8902 | ARM_ShifterType shift_t; |
8903 | uint32_t shift_n; // the shift applied to the value read from Rm |
8904 | bool setflags; |
8905 | uint32_t carry; |
8906 | switch (encoding) { |
8907 | case eEncodingT1: |
8908 | Rd = Rn = Bits32(bits: opcode, msbit: 2, lsbit: 0); |
8909 | Rm = Bits32(bits: opcode, msbit: 5, lsbit: 3); |
8910 | setflags = !InITBlock(); |
8911 | shift_t = SRType_LSL; |
8912 | shift_n = 0; |
8913 | break; |
8914 | case eEncodingT2: |
8915 | Rd = Bits32(bits: opcode, msbit: 11, lsbit: 8); |
8916 | Rn = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
8917 | Rm = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
8918 | setflags = BitIsSet(value: opcode, bit: 20); |
8919 | shift_n = DecodeImmShiftThumb(opcode, shift_t); |
8920 | // if Rd == '1111' && S == '1' then SEE TEQ (register); |
8921 | if (Rd == 15 && setflags) |
8922 | return EmulateTEQReg(opcode, encoding: eEncodingT1); |
8923 | if (Rd == 13 || (Rd == 15 && !setflags) || BadReg(n: Rn) || BadReg(n: Rm)) |
8924 | return false; |
8925 | break; |
8926 | case eEncodingA1: |
8927 | Rd = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
8928 | Rn = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
8929 | Rm = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
8930 | setflags = BitIsSet(value: opcode, bit: 20); |
8931 | shift_n = DecodeImmShiftARM(opcode, shift_t); |
8932 | |
8933 | // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related |
8934 | // instructions; |
8935 | if (Rd == 15 && setflags) |
8936 | return EmulateSUBSPcLrEtc(opcode, encoding); |
8937 | break; |
8938 | default: |
8939 | return false; |
8940 | } |
8941 | |
8942 | // Read the first operand. |
8943 | uint32_t val1 = ReadCoreReg(regnum: Rn, success: &success); |
8944 | if (!success) |
8945 | return false; |
8946 | |
8947 | // Read the second operand. |
8948 | uint32_t val2 = ReadCoreReg(regnum: Rm, success: &success); |
8949 | if (!success) |
8950 | return false; |
8951 | |
8952 | uint32_t shifted = Shift_C(value: val2, type: shift_t, amount: shift_n, APSR_C, carry_out&: carry, success: &success); |
8953 | if (!success) |
8954 | return false; |
8955 | uint32_t result = val1 ^ shifted; |
8956 | |
8957 | EmulateInstruction::Context context; |
8958 | context.type = EmulateInstruction::eContextImmediate; |
8959 | context.SetNoArgs(); |
8960 | |
8961 | if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry)) |
8962 | return false; |
8963 | } |
8964 | return true; |
8965 | } |
8966 | |
8967 | // Bitwise OR (immediate) performs a bitwise (inclusive) OR of a register value |
8968 | // and an immediate value, and writes the result to the destination register. |
8969 | // It can optionally update the condition flags based on the result. |
8970 | bool EmulateInstructionARM::EmulateORRImm(const uint32_t opcode, |
8971 | const ARMEncoding encoding) { |
8972 | #if 0 |
8973 | // ARM pseudo code... |
8974 | if ConditionPassed() then |
8975 | EncodingSpecificOperations(); |
8976 | result = R[n] OR imm32; |
8977 | if d == 15 then // Can only occur for ARM encoding |
8978 | ALUWritePC(result); // setflags is always FALSE here |
8979 | else |
8980 | R[d] = result; |
8981 | if setflags then |
8982 | APSR.N = result<31>; |
8983 | APSR.Z = IsZeroBit(result); |
8984 | APSR.C = carry; |
8985 | // APSR.V unchanged |
8986 | #endif |
8987 | |
8988 | bool success = false; |
8989 | |
8990 | if (ConditionPassed(opcode)) { |
8991 | uint32_t Rd, Rn; |
8992 | uint32_t |
8993 | imm32; // the immediate value to be ORed to the value obtained from Rn |
8994 | bool setflags; |
8995 | uint32_t carry; // the carry bit after ARM/Thumb Expand operation |
8996 | switch (encoding) { |
8997 | case eEncodingT1: |
8998 | Rd = Bits32(bits: opcode, msbit: 11, lsbit: 8); |
8999 | Rn = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
9000 | setflags = BitIsSet(value: opcode, bit: 20); |
9001 | imm32 = ThumbExpandImm_C( |
9002 | opcode, APSR_C, |
9003 | carry_out&: carry); // (imm32, carry) = ThumbExpandImm(i:imm3:imm8, APSR.C) |
9004 | // if Rn == '1111' then SEE MOV (immediate); |
9005 | if (Rn == 15) |
9006 | return EmulateMOVRdImm(opcode, encoding: eEncodingT2); |
9007 | if (BadReg(n: Rd) || Rn == 13) |
9008 | return false; |
9009 | break; |
9010 | case eEncodingA1: |
9011 | Rd = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
9012 | Rn = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
9013 | setflags = BitIsSet(value: opcode, bit: 20); |
9014 | imm32 = |
9015 | ARMExpandImm_C(opcode, APSR_C, |
9016 | carry_out&: carry); // (imm32, carry) = ARMExpandImm(imm12, APSR.C) |
9017 | |
9018 | if (Rd == 15 && setflags) |
9019 | return EmulateSUBSPcLrEtc(opcode, encoding); |
9020 | break; |
9021 | default: |
9022 | return false; |
9023 | } |
9024 | |
9025 | // Read the first operand. |
9026 | uint32_t val1 = ReadCoreReg(regnum: Rn, success: &success); |
9027 | if (!success) |
9028 | return false; |
9029 | |
9030 | uint32_t result = val1 | imm32; |
9031 | |
9032 | EmulateInstruction::Context context; |
9033 | context.type = EmulateInstruction::eContextImmediate; |
9034 | context.SetNoArgs(); |
9035 | |
9036 | if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry)) |
9037 | return false; |
9038 | } |
9039 | return true; |
9040 | } |
9041 | |
9042 | // Bitwise OR (register) performs a bitwise (inclusive) OR of a register value |
9043 | // and an optionally-shifted register value, and writes the result to the |
9044 | // destination register. It can optionally update the condition flags based on |
9045 | // the result. |
9046 | bool EmulateInstructionARM::EmulateORRReg(const uint32_t opcode, |
9047 | const ARMEncoding encoding) { |
9048 | #if 0 |
9049 | // ARM pseudo code... |
9050 | if ConditionPassed() then |
9051 | EncodingSpecificOperations(); |
9052 | (shifted, carry) = Shift_C(R[m], shift_t, shift_n, APSR.C); |
9053 | result = R[n] OR shifted; |
9054 | if d == 15 then // Can only occur for ARM encoding |
9055 | ALUWritePC(result); // setflags is always FALSE here |
9056 | else |
9057 | R[d] = result; |
9058 | if setflags then |
9059 | APSR.N = result<31>; |
9060 | APSR.Z = IsZeroBit(result); |
9061 | APSR.C = carry; |
9062 | // APSR.V unchanged |
9063 | #endif |
9064 | |
9065 | bool success = false; |
9066 | |
9067 | if (ConditionPassed(opcode)) { |
9068 | uint32_t Rd, Rn, Rm; |
9069 | ARM_ShifterType shift_t; |
9070 | uint32_t shift_n; // the shift applied to the value read from Rm |
9071 | bool setflags; |
9072 | uint32_t carry; |
9073 | switch (encoding) { |
9074 | case eEncodingT1: |
9075 | Rd = Rn = Bits32(bits: opcode, msbit: 2, lsbit: 0); |
9076 | Rm = Bits32(bits: opcode, msbit: 5, lsbit: 3); |
9077 | setflags = !InITBlock(); |
9078 | shift_t = SRType_LSL; |
9079 | shift_n = 0; |
9080 | break; |
9081 | case eEncodingT2: |
9082 | Rd = Bits32(bits: opcode, msbit: 11, lsbit: 8); |
9083 | Rn = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
9084 | Rm = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
9085 | setflags = BitIsSet(value: opcode, bit: 20); |
9086 | shift_n = DecodeImmShiftThumb(opcode, shift_t); |
9087 | // if Rn == '1111' then SEE MOV (register); |
9088 | if (Rn == 15) |
9089 | return EmulateMOVRdRm(opcode, encoding: eEncodingT3); |
9090 | if (BadReg(n: Rd) || Rn == 13 || BadReg(n: Rm)) |
9091 | return false; |
9092 | break; |
9093 | case eEncodingA1: |
9094 | Rd = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
9095 | Rn = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
9096 | Rm = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
9097 | setflags = BitIsSet(value: opcode, bit: 20); |
9098 | shift_n = DecodeImmShiftARM(opcode, shift_t); |
9099 | |
9100 | if (Rd == 15 && setflags) |
9101 | return EmulateSUBSPcLrEtc(opcode, encoding); |
9102 | break; |
9103 | default: |
9104 | return false; |
9105 | } |
9106 | |
9107 | // Read the first operand. |
9108 | uint32_t val1 = ReadCoreReg(regnum: Rn, success: &success); |
9109 | if (!success) |
9110 | return false; |
9111 | |
9112 | // Read the second operand. |
9113 | uint32_t val2 = ReadCoreReg(regnum: Rm, success: &success); |
9114 | if (!success) |
9115 | return false; |
9116 | |
9117 | uint32_t shifted = Shift_C(value: val2, type: shift_t, amount: shift_n, APSR_C, carry_out&: carry, success: &success); |
9118 | if (!success) |
9119 | return false; |
9120 | uint32_t result = val1 | shifted; |
9121 | |
9122 | EmulateInstruction::Context context; |
9123 | context.type = EmulateInstruction::eContextImmediate; |
9124 | context.SetNoArgs(); |
9125 | |
9126 | if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry)) |
9127 | return false; |
9128 | } |
9129 | return true; |
9130 | } |
9131 | |
9132 | // Reverse Subtract (immediate) subtracts a register value from an immediate |
9133 | // value, and writes the result to the destination register. It can optionally |
9134 | // update the condition flags based on the result. |
9135 | bool EmulateInstructionARM::EmulateRSBImm(const uint32_t opcode, |
9136 | const ARMEncoding encoding) { |
9137 | #if 0 |
9138 | // ARM pseudo code... |
9139 | if ConditionPassed() then |
9140 | EncodingSpecificOperations(); |
9141 | (result, carry, overflow) = AddWithCarry(NOT(R[n]), imm32, '1'); |
9142 | if d == 15 then // Can only occur for ARM encoding |
9143 | ALUWritePC(result); // setflags is always FALSE here |
9144 | else |
9145 | R[d] = result; |
9146 | if setflags then |
9147 | APSR.N = result<31>; |
9148 | APSR.Z = IsZeroBit(result); |
9149 | APSR.C = carry; |
9150 | APSR.V = overflow; |
9151 | #endif |
9152 | |
9153 | bool success = false; |
9154 | |
9155 | uint32_t Rd; // the destination register |
9156 | uint32_t Rn; // the first operand |
9157 | bool setflags; |
9158 | uint32_t |
9159 | imm32; // the immediate value to be added to the value obtained from Rn |
9160 | switch (encoding) { |
9161 | case eEncodingT1: |
9162 | Rd = Bits32(bits: opcode, msbit: 2, lsbit: 0); |
9163 | Rn = Bits32(bits: opcode, msbit: 5, lsbit: 3); |
9164 | setflags = !InITBlock(); |
9165 | imm32 = 0; |
9166 | break; |
9167 | case eEncodingT2: |
9168 | Rd = Bits32(bits: opcode, msbit: 11, lsbit: 8); |
9169 | Rn = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
9170 | setflags = BitIsSet(value: opcode, bit: 20); |
9171 | imm32 = ThumbExpandImm(opcode); // imm32 = ThumbExpandImm(i:imm3:imm8) |
9172 | if (BadReg(n: Rd) || BadReg(n: Rn)) |
9173 | return false; |
9174 | break; |
9175 | case eEncodingA1: |
9176 | Rd = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
9177 | Rn = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
9178 | setflags = BitIsSet(value: opcode, bit: 20); |
9179 | imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12) |
9180 | |
9181 | // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related |
9182 | // instructions; |
9183 | if (Rd == 15 && setflags) |
9184 | return EmulateSUBSPcLrEtc(opcode, encoding); |
9185 | break; |
9186 | default: |
9187 | return false; |
9188 | } |
9189 | // Read the register value from the operand register Rn. |
9190 | uint32_t reg_val = ReadCoreReg(regnum: Rn, success: &success); |
9191 | if (!success) |
9192 | return false; |
9193 | |
9194 | AddWithCarryResult res = AddWithCarry(x: ~reg_val, y: imm32, carry_in: 1); |
9195 | |
9196 | EmulateInstruction::Context context; |
9197 | context.type = EmulateInstruction::eContextImmediate; |
9198 | context.SetNoArgs(); |
9199 | |
9200 | return WriteCoreRegOptionalFlags(context, result: res.result, Rd, setflags, |
9201 | carry: res.carry_out, overflow: res.overflow); |
9202 | } |
9203 | |
9204 | // Reverse Subtract (register) subtracts a register value from an optionally- |
9205 | // shifted register value, and writes the result to the destination register. |
9206 | // It can optionally update the condition flags based on the result. |
9207 | bool EmulateInstructionARM::EmulateRSBReg(const uint32_t opcode, |
9208 | const ARMEncoding encoding) { |
9209 | #if 0 |
9210 | // ARM pseudo code... |
9211 | if ConditionPassed() then |
9212 | EncodingSpecificOperations(); |
9213 | shifted = Shift(R[m], shift_t, shift_n, APSR.C); |
9214 | (result, carry, overflow) = AddWithCarry(NOT(R[n]), shifted, '1'); |
9215 | if d == 15 then // Can only occur for ARM encoding |
9216 | ALUWritePC(result); // setflags is always FALSE here |
9217 | else |
9218 | R[d] = result; |
9219 | if setflags then |
9220 | APSR.N = result<31>; |
9221 | APSR.Z = IsZeroBit(result); |
9222 | APSR.C = carry; |
9223 | APSR.V = overflow; |
9224 | #endif |
9225 | |
9226 | bool success = false; |
9227 | |
9228 | uint32_t Rd; // the destination register |
9229 | uint32_t Rn; // the first operand |
9230 | uint32_t Rm; // the second operand |
9231 | bool setflags; |
9232 | ARM_ShifterType shift_t; |
9233 | uint32_t shift_n; // the shift applied to the value read from Rm |
9234 | switch (encoding) { |
9235 | case eEncodingT1: |
9236 | Rd = Bits32(bits: opcode, msbit: 11, lsbit: 8); |
9237 | Rn = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
9238 | Rm = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
9239 | setflags = BitIsSet(value: opcode, bit: 20); |
9240 | shift_n = DecodeImmShiftThumb(opcode, shift_t); |
9241 | // if (BadReg(d) || BadReg(m)) then UNPREDICTABLE; |
9242 | if (BadReg(n: Rd) || BadReg(n: Rn) || BadReg(n: Rm)) |
9243 | return false; |
9244 | break; |
9245 | case eEncodingA1: |
9246 | Rd = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
9247 | Rn = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
9248 | Rm = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
9249 | setflags = BitIsSet(value: opcode, bit: 20); |
9250 | shift_n = DecodeImmShiftARM(opcode, shift_t); |
9251 | |
9252 | // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related |
9253 | // instructions; |
9254 | if (Rd == 15 && setflags) |
9255 | return EmulateSUBSPcLrEtc(opcode, encoding); |
9256 | break; |
9257 | default: |
9258 | return false; |
9259 | } |
9260 | // Read the register value from register Rn. |
9261 | uint32_t val1 = ReadCoreReg(regnum: Rn, success: &success); |
9262 | if (!success) |
9263 | return false; |
9264 | |
9265 | // Read the register value from register Rm. |
9266 | uint32_t val2 = ReadCoreReg(regnum: Rm, success: &success); |
9267 | if (!success) |
9268 | return false; |
9269 | |
9270 | uint32_t shifted = Shift(value: val2, type: shift_t, amount: shift_n, APSR_C, success: &success); |
9271 | if (!success) |
9272 | return false; |
9273 | AddWithCarryResult res = AddWithCarry(x: ~val1, y: shifted, carry_in: 1); |
9274 | |
9275 | EmulateInstruction::Context context; |
9276 | context.type = EmulateInstruction::eContextImmediate; |
9277 | context.SetNoArgs(); |
9278 | return WriteCoreRegOptionalFlags(context, result: res.result, Rd, setflags, |
9279 | carry: res.carry_out, overflow: res.overflow); |
9280 | } |
9281 | |
9282 | // Reverse Subtract with Carry (immediate) subtracts a register value and the |
9283 | // value of NOT (Carry flag) from an immediate value, and writes the result to |
9284 | // the destination register. It can optionally update the condition flags based |
9285 | // on the result. |
9286 | bool EmulateInstructionARM::EmulateRSCImm(const uint32_t opcode, |
9287 | const ARMEncoding encoding) { |
9288 | #if 0 |
9289 | // ARM pseudo code... |
9290 | if ConditionPassed() then |
9291 | EncodingSpecificOperations(); |
9292 | (result, carry, overflow) = AddWithCarry(NOT(R[n]), imm32, APSR.C); |
9293 | if d == 15 then |
9294 | ALUWritePC(result); // setflags is always FALSE here |
9295 | else |
9296 | R[d] = result; |
9297 | if setflags then |
9298 | APSR.N = result<31>; |
9299 | APSR.Z = IsZeroBit(result); |
9300 | APSR.C = carry; |
9301 | APSR.V = overflow; |
9302 | #endif |
9303 | |
9304 | bool success = false; |
9305 | |
9306 | uint32_t Rd; // the destination register |
9307 | uint32_t Rn; // the first operand |
9308 | bool setflags; |
9309 | uint32_t |
9310 | imm32; // the immediate value to be added to the value obtained from Rn |
9311 | switch (encoding) { |
9312 | case eEncodingA1: |
9313 | Rd = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
9314 | Rn = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
9315 | setflags = BitIsSet(value: opcode, bit: 20); |
9316 | imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12) |
9317 | |
9318 | // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related |
9319 | // instructions; |
9320 | if (Rd == 15 && setflags) |
9321 | return EmulateSUBSPcLrEtc(opcode, encoding); |
9322 | break; |
9323 | default: |
9324 | return false; |
9325 | } |
9326 | // Read the register value from the operand register Rn. |
9327 | uint32_t reg_val = ReadCoreReg(regnum: Rn, success: &success); |
9328 | if (!success) |
9329 | return false; |
9330 | |
9331 | AddWithCarryResult res = AddWithCarry(x: ~reg_val, y: imm32, APSR_C); |
9332 | |
9333 | EmulateInstruction::Context context; |
9334 | context.type = EmulateInstruction::eContextImmediate; |
9335 | context.SetNoArgs(); |
9336 | |
9337 | return WriteCoreRegOptionalFlags(context, result: res.result, Rd, setflags, |
9338 | carry: res.carry_out, overflow: res.overflow); |
9339 | } |
9340 | |
9341 | // Reverse Subtract with Carry (register) subtracts a register value and the |
9342 | // value of NOT (Carry flag) from an optionally-shifted register value, and |
9343 | // writes the result to the destination register. It can optionally update the |
9344 | // condition flags based on the result. |
9345 | bool EmulateInstructionARM::EmulateRSCReg(const uint32_t opcode, |
9346 | const ARMEncoding encoding) { |
9347 | #if 0 |
9348 | // ARM pseudo code... |
9349 | if ConditionPassed() then |
9350 | EncodingSpecificOperations(); |
9351 | shifted = Shift(R[m], shift_t, shift_n, APSR.C); |
9352 | (result, carry, overflow) = AddWithCarry(NOT(R[n]), shifted, APSR.C); |
9353 | if d == 15 then |
9354 | ALUWritePC(result); // setflags is always FALSE here |
9355 | else |
9356 | R[d] = result; |
9357 | if setflags then |
9358 | APSR.N = result<31>; |
9359 | APSR.Z = IsZeroBit(result); |
9360 | APSR.C = carry; |
9361 | APSR.V = overflow; |
9362 | #endif |
9363 | |
9364 | bool success = false; |
9365 | |
9366 | uint32_t Rd; // the destination register |
9367 | uint32_t Rn; // the first operand |
9368 | uint32_t Rm; // the second operand |
9369 | bool setflags; |
9370 | ARM_ShifterType shift_t; |
9371 | uint32_t shift_n; // the shift applied to the value read from Rm |
9372 | switch (encoding) { |
9373 | case eEncodingA1: |
9374 | Rd = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
9375 | Rn = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
9376 | Rm = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
9377 | setflags = BitIsSet(value: opcode, bit: 20); |
9378 | shift_n = DecodeImmShiftARM(opcode, shift_t); |
9379 | |
9380 | // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related |
9381 | // instructions; |
9382 | if (Rd == 15 && setflags) |
9383 | return EmulateSUBSPcLrEtc(opcode, encoding); |
9384 | break; |
9385 | default: |
9386 | return false; |
9387 | } |
9388 | // Read the register value from register Rn. |
9389 | uint32_t val1 = ReadCoreReg(regnum: Rn, success: &success); |
9390 | if (!success) |
9391 | return false; |
9392 | |
9393 | // Read the register value from register Rm. |
9394 | uint32_t val2 = ReadCoreReg(regnum: Rm, success: &success); |
9395 | if (!success) |
9396 | return false; |
9397 | |
9398 | uint32_t shifted = Shift(value: val2, type: shift_t, amount: shift_n, APSR_C, success: &success); |
9399 | if (!success) |
9400 | return false; |
9401 | AddWithCarryResult res = AddWithCarry(x: ~val1, y: shifted, APSR_C); |
9402 | |
9403 | EmulateInstruction::Context context; |
9404 | context.type = EmulateInstruction::eContextImmediate; |
9405 | context.SetNoArgs(); |
9406 | return WriteCoreRegOptionalFlags(context, result: res.result, Rd, setflags, |
9407 | carry: res.carry_out, overflow: res.overflow); |
9408 | } |
9409 | |
9410 | // Subtract with Carry (immediate) subtracts an immediate value and the value |
9411 | // of |
9412 | // NOT (Carry flag) from a register value, and writes the result to the |
9413 | // destination register. |
9414 | // It can optionally update the condition flags based on the result. |
9415 | bool EmulateInstructionARM::EmulateSBCImm(const uint32_t opcode, |
9416 | const ARMEncoding encoding) { |
9417 | #if 0 |
9418 | // ARM pseudo code... |
9419 | if ConditionPassed() then |
9420 | EncodingSpecificOperations(); |
9421 | (result, carry, overflow) = AddWithCarry(R[n], NOT(imm32), APSR.C); |
9422 | if d == 15 then // Can only occur for ARM encoding |
9423 | ALUWritePC(result); // setflags is always FALSE here |
9424 | else |
9425 | R[d] = result; |
9426 | if setflags then |
9427 | APSR.N = result<31>; |
9428 | APSR.Z = IsZeroBit(result); |
9429 | APSR.C = carry; |
9430 | APSR.V = overflow; |
9431 | #endif |
9432 | |
9433 | bool success = false; |
9434 | |
9435 | uint32_t Rd; // the destination register |
9436 | uint32_t Rn; // the first operand |
9437 | bool setflags; |
9438 | uint32_t |
9439 | imm32; // the immediate value to be added to the value obtained from Rn |
9440 | switch (encoding) { |
9441 | case eEncodingT1: |
9442 | Rd = Bits32(bits: opcode, msbit: 11, lsbit: 8); |
9443 | Rn = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
9444 | setflags = BitIsSet(value: opcode, bit: 20); |
9445 | imm32 = ThumbExpandImm(opcode); // imm32 = ThumbExpandImm(i:imm3:imm8) |
9446 | if (BadReg(n: Rd) || BadReg(n: Rn)) |
9447 | return false; |
9448 | break; |
9449 | case eEncodingA1: |
9450 | Rd = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
9451 | Rn = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
9452 | setflags = BitIsSet(value: opcode, bit: 20); |
9453 | imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12) |
9454 | |
9455 | // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related |
9456 | // instructions; |
9457 | if (Rd == 15 && setflags) |
9458 | return EmulateSUBSPcLrEtc(opcode, encoding); |
9459 | break; |
9460 | default: |
9461 | return false; |
9462 | } |
9463 | // Read the register value from the operand register Rn. |
9464 | uint32_t reg_val = ReadCoreReg(regnum: Rn, success: &success); |
9465 | if (!success) |
9466 | return false; |
9467 | |
9468 | AddWithCarryResult res = AddWithCarry(x: reg_val, y: ~imm32, APSR_C); |
9469 | |
9470 | EmulateInstruction::Context context; |
9471 | context.type = EmulateInstruction::eContextImmediate; |
9472 | context.SetNoArgs(); |
9473 | |
9474 | return WriteCoreRegOptionalFlags(context, result: res.result, Rd, setflags, |
9475 | carry: res.carry_out, overflow: res.overflow); |
9476 | } |
9477 | |
9478 | // Subtract with Carry (register) subtracts an optionally-shifted register |
9479 | // value and the value of |
9480 | // NOT (Carry flag) from a register value, and writes the result to the |
9481 | // destination register. |
9482 | // It can optionally update the condition flags based on the result. |
9483 | bool EmulateInstructionARM::EmulateSBCReg(const uint32_t opcode, |
9484 | const ARMEncoding encoding) { |
9485 | #if 0 |
9486 | // ARM pseudo code... |
9487 | if ConditionPassed() then |
9488 | EncodingSpecificOperations(); |
9489 | shifted = Shift(R[m], shift_t, shift_n, APSR.C); |
9490 | (result, carry, overflow) = AddWithCarry(R[n], NOT(shifted), APSR.C); |
9491 | if d == 15 then // Can only occur for ARM encoding |
9492 | ALUWritePC(result); // setflags is always FALSE here |
9493 | else |
9494 | R[d] = result; |
9495 | if setflags then |
9496 | APSR.N = result<31>; |
9497 | APSR.Z = IsZeroBit(result); |
9498 | APSR.C = carry; |
9499 | APSR.V = overflow; |
9500 | #endif |
9501 | |
9502 | bool success = false; |
9503 | |
9504 | uint32_t Rd; // the destination register |
9505 | uint32_t Rn; // the first operand |
9506 | uint32_t Rm; // the second operand |
9507 | bool setflags; |
9508 | ARM_ShifterType shift_t; |
9509 | uint32_t shift_n; // the shift applied to the value read from Rm |
9510 | switch (encoding) { |
9511 | case eEncodingT1: |
9512 | Rd = Rn = Bits32(bits: opcode, msbit: 2, lsbit: 0); |
9513 | Rm = Bits32(bits: opcode, msbit: 5, lsbit: 3); |
9514 | setflags = !InITBlock(); |
9515 | shift_t = SRType_LSL; |
9516 | shift_n = 0; |
9517 | break; |
9518 | case eEncodingT2: |
9519 | Rd = Bits32(bits: opcode, msbit: 11, lsbit: 8); |
9520 | Rn = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
9521 | Rm = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
9522 | setflags = BitIsSet(value: opcode, bit: 20); |
9523 | shift_n = DecodeImmShiftThumb(opcode, shift_t); |
9524 | if (BadReg(n: Rd) || BadReg(n: Rn) || BadReg(n: Rm)) |
9525 | return false; |
9526 | break; |
9527 | case eEncodingA1: |
9528 | Rd = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
9529 | Rn = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
9530 | Rm = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
9531 | setflags = BitIsSet(value: opcode, bit: 20); |
9532 | shift_n = DecodeImmShiftARM(opcode, shift_t); |
9533 | |
9534 | // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related |
9535 | // instructions; |
9536 | if (Rd == 15 && setflags) |
9537 | return EmulateSUBSPcLrEtc(opcode, encoding); |
9538 | break; |
9539 | default: |
9540 | return false; |
9541 | } |
9542 | // Read the register value from register Rn. |
9543 | uint32_t val1 = ReadCoreReg(regnum: Rn, success: &success); |
9544 | if (!success) |
9545 | return false; |
9546 | |
9547 | // Read the register value from register Rm. |
9548 | uint32_t val2 = ReadCoreReg(regnum: Rm, success: &success); |
9549 | if (!success) |
9550 | return false; |
9551 | |
9552 | uint32_t shifted = Shift(value: val2, type: shift_t, amount: shift_n, APSR_C, success: &success); |
9553 | if (!success) |
9554 | return false; |
9555 | AddWithCarryResult res = AddWithCarry(x: val1, y: ~shifted, APSR_C); |
9556 | |
9557 | EmulateInstruction::Context context; |
9558 | context.type = EmulateInstruction::eContextImmediate; |
9559 | context.SetNoArgs(); |
9560 | return WriteCoreRegOptionalFlags(context, result: res.result, Rd, setflags, |
9561 | carry: res.carry_out, overflow: res.overflow); |
9562 | } |
9563 | |
9564 | // This instruction subtracts an immediate value from a register value, and |
9565 | // writes the result to the destination register. It can optionally update the |
9566 | // condition flags based on the result. |
9567 | bool EmulateInstructionARM::EmulateSUBImmThumb(const uint32_t opcode, |
9568 | const ARMEncoding encoding) { |
9569 | #if 0 |
9570 | // ARM pseudo code... |
9571 | if ConditionPassed() then |
9572 | EncodingSpecificOperations(); |
9573 | (result, carry, overflow) = AddWithCarry(R[n], NOT(imm32), '1'); |
9574 | R[d] = result; |
9575 | if setflags then |
9576 | APSR.N = result<31>; |
9577 | APSR.Z = IsZeroBit(result); |
9578 | APSR.C = carry; |
9579 | APSR.V = overflow; |
9580 | #endif |
9581 | |
9582 | bool success = false; |
9583 | |
9584 | uint32_t Rd; // the destination register |
9585 | uint32_t Rn; // the first operand |
9586 | bool setflags; |
9587 | uint32_t imm32; // the immediate value to be subtracted from the value |
9588 | // obtained from Rn |
9589 | switch (encoding) { |
9590 | case eEncodingT1: |
9591 | Rd = Bits32(bits: opcode, msbit: 2, lsbit: 0); |
9592 | Rn = Bits32(bits: opcode, msbit: 5, lsbit: 3); |
9593 | setflags = !InITBlock(); |
9594 | imm32 = Bits32(bits: opcode, msbit: 8, lsbit: 6); // imm32 = ZeroExtend(imm3, 32) |
9595 | break; |
9596 | case eEncodingT2: |
9597 | Rd = Rn = Bits32(bits: opcode, msbit: 10, lsbit: 8); |
9598 | setflags = !InITBlock(); |
9599 | imm32 = Bits32(bits: opcode, msbit: 7, lsbit: 0); // imm32 = ZeroExtend(imm8, 32) |
9600 | break; |
9601 | case eEncodingT3: |
9602 | Rd = Bits32(bits: opcode, msbit: 11, lsbit: 8); |
9603 | Rn = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
9604 | setflags = BitIsSet(value: opcode, bit: 20); |
9605 | imm32 = ThumbExpandImm(opcode); // imm32 = ThumbExpandImm(i:imm3:imm8) |
9606 | |
9607 | // if Rd == '1111' && S == '1' then SEE CMP (immediate); |
9608 | if (Rd == 15 && setflags) |
9609 | return EmulateCMPImm(opcode, encoding: eEncodingT2); |
9610 | |
9611 | // if Rn == '1101' then SEE SUB (SP minus immediate); |
9612 | if (Rn == 13) |
9613 | return EmulateSUBSPImm(opcode, encoding: eEncodingT2); |
9614 | |
9615 | // if d == 13 || (d == 15 && S == '0') || n == 15 then UNPREDICTABLE; |
9616 | if (Rd == 13 || (Rd == 15 && !setflags) || Rn == 15) |
9617 | return false; |
9618 | break; |
9619 | case eEncodingT4: |
9620 | Rd = Bits32(bits: opcode, msbit: 11, lsbit: 8); |
9621 | Rn = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
9622 | setflags = BitIsSet(value: opcode, bit: 20); |
9623 | imm32 = ThumbImm12(opcode); // imm32 = ZeroExtend(i:imm3:imm8, 32) |
9624 | |
9625 | // if Rn == '1111' then SEE ADR; |
9626 | if (Rn == 15) |
9627 | return EmulateADR(opcode, encoding: eEncodingT2); |
9628 | |
9629 | // if Rn == '1101' then SEE SUB (SP minus immediate); |
9630 | if (Rn == 13) |
9631 | return EmulateSUBSPImm(opcode, encoding: eEncodingT3); |
9632 | |
9633 | if (BadReg(n: Rd)) |
9634 | return false; |
9635 | break; |
9636 | default: |
9637 | return false; |
9638 | } |
9639 | // Read the register value from the operand register Rn. |
9640 | uint32_t reg_val = ReadCoreReg(regnum: Rn, success: &success); |
9641 | if (!success) |
9642 | return false; |
9643 | |
9644 | AddWithCarryResult res = AddWithCarry(x: reg_val, y: ~imm32, carry_in: 1); |
9645 | |
9646 | EmulateInstruction::Context context; |
9647 | context.type = EmulateInstruction::eContextImmediate; |
9648 | context.SetNoArgs(); |
9649 | |
9650 | return WriteCoreRegOptionalFlags(context, result: res.result, Rd, setflags, |
9651 | carry: res.carry_out, overflow: res.overflow); |
9652 | } |
9653 | |
9654 | // This instruction subtracts an immediate value from a register value, and |
9655 | // writes the result to the destination register. It can optionally update the |
9656 | // condition flags based on the result. |
9657 | bool EmulateInstructionARM::EmulateSUBImmARM(const uint32_t opcode, |
9658 | const ARMEncoding encoding) { |
9659 | #if 0 |
9660 | // ARM pseudo code... |
9661 | if ConditionPassed() then |
9662 | EncodingSpecificOperations(); |
9663 | (result, carry, overflow) = AddWithCarry(R[n], NOT(imm32), '1'); |
9664 | if d == 15 then |
9665 | ALUWritePC(result); // setflags is always FALSE here |
9666 | else |
9667 | R[d] = result; |
9668 | if setflags then |
9669 | APSR.N = result<31>; |
9670 | APSR.Z = IsZeroBit(result); |
9671 | APSR.C = carry; |
9672 | APSR.V = overflow; |
9673 | #endif |
9674 | |
9675 | bool success = false; |
9676 | |
9677 | if (ConditionPassed(opcode)) { |
9678 | uint32_t Rd; // the destination register |
9679 | uint32_t Rn; // the first operand |
9680 | bool setflags; |
9681 | uint32_t imm32; // the immediate value to be subtracted from the value |
9682 | // obtained from Rn |
9683 | switch (encoding) { |
9684 | case eEncodingA1: |
9685 | Rd = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
9686 | Rn = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
9687 | setflags = BitIsSet(value: opcode, bit: 20); |
9688 | imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12) |
9689 | |
9690 | // if Rn == '1111' && S == '0' then SEE ADR; |
9691 | if (Rn == 15 && !setflags) |
9692 | return EmulateADR(opcode, encoding: eEncodingA2); |
9693 | |
9694 | // if Rn == '1101' then SEE SUB (SP minus immediate); |
9695 | if (Rn == 13) |
9696 | return EmulateSUBSPImm(opcode, encoding: eEncodingA1); |
9697 | |
9698 | // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related |
9699 | // instructions; |
9700 | if (Rd == 15 && setflags) |
9701 | return EmulateSUBSPcLrEtc(opcode, encoding); |
9702 | break; |
9703 | default: |
9704 | return false; |
9705 | } |
9706 | // Read the register value from the operand register Rn. |
9707 | uint32_t reg_val = ReadCoreReg(regnum: Rn, success: &success); |
9708 | if (!success) |
9709 | return false; |
9710 | |
9711 | AddWithCarryResult res = AddWithCarry(x: reg_val, y: ~imm32, carry_in: 1); |
9712 | |
9713 | EmulateInstruction::Context context; |
9714 | if (Rd == 13) |
9715 | context.type = EmulateInstruction::eContextAdjustStackPointer; |
9716 | else |
9717 | context.type = EmulateInstruction::eContextRegisterPlusOffset; |
9718 | |
9719 | std::optional<RegisterInfo> dwarf_reg = |
9720 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: Rn); |
9721 | int64_t imm32_signed = imm32; |
9722 | context.SetRegisterPlusOffset(base_reg: *dwarf_reg, signed_offset: -imm32_signed); |
9723 | |
9724 | if (!WriteCoreRegOptionalFlags(context, result: res.result, Rd, setflags, |
9725 | carry: res.carry_out, overflow: res.overflow)) |
9726 | return false; |
9727 | } |
9728 | return true; |
9729 | } |
9730 | |
9731 | // Test Equivalence (immediate) performs a bitwise exclusive OR operation on a |
9732 | // register value and an immediate value. It updates the condition flags based |
9733 | // on the result, and discards the result. |
9734 | bool EmulateInstructionARM::EmulateTEQImm(const uint32_t opcode, |
9735 | const ARMEncoding encoding) { |
9736 | #if 0 |
9737 | // ARM pseudo code... |
9738 | if ConditionPassed() then |
9739 | EncodingSpecificOperations(); |
9740 | result = R[n] EOR imm32; |
9741 | APSR.N = result<31>; |
9742 | APSR.Z = IsZeroBit(result); |
9743 | APSR.C = carry; |
9744 | // APSR.V unchanged |
9745 | #endif |
9746 | |
9747 | bool success = false; |
9748 | |
9749 | if (ConditionPassed(opcode)) { |
9750 | uint32_t Rn; |
9751 | uint32_t |
9752 | imm32; // the immediate value to be ANDed to the value obtained from Rn |
9753 | uint32_t carry; // the carry bit after ARM/Thumb Expand operation |
9754 | switch (encoding) { |
9755 | case eEncodingT1: |
9756 | Rn = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
9757 | imm32 = ThumbExpandImm_C( |
9758 | opcode, APSR_C, |
9759 | carry_out&: carry); // (imm32, carry) = ThumbExpandImm(i:imm3:imm8, APSR.C) |
9760 | if (BadReg(n: Rn)) |
9761 | return false; |
9762 | break; |
9763 | case eEncodingA1: |
9764 | Rn = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
9765 | imm32 = |
9766 | ARMExpandImm_C(opcode, APSR_C, |
9767 | carry_out&: carry); // (imm32, carry) = ARMExpandImm(imm12, APSR.C) |
9768 | break; |
9769 | default: |
9770 | return false; |
9771 | } |
9772 | |
9773 | // Read the first operand. |
9774 | uint32_t val1 = ReadCoreReg(regnum: Rn, success: &success); |
9775 | if (!success) |
9776 | return false; |
9777 | |
9778 | uint32_t result = val1 ^ imm32; |
9779 | |
9780 | EmulateInstruction::Context context; |
9781 | context.type = EmulateInstruction::eContextImmediate; |
9782 | context.SetNoArgs(); |
9783 | |
9784 | if (!WriteFlags(context, result, carry)) |
9785 | return false; |
9786 | } |
9787 | return true; |
9788 | } |
9789 | |
9790 | // Test Equivalence (register) performs a bitwise exclusive OR operation on a |
9791 | // register value and an optionally-shifted register value. It updates the |
9792 | // condition flags based on the result, and discards the result. |
9793 | bool EmulateInstructionARM::EmulateTEQReg(const uint32_t opcode, |
9794 | const ARMEncoding encoding) { |
9795 | #if 0 |
9796 | // ARM pseudo code... |
9797 | if ConditionPassed() then |
9798 | EncodingSpecificOperations(); |
9799 | (shifted, carry) = Shift_C(R[m], shift_t, shift_n, APSR.C); |
9800 | result = R[n] EOR shifted; |
9801 | APSR.N = result<31>; |
9802 | APSR.Z = IsZeroBit(result); |
9803 | APSR.C = carry; |
9804 | // APSR.V unchanged |
9805 | #endif |
9806 | |
9807 | bool success = false; |
9808 | |
9809 | if (ConditionPassed(opcode)) { |
9810 | uint32_t Rn, Rm; |
9811 | ARM_ShifterType shift_t; |
9812 | uint32_t shift_n; // the shift applied to the value read from Rm |
9813 | uint32_t carry; |
9814 | switch (encoding) { |
9815 | case eEncodingT1: |
9816 | Rn = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
9817 | Rm = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
9818 | shift_n = DecodeImmShiftThumb(opcode, shift_t); |
9819 | if (BadReg(n: Rn) || BadReg(n: Rm)) |
9820 | return false; |
9821 | break; |
9822 | case eEncodingA1: |
9823 | Rn = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
9824 | Rm = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
9825 | shift_n = DecodeImmShiftARM(opcode, shift_t); |
9826 | break; |
9827 | default: |
9828 | return false; |
9829 | } |
9830 | |
9831 | // Read the first operand. |
9832 | uint32_t val1 = ReadCoreReg(regnum: Rn, success: &success); |
9833 | if (!success) |
9834 | return false; |
9835 | |
9836 | // Read the second operand. |
9837 | uint32_t val2 = ReadCoreReg(regnum: Rm, success: &success); |
9838 | if (!success) |
9839 | return false; |
9840 | |
9841 | uint32_t shifted = Shift_C(value: val2, type: shift_t, amount: shift_n, APSR_C, carry_out&: carry, success: &success); |
9842 | if (!success) |
9843 | return false; |
9844 | uint32_t result = val1 ^ shifted; |
9845 | |
9846 | EmulateInstruction::Context context; |
9847 | context.type = EmulateInstruction::eContextImmediate; |
9848 | context.SetNoArgs(); |
9849 | |
9850 | if (!WriteFlags(context, result, carry)) |
9851 | return false; |
9852 | } |
9853 | return true; |
9854 | } |
9855 | |
9856 | // Test (immediate) performs a bitwise AND operation on a register value and an |
9857 | // immediate value. It updates the condition flags based on the result, and |
9858 | // discards the result. |
9859 | bool EmulateInstructionARM::EmulateTSTImm(const uint32_t opcode, |
9860 | const ARMEncoding encoding) { |
9861 | #if 0 |
9862 | // ARM pseudo code... |
9863 | if ConditionPassed() then |
9864 | EncodingSpecificOperations(); |
9865 | result = R[n] AND imm32; |
9866 | APSR.N = result<31>; |
9867 | APSR.Z = IsZeroBit(result); |
9868 | APSR.C = carry; |
9869 | // APSR.V unchanged |
9870 | #endif |
9871 | |
9872 | bool success = false; |
9873 | |
9874 | if (ConditionPassed(opcode)) { |
9875 | uint32_t Rn; |
9876 | uint32_t |
9877 | imm32; // the immediate value to be ANDed to the value obtained from Rn |
9878 | uint32_t carry; // the carry bit after ARM/Thumb Expand operation |
9879 | switch (encoding) { |
9880 | case eEncodingT1: |
9881 | Rn = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
9882 | imm32 = ThumbExpandImm_C( |
9883 | opcode, APSR_C, |
9884 | carry_out&: carry); // (imm32, carry) = ThumbExpandImm(i:imm3:imm8, APSR.C) |
9885 | if (BadReg(n: Rn)) |
9886 | return false; |
9887 | break; |
9888 | case eEncodingA1: |
9889 | Rn = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
9890 | imm32 = |
9891 | ARMExpandImm_C(opcode, APSR_C, |
9892 | carry_out&: carry); // (imm32, carry) = ARMExpandImm(imm12, APSR.C) |
9893 | break; |
9894 | default: |
9895 | return false; |
9896 | } |
9897 | |
9898 | // Read the first operand. |
9899 | uint32_t val1 = ReadCoreReg(regnum: Rn, success: &success); |
9900 | if (!success) |
9901 | return false; |
9902 | |
9903 | uint32_t result = val1 & imm32; |
9904 | |
9905 | EmulateInstruction::Context context; |
9906 | context.type = EmulateInstruction::eContextImmediate; |
9907 | context.SetNoArgs(); |
9908 | |
9909 | if (!WriteFlags(context, result, carry)) |
9910 | return false; |
9911 | } |
9912 | return true; |
9913 | } |
9914 | |
9915 | // Test (register) performs a bitwise AND operation on a register value and an |
9916 | // optionally-shifted register value. It updates the condition flags based on |
9917 | // the result, and discards the result. |
9918 | bool EmulateInstructionARM::EmulateTSTReg(const uint32_t opcode, |
9919 | const ARMEncoding encoding) { |
9920 | #if 0 |
9921 | // ARM pseudo code... |
9922 | if ConditionPassed() then |
9923 | EncodingSpecificOperations(); |
9924 | (shifted, carry) = Shift_C(R[m], shift_t, shift_n, APSR.C); |
9925 | result = R[n] AND shifted; |
9926 | APSR.N = result<31>; |
9927 | APSR.Z = IsZeroBit(result); |
9928 | APSR.C = carry; |
9929 | // APSR.V unchanged |
9930 | #endif |
9931 | |
9932 | bool success = false; |
9933 | |
9934 | if (ConditionPassed(opcode)) { |
9935 | uint32_t Rn, Rm; |
9936 | ARM_ShifterType shift_t; |
9937 | uint32_t shift_n; // the shift applied to the value read from Rm |
9938 | uint32_t carry; |
9939 | switch (encoding) { |
9940 | case eEncodingT1: |
9941 | Rn = Bits32(bits: opcode, msbit: 2, lsbit: 0); |
9942 | Rm = Bits32(bits: opcode, msbit: 5, lsbit: 3); |
9943 | shift_t = SRType_LSL; |
9944 | shift_n = 0; |
9945 | break; |
9946 | case eEncodingT2: |
9947 | Rn = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
9948 | Rm = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
9949 | shift_n = DecodeImmShiftThumb(opcode, shift_t); |
9950 | if (BadReg(n: Rn) || BadReg(n: Rm)) |
9951 | return false; |
9952 | break; |
9953 | case eEncodingA1: |
9954 | Rn = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
9955 | Rm = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
9956 | shift_n = DecodeImmShiftARM(opcode, shift_t); |
9957 | break; |
9958 | default: |
9959 | return false; |
9960 | } |
9961 | |
9962 | // Read the first operand. |
9963 | uint32_t val1 = ReadCoreReg(regnum: Rn, success: &success); |
9964 | if (!success) |
9965 | return false; |
9966 | |
9967 | // Read the second operand. |
9968 | uint32_t val2 = ReadCoreReg(regnum: Rm, success: &success); |
9969 | if (!success) |
9970 | return false; |
9971 | |
9972 | uint32_t shifted = Shift_C(value: val2, type: shift_t, amount: shift_n, APSR_C, carry_out&: carry, success: &success); |
9973 | if (!success) |
9974 | return false; |
9975 | uint32_t result = val1 & shifted; |
9976 | |
9977 | EmulateInstruction::Context context; |
9978 | context.type = EmulateInstruction::eContextImmediate; |
9979 | context.SetNoArgs(); |
9980 | |
9981 | if (!WriteFlags(context, result, carry)) |
9982 | return false; |
9983 | } |
9984 | return true; |
9985 | } |
9986 | |
9987 | // A8.6.216 SUB (SP minus register) |
9988 | bool EmulateInstructionARM::EmulateSUBSPReg(const uint32_t opcode, |
9989 | const ARMEncoding encoding) { |
9990 | #if 0 |
9991 | if ConditionPassed() then |
9992 | EncodingSpecificOperations(); |
9993 | shifted = Shift(R[m], shift_t, shift_n, APSR.C); |
9994 | (result, carry, overflow) = AddWithCarry(SP, NOT(shifted), '1'); |
9995 | if d == 15 then // Can only occur for ARM encoding |
9996 | ALUWritePC(result); // setflags is always FALSE here |
9997 | else |
9998 | R[d] = result; |
9999 | if setflags then |
10000 | APSR.N = result<31>; |
10001 | APSR.Z = IsZeroBit(result); |
10002 | APSR.C = carry; |
10003 | APSR.V = overflow; |
10004 | #endif |
10005 | |
10006 | bool success = false; |
10007 | |
10008 | if (ConditionPassed(opcode)) { |
10009 | uint32_t d; |
10010 | uint32_t m; |
10011 | bool setflags; |
10012 | ARM_ShifterType shift_t; |
10013 | uint32_t shift_n; |
10014 | |
10015 | switch (encoding) { |
10016 | case eEncodingT1: |
10017 | // d = UInt(Rd); m = UInt(Rm); setflags = (S == '1'); |
10018 | d = Bits32(bits: opcode, msbit: 11, lsbit: 8); |
10019 | m = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
10020 | setflags = BitIsSet(value: opcode, bit: 20); |
10021 | |
10022 | // (shift_t, shift_n) = DecodeImmShift(type, imm3:imm2); |
10023 | shift_n = DecodeImmShiftThumb(opcode, shift_t); |
10024 | |
10025 | // if d == 13 && (shift_t != SRType_LSL || shift_n > 3) then |
10026 | // UNPREDICTABLE; |
10027 | if ((d == 13) && ((shift_t != SRType_LSL) || (shift_n > 3))) |
10028 | return false; |
10029 | |
10030 | // if d == 15 || BadReg(m) then UNPREDICTABLE; |
10031 | if ((d == 15) || BadReg(n: m)) |
10032 | return false; |
10033 | break; |
10034 | |
10035 | case eEncodingA1: |
10036 | // d = UInt(Rd); m = UInt(Rm); setflags = (S == '1'); |
10037 | d = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
10038 | m = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
10039 | setflags = BitIsSet(value: opcode, bit: 20); |
10040 | |
10041 | // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related |
10042 | // instructions; |
10043 | if (d == 15 && setflags) |
10044 | EmulateSUBSPcLrEtc(opcode, encoding); |
10045 | |
10046 | // (shift_t, shift_n) = DecodeImmShift(type, imm5); |
10047 | shift_n = DecodeImmShiftARM(opcode, shift_t); |
10048 | break; |
10049 | |
10050 | default: |
10051 | return false; |
10052 | } |
10053 | |
10054 | // shifted = Shift(R[m], shift_t, shift_n, APSR.C); |
10055 | uint32_t Rm = ReadCoreReg(regnum: m, success: &success); |
10056 | if (!success) |
10057 | return false; |
10058 | |
10059 | uint32_t shifted = Shift(value: Rm, type: shift_t, amount: shift_n, APSR_C, success: &success); |
10060 | if (!success) |
10061 | return false; |
10062 | |
10063 | // (result, carry, overflow) = AddWithCarry(SP, NOT(shifted), '1'); |
10064 | uint32_t sp_val = ReadCoreReg(SP_REG, success: &success); |
10065 | if (!success) |
10066 | return false; |
10067 | |
10068 | AddWithCarryResult res = AddWithCarry(x: sp_val, y: ~shifted, carry_in: 1); |
10069 | |
10070 | EmulateInstruction::Context context; |
10071 | context.type = eContextArithmetic; |
10072 | std::optional<RegisterInfo> sp_reg = |
10073 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_sp); |
10074 | std::optional<RegisterInfo> dwarf_reg = |
10075 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + m); |
10076 | context.SetRegisterRegisterOperands(op1_reg: *sp_reg, op2_reg: *dwarf_reg); |
10077 | |
10078 | if (!WriteCoreRegOptionalFlags(context, result: res.result, Rd: dwarf_r0 + d, setflags, |
10079 | carry: res.carry_out, overflow: res.overflow)) |
10080 | return false; |
10081 | } |
10082 | return true; |
10083 | } |
10084 | |
10085 | // A8.6.7 ADD (register-shifted register) |
10086 | bool EmulateInstructionARM::EmulateADDRegShift(const uint32_t opcode, |
10087 | const ARMEncoding encoding) { |
10088 | #if 0 |
10089 | if ConditionPassed() then |
10090 | EncodingSpecificOperations(); |
10091 | shift_n = UInt(R[s]<7:0>); |
10092 | shifted = Shift(R[m], shift_t, shift_n, APSR.C); |
10093 | (result, carry, overflow) = AddWithCarry(R[n], shifted, '0'); |
10094 | R[d] = result; |
10095 | if setflags then |
10096 | APSR.N = result<31>; |
10097 | APSR.Z = IsZeroBit(result); |
10098 | APSR.C = carry; |
10099 | APSR.V = overflow; |
10100 | #endif |
10101 | |
10102 | bool success = false; |
10103 | |
10104 | if (ConditionPassed(opcode)) { |
10105 | uint32_t d; |
10106 | uint32_t n; |
10107 | uint32_t m; |
10108 | uint32_t s; |
10109 | bool setflags; |
10110 | ARM_ShifterType shift_t; |
10111 | |
10112 | switch (encoding) { |
10113 | case eEncodingA1: |
10114 | // d = UInt(Rd); n = UInt(Rn); m = UInt(Rm); s = UInt(Rs); |
10115 | d = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
10116 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
10117 | m = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
10118 | s = Bits32(bits: opcode, msbit: 11, lsbit: 8); |
10119 | |
10120 | // setflags = (S == '1'); shift_t = DecodeRegShift(type); |
10121 | setflags = BitIsSet(value: opcode, bit: 20); |
10122 | shift_t = DecodeRegShift(type: Bits32(bits: opcode, msbit: 6, lsbit: 5)); |
10123 | |
10124 | // if d == 15 || n == 15 || m == 15 || s == 15 then UNPREDICTABLE; |
10125 | if ((d == 15) || (n == 15) || (m == 15) || (s == 15)) |
10126 | return false; |
10127 | break; |
10128 | |
10129 | default: |
10130 | return false; |
10131 | } |
10132 | |
10133 | // shift_n = UInt(R[s]<7:0>); |
10134 | uint32_t Rs = ReadCoreReg(regnum: s, success: &success); |
10135 | if (!success) |
10136 | return false; |
10137 | |
10138 | uint32_t shift_n = Bits32(bits: Rs, msbit: 7, lsbit: 0); |
10139 | |
10140 | // shifted = Shift(R[m], shift_t, shift_n, APSR.C); |
10141 | uint32_t Rm = ReadCoreReg(regnum: m, success: &success); |
10142 | if (!success) |
10143 | return false; |
10144 | |
10145 | uint32_t shifted = Shift(value: Rm, type: shift_t, amount: shift_n, APSR_C, success: &success); |
10146 | if (!success) |
10147 | return false; |
10148 | |
10149 | // (result, carry, overflow) = AddWithCarry(R[n], shifted, '0'); |
10150 | uint32_t Rn = ReadCoreReg(regnum: n, success: &success); |
10151 | if (!success) |
10152 | return false; |
10153 | |
10154 | AddWithCarryResult res = AddWithCarry(x: Rn, y: shifted, carry_in: 0); |
10155 | |
10156 | // R[d] = result; |
10157 | EmulateInstruction::Context context; |
10158 | context.type = eContextArithmetic; |
10159 | std::optional<RegisterInfo> reg_n = |
10160 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n); |
10161 | std::optional<RegisterInfo> reg_m = |
10162 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + m); |
10163 | |
10164 | context.SetRegisterRegisterOperands(op1_reg: *reg_n, op2_reg: *reg_m); |
10165 | |
10166 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + d, |
10167 | reg_value: res.result)) |
10168 | return false; |
10169 | |
10170 | // if setflags then |
10171 | // APSR.N = result<31>; |
10172 | // APSR.Z = IsZeroBit(result); |
10173 | // APSR.C = carry; |
10174 | // APSR.V = overflow; |
10175 | if (setflags) |
10176 | return WriteFlags(context, result: res.result, carry: res.carry_out, overflow: res.overflow); |
10177 | } |
10178 | return true; |
10179 | } |
10180 | |
10181 | // A8.6.213 SUB (register) |
10182 | bool EmulateInstructionARM::EmulateSUBReg(const uint32_t opcode, |
10183 | const ARMEncoding encoding) { |
10184 | #if 0 |
10185 | if ConditionPassed() then |
10186 | EncodingSpecificOperations(); |
10187 | shifted = Shift(R[m], shift_t, shift_n, APSR.C); |
10188 | (result, carry, overflow) = AddWithCarry(R[n], NOT(shifted), '1'); |
10189 | if d == 15 then // Can only occur for ARM encoding |
10190 | ALUWritePC(result); // setflags is always FALSE here |
10191 | else |
10192 | R[d] = result; |
10193 | if setflags then |
10194 | APSR.N = result<31>; |
10195 | APSR.Z = IsZeroBit(result); |
10196 | APSR.C = carry; |
10197 | APSR.V = overflow; |
10198 | #endif |
10199 | |
10200 | bool success = false; |
10201 | |
10202 | if (ConditionPassed(opcode)) { |
10203 | uint32_t d; |
10204 | uint32_t n; |
10205 | uint32_t m; |
10206 | bool setflags; |
10207 | ARM_ShifterType shift_t; |
10208 | uint32_t shift_n; |
10209 | |
10210 | switch (encoding) { |
10211 | case eEncodingT1: |
10212 | // d = UInt(Rd); n = UInt(Rn); m = UInt(Rm); setflags = !InITBlock(); |
10213 | d = Bits32(bits: opcode, msbit: 2, lsbit: 0); |
10214 | n = Bits32(bits: opcode, msbit: 5, lsbit: 3); |
10215 | m = Bits32(bits: opcode, msbit: 8, lsbit: 6); |
10216 | setflags = !InITBlock(); |
10217 | |
10218 | // (shift_t, shift_n) = (SRType_LSL, 0); |
10219 | shift_t = SRType_LSL; |
10220 | shift_n = 0; |
10221 | |
10222 | break; |
10223 | |
10224 | case eEncodingT2: |
10225 | // d = UInt(Rd); n = UInt(Rn); m = UInt(Rm); setflags = (S =="1"); |
10226 | d = Bits32(bits: opcode, msbit: 11, lsbit: 8); |
10227 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
10228 | m = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
10229 | setflags = BitIsSet(value: opcode, bit: 20); |
10230 | |
10231 | // if Rd == "1111" && S == "1" then SEE CMP (register); |
10232 | if (d == 15 && setflags == 1) |
10233 | return EmulateCMPImm(opcode, encoding: eEncodingT3); |
10234 | |
10235 | // if Rn == "1101" then SEE SUB (SP minus register); |
10236 | if (n == 13) |
10237 | return EmulateSUBSPReg(opcode, encoding: eEncodingT1); |
10238 | |
10239 | // (shift_t, shift_n) = DecodeImmShift(type, imm3:imm2); |
10240 | shift_n = DecodeImmShiftThumb(opcode, shift_t); |
10241 | |
10242 | // if d == 13 || (d == 15 && S == '0') || n == 15 || BadReg(m) then |
10243 | // UNPREDICTABLE; |
10244 | if ((d == 13) || ((d == 15) && BitIsClear(value: opcode, bit: 20)) || (n == 15) || |
10245 | BadReg(n: m)) |
10246 | return false; |
10247 | |
10248 | break; |
10249 | |
10250 | case eEncodingA1: |
10251 | // if Rn == '1101' then SEE SUB (SP minus register); |
10252 | // d = UInt(Rd); n = UInt(Rn); m = UInt(Rm); setflags = (S == '1'); |
10253 | d = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
10254 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
10255 | m = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
10256 | setflags = BitIsSet(value: opcode, bit: 20); |
10257 | |
10258 | // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related |
10259 | // instructions; |
10260 | if ((d == 15) && setflags) |
10261 | EmulateSUBSPcLrEtc(opcode, encoding); |
10262 | |
10263 | // (shift_t, shift_n) = DecodeImmShift(type, imm5); |
10264 | shift_n = DecodeImmShiftARM(opcode, shift_t); |
10265 | |
10266 | break; |
10267 | |
10268 | default: |
10269 | return false; |
10270 | } |
10271 | |
10272 | // shifted = Shift(R[m], shift_t, shift_n, APSR.C); |
10273 | uint32_t Rm = ReadCoreReg(regnum: m, success: &success); |
10274 | if (!success) |
10275 | return false; |
10276 | |
10277 | uint32_t shifted = Shift(value: Rm, type: shift_t, amount: shift_n, APSR_C, success: &success); |
10278 | if (!success) |
10279 | return false; |
10280 | |
10281 | // (result, carry, overflow) = AddWithCarry(R[n], NOT(shifted), '1'); |
10282 | uint32_t Rn = ReadCoreReg(regnum: n, success: &success); |
10283 | if (!success) |
10284 | return false; |
10285 | |
10286 | AddWithCarryResult res = AddWithCarry(x: Rn, y: ~shifted, carry_in: 1); |
10287 | |
10288 | // if d == 15 then // Can only occur for ARM encoding ALUWritePC(result); |
10289 | // // setflags is always FALSE here else |
10290 | // R[d] = result; |
10291 | // if setflags then |
10292 | // APSR.N = result<31>; |
10293 | // APSR.Z = IsZeroBit(result); |
10294 | // APSR.C = carry; |
10295 | // APSR.V = overflow; |
10296 | |
10297 | EmulateInstruction::Context context; |
10298 | context.type = eContextArithmetic; |
10299 | std::optional<RegisterInfo> reg_n = |
10300 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n); |
10301 | std::optional<RegisterInfo> reg_m = |
10302 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + m); |
10303 | context.SetRegisterRegisterOperands(op1_reg: *reg_n, op2_reg: *reg_m); |
10304 | |
10305 | if (!WriteCoreRegOptionalFlags(context, result: res.result, Rd: dwarf_r0 + d, setflags, |
10306 | carry: res.carry_out, overflow: res.overflow)) |
10307 | return false; |
10308 | } |
10309 | return true; |
10310 | } |
10311 | |
10312 | // A8.6.202 STREX |
10313 | // Store Register Exclusive calculates an address from a base register value |
10314 | // and an immediate offset, and stores a word from a register to memory if the |
10315 | // executing processor has exclusive access to the memory addressed. |
10316 | bool EmulateInstructionARM::EmulateSTREX(const uint32_t opcode, |
10317 | const ARMEncoding encoding) { |
10318 | #if 0 |
10319 | if ConditionPassed() then |
10320 | EncodingSpecificOperations(); NullCheckIfThumbEE(n); |
10321 | address = R[n] + imm32; |
10322 | if ExclusiveMonitorsPass(address,4) then |
10323 | MemA[address,4] = R[t]; |
10324 | R[d] = 0; |
10325 | else |
10326 | R[d] = 1; |
10327 | #endif |
10328 | |
10329 | bool success = false; |
10330 | |
10331 | if (ConditionPassed(opcode)) { |
10332 | uint32_t d; |
10333 | uint32_t t; |
10334 | uint32_t n; |
10335 | uint32_t imm32; |
10336 | const uint32_t addr_byte_size = GetAddressByteSize(); |
10337 | |
10338 | switch (encoding) { |
10339 | case eEncodingT1: |
10340 | // d = UInt(Rd); t = UInt(Rt); n = UInt(Rn); imm32 = |
10341 | // ZeroExtend(imm8:'00', |
10342 | // 32); |
10343 | d = Bits32(bits: opcode, msbit: 11, lsbit: 8); |
10344 | t = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
10345 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
10346 | imm32 = Bits32(bits: opcode, msbit: 7, lsbit: 0) << 2; |
10347 | |
10348 | // if BadReg(d) || BadReg(t) || n == 15 then UNPREDICTABLE; |
10349 | if (BadReg(n: d) || BadReg(n: t) || (n == 15)) |
10350 | return false; |
10351 | |
10352 | // if d == n || d == t then UNPREDICTABLE; |
10353 | if ((d == n) || (d == t)) |
10354 | return false; |
10355 | |
10356 | break; |
10357 | |
10358 | case eEncodingA1: |
10359 | // d = UInt(Rd); t = UInt(Rt); n = UInt(Rn); imm32 = Zeros(32); // Zero |
10360 | // offset |
10361 | d = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
10362 | t = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
10363 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
10364 | imm32 = 0; |
10365 | |
10366 | // if d == 15 || t == 15 || n == 15 then UNPREDICTABLE; |
10367 | if ((d == 15) || (t == 15) || (n == 15)) |
10368 | return false; |
10369 | |
10370 | // if d == n || d == t then UNPREDICTABLE; |
10371 | if ((d == n) || (d == t)) |
10372 | return false; |
10373 | |
10374 | break; |
10375 | |
10376 | default: |
10377 | return false; |
10378 | } |
10379 | |
10380 | // address = R[n] + imm32; |
10381 | uint32_t Rn = ReadCoreReg(regnum: n, success: &success); |
10382 | if (!success) |
10383 | return false; |
10384 | |
10385 | addr_t address = Rn + imm32; |
10386 | |
10387 | std::optional<RegisterInfo> base_reg = |
10388 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n); |
10389 | std::optional<RegisterInfo> data_reg = |
10390 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + t); |
10391 | EmulateInstruction::Context context; |
10392 | context.type = eContextRegisterStore; |
10393 | context.SetRegisterToRegisterPlusOffset(data_reg: *data_reg, base_reg: *base_reg, offset: imm32); |
10394 | |
10395 | // if ExclusiveMonitorsPass(address,4) then if (ExclusiveMonitorsPass |
10396 | // (address, addr_byte_size)) -- For now, for the sake of emulation, we |
10397 | // will say this |
10398 | // always return |
10399 | // true. |
10400 | if (true) { |
10401 | // MemA[address,4] = R[t]; |
10402 | uint32_t Rt = |
10403 | ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + t, fail_value: 0, success_ptr: &success); |
10404 | if (!success) |
10405 | return false; |
10406 | |
10407 | if (!MemAWrite(context, address, data_val: Rt, size: addr_byte_size)) |
10408 | return false; |
10409 | |
10410 | // R[d] = 0; |
10411 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + t, reg_value: 0)) |
10412 | return false; |
10413 | } |
10414 | #if 0 // unreachable because if true |
10415 | else |
10416 | { |
10417 | // R[d] = 1; |
10418 | if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, 1)) |
10419 | return false; |
10420 | } |
10421 | #endif // unreachable because if true |
10422 | } |
10423 | return true; |
10424 | } |
10425 | |
10426 | // A8.6.197 STRB (immediate, ARM) |
10427 | bool EmulateInstructionARM::EmulateSTRBImmARM(const uint32_t opcode, |
10428 | const ARMEncoding encoding) { |
10429 | #if 0 |
10430 | if ConditionPassed() then |
10431 | EncodingSpecificOperations(); |
10432 | offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); |
10433 | address = if index then offset_addr else R[n]; |
10434 | MemU[address,1] = R[t]<7:0>; |
10435 | if wback then R[n] = offset_addr; |
10436 | #endif |
10437 | |
10438 | bool success = false; |
10439 | |
10440 | if (ConditionPassed(opcode)) { |
10441 | uint32_t t; |
10442 | uint32_t n; |
10443 | uint32_t imm32; |
10444 | bool index; |
10445 | bool add; |
10446 | bool wback; |
10447 | |
10448 | switch (encoding) { |
10449 | case eEncodingA1: |
10450 | // if P == '0' && W == '1' then SEE STRBT; |
10451 | // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm12, 32); |
10452 | t = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
10453 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
10454 | imm32 = Bits32(bits: opcode, msbit: 11, lsbit: 0); |
10455 | |
10456 | // index = (P == '1'); add = (U == '1'); wback = (P == '0') || (W == '1'); |
10457 | index = BitIsSet(value: opcode, bit: 24); |
10458 | add = BitIsSet(value: opcode, bit: 23); |
10459 | wback = BitIsClear(value: opcode, bit: 24) || BitIsSet(value: opcode, bit: 21); |
10460 | |
10461 | // if t == 15 then UNPREDICTABLE; |
10462 | if (t == 15) |
10463 | return false; |
10464 | |
10465 | // if wback && (n == 15 || n == t) then UNPREDICTABLE; |
10466 | if (wback && ((n == 15) || (n == t))) |
10467 | return false; |
10468 | |
10469 | break; |
10470 | |
10471 | default: |
10472 | return false; |
10473 | } |
10474 | |
10475 | // offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); |
10476 | uint32_t Rn = ReadCoreReg(regnum: n, success: &success); |
10477 | if (!success) |
10478 | return false; |
10479 | |
10480 | addr_t offset_addr; |
10481 | if (add) |
10482 | offset_addr = Rn + imm32; |
10483 | else |
10484 | offset_addr = Rn - imm32; |
10485 | |
10486 | // address = if index then offset_addr else R[n]; |
10487 | addr_t address; |
10488 | if (index) |
10489 | address = offset_addr; |
10490 | else |
10491 | address = Rn; |
10492 | |
10493 | // MemU[address,1] = R[t]<7:0>; |
10494 | uint32_t Rt = ReadCoreReg(regnum: t, success: &success); |
10495 | if (!success) |
10496 | return false; |
10497 | |
10498 | std::optional<RegisterInfo> base_reg = |
10499 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n); |
10500 | std::optional<RegisterInfo> data_reg = |
10501 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + t); |
10502 | EmulateInstruction::Context context; |
10503 | context.type = eContextRegisterStore; |
10504 | context.SetRegisterToRegisterPlusOffset(data_reg: *data_reg, base_reg: *base_reg, offset: address - Rn); |
10505 | |
10506 | if (!MemUWrite(context, address, data_val: Bits32(bits: Rt, msbit: 7, lsbit: 0), size: 1)) |
10507 | return false; |
10508 | |
10509 | // if wback then R[n] = offset_addr; |
10510 | if (wback) { |
10511 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n, |
10512 | reg_value: offset_addr)) |
10513 | return false; |
10514 | } |
10515 | } |
10516 | return true; |
10517 | } |
10518 | |
10519 | // A8.6.194 STR (immediate, ARM) |
10520 | bool EmulateInstructionARM::EmulateSTRImmARM(const uint32_t opcode, |
10521 | const ARMEncoding encoding) { |
10522 | #if 0 |
10523 | if ConditionPassed() then |
10524 | EncodingSpecificOperations(); |
10525 | offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); |
10526 | address = if index then offset_addr else R[n]; |
10527 | MemU[address,4] = if t == 15 then PCStoreValue() else R[t]; |
10528 | if wback then R[n] = offset_addr; |
10529 | #endif |
10530 | |
10531 | bool success = false; |
10532 | |
10533 | if (ConditionPassed(opcode)) { |
10534 | uint32_t t; |
10535 | uint32_t n; |
10536 | uint32_t imm32; |
10537 | bool index; |
10538 | bool add; |
10539 | bool wback; |
10540 | |
10541 | const uint32_t addr_byte_size = GetAddressByteSize(); |
10542 | |
10543 | switch (encoding) { |
10544 | case eEncodingA1: |
10545 | // if P == '0' && W == '1' then SEE STRT; |
10546 | // if Rn == '1101' && P == '1' && U == '0' && W == '1' && imm12 == |
10547 | // '000000000100' then SEE PUSH; |
10548 | // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm12, 32); |
10549 | t = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
10550 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
10551 | imm32 = Bits32(bits: opcode, msbit: 11, lsbit: 0); |
10552 | |
10553 | // index = (P == '1'); add = (U == '1'); wback = (P == '0') || (W == '1'); |
10554 | index = BitIsSet(value: opcode, bit: 24); |
10555 | add = BitIsSet(value: opcode, bit: 23); |
10556 | wback = BitIsClear(value: opcode, bit: 24) || BitIsSet(value: opcode, bit: 21); |
10557 | |
10558 | // if wback && (n == 15 || n == t) then UNPREDICTABLE; |
10559 | if (wback && ((n == 15) || (n == t))) |
10560 | return false; |
10561 | |
10562 | break; |
10563 | |
10564 | default: |
10565 | return false; |
10566 | } |
10567 | |
10568 | // offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); |
10569 | uint32_t Rn = ReadCoreReg(regnum: n, success: &success); |
10570 | if (!success) |
10571 | return false; |
10572 | |
10573 | addr_t offset_addr; |
10574 | if (add) |
10575 | offset_addr = Rn + imm32; |
10576 | else |
10577 | offset_addr = Rn - imm32; |
10578 | |
10579 | // address = if index then offset_addr else R[n]; |
10580 | addr_t address; |
10581 | if (index) |
10582 | address = offset_addr; |
10583 | else |
10584 | address = Rn; |
10585 | |
10586 | std::optional<RegisterInfo> base_reg = |
10587 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n); |
10588 | std::optional<RegisterInfo> data_reg = |
10589 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + t); |
10590 | EmulateInstruction::Context context; |
10591 | context.type = eContextRegisterStore; |
10592 | context.SetRegisterToRegisterPlusOffset(data_reg: *data_reg, base_reg: *base_reg, offset: address - Rn); |
10593 | |
10594 | // MemU[address,4] = if t == 15 then PCStoreValue() else R[t]; |
10595 | uint32_t Rt = ReadCoreReg(regnum: t, success: &success); |
10596 | if (!success) |
10597 | return false; |
10598 | |
10599 | if (t == 15) { |
10600 | uint32_t pc_value = ReadCoreReg(PC_REG, success: &success); |
10601 | if (!success) |
10602 | return false; |
10603 | |
10604 | if (!MemUWrite(context, address, data_val: pc_value, size: addr_byte_size)) |
10605 | return false; |
10606 | } else { |
10607 | if (!MemUWrite(context, address, data_val: Rt, size: addr_byte_size)) |
10608 | return false; |
10609 | } |
10610 | |
10611 | // if wback then R[n] = offset_addr; |
10612 | if (wback) { |
10613 | context.type = eContextAdjustBaseRegister; |
10614 | context.SetImmediate(offset_addr); |
10615 | |
10616 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n, |
10617 | reg_value: offset_addr)) |
10618 | return false; |
10619 | } |
10620 | } |
10621 | return true; |
10622 | } |
10623 | |
10624 | // A8.6.66 LDRD (immediate) |
10625 | // Load Register Dual (immediate) calculates an address from a base register |
10626 | // value and an immediate offset, loads two words from memory, and writes them |
10627 | // to two registers. It can use offset, post-indexed, or pre-indexed |
10628 | // addressing. |
10629 | bool EmulateInstructionARM::EmulateLDRDImmediate(const uint32_t opcode, |
10630 | const ARMEncoding encoding) { |
10631 | #if 0 |
10632 | if ConditionPassed() then |
10633 | EncodingSpecificOperations(); NullCheckIfThumbEE(n); |
10634 | offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); |
10635 | address = if index then offset_addr else R[n]; |
10636 | R[t] = MemA[address,4]; |
10637 | R[t2] = MemA[address+4,4]; |
10638 | if wback then R[n] = offset_addr; |
10639 | #endif |
10640 | |
10641 | bool success = false; |
10642 | |
10643 | if (ConditionPassed(opcode)) { |
10644 | uint32_t t; |
10645 | uint32_t t2; |
10646 | uint32_t n; |
10647 | uint32_t imm32; |
10648 | bool index; |
10649 | bool add; |
10650 | bool wback; |
10651 | |
10652 | switch (encoding) { |
10653 | case eEncodingT1: |
10654 | // if P == '0' && W == '0' then SEE 'Related encodings'; |
10655 | // if Rn == '1111' then SEE LDRD (literal); |
10656 | // t = UInt(Rt); t2 = UInt(Rt2); n = UInt(Rn); imm32 = |
10657 | // ZeroExtend(imm8:'00', 32); |
10658 | t = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
10659 | t2 = Bits32(bits: opcode, msbit: 11, lsbit: 8); |
10660 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
10661 | imm32 = Bits32(bits: opcode, msbit: 7, lsbit: 0) << 2; |
10662 | |
10663 | // index = (P == '1'); add = (U == '1'); wback = (W == '1'); |
10664 | index = BitIsSet(value: opcode, bit: 24); |
10665 | add = BitIsSet(value: opcode, bit: 23); |
10666 | wback = BitIsSet(value: opcode, bit: 21); |
10667 | |
10668 | // if wback && (n == t || n == t2) then UNPREDICTABLE; |
10669 | if (wback && ((n == t) || (n == t2))) |
10670 | return false; |
10671 | |
10672 | // if BadReg(t) || BadReg(t2) || t == t2 then UNPREDICTABLE; |
10673 | if (BadReg(n: t) || BadReg(n: t2) || (t == t2)) |
10674 | return false; |
10675 | |
10676 | break; |
10677 | |
10678 | case eEncodingA1: |
10679 | // if Rn == '1111' then SEE LDRD (literal); |
10680 | // if Rt<0> == '1' then UNPREDICTABLE; |
10681 | // t = UInt(Rt); t2 = t+1; n = UInt(Rn); imm32 = ZeroExtend(imm4H:imm4L, |
10682 | // 32); |
10683 | t = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
10684 | if (BitIsSet(value: t, bit: 0)) |
10685 | return false; |
10686 | t2 = t + 1; |
10687 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
10688 | imm32 = (Bits32(bits: opcode, msbit: 11, lsbit: 8) << 4) | Bits32(bits: opcode, msbit: 3, lsbit: 0); |
10689 | |
10690 | // index = (P == '1'); add = (U == '1'); wback = (P == '0') || (W == '1'); |
10691 | index = BitIsSet(value: opcode, bit: 24); |
10692 | add = BitIsSet(value: opcode, bit: 23); |
10693 | wback = BitIsClear(value: opcode, bit: 24) || BitIsSet(value: opcode, bit: 21); |
10694 | |
10695 | // if P == '0' && W == '1' then UNPREDICTABLE; |
10696 | if (BitIsClear(value: opcode, bit: 24) && BitIsSet(value: opcode, bit: 21)) |
10697 | return false; |
10698 | |
10699 | // if wback && (n == t || n == t2) then UNPREDICTABLE; |
10700 | if (wback && ((n == t) || (n == t2))) |
10701 | return false; |
10702 | |
10703 | // if t2 == 15 then UNPREDICTABLE; |
10704 | if (t2 == 15) |
10705 | return false; |
10706 | |
10707 | break; |
10708 | |
10709 | default: |
10710 | return false; |
10711 | } |
10712 | |
10713 | // offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); |
10714 | uint32_t Rn = ReadCoreReg(regnum: n, success: &success); |
10715 | if (!success) |
10716 | return false; |
10717 | |
10718 | addr_t offset_addr; |
10719 | if (add) |
10720 | offset_addr = Rn + imm32; |
10721 | else |
10722 | offset_addr = Rn - imm32; |
10723 | |
10724 | // address = if index then offset_addr else R[n]; |
10725 | addr_t address; |
10726 | if (index) |
10727 | address = offset_addr; |
10728 | else |
10729 | address = Rn; |
10730 | |
10731 | // R[t] = MemA[address,4]; |
10732 | |
10733 | EmulateInstruction::Context context; |
10734 | if (n == 13) |
10735 | context.type = eContextPopRegisterOffStack; |
10736 | else |
10737 | context.type = eContextRegisterLoad; |
10738 | context.SetAddress(address); |
10739 | |
10740 | const uint32_t addr_byte_size = GetAddressByteSize(); |
10741 | uint32_t data = MemARead(context, address, size: addr_byte_size, fail_value: 0, success_ptr: &success); |
10742 | if (!success) |
10743 | return false; |
10744 | |
10745 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + t, reg_value: data)) |
10746 | return false; |
10747 | |
10748 | // R[t2] = MemA[address+4,4]; |
10749 | context.SetAddress(address + 4); |
10750 | data = MemARead(context, address: address + 4, size: addr_byte_size, fail_value: 0, success_ptr: &success); |
10751 | if (!success) |
10752 | return false; |
10753 | |
10754 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + t2, |
10755 | reg_value: data)) |
10756 | return false; |
10757 | |
10758 | // if wback then R[n] = offset_addr; |
10759 | if (wback) { |
10760 | context.type = eContextAdjustBaseRegister; |
10761 | context.SetAddress(offset_addr); |
10762 | |
10763 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n, |
10764 | reg_value: offset_addr)) |
10765 | return false; |
10766 | } |
10767 | } |
10768 | return true; |
10769 | } |
10770 | |
10771 | // A8.6.68 LDRD (register) |
10772 | // Load Register Dual (register) calculates an address from a base register |
10773 | // value and a register offset, loads two words from memory, and writes them to |
10774 | // two registers. It can use offset, post-indexed or pre-indexed addressing. |
10775 | bool EmulateInstructionARM::EmulateLDRDRegister(const uint32_t opcode, |
10776 | const ARMEncoding encoding) { |
10777 | #if 0 |
10778 | if ConditionPassed() then |
10779 | EncodingSpecificOperations(); |
10780 | offset_addr = if add then (R[n] + R[m]) else (R[n] - R[m]); |
10781 | address = if index then offset_addr else R[n]; |
10782 | R[t] = MemA[address,4]; |
10783 | R[t2] = MemA[address+4,4]; |
10784 | if wback then R[n] = offset_addr; |
10785 | #endif |
10786 | |
10787 | bool success = false; |
10788 | |
10789 | if (ConditionPassed(opcode)) { |
10790 | uint32_t t; |
10791 | uint32_t t2; |
10792 | uint32_t n; |
10793 | uint32_t m; |
10794 | bool index; |
10795 | bool add; |
10796 | bool wback; |
10797 | |
10798 | switch (encoding) { |
10799 | case eEncodingA1: |
10800 | // if Rt<0> == '1' then UNPREDICTABLE; |
10801 | // t = UInt(Rt); t2 = t+1; n = UInt(Rn); m = UInt(Rm); |
10802 | t = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
10803 | if (BitIsSet(value: t, bit: 0)) |
10804 | return false; |
10805 | t2 = t + 1; |
10806 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
10807 | m = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
10808 | |
10809 | // index = (P == '1'); add = (U == '1'); wback = (P == '0') || (W == '1'); |
10810 | index = BitIsSet(value: opcode, bit: 24); |
10811 | add = BitIsSet(value: opcode, bit: 23); |
10812 | wback = BitIsClear(value: opcode, bit: 24) || BitIsSet(value: opcode, bit: 21); |
10813 | |
10814 | // if P == '0' && W == '1' then UNPREDICTABLE; |
10815 | if (BitIsClear(value: opcode, bit: 24) && BitIsSet(value: opcode, bit: 21)) |
10816 | return false; |
10817 | |
10818 | // if t2 == 15 || m == 15 || m == t || m == t2 then UNPREDICTABLE; |
10819 | if ((t2 == 15) || (m == 15) || (m == t) || (m == t2)) |
10820 | return false; |
10821 | |
10822 | // if wback && (n == 15 || n == t || n == t2) then UNPREDICTABLE; |
10823 | if (wback && ((n == 15) || (n == t) || (n == t2))) |
10824 | return false; |
10825 | |
10826 | // if ArchVersion() < 6 && wback && m == n then UNPREDICTABLE; |
10827 | if ((ArchVersion() < 6) && wback && (m == n)) |
10828 | return false; |
10829 | break; |
10830 | |
10831 | default: |
10832 | return false; |
10833 | } |
10834 | |
10835 | uint32_t Rn = ReadCoreReg(regnum: n, success: &success); |
10836 | if (!success) |
10837 | return false; |
10838 | |
10839 | uint32_t Rm = ReadCoreReg(regnum: m, success: &success); |
10840 | if (!success) |
10841 | return false; |
10842 | |
10843 | // offset_addr = if add then (R[n] + R[m]) else (R[n] - R[m]); |
10844 | addr_t offset_addr; |
10845 | if (add) |
10846 | offset_addr = Rn + Rm; |
10847 | else |
10848 | offset_addr = Rn - Rm; |
10849 | |
10850 | // address = if index then offset_addr else R[n]; |
10851 | addr_t address; |
10852 | if (index) |
10853 | address = offset_addr; |
10854 | else |
10855 | address = Rn; |
10856 | |
10857 | EmulateInstruction::Context context; |
10858 | if (n == 13) |
10859 | context.type = eContextPopRegisterOffStack; |
10860 | else |
10861 | context.type = eContextRegisterLoad; |
10862 | context.SetAddress(address); |
10863 | |
10864 | // R[t] = MemA[address,4]; |
10865 | const uint32_t addr_byte_size = GetAddressByteSize(); |
10866 | uint32_t data = MemARead(context, address, size: addr_byte_size, fail_value: 0, success_ptr: &success); |
10867 | if (!success) |
10868 | return false; |
10869 | |
10870 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + t, reg_value: data)) |
10871 | return false; |
10872 | |
10873 | // R[t2] = MemA[address+4,4]; |
10874 | |
10875 | data = MemARead(context, address: address + 4, size: addr_byte_size, fail_value: 0, success_ptr: &success); |
10876 | if (!success) |
10877 | return false; |
10878 | |
10879 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + t2, |
10880 | reg_value: data)) |
10881 | return false; |
10882 | |
10883 | // if wback then R[n] = offset_addr; |
10884 | if (wback) { |
10885 | context.type = eContextAdjustBaseRegister; |
10886 | context.SetAddress(offset_addr); |
10887 | |
10888 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n, |
10889 | reg_value: offset_addr)) |
10890 | return false; |
10891 | } |
10892 | } |
10893 | return true; |
10894 | } |
10895 | |
10896 | // A8.6.200 STRD (immediate) |
10897 | // Store Register Dual (immediate) calculates an address from a base register |
10898 | // value and an immediate offset, and stores two words from two registers to |
10899 | // memory. It can use offset, post-indexed, or pre-indexed addressing. |
10900 | bool EmulateInstructionARM::EmulateSTRDImm(const uint32_t opcode, |
10901 | const ARMEncoding encoding) { |
10902 | #if 0 |
10903 | if ConditionPassed() then |
10904 | EncodingSpecificOperations(); NullCheckIfThumbEE(n); |
10905 | offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); |
10906 | address = if index then offset_addr else R[n]; |
10907 | MemA[address,4] = R[t]; |
10908 | MemA[address+4,4] = R[t2]; |
10909 | if wback then R[n] = offset_addr; |
10910 | #endif |
10911 | |
10912 | bool success = false; |
10913 | |
10914 | if (ConditionPassed(opcode)) { |
10915 | uint32_t t; |
10916 | uint32_t t2; |
10917 | uint32_t n; |
10918 | uint32_t imm32; |
10919 | bool index; |
10920 | bool add; |
10921 | bool wback; |
10922 | |
10923 | switch (encoding) { |
10924 | case eEncodingT1: |
10925 | // if P == '0' && W == '0' then SEE 'Related encodings'; |
10926 | // t = UInt(Rt); t2 = UInt(Rt2); n = UInt(Rn); imm32 = |
10927 | // ZeroExtend(imm8:'00', 32); |
10928 | t = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
10929 | t2 = Bits32(bits: opcode, msbit: 11, lsbit: 8); |
10930 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
10931 | imm32 = Bits32(bits: opcode, msbit: 7, lsbit: 0) << 2; |
10932 | |
10933 | // index = (P == '1'); add = (U == '1'); wback = (W == '1'); |
10934 | index = BitIsSet(value: opcode, bit: 24); |
10935 | add = BitIsSet(value: opcode, bit: 23); |
10936 | wback = BitIsSet(value: opcode, bit: 21); |
10937 | |
10938 | // if wback && (n == t || n == t2) then UNPREDICTABLE; |
10939 | if (wback && ((n == t) || (n == t2))) |
10940 | return false; |
10941 | |
10942 | // if n == 15 || BadReg(t) || BadReg(t2) then UNPREDICTABLE; |
10943 | if ((n == 15) || BadReg(n: t) || BadReg(n: t2)) |
10944 | return false; |
10945 | |
10946 | break; |
10947 | |
10948 | case eEncodingA1: |
10949 | // if Rt<0> == '1' then UNPREDICTABLE; |
10950 | // t = UInt(Rt); t2 = t+1; n = UInt(Rn); imm32 = ZeroExtend(imm4H:imm4L, |
10951 | // 32); |
10952 | t = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
10953 | if (BitIsSet(value: t, bit: 0)) |
10954 | return false; |
10955 | |
10956 | t2 = t + 1; |
10957 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
10958 | imm32 = (Bits32(bits: opcode, msbit: 11, lsbit: 8) << 4) | Bits32(bits: opcode, msbit: 3, lsbit: 0); |
10959 | |
10960 | // index = (P == '1'); add = (U == '1'); wback = (P == '0') || (W == '1'); |
10961 | index = BitIsSet(value: opcode, bit: 24); |
10962 | add = BitIsSet(value: opcode, bit: 23); |
10963 | wback = BitIsClear(value: opcode, bit: 24) || BitIsSet(value: opcode, bit: 21); |
10964 | |
10965 | // if P == '0' && W == '1' then UNPREDICTABLE; |
10966 | if (BitIsClear(value: opcode, bit: 24) && BitIsSet(value: opcode, bit: 21)) |
10967 | return false; |
10968 | |
10969 | // if wback && (n == 15 || n == t || n == t2) then UNPREDICTABLE; |
10970 | if (wback && ((n == 15) || (n == t) || (n == t2))) |
10971 | return false; |
10972 | |
10973 | // if t2 == 15 then UNPREDICTABLE; |
10974 | if (t2 == 15) |
10975 | return false; |
10976 | |
10977 | break; |
10978 | |
10979 | default: |
10980 | return false; |
10981 | } |
10982 | |
10983 | std::optional<RegisterInfo> base_reg = |
10984 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n); |
10985 | |
10986 | uint32_t Rn = ReadCoreReg(regnum: n, success: &success); |
10987 | if (!success) |
10988 | return false; |
10989 | |
10990 | // offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); |
10991 | addr_t offset_addr; |
10992 | if (add) |
10993 | offset_addr = Rn + imm32; |
10994 | else |
10995 | offset_addr = Rn - imm32; |
10996 | |
10997 | // address = if index then offset_addr else R[n]; |
10998 | addr_t address; |
10999 | if (index) |
11000 | address = offset_addr; |
11001 | else |
11002 | address = Rn; |
11003 | |
11004 | // MemA[address,4] = R[t]; |
11005 | std::optional<RegisterInfo> data_reg = |
11006 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + t); |
11007 | |
11008 | uint32_t data = ReadCoreReg(regnum: t, success: &success); |
11009 | if (!success) |
11010 | return false; |
11011 | |
11012 | EmulateInstruction::Context context; |
11013 | if (n == 13) |
11014 | context.type = eContextPushRegisterOnStack; |
11015 | else |
11016 | context.type = eContextRegisterStore; |
11017 | context.SetRegisterToRegisterPlusOffset(data_reg: *data_reg, base_reg: *base_reg, offset: address - Rn); |
11018 | |
11019 | const uint32_t addr_byte_size = GetAddressByteSize(); |
11020 | |
11021 | if (!MemAWrite(context, address, data_val: data, size: addr_byte_size)) |
11022 | return false; |
11023 | |
11024 | // MemA[address+4,4] = R[t2]; |
11025 | data_reg = GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + t2); |
11026 | context.SetRegisterToRegisterPlusOffset(data_reg: *data_reg, base_reg: *base_reg, |
11027 | offset: (address + 4) - Rn); |
11028 | |
11029 | data = ReadCoreReg(regnum: t2, success: &success); |
11030 | if (!success) |
11031 | return false; |
11032 | |
11033 | if (!MemAWrite(context, address: address + 4, data_val: data, size: addr_byte_size)) |
11034 | return false; |
11035 | |
11036 | // if wback then R[n] = offset_addr; |
11037 | if (wback) { |
11038 | if (n == 13) |
11039 | context.type = eContextAdjustStackPointer; |
11040 | else |
11041 | context.type = eContextAdjustBaseRegister; |
11042 | context.SetAddress(offset_addr); |
11043 | |
11044 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n, |
11045 | reg_value: offset_addr)) |
11046 | return false; |
11047 | } |
11048 | } |
11049 | return true; |
11050 | } |
11051 | |
11052 | // A8.6.201 STRD (register) |
11053 | bool EmulateInstructionARM::EmulateSTRDReg(const uint32_t opcode, |
11054 | const ARMEncoding encoding) { |
11055 | #if 0 |
11056 | if ConditionPassed() then |
11057 | EncodingSpecificOperations(); |
11058 | offset_addr = if add then (R[n] + R[m]) else (R[n] - R[m]); |
11059 | address = if index then offset_addr else R[n]; |
11060 | MemA[address,4] = R[t]; |
11061 | MemA[address+4,4] = R[t2]; |
11062 | if wback then R[n] = offset_addr; |
11063 | #endif |
11064 | |
11065 | bool success = false; |
11066 | |
11067 | if (ConditionPassed(opcode)) { |
11068 | uint32_t t; |
11069 | uint32_t t2; |
11070 | uint32_t n; |
11071 | uint32_t m; |
11072 | bool index; |
11073 | bool add; |
11074 | bool wback; |
11075 | |
11076 | switch (encoding) { |
11077 | case eEncodingA1: |
11078 | // if Rt<0> == '1' then UNPREDICTABLE; |
11079 | // t = UInt(Rt); t2 = t+1; n = UInt(Rn); m = UInt(Rm); |
11080 | t = Bits32(bits: opcode, msbit: 15, lsbit: 12); |
11081 | if (BitIsSet(value: t, bit: 0)) |
11082 | return false; |
11083 | |
11084 | t2 = t + 1; |
11085 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
11086 | m = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
11087 | |
11088 | // index = (P == '1'); add = (U == '1'); wback = (P == '0') || (W == '1'); |
11089 | index = BitIsSet(value: opcode, bit: 24); |
11090 | add = BitIsSet(value: opcode, bit: 23); |
11091 | wback = BitIsClear(value: opcode, bit: 24) || BitIsSet(value: opcode, bit: 21); |
11092 | |
11093 | // if P == '0' && W == '1' then UNPREDICTABLE; |
11094 | if (BitIsClear(value: opcode, bit: 24) && BitIsSet(value: opcode, bit: 21)) |
11095 | return false; |
11096 | |
11097 | // if t2 == 15 || m == 15 then UNPREDICTABLE; |
11098 | if ((t2 == 15) || (m == 15)) |
11099 | return false; |
11100 | |
11101 | // if wback && (n == 15 || n == t || n == t2) then UNPREDICTABLE; |
11102 | if (wback && ((n == 15) || (n == t) || (n == t2))) |
11103 | return false; |
11104 | |
11105 | // if ArchVersion() < 6 && wback && m == n then UNPREDICTABLE; |
11106 | if ((ArchVersion() < 6) && wback && (m == n)) |
11107 | return false; |
11108 | |
11109 | break; |
11110 | |
11111 | default: |
11112 | return false; |
11113 | } |
11114 | |
11115 | uint32_t Rn = ReadCoreReg(regnum: n, success: &success); |
11116 | if (!success) |
11117 | return false; |
11118 | |
11119 | uint32_t Rm = ReadCoreReg(regnum: m, success: &success); |
11120 | if (!success) |
11121 | return false; |
11122 | |
11123 | // offset_addr = if add then (R[n] + R[m]) else (R[n] - R[m]); |
11124 | addr_t offset_addr; |
11125 | if (add) |
11126 | offset_addr = Rn + Rm; |
11127 | else |
11128 | offset_addr = Rn - Rm; |
11129 | |
11130 | // address = if index then offset_addr else R[n]; |
11131 | addr_t address; |
11132 | if (index) |
11133 | address = offset_addr; |
11134 | else |
11135 | address = Rn; |
11136 | // MemA[address,4] = R[t]; |
11137 | uint32_t Rt = ReadCoreReg(regnum: t, success: &success); |
11138 | if (!success) |
11139 | return false; |
11140 | |
11141 | EmulateInstruction::Context context; |
11142 | if (t == 13) |
11143 | context.type = eContextPushRegisterOnStack; |
11144 | else |
11145 | context.type = eContextRegisterStore; |
11146 | |
11147 | std::optional<RegisterInfo> base_reg = |
11148 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n); |
11149 | std::optional<RegisterInfo> offset_reg = |
11150 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + m); |
11151 | std::optional<RegisterInfo> data_reg = |
11152 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + t); |
11153 | context.SetRegisterToRegisterPlusIndirectOffset(base_reg: *base_reg, offset_reg: *offset_reg, |
11154 | data_reg: *data_reg); |
11155 | |
11156 | const uint32_t addr_byte_size = GetAddressByteSize(); |
11157 | |
11158 | if (!MemAWrite(context, address, data_val: Rt, size: addr_byte_size)) |
11159 | return false; |
11160 | |
11161 | // MemA[address+4,4] = R[t2]; |
11162 | uint32_t Rt2 = ReadCoreReg(regnum: t2, success: &success); |
11163 | if (!success) |
11164 | return false; |
11165 | |
11166 | data_reg = GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + t2); |
11167 | |
11168 | context.SetRegisterToRegisterPlusIndirectOffset(base_reg: *base_reg, offset_reg: *offset_reg, |
11169 | data_reg: *data_reg); |
11170 | |
11171 | if (!MemAWrite(context, address: address + 4, data_val: Rt2, size: addr_byte_size)) |
11172 | return false; |
11173 | |
11174 | // if wback then R[n] = offset_addr; |
11175 | if (wback) { |
11176 | context.type = eContextAdjustBaseRegister; |
11177 | context.SetAddress(offset_addr); |
11178 | |
11179 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n, |
11180 | reg_value: offset_addr)) |
11181 | return false; |
11182 | } |
11183 | } |
11184 | return true; |
11185 | } |
11186 | |
11187 | // A8.6.319 VLDM |
11188 | // Vector Load Multiple loads multiple extension registers from consecutive |
11189 | // memory locations using an address from an ARM core register. |
11190 | bool EmulateInstructionARM::EmulateVLDM(const uint32_t opcode, |
11191 | const ARMEncoding encoding) { |
11192 | #if 0 |
11193 | if ConditionPassed() then |
11194 | EncodingSpecificOperations(); CheckVFPEnabled(TRUE); NullCheckIfThumbEE(n); |
11195 | address = if add then R[n] else R[n]-imm32; |
11196 | if wback then R[n] = if add then R[n]+imm32 else R[n]-imm32; |
11197 | for r = 0 to regs-1 |
11198 | if single_regs then |
11199 | S[d+r] = MemA[address,4]; address = address+4; |
11200 | else |
11201 | word1 = MemA[address,4]; word2 = MemA[address+4,4]; address = address+8; |
11202 | // Combine the word-aligned words in the correct order for |
11203 | // current endianness. |
11204 | D[d+r] = if BigEndian() then word1:word2 else word2:word1; |
11205 | #endif |
11206 | |
11207 | bool success = false; |
11208 | |
11209 | if (ConditionPassed(opcode)) { |
11210 | bool single_regs; |
11211 | bool add; |
11212 | bool wback; |
11213 | uint32_t d; |
11214 | uint32_t n; |
11215 | uint32_t imm32; |
11216 | uint32_t regs; |
11217 | |
11218 | switch (encoding) { |
11219 | case eEncodingT1: |
11220 | case eEncodingA1: |
11221 | // if P == '0' && U == '0' && W == '0' then SEE 'Related encodings'; |
11222 | // if P == '0' && U == '1' && W == '1' && Rn == '1101' then SEE VPOP; |
11223 | // if P == '1' && W == '0' then SEE VLDR; |
11224 | // if P == U && W == '1' then UNDEFINED; |
11225 | if ((Bit32(bits: opcode, bit: 24) == Bit32(bits: opcode, bit: 23)) && BitIsSet(value: opcode, bit: 21)) |
11226 | return false; |
11227 | |
11228 | // // Remaining combinations are PUW = 010 (IA without !), 011 (IA with |
11229 | // !), 101 (DB with !) |
11230 | // single_regs = FALSE; add = (U == '1'); wback = (W == '1'); |
11231 | single_regs = false; |
11232 | add = BitIsSet(value: opcode, bit: 23); |
11233 | wback = BitIsSet(value: opcode, bit: 21); |
11234 | |
11235 | // d = UInt(D:Vd); n = UInt(Rn); imm32 = ZeroExtend(imm8:'00', 32); |
11236 | d = (Bit32(bits: opcode, bit: 22) << 4) | Bits32(bits: opcode, msbit: 15, lsbit: 12); |
11237 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
11238 | imm32 = Bits32(bits: opcode, msbit: 7, lsbit: 0) << 2; |
11239 | |
11240 | // regs = UInt(imm8) DIV 2; // If UInt(imm8) is odd, see 'FLDMX'. |
11241 | regs = Bits32(bits: opcode, msbit: 7, lsbit: 0) / 2; |
11242 | |
11243 | // if n == 15 && (wback || CurrentInstrSet() != InstrSet_ARM) then |
11244 | // UNPREDICTABLE; |
11245 | if (n == 15 && (wback || CurrentInstrSet() != eModeARM)) |
11246 | return false; |
11247 | |
11248 | // if regs == 0 || regs > 16 || (d+regs) > 32 then UNPREDICTABLE; |
11249 | if ((regs == 0) || (regs > 16) || ((d + regs) > 32)) |
11250 | return false; |
11251 | |
11252 | break; |
11253 | |
11254 | case eEncodingT2: |
11255 | case eEncodingA2: |
11256 | // if P == '0' && U == '0' && W == '0' then SEE 'Related encodings'; |
11257 | // if P == '0' && U == '1' && W == '1' && Rn == '1101' then SEE VPOP; |
11258 | // if P == '1' && W == '0' then SEE VLDR; |
11259 | // if P == U && W == '1' then UNDEFINED; |
11260 | if ((Bit32(bits: opcode, bit: 24) == Bit32(bits: opcode, bit: 23)) && BitIsSet(value: opcode, bit: 21)) |
11261 | return false; |
11262 | |
11263 | // // Remaining combinations are PUW = 010 (IA without !), 011 (IA with |
11264 | // !), 101 (DB with !) single_regs = TRUE; add = (U == '1'); wback = (W |
11265 | // == '1'); d = |
11266 | // UInt(Vd:D); n = UInt(Rn); |
11267 | single_regs = true; |
11268 | add = BitIsSet(value: opcode, bit: 23); |
11269 | wback = BitIsSet(value: opcode, bit: 21); |
11270 | d = (Bits32(bits: opcode, msbit: 15, lsbit: 12) << 1) | Bit32(bits: opcode, bit: 22); |
11271 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
11272 | |
11273 | // imm32 = ZeroExtend(imm8:'00', 32); regs = UInt(imm8); |
11274 | imm32 = Bits32(bits: opcode, msbit: 7, lsbit: 0) << 2; |
11275 | regs = Bits32(bits: opcode, msbit: 7, lsbit: 0); |
11276 | |
11277 | // if n == 15 && (wback || CurrentInstrSet() != InstrSet_ARM) then |
11278 | // UNPREDICTABLE; |
11279 | if ((n == 15) && (wback || (CurrentInstrSet() != eModeARM))) |
11280 | return false; |
11281 | |
11282 | // if regs == 0 || (d+regs) > 32 then UNPREDICTABLE; |
11283 | if ((regs == 0) || ((d + regs) > 32)) |
11284 | return false; |
11285 | break; |
11286 | |
11287 | default: |
11288 | return false; |
11289 | } |
11290 | |
11291 | uint32_t Rn = ReadCoreReg(regnum: n, success: &success); |
11292 | if (!success) |
11293 | return false; |
11294 | |
11295 | // address = if add then R[n] else R[n]-imm32; |
11296 | addr_t address; |
11297 | if (add) |
11298 | address = Rn; |
11299 | else |
11300 | address = Rn - imm32; |
11301 | |
11302 | // if wback then R[n] = if add then R[n]+imm32 else R[n]-imm32; |
11303 | EmulateInstruction::Context context; |
11304 | |
11305 | if (wback) { |
11306 | uint32_t value; |
11307 | if (add) |
11308 | value = Rn + imm32; |
11309 | else |
11310 | value = Rn - imm32; |
11311 | |
11312 | context.type = eContextAdjustBaseRegister; |
11313 | context.SetImmediateSigned(value - Rn); |
11314 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n, |
11315 | reg_value: value)) |
11316 | return false; |
11317 | } |
11318 | |
11319 | const uint32_t addr_byte_size = GetAddressByteSize(); |
11320 | uint32_t start_reg = single_regs ? dwarf_s0 : dwarf_d0; |
11321 | |
11322 | context.type = eContextRegisterLoad; |
11323 | |
11324 | std::optional<RegisterInfo> base_reg = |
11325 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n); |
11326 | |
11327 | // for r = 0 to regs-1 |
11328 | for (uint32_t r = 0; r < regs; ++r) { |
11329 | if (single_regs) { |
11330 | // S[d+r] = MemA[address,4]; address = address+4; |
11331 | context.SetRegisterPlusOffset(base_reg: *base_reg, signed_offset: address - Rn); |
11332 | |
11333 | uint32_t data = MemARead(context, address, size: addr_byte_size, fail_value: 0, success_ptr: &success); |
11334 | if (!success) |
11335 | return false; |
11336 | |
11337 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, |
11338 | reg_num: start_reg + d + r, reg_value: data)) |
11339 | return false; |
11340 | |
11341 | address = address + 4; |
11342 | } else { |
11343 | // word1 = MemA[address,4]; word2 = MemA[address+4,4]; address = |
11344 | // address+8; |
11345 | context.SetRegisterPlusOffset(base_reg: *base_reg, signed_offset: address - Rn); |
11346 | uint32_t word1 = |
11347 | MemARead(context, address, size: addr_byte_size, fail_value: 0, success_ptr: &success); |
11348 | if (!success) |
11349 | return false; |
11350 | |
11351 | context.SetRegisterPlusOffset(base_reg: *base_reg, signed_offset: (address + 4) - Rn); |
11352 | uint32_t word2 = |
11353 | MemARead(context, address: address + 4, size: addr_byte_size, fail_value: 0, success_ptr: &success); |
11354 | if (!success) |
11355 | return false; |
11356 | |
11357 | address = address + 8; |
11358 | // // Combine the word-aligned words in the correct order for current |
11359 | // endianness. |
11360 | // D[d+r] = if BigEndian() then word1:word2 else word2:word1; |
11361 | uint64_t data; |
11362 | if (GetByteOrder() == eByteOrderBig) { |
11363 | data = word1; |
11364 | data = (data << 32) | word2; |
11365 | } else { |
11366 | data = word2; |
11367 | data = (data << 32) | word1; |
11368 | } |
11369 | |
11370 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, |
11371 | reg_num: start_reg + d + r, reg_value: data)) |
11372 | return false; |
11373 | } |
11374 | } |
11375 | } |
11376 | return true; |
11377 | } |
11378 | |
11379 | // A8.6.399 VSTM |
11380 | // Vector Store Multiple stores multiple extension registers to consecutive |
11381 | // memory locations using an address from an |
11382 | // ARM core register. |
11383 | bool EmulateInstructionARM::EmulateVSTM(const uint32_t opcode, |
11384 | const ARMEncoding encoding) { |
11385 | #if 0 |
11386 | if ConditionPassed() then |
11387 | EncodingSpecificOperations(); CheckVFPEnabled(TRUE); NullCheckIfThumbEE(n); |
11388 | address = if add then R[n] else R[n]-imm32; |
11389 | if wback then R[n] = if add then R[n]+imm32 else R[n]-imm32; |
11390 | for r = 0 to regs-1 |
11391 | if single_regs then |
11392 | MemA[address,4] = S[d+r]; address = address+4; |
11393 | else |
11394 | // Store as two word-aligned words in the correct order for |
11395 | // current endianness. |
11396 | MemA[address,4] = if BigEndian() then D[d+r]<63:32> else D[d+r]<31:0>; |
11397 | MemA[address+4,4] = if BigEndian() then D[d+r]<31:0> else D[d+r]<63:32>; |
11398 | address = address+8; |
11399 | #endif |
11400 | |
11401 | bool success = false; |
11402 | |
11403 | if (ConditionPassed(opcode)) { |
11404 | bool single_regs; |
11405 | bool add; |
11406 | bool wback; |
11407 | uint32_t d; |
11408 | uint32_t n; |
11409 | uint32_t imm32; |
11410 | uint32_t regs; |
11411 | |
11412 | switch (encoding) { |
11413 | case eEncodingT1: |
11414 | case eEncodingA1: |
11415 | // if P == '0' && U == '0' && W == '0' then SEE 'Related encodings'; |
11416 | // if P == '1' && U == '0' && W == '1' && Rn == '1101' then SEE VPUSH; |
11417 | // if P == '1' && W == '0' then SEE VSTR; |
11418 | // if P == U && W == '1' then UNDEFINED; |
11419 | if ((Bit32(bits: opcode, bit: 24) == Bit32(bits: opcode, bit: 23)) && BitIsSet(value: opcode, bit: 21)) |
11420 | return false; |
11421 | |
11422 | // // Remaining combinations are PUW = 010 (IA without !), 011 (IA with |
11423 | // !), 101 (DB with !) |
11424 | // single_regs = FALSE; add = (U == '1'); wback = (W == '1'); |
11425 | single_regs = false; |
11426 | add = BitIsSet(value: opcode, bit: 23); |
11427 | wback = BitIsSet(value: opcode, bit: 21); |
11428 | |
11429 | // d = UInt(D:Vd); n = UInt(Rn); imm32 = ZeroExtend(imm8:'00', 32); |
11430 | d = (Bit32(bits: opcode, bit: 22) << 4) | Bits32(bits: opcode, msbit: 15, lsbit: 12); |
11431 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
11432 | imm32 = Bits32(bits: opcode, msbit: 7, lsbit: 0) << 2; |
11433 | |
11434 | // regs = UInt(imm8) DIV 2; // If UInt(imm8) is odd, see 'FSTMX'. |
11435 | regs = Bits32(bits: opcode, msbit: 7, lsbit: 0) / 2; |
11436 | |
11437 | // if n == 15 && (wback || CurrentInstrSet() != InstrSet_ARM) then |
11438 | // UNPREDICTABLE; |
11439 | if ((n == 15) && (wback || (CurrentInstrSet() != eModeARM))) |
11440 | return false; |
11441 | |
11442 | // if regs == 0 || regs > 16 || (d+regs) > 32 then UNPREDICTABLE; |
11443 | if ((regs == 0) || (regs > 16) || ((d + regs) > 32)) |
11444 | return false; |
11445 | |
11446 | break; |
11447 | |
11448 | case eEncodingT2: |
11449 | case eEncodingA2: |
11450 | // if P == '0' && U == '0' && W == '0' then SEE 'Related encodings'; |
11451 | // if P == '1' && U == '0' && W == '1' && Rn == '1101' then SEE VPUSH; |
11452 | // if P == '1' && W == '0' then SEE VSTR; |
11453 | // if P == U && W == '1' then UNDEFINED; |
11454 | if ((Bit32(bits: opcode, bit: 24) == Bit32(bits: opcode, bit: 23)) && BitIsSet(value: opcode, bit: 21)) |
11455 | return false; |
11456 | |
11457 | // // Remaining combinations are PUW = 010 (IA without !), 011 (IA with |
11458 | // !), 101 (DB with !) single_regs = TRUE; add = (U == '1'); wback = (W |
11459 | // == '1'); d = |
11460 | // UInt(Vd:D); n = UInt(Rn); |
11461 | single_regs = true; |
11462 | add = BitIsSet(value: opcode, bit: 23); |
11463 | wback = BitIsSet(value: opcode, bit: 21); |
11464 | d = (Bits32(bits: opcode, msbit: 15, lsbit: 12) << 1) | Bit32(bits: opcode, bit: 22); |
11465 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
11466 | |
11467 | // imm32 = ZeroExtend(imm8:'00', 32); regs = UInt(imm8); |
11468 | imm32 = Bits32(bits: opcode, msbit: 7, lsbit: 0) << 2; |
11469 | regs = Bits32(bits: opcode, msbit: 7, lsbit: 0); |
11470 | |
11471 | // if n == 15 && (wback || CurrentInstrSet() != InstrSet_ARM) then |
11472 | // UNPREDICTABLE; |
11473 | if ((n == 15) && (wback || (CurrentInstrSet() != eModeARM))) |
11474 | return false; |
11475 | |
11476 | // if regs == 0 || (d+regs) > 32 then UNPREDICTABLE; |
11477 | if ((regs == 0) || ((d + regs) > 32)) |
11478 | return false; |
11479 | |
11480 | break; |
11481 | |
11482 | default: |
11483 | return false; |
11484 | } |
11485 | |
11486 | std::optional<RegisterInfo> base_reg = |
11487 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n); |
11488 | |
11489 | uint32_t Rn = ReadCoreReg(regnum: n, success: &success); |
11490 | if (!success) |
11491 | return false; |
11492 | |
11493 | // address = if add then R[n] else R[n]-imm32; |
11494 | addr_t address; |
11495 | if (add) |
11496 | address = Rn; |
11497 | else |
11498 | address = Rn - imm32; |
11499 | |
11500 | EmulateInstruction::Context context; |
11501 | // if wback then R[n] = if add then R[n]+imm32 else R[n]-imm32; |
11502 | if (wback) { |
11503 | uint32_t value; |
11504 | if (add) |
11505 | value = Rn + imm32; |
11506 | else |
11507 | value = Rn - imm32; |
11508 | |
11509 | context.type = eContextAdjustBaseRegister; |
11510 | context.SetRegisterPlusOffset(base_reg: *base_reg, signed_offset: value - Rn); |
11511 | |
11512 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n, |
11513 | reg_value: value)) |
11514 | return false; |
11515 | } |
11516 | |
11517 | const uint32_t addr_byte_size = GetAddressByteSize(); |
11518 | uint32_t start_reg = single_regs ? dwarf_s0 : dwarf_d0; |
11519 | |
11520 | context.type = eContextRegisterStore; |
11521 | // for r = 0 to regs-1 |
11522 | for (uint32_t r = 0; r < regs; ++r) { |
11523 | |
11524 | if (single_regs) { |
11525 | // MemA[address,4] = S[d+r]; address = address+4; |
11526 | uint32_t data = ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, |
11527 | reg_num: start_reg + d + r, fail_value: 0, success_ptr: &success); |
11528 | if (!success) |
11529 | return false; |
11530 | |
11531 | std::optional<RegisterInfo> data_reg = |
11532 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: start_reg + d + r); |
11533 | context.SetRegisterToRegisterPlusOffset(data_reg: *data_reg, base_reg: *base_reg, |
11534 | offset: address - Rn); |
11535 | if (!MemAWrite(context, address, data_val: data, size: addr_byte_size)) |
11536 | return false; |
11537 | |
11538 | address = address + 4; |
11539 | } else { |
11540 | // // Store as two word-aligned words in the correct order for current |
11541 | // endianness. MemA[address,4] = if BigEndian() then D[d+r]<63:32> else |
11542 | // D[d+r]<31:0>; |
11543 | // MemA[address+4,4] = if BigEndian() then D[d+r]<31:0> else |
11544 | // D[d+r]<63:32>; |
11545 | uint64_t data = ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, |
11546 | reg_num: start_reg + d + r, fail_value: 0, success_ptr: &success); |
11547 | if (!success) |
11548 | return false; |
11549 | |
11550 | std::optional<RegisterInfo> data_reg = |
11551 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: start_reg + d + r); |
11552 | |
11553 | if (GetByteOrder() == eByteOrderBig) { |
11554 | context.SetRegisterToRegisterPlusOffset(data_reg: *data_reg, base_reg: *base_reg, |
11555 | offset: address - Rn); |
11556 | if (!MemAWrite(context, address, data_val: Bits64(bits: data, msbit: 63, lsbit: 32), |
11557 | size: addr_byte_size)) |
11558 | return false; |
11559 | |
11560 | context.SetRegisterToRegisterPlusOffset(data_reg: *data_reg, base_reg: *base_reg, |
11561 | offset: (address + 4) - Rn); |
11562 | if (!MemAWrite(context, address: address + 4, data_val: Bits64(bits: data, msbit: 31, lsbit: 0), |
11563 | size: addr_byte_size)) |
11564 | return false; |
11565 | } else { |
11566 | context.SetRegisterToRegisterPlusOffset(data_reg: *data_reg, base_reg: *base_reg, |
11567 | offset: address - Rn); |
11568 | if (!MemAWrite(context, address, data_val: Bits64(bits: data, msbit: 31, lsbit: 0), size: addr_byte_size)) |
11569 | return false; |
11570 | |
11571 | context.SetRegisterToRegisterPlusOffset(data_reg: *data_reg, base_reg: *base_reg, |
11572 | offset: (address + 4) - Rn); |
11573 | if (!MemAWrite(context, address: address + 4, data_val: Bits64(bits: data, msbit: 63, lsbit: 32), |
11574 | size: addr_byte_size)) |
11575 | return false; |
11576 | } |
11577 | // address = address+8; |
11578 | address = address + 8; |
11579 | } |
11580 | } |
11581 | } |
11582 | return true; |
11583 | } |
11584 | |
11585 | // A8.6.320 |
11586 | // This instruction loads a single extension register from memory, using an |
11587 | // address from an ARM core register, with an optional offset. |
11588 | bool EmulateInstructionARM::EmulateVLDR(const uint32_t opcode, |
11589 | ARMEncoding encoding) { |
11590 | #if 0 |
11591 | if ConditionPassed() then |
11592 | EncodingSpecificOperations(); CheckVFPEnabled(TRUE); NullCheckIfThumbEE(n); |
11593 | base = if n == 15 then Align(PC,4) else R[n]; |
11594 | address = if add then (base + imm32) else (base - imm32); |
11595 | if single_reg then |
11596 | S[d] = MemA[address,4]; |
11597 | else |
11598 | word1 = MemA[address,4]; word2 = MemA[address+4,4]; |
11599 | // Combine the word-aligned words in the correct order for current |
11600 | // endianness. |
11601 | D[d] = if BigEndian() then word1:word2 else word2:word1; |
11602 | #endif |
11603 | |
11604 | bool success = false; |
11605 | |
11606 | if (ConditionPassed(opcode)) { |
11607 | bool single_reg; |
11608 | bool add; |
11609 | uint32_t imm32; |
11610 | uint32_t d; |
11611 | uint32_t n; |
11612 | |
11613 | switch (encoding) { |
11614 | case eEncodingT1: |
11615 | case eEncodingA1: |
11616 | // single_reg = FALSE; add = (U == '1'); imm32 = ZeroExtend(imm8:'00', |
11617 | // 32); |
11618 | single_reg = false; |
11619 | add = BitIsSet(value: opcode, bit: 23); |
11620 | imm32 = Bits32(bits: opcode, msbit: 7, lsbit: 0) << 2; |
11621 | |
11622 | // d = UInt(D:Vd); n = UInt(Rn); |
11623 | d = (Bit32(bits: opcode, bit: 22) << 4) | Bits32(bits: opcode, msbit: 15, lsbit: 12); |
11624 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
11625 | |
11626 | break; |
11627 | |
11628 | case eEncodingT2: |
11629 | case eEncodingA2: |
11630 | // single_reg = TRUE; add = (U == '1'); imm32 = ZeroExtend(imm8:'00', 32); |
11631 | single_reg = true; |
11632 | add = BitIsSet(value: opcode, bit: 23); |
11633 | imm32 = Bits32(bits: opcode, msbit: 7, lsbit: 0) << 2; |
11634 | |
11635 | // d = UInt(Vd:D); n = UInt(Rn); |
11636 | d = (Bits32(bits: opcode, msbit: 15, lsbit: 12) << 1) | Bit32(bits: opcode, bit: 22); |
11637 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
11638 | |
11639 | break; |
11640 | |
11641 | default: |
11642 | return false; |
11643 | } |
11644 | std::optional<RegisterInfo> base_reg = |
11645 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n); |
11646 | |
11647 | uint32_t Rn = ReadCoreReg(regnum: n, success: &success); |
11648 | if (!success) |
11649 | return false; |
11650 | |
11651 | // base = if n == 15 then Align(PC,4) else R[n]; |
11652 | uint32_t base; |
11653 | if (n == 15) |
11654 | base = AlignPC(Rn); |
11655 | else |
11656 | base = Rn; |
11657 | |
11658 | // address = if add then (base + imm32) else (base - imm32); |
11659 | addr_t address; |
11660 | if (add) |
11661 | address = base + imm32; |
11662 | else |
11663 | address = base - imm32; |
11664 | |
11665 | const uint32_t addr_byte_size = GetAddressByteSize(); |
11666 | uint32_t start_reg = single_reg ? dwarf_s0 : dwarf_d0; |
11667 | |
11668 | EmulateInstruction::Context context; |
11669 | context.type = eContextRegisterLoad; |
11670 | context.SetRegisterPlusOffset(base_reg: *base_reg, signed_offset: address - base); |
11671 | |
11672 | if (single_reg) { |
11673 | // S[d] = MemA[address,4]; |
11674 | uint32_t data = MemARead(context, address, size: addr_byte_size, fail_value: 0, success_ptr: &success); |
11675 | if (!success) |
11676 | return false; |
11677 | |
11678 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: start_reg + d, |
11679 | reg_value: data)) |
11680 | return false; |
11681 | } else { |
11682 | // word1 = MemA[address,4]; word2 = MemA[address+4,4]; |
11683 | uint32_t word1 = MemARead(context, address, size: addr_byte_size, fail_value: 0, success_ptr: &success); |
11684 | if (!success) |
11685 | return false; |
11686 | |
11687 | context.SetRegisterPlusOffset(base_reg: *base_reg, signed_offset: (address + 4) - base); |
11688 | uint32_t word2 = |
11689 | MemARead(context, address: address + 4, size: addr_byte_size, fail_value: 0, success_ptr: &success); |
11690 | if (!success) |
11691 | return false; |
11692 | // // Combine the word-aligned words in the correct order for current |
11693 | // endianness. |
11694 | // D[d] = if BigEndian() then word1:word2 else word2:word1; |
11695 | uint64_t data64; |
11696 | if (GetByteOrder() == eByteOrderBig) { |
11697 | data64 = word1; |
11698 | data64 = (data64 << 32) | word2; |
11699 | } else { |
11700 | data64 = word2; |
11701 | data64 = (data64 << 32) | word1; |
11702 | } |
11703 | |
11704 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: start_reg + d, |
11705 | reg_value: data64)) |
11706 | return false; |
11707 | } |
11708 | } |
11709 | return true; |
11710 | } |
11711 | |
11712 | // A8.6.400 VSTR |
11713 | // This instruction stores a signle extension register to memory, using an |
11714 | // address from an ARM core register, with an optional offset. |
11715 | bool EmulateInstructionARM::EmulateVSTR(const uint32_t opcode, |
11716 | ARMEncoding encoding) { |
11717 | #if 0 |
11718 | if ConditionPassed() then |
11719 | EncodingSpecificOperations(); CheckVFPEnabled(TRUE); NullCheckIfThumbEE(n); |
11720 | address = if add then (R[n] + imm32) else (R[n] - imm32); |
11721 | if single_reg then |
11722 | MemA[address,4] = S[d]; |
11723 | else |
11724 | // Store as two word-aligned words in the correct order for current |
11725 | // endianness. |
11726 | MemA[address,4] = if BigEndian() then D[d]<63:32> else D[d]<31:0>; |
11727 | MemA[address+4,4] = if BigEndian() then D[d]<31:0> else D[d]<63:32>; |
11728 | #endif |
11729 | |
11730 | bool success = false; |
11731 | |
11732 | if (ConditionPassed(opcode)) { |
11733 | bool single_reg; |
11734 | bool add; |
11735 | uint32_t imm32; |
11736 | uint32_t d; |
11737 | uint32_t n; |
11738 | |
11739 | switch (encoding) { |
11740 | case eEncodingT1: |
11741 | case eEncodingA1: |
11742 | // single_reg = FALSE; add = (U == '1'); imm32 = ZeroExtend(imm8:'00', |
11743 | // 32); |
11744 | single_reg = false; |
11745 | add = BitIsSet(value: opcode, bit: 23); |
11746 | imm32 = Bits32(bits: opcode, msbit: 7, lsbit: 0) << 2; |
11747 | |
11748 | // d = UInt(D:Vd); n = UInt(Rn); |
11749 | d = (Bit32(bits: opcode, bit: 22) << 4) | Bits32(bits: opcode, msbit: 15, lsbit: 12); |
11750 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
11751 | |
11752 | // if n == 15 && CurrentInstrSet() != InstrSet_ARM then UNPREDICTABLE; |
11753 | if ((n == 15) && (CurrentInstrSet() != eModeARM)) |
11754 | return false; |
11755 | |
11756 | break; |
11757 | |
11758 | case eEncodingT2: |
11759 | case eEncodingA2: |
11760 | // single_reg = TRUE; add = (U == '1'); imm32 = ZeroExtend(imm8:'00', 32); |
11761 | single_reg = true; |
11762 | add = BitIsSet(value: opcode, bit: 23); |
11763 | imm32 = Bits32(bits: opcode, msbit: 7, lsbit: 0) << 2; |
11764 | |
11765 | // d = UInt(Vd:D); n = UInt(Rn); |
11766 | d = (Bits32(bits: opcode, msbit: 15, lsbit: 12) << 1) | Bit32(bits: opcode, bit: 22); |
11767 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
11768 | |
11769 | // if n == 15 && CurrentInstrSet() != InstrSet_ARM then UNPREDICTABLE; |
11770 | if ((n == 15) && (CurrentInstrSet() != eModeARM)) |
11771 | return false; |
11772 | |
11773 | break; |
11774 | |
11775 | default: |
11776 | return false; |
11777 | } |
11778 | |
11779 | uint32_t Rn = ReadCoreReg(regnum: n, success: &success); |
11780 | if (!success) |
11781 | return false; |
11782 | |
11783 | // address = if add then (R[n] + imm32) else (R[n] - imm32); |
11784 | addr_t address; |
11785 | if (add) |
11786 | address = Rn + imm32; |
11787 | else |
11788 | address = Rn - imm32; |
11789 | |
11790 | const uint32_t addr_byte_size = GetAddressByteSize(); |
11791 | uint32_t start_reg = single_reg ? dwarf_s0 : dwarf_d0; |
11792 | |
11793 | std::optional<RegisterInfo> base_reg = |
11794 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n); |
11795 | std::optional<RegisterInfo> data_reg = |
11796 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: start_reg + d); |
11797 | EmulateInstruction::Context context; |
11798 | context.type = eContextRegisterStore; |
11799 | context.SetRegisterToRegisterPlusOffset(data_reg: *data_reg, base_reg: *base_reg, offset: address - Rn); |
11800 | |
11801 | if (single_reg) { |
11802 | // MemA[address,4] = S[d]; |
11803 | uint32_t data = |
11804 | ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: start_reg + d, fail_value: 0, success_ptr: &success); |
11805 | if (!success) |
11806 | return false; |
11807 | |
11808 | if (!MemAWrite(context, address, data_val: data, size: addr_byte_size)) |
11809 | return false; |
11810 | } else { |
11811 | // // Store as two word-aligned words in the correct order for current |
11812 | // endianness. |
11813 | // MemA[address,4] = if BigEndian() then D[d]<63:32> else D[d]<31:0>; |
11814 | // MemA[address+4,4] = if BigEndian() then D[d]<31:0> else D[d]<63:32>; |
11815 | uint64_t data = |
11816 | ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: start_reg + d, fail_value: 0, success_ptr: &success); |
11817 | if (!success) |
11818 | return false; |
11819 | |
11820 | if (GetByteOrder() == eByteOrderBig) { |
11821 | if (!MemAWrite(context, address, data_val: Bits64(bits: data, msbit: 63, lsbit: 32), size: addr_byte_size)) |
11822 | return false; |
11823 | |
11824 | context.SetRegisterToRegisterPlusOffset(data_reg: *data_reg, base_reg: *base_reg, |
11825 | offset: (address + 4) - Rn); |
11826 | if (!MemAWrite(context, address: address + 4, data_val: Bits64(bits: data, msbit: 31, lsbit: 0), |
11827 | size: addr_byte_size)) |
11828 | return false; |
11829 | } else { |
11830 | if (!MemAWrite(context, address, data_val: Bits64(bits: data, msbit: 31, lsbit: 0), size: addr_byte_size)) |
11831 | return false; |
11832 | |
11833 | context.SetRegisterToRegisterPlusOffset(data_reg: *data_reg, base_reg: *base_reg, |
11834 | offset: (address + 4) - Rn); |
11835 | if (!MemAWrite(context, address: address + 4, data_val: Bits64(bits: data, msbit: 63, lsbit: 32), |
11836 | size: addr_byte_size)) |
11837 | return false; |
11838 | } |
11839 | } |
11840 | } |
11841 | return true; |
11842 | } |
11843 | |
11844 | // A8.6.307 VLDI1 (multiple single elements) This instruction loads elements |
11845 | // from memory into one, two, three or four registers, without de-interleaving. |
11846 | // Every element of each register is loaded. |
11847 | bool EmulateInstructionARM::EmulateVLD1Multiple(const uint32_t opcode, |
11848 | ARMEncoding encoding) { |
11849 | #if 0 |
11850 | if ConditionPassed() then |
11851 | EncodingSpecificOperations(); CheckAdvSIMDEnabled(); NullCheckIfThumbEE(n); |
11852 | address = R[n]; if (address MOD alignment) != 0 then GenerateAlignmentException(); |
11853 | if wback then R[n] = R[n] + (if register_index then R[m] else 8*regs); |
11854 | for r = 0 to regs-1 |
11855 | for e = 0 to elements-1 |
11856 | Elem[D[d+r],e,esize] = MemU[address,ebytes]; |
11857 | address = address + ebytes; |
11858 | #endif |
11859 | |
11860 | bool success = false; |
11861 | |
11862 | if (ConditionPassed(opcode)) { |
11863 | uint32_t regs; |
11864 | uint32_t alignment; |
11865 | uint32_t ebytes; |
11866 | uint32_t esize; |
11867 | uint32_t elements; |
11868 | uint32_t d; |
11869 | uint32_t n; |
11870 | uint32_t m; |
11871 | bool wback; |
11872 | bool register_index; |
11873 | |
11874 | switch (encoding) { |
11875 | case eEncodingT1: |
11876 | case eEncodingA1: { |
11877 | // case type of |
11878 | // when '0111' |
11879 | // regs = 1; if align<1> == '1' then UNDEFINED; |
11880 | // when '1010' |
11881 | // regs = 2; if align == '11' then UNDEFINED; |
11882 | // when '0110' |
11883 | // regs = 3; if align<1> == '1' then UNDEFINED; |
11884 | // when '0010' |
11885 | // regs = 4; |
11886 | // otherwise |
11887 | // SEE 'Related encodings'; |
11888 | uint32_t type = Bits32(bits: opcode, msbit: 11, lsbit: 8); |
11889 | uint32_t align = Bits32(bits: opcode, msbit: 5, lsbit: 4); |
11890 | if (type == 7) // '0111' |
11891 | { |
11892 | regs = 1; |
11893 | if (BitIsSet(value: align, bit: 1)) |
11894 | return false; |
11895 | } else if (type == 10) // '1010' |
11896 | { |
11897 | regs = 2; |
11898 | if (align == 3) |
11899 | return false; |
11900 | |
11901 | } else if (type == 6) // '0110' |
11902 | { |
11903 | regs = 3; |
11904 | if (BitIsSet(value: align, bit: 1)) |
11905 | return false; |
11906 | } else if (type == 2) // '0010' |
11907 | { |
11908 | regs = 4; |
11909 | } else |
11910 | return false; |
11911 | |
11912 | // alignment = if align == '00' then 1 else 4 << UInt(align); |
11913 | if (align == 0) |
11914 | alignment = 1; |
11915 | else |
11916 | alignment = 4 << align; |
11917 | |
11918 | // ebytes = 1 << UInt(size); esize = 8 * ebytes; elements = 8 DIV ebytes; |
11919 | ebytes = 1 << Bits32(bits: opcode, msbit: 7, lsbit: 6); |
11920 | esize = 8 * ebytes; |
11921 | elements = 8 / ebytes; |
11922 | |
11923 | // d = UInt(D:Vd); n = UInt(Rn); m = UInt(Rm); |
11924 | d = (Bit32(bits: opcode, bit: 22) << 4) | Bits32(bits: opcode, msbit: 15, lsbit: 12); |
11925 | n = Bits32(bits: opcode, msbit: 19, lsbit: 15); |
11926 | m = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
11927 | |
11928 | // wback = (m != 15); register_index = (m != 15 && m != 13); |
11929 | wback = (m != 15); |
11930 | register_index = ((m != 15) && (m != 13)); |
11931 | |
11932 | // if d+regs > 32 then UNPREDICTABLE; |
11933 | if ((d + regs) > 32) |
11934 | return false; |
11935 | } break; |
11936 | |
11937 | default: |
11938 | return false; |
11939 | } |
11940 | |
11941 | std::optional<RegisterInfo> base_reg = |
11942 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n); |
11943 | |
11944 | uint32_t Rn = ReadCoreReg(regnum: n, success: &success); |
11945 | if (!success) |
11946 | return false; |
11947 | |
11948 | // address = R[n]; if (address MOD alignment) != 0 then |
11949 | // GenerateAlignmentException(); |
11950 | addr_t address = Rn; |
11951 | if ((address % alignment) != 0) |
11952 | return false; |
11953 | |
11954 | EmulateInstruction::Context context; |
11955 | // if wback then R[n] = R[n] + (if register_index then R[m] else 8*regs); |
11956 | if (wback) { |
11957 | uint32_t Rm = ReadCoreReg(regnum: m, success: &success); |
11958 | if (!success) |
11959 | return false; |
11960 | |
11961 | uint32_t offset; |
11962 | if (register_index) |
11963 | offset = Rm; |
11964 | else |
11965 | offset = 8 * regs; |
11966 | |
11967 | uint32_t value = Rn + offset; |
11968 | context.type = eContextAdjustBaseRegister; |
11969 | context.SetRegisterPlusOffset(base_reg: *base_reg, signed_offset: offset); |
11970 | |
11971 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n, |
11972 | reg_value: value)) |
11973 | return false; |
11974 | } |
11975 | |
11976 | // for r = 0 to regs-1 |
11977 | for (uint32_t r = 0; r < regs; ++r) { |
11978 | // for e = 0 to elements-1 |
11979 | uint64_t assembled_data = 0; |
11980 | for (uint32_t e = 0; e < elements; ++e) { |
11981 | // Elem[D[d+r],e,esize] = MemU[address,ebytes]; |
11982 | context.type = eContextRegisterLoad; |
11983 | context.SetRegisterPlusOffset(base_reg: *base_reg, signed_offset: address - Rn); |
11984 | uint64_t data = MemURead(context, address, size: ebytes, fail_value: 0, success_ptr: &success); |
11985 | if (!success) |
11986 | return false; |
11987 | |
11988 | assembled_data = |
11989 | (data << (e * esize)) | |
11990 | assembled_data; // New data goes to the left of existing data |
11991 | |
11992 | // address = address + ebytes; |
11993 | address = address + ebytes; |
11994 | } |
11995 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_d0 + d + r, |
11996 | reg_value: assembled_data)) |
11997 | return false; |
11998 | } |
11999 | } |
12000 | return true; |
12001 | } |
12002 | |
12003 | // A8.6.308 VLD1 (single element to one lane) |
12004 | // |
12005 | bool EmulateInstructionARM::EmulateVLD1Single(const uint32_t opcode, |
12006 | const ARMEncoding encoding) { |
12007 | #if 0 |
12008 | if ConditionPassed() then |
12009 | EncodingSpecificOperations(); CheckAdvSIMDEnabled(); NullCheckIfThumbEE(n); |
12010 | address = R[n]; if (address MOD alignment) != 0 then GenerateAlignmentException(); |
12011 | if wback then R[n] = R[n] + (if register_index then R[m] else ebytes); |
12012 | Elem[D[d],index,esize] = MemU[address,ebytes]; |
12013 | #endif |
12014 | |
12015 | bool success = false; |
12016 | |
12017 | if (ConditionPassed(opcode)) { |
12018 | uint32_t ebytes; |
12019 | uint32_t esize; |
12020 | uint32_t index; |
12021 | uint32_t alignment; |
12022 | uint32_t d; |
12023 | uint32_t n; |
12024 | uint32_t m; |
12025 | bool wback; |
12026 | bool register_index; |
12027 | |
12028 | switch (encoding) { |
12029 | case eEncodingT1: |
12030 | case eEncodingA1: { |
12031 | uint32_t size = Bits32(bits: opcode, msbit: 11, lsbit: 10); |
12032 | uint32_t index_align = Bits32(bits: opcode, msbit: 7, lsbit: 4); |
12033 | // if size == '11' then SEE VLD1 (single element to all lanes); |
12034 | if (size == 3) |
12035 | return EmulateVLD1SingleAll(opcode, encoding); |
12036 | // case size of |
12037 | if (size == 0) // when '00' |
12038 | { |
12039 | // if index_align<0> != '0' then UNDEFINED; |
12040 | if (BitIsClear(value: index_align, bit: 0)) |
12041 | return false; |
12042 | |
12043 | // ebytes = 1; esize = 8; index = UInt(index_align<3:1>); alignment = 1; |
12044 | ebytes = 1; |
12045 | esize = 8; |
12046 | index = Bits32(bits: index_align, msbit: 3, lsbit: 1); |
12047 | alignment = 1; |
12048 | } else if (size == 1) // when '01' |
12049 | { |
12050 | // if index_align<1> != '0' then UNDEFINED; |
12051 | if (BitIsClear(value: index_align, bit: 1)) |
12052 | return false; |
12053 | |
12054 | // ebytes = 2; esize = 16; index = UInt(index_align<3:2>); |
12055 | ebytes = 2; |
12056 | esize = 16; |
12057 | index = Bits32(bits: index_align, msbit: 3, lsbit: 2); |
12058 | |
12059 | // alignment = if index_align<0> == '0' then 1 else 2; |
12060 | if (BitIsClear(value: index_align, bit: 0)) |
12061 | alignment = 1; |
12062 | else |
12063 | alignment = 2; |
12064 | } else if (size == 2) // when '10' |
12065 | { |
12066 | // if index_align<2> != '0' then UNDEFINED; |
12067 | if (BitIsClear(value: index_align, bit: 2)) |
12068 | return false; |
12069 | |
12070 | // if index_align<1:0> != '00' && index_align<1:0> != '11' then |
12071 | // UNDEFINED; |
12072 | if ((Bits32(bits: index_align, msbit: 1, lsbit: 0) != 0) && |
12073 | (Bits32(bits: index_align, msbit: 1, lsbit: 0) != 3)) |
12074 | return false; |
12075 | |
12076 | // ebytes = 4; esize = 32; index = UInt(index_align<3>); |
12077 | ebytes = 4; |
12078 | esize = 32; |
12079 | index = Bit32(bits: index_align, bit: 3); |
12080 | |
12081 | // alignment = if index_align<1:0> == '00' then 1 else 4; |
12082 | if (Bits32(bits: index_align, msbit: 1, lsbit: 0) == 0) |
12083 | alignment = 1; |
12084 | else |
12085 | alignment = 4; |
12086 | } else { |
12087 | return false; |
12088 | } |
12089 | // d = UInt(D:Vd); n = UInt(Rn); m = UInt(Rm); |
12090 | d = (Bit32(bits: opcode, bit: 22) << 4) | Bits32(bits: opcode, msbit: 15, lsbit: 12); |
12091 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
12092 | m = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
12093 | |
12094 | // wback = (m != 15); register_index = (m != 15 && m != 13); if n == 15 |
12095 | // then UNPREDICTABLE; |
12096 | wback = (m != 15); |
12097 | register_index = ((m != 15) && (m != 13)); |
12098 | |
12099 | if (n == 15) |
12100 | return false; |
12101 | |
12102 | } break; |
12103 | |
12104 | default: |
12105 | return false; |
12106 | } |
12107 | |
12108 | uint32_t Rn = ReadCoreReg(regnum: n, success: &success); |
12109 | if (!success) |
12110 | return false; |
12111 | |
12112 | // address = R[n]; if (address MOD alignment) != 0 then |
12113 | // GenerateAlignmentException(); |
12114 | addr_t address = Rn; |
12115 | if ((address % alignment) != 0) |
12116 | return false; |
12117 | |
12118 | EmulateInstruction::Context context; |
12119 | // if wback then R[n] = R[n] + (if register_index then R[m] else ebytes); |
12120 | if (wback) { |
12121 | uint32_t Rm = ReadCoreReg(regnum: m, success: &success); |
12122 | if (!success) |
12123 | return false; |
12124 | |
12125 | uint32_t offset; |
12126 | if (register_index) |
12127 | offset = Rm; |
12128 | else |
12129 | offset = ebytes; |
12130 | |
12131 | uint32_t value = Rn + offset; |
12132 | |
12133 | context.type = eContextAdjustBaseRegister; |
12134 | std::optional<RegisterInfo> base_reg = |
12135 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n); |
12136 | context.SetRegisterPlusOffset(base_reg: *base_reg, signed_offset: offset); |
12137 | |
12138 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n, |
12139 | reg_value: value)) |
12140 | return false; |
12141 | } |
12142 | |
12143 | // Elem[D[d],index,esize] = MemU[address,ebytes]; |
12144 | uint32_t element = MemURead(context, address, size: esize, fail_value: 0, success_ptr: &success); |
12145 | if (!success) |
12146 | return false; |
12147 | |
12148 | element = element << (index * esize); |
12149 | |
12150 | uint64_t reg_data = |
12151 | ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_d0 + d, fail_value: 0, success_ptr: &success); |
12152 | if (!success) |
12153 | return false; |
12154 | |
12155 | uint64_t all_ones = -1; |
12156 | uint64_t mask = all_ones |
12157 | << ((index + 1) * esize); // mask is all 1's to left of |
12158 | // where 'element' goes, & all 0's |
12159 | // at element & to the right of element. |
12160 | if (index > 0) |
12161 | mask = mask | Bits64(bits: all_ones, msbit: (index * esize) - 1, |
12162 | lsbit: 0); // add 1's to the right of where 'element' goes. |
12163 | // now mask should be 0's where element goes & 1's everywhere else. |
12164 | |
12165 | uint64_t masked_reg = |
12166 | reg_data & mask; // Take original reg value & zero out 'element' bits |
12167 | reg_data = |
12168 | masked_reg & element; // Put 'element' into those bits in reg_data. |
12169 | |
12170 | context.type = eContextRegisterLoad; |
12171 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + d, |
12172 | reg_value: reg_data)) |
12173 | return false; |
12174 | } |
12175 | return true; |
12176 | } |
12177 | |
12178 | // A8.6.391 VST1 (multiple single elements) Vector Store (multiple single |
12179 | // elements) stores elements to memory from one, two, three, or four registers, |
12180 | // without interleaving. Every element of each register is stored. |
12181 | bool EmulateInstructionARM::EmulateVST1Multiple(const uint32_t opcode, |
12182 | ARMEncoding encoding) { |
12183 | #if 0 |
12184 | if ConditionPassed() then |
12185 | EncodingSpecificOperations(); CheckAdvSIMDEnabled(); NullCheckIfThumbEE(n); |
12186 | address = R[n]; if (address MOD alignment) != 0 then GenerateAlignmentException(); |
12187 | if wback then R[n] = R[n] + (if register_index then R[m] else 8*regs); |
12188 | for r = 0 to regs-1 |
12189 | for e = 0 to elements-1 |
12190 | MemU[address,ebytes] = Elem[D[d+r],e,esize]; |
12191 | address = address + ebytes; |
12192 | #endif |
12193 | |
12194 | bool success = false; |
12195 | |
12196 | if (ConditionPassed(opcode)) { |
12197 | uint32_t regs; |
12198 | uint32_t alignment; |
12199 | uint32_t ebytes; |
12200 | uint32_t esize; |
12201 | uint32_t elements; |
12202 | uint32_t d; |
12203 | uint32_t n; |
12204 | uint32_t m; |
12205 | bool wback; |
12206 | bool register_index; |
12207 | |
12208 | switch (encoding) { |
12209 | case eEncodingT1: |
12210 | case eEncodingA1: { |
12211 | uint32_t type = Bits32(bits: opcode, msbit: 11, lsbit: 8); |
12212 | uint32_t align = Bits32(bits: opcode, msbit: 5, lsbit: 4); |
12213 | |
12214 | // case type of |
12215 | if (type == 7) // when '0111' |
12216 | { |
12217 | // regs = 1; if align<1> == '1' then UNDEFINED; |
12218 | regs = 1; |
12219 | if (BitIsSet(value: align, bit: 1)) |
12220 | return false; |
12221 | } else if (type == 10) // when '1010' |
12222 | { |
12223 | // regs = 2; if align == '11' then UNDEFINED; |
12224 | regs = 2; |
12225 | if (align == 3) |
12226 | return false; |
12227 | } else if (type == 6) // when '0110' |
12228 | { |
12229 | // regs = 3; if align<1> == '1' then UNDEFINED; |
12230 | regs = 3; |
12231 | if (BitIsSet(value: align, bit: 1)) |
12232 | return false; |
12233 | } else if (type == 2) // when '0010' |
12234 | // regs = 4; |
12235 | regs = 4; |
12236 | else // otherwise |
12237 | // SEE 'Related encodings'; |
12238 | return false; |
12239 | |
12240 | // alignment = if align == '00' then 1 else 4 << UInt(align); |
12241 | if (align == 0) |
12242 | alignment = 1; |
12243 | else |
12244 | alignment = 4 << align; |
12245 | |
12246 | // ebytes = 1 << UInt(size); esize = 8 * ebytes; elements = 8 DIV ebytes; |
12247 | ebytes = 1 << Bits32(bits: opcode, msbit: 7, lsbit: 6); |
12248 | esize = 8 * ebytes; |
12249 | elements = 8 / ebytes; |
12250 | |
12251 | // d = UInt(D:Vd); n = UInt(Rn); m = UInt(Rm); |
12252 | d = (Bit32(bits: opcode, bit: 22) << 4) | Bits32(bits: opcode, msbit: 15, lsbit: 12); |
12253 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
12254 | m = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
12255 | |
12256 | // wback = (m != 15); register_index = (m != 15 && m != 13); |
12257 | wback = (m != 15); |
12258 | register_index = ((m != 15) && (m != 13)); |
12259 | |
12260 | // if d+regs > 32 then UNPREDICTABLE; if n == 15 then UNPREDICTABLE; |
12261 | if ((d + regs) > 32) |
12262 | return false; |
12263 | |
12264 | if (n == 15) |
12265 | return false; |
12266 | |
12267 | } break; |
12268 | |
12269 | default: |
12270 | return false; |
12271 | } |
12272 | |
12273 | std::optional<RegisterInfo> base_reg = |
12274 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n); |
12275 | |
12276 | uint32_t Rn = ReadCoreReg(regnum: n, success: &success); |
12277 | if (!success) |
12278 | return false; |
12279 | |
12280 | // address = R[n]; if (address MOD alignment) != 0 then |
12281 | // GenerateAlignmentException(); |
12282 | addr_t address = Rn; |
12283 | if ((address % alignment) != 0) |
12284 | return false; |
12285 | |
12286 | EmulateInstruction::Context context; |
12287 | // if wback then R[n] = R[n] + (if register_index then R[m] else 8*regs); |
12288 | if (wback) { |
12289 | uint32_t Rm = ReadCoreReg(regnum: m, success: &success); |
12290 | if (!success) |
12291 | return false; |
12292 | |
12293 | uint32_t offset; |
12294 | if (register_index) |
12295 | offset = Rm; |
12296 | else |
12297 | offset = 8 * regs; |
12298 | |
12299 | context.type = eContextAdjustBaseRegister; |
12300 | context.SetRegisterPlusOffset(base_reg: *base_reg, signed_offset: offset); |
12301 | |
12302 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n, |
12303 | reg_value: Rn + offset)) |
12304 | return false; |
12305 | } |
12306 | |
12307 | context.type = eContextRegisterStore; |
12308 | // for r = 0 to regs-1 |
12309 | for (uint32_t r = 0; r < regs; ++r) { |
12310 | std::optional<RegisterInfo> data_reg = |
12311 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_d0 + d + r); |
12312 | uint64_t register_data = ReadRegisterUnsigned( |
12313 | reg_kind: eRegisterKindDWARF, reg_num: dwarf_d0 + d + r, fail_value: 0, success_ptr: &success); |
12314 | if (!success) |
12315 | return false; |
12316 | |
12317 | // for e = 0 to elements-1 |
12318 | for (uint32_t e = 0; e < elements; ++e) { |
12319 | // MemU[address,ebytes] = Elem[D[d+r],e,esize]; |
12320 | uint64_t word = Bits64(bits: register_data, msbit: ((e + 1) * esize) - 1, lsbit: e * esize); |
12321 | |
12322 | context.SetRegisterToRegisterPlusOffset(data_reg: *data_reg, base_reg: *base_reg, |
12323 | offset: address - Rn); |
12324 | if (!MemUWrite(context, address, data_val: word, size: ebytes)) |
12325 | return false; |
12326 | |
12327 | // address = address + ebytes; |
12328 | address = address + ebytes; |
12329 | } |
12330 | } |
12331 | } |
12332 | return true; |
12333 | } |
12334 | |
12335 | // A8.6.392 VST1 (single element from one lane) This instruction stores one |
12336 | // element to memory from one element of a register. |
12337 | bool EmulateInstructionARM::EmulateVST1Single(const uint32_t opcode, |
12338 | ARMEncoding encoding) { |
12339 | #if 0 |
12340 | if ConditionPassed() then |
12341 | EncodingSpecificOperations(); CheckAdvSIMDEnabled(); NullCheckIfThumbEE(n); |
12342 | address = R[n]; if (address MOD alignment) != 0 then GenerateAlignmentException(); |
12343 | if wback then R[n] = R[n] + (if register_index then R[m] else ebytes); |
12344 | MemU[address,ebytes] = Elem[D[d],index,esize]; |
12345 | #endif |
12346 | |
12347 | bool success = false; |
12348 | |
12349 | if (ConditionPassed(opcode)) { |
12350 | uint32_t ebytes; |
12351 | uint32_t esize; |
12352 | uint32_t index; |
12353 | uint32_t alignment; |
12354 | uint32_t d; |
12355 | uint32_t n; |
12356 | uint32_t m; |
12357 | bool wback; |
12358 | bool register_index; |
12359 | |
12360 | switch (encoding) { |
12361 | case eEncodingT1: |
12362 | case eEncodingA1: { |
12363 | uint32_t size = Bits32(bits: opcode, msbit: 11, lsbit: 10); |
12364 | uint32_t index_align = Bits32(bits: opcode, msbit: 7, lsbit: 4); |
12365 | |
12366 | // if size == '11' then UNDEFINED; |
12367 | if (size == 3) |
12368 | return false; |
12369 | |
12370 | // case size of |
12371 | if (size == 0) // when '00' |
12372 | { |
12373 | // if index_align<0> != '0' then UNDEFINED; |
12374 | if (BitIsClear(value: index_align, bit: 0)) |
12375 | return false; |
12376 | // ebytes = 1; esize = 8; index = UInt(index_align<3:1>); alignment = 1; |
12377 | ebytes = 1; |
12378 | esize = 8; |
12379 | index = Bits32(bits: index_align, msbit: 3, lsbit: 1); |
12380 | alignment = 1; |
12381 | } else if (size == 1) // when '01' |
12382 | { |
12383 | // if index_align<1> != '0' then UNDEFINED; |
12384 | if (BitIsClear(value: index_align, bit: 1)) |
12385 | return false; |
12386 | |
12387 | // ebytes = 2; esize = 16; index = UInt(index_align<3:2>); |
12388 | ebytes = 2; |
12389 | esize = 16; |
12390 | index = Bits32(bits: index_align, msbit: 3, lsbit: 2); |
12391 | |
12392 | // alignment = if index_align<0> == '0' then 1 else 2; |
12393 | if (BitIsClear(value: index_align, bit: 0)) |
12394 | alignment = 1; |
12395 | else |
12396 | alignment = 2; |
12397 | } else if (size == 2) // when '10' |
12398 | { |
12399 | // if index_align<2> != '0' then UNDEFINED; |
12400 | if (BitIsClear(value: index_align, bit: 2)) |
12401 | return false; |
12402 | |
12403 | // if index_align<1:0> != '00' && index_align<1:0> != '11' then |
12404 | // UNDEFINED; |
12405 | if ((Bits32(bits: index_align, msbit: 1, lsbit: 0) != 0) && |
12406 | (Bits32(bits: index_align, msbit: 1, lsbit: 0) != 3)) |
12407 | return false; |
12408 | |
12409 | // ebytes = 4; esize = 32; index = UInt(index_align<3>); |
12410 | ebytes = 4; |
12411 | esize = 32; |
12412 | index = Bit32(bits: index_align, bit: 3); |
12413 | |
12414 | // alignment = if index_align<1:0> == '00' then 1 else 4; |
12415 | if (Bits32(bits: index_align, msbit: 1, lsbit: 0) == 0) |
12416 | alignment = 1; |
12417 | else |
12418 | alignment = 4; |
12419 | } else { |
12420 | return false; |
12421 | } |
12422 | // d = UInt(D:Vd); n = UInt(Rn); m = UInt(Rm); |
12423 | d = (Bit32(bits: opcode, bit: 22) << 4) | Bits32(bits: opcode, msbit: 15, lsbit: 12); |
12424 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
12425 | m = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
12426 | |
12427 | // wback = (m != 15); register_index = (m != 15 && m != 13); if n == 15 |
12428 | // then UNPREDICTABLE; |
12429 | wback = (m != 15); |
12430 | register_index = ((m != 15) && (m != 13)); |
12431 | |
12432 | if (n == 15) |
12433 | return false; |
12434 | } break; |
12435 | |
12436 | default: |
12437 | return false; |
12438 | } |
12439 | |
12440 | std::optional<RegisterInfo> base_reg = |
12441 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n); |
12442 | |
12443 | uint32_t Rn = ReadCoreReg(regnum: n, success: &success); |
12444 | if (!success) |
12445 | return false; |
12446 | |
12447 | // address = R[n]; if (address MOD alignment) != 0 then |
12448 | // GenerateAlignmentException(); |
12449 | addr_t address = Rn; |
12450 | if ((address % alignment) != 0) |
12451 | return false; |
12452 | |
12453 | EmulateInstruction::Context context; |
12454 | // if wback then R[n] = R[n] + (if register_index then R[m] else ebytes); |
12455 | if (wback) { |
12456 | uint32_t Rm = ReadCoreReg(regnum: m, success: &success); |
12457 | if (!success) |
12458 | return false; |
12459 | |
12460 | uint32_t offset; |
12461 | if (register_index) |
12462 | offset = Rm; |
12463 | else |
12464 | offset = ebytes; |
12465 | |
12466 | context.type = eContextAdjustBaseRegister; |
12467 | context.SetRegisterPlusOffset(base_reg: *base_reg, signed_offset: offset); |
12468 | |
12469 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n, |
12470 | reg_value: Rn + offset)) |
12471 | return false; |
12472 | } |
12473 | |
12474 | // MemU[address,ebytes] = Elem[D[d],index,esize]; |
12475 | uint64_t register_data = |
12476 | ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_d0 + d, fail_value: 0, success_ptr: &success); |
12477 | if (!success) |
12478 | return false; |
12479 | |
12480 | uint64_t word = |
12481 | Bits64(bits: register_data, msbit: ((index + 1) * esize) - 1, lsbit: index * esize); |
12482 | |
12483 | std::optional<RegisterInfo> data_reg = |
12484 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_d0 + d); |
12485 | context.type = eContextRegisterStore; |
12486 | context.SetRegisterToRegisterPlusOffset(data_reg: *data_reg, base_reg: *base_reg, offset: address - Rn); |
12487 | |
12488 | if (!MemUWrite(context, address, data_val: word, size: ebytes)) |
12489 | return false; |
12490 | } |
12491 | return true; |
12492 | } |
12493 | |
12494 | // A8.6.309 VLD1 (single element to all lanes) This instruction loads one |
12495 | // element from memory into every element of one or two vectors. |
12496 | bool EmulateInstructionARM::EmulateVLD1SingleAll(const uint32_t opcode, |
12497 | const ARMEncoding encoding) { |
12498 | #if 0 |
12499 | if ConditionPassed() then |
12500 | EncodingSpecificOperations(); CheckAdvSIMDEnabled(); NullCheckIfThumbEE(n); |
12501 | address = R[n]; if (address MOD alignment) != 0 then GenerateAlignmentException(); |
12502 | if wback then R[n] = R[n] + (if register_index then R[m] else ebytes); |
12503 | replicated_element = Replicate(MemU[address,ebytes], elements); |
12504 | for r = 0 to regs-1 |
12505 | D[d+r] = replicated_element; |
12506 | #endif |
12507 | |
12508 | bool success = false; |
12509 | |
12510 | if (ConditionPassed(opcode)) { |
12511 | uint32_t ebytes; |
12512 | uint32_t elements; |
12513 | uint32_t regs; |
12514 | uint32_t alignment; |
12515 | uint32_t d; |
12516 | uint32_t n; |
12517 | uint32_t m; |
12518 | bool wback; |
12519 | bool register_index; |
12520 | |
12521 | switch (encoding) { |
12522 | case eEncodingT1: |
12523 | case eEncodingA1: { |
12524 | // if size == '11' || (size == '00' && a == '1') then UNDEFINED; |
12525 | uint32_t size = Bits32(bits: opcode, msbit: 7, lsbit: 6); |
12526 | if ((size == 3) || ((size == 0) && BitIsSet(value: opcode, bit: 4))) |
12527 | return false; |
12528 | |
12529 | // ebytes = 1 << UInt(size); elements = 8 DIV ebytes; regs = if T == '0' |
12530 | // then 1 else 2; |
12531 | ebytes = 1 << size; |
12532 | elements = 8 / ebytes; |
12533 | if (BitIsClear(value: opcode, bit: 5)) |
12534 | regs = 1; |
12535 | else |
12536 | regs = 2; |
12537 | |
12538 | // alignment = if a == '0' then 1 else ebytes; |
12539 | if (BitIsClear(value: opcode, bit: 4)) |
12540 | alignment = 1; |
12541 | else |
12542 | alignment = ebytes; |
12543 | |
12544 | // d = UInt(D:Vd); n = UInt(Rn); m = UInt(Rm); |
12545 | d = (Bit32(bits: opcode, bit: 22) << 4) | Bits32(bits: opcode, msbit: 15, lsbit: 12); |
12546 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
12547 | m = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
12548 | |
12549 | // wback = (m != 15); register_index = (m != 15 && m != 13); |
12550 | wback = (m != 15); |
12551 | register_index = ((m != 15) && (m != 13)); |
12552 | |
12553 | // if d+regs > 32 then UNPREDICTABLE; if n == 15 then UNPREDICTABLE; |
12554 | if ((d + regs) > 32) |
12555 | return false; |
12556 | |
12557 | if (n == 15) |
12558 | return false; |
12559 | } break; |
12560 | |
12561 | default: |
12562 | return false; |
12563 | } |
12564 | |
12565 | uint32_t Rn = ReadCoreReg(regnum: n, success: &success); |
12566 | if (!success) |
12567 | return false; |
12568 | |
12569 | // address = R[n]; if (address MOD alignment) != 0 then |
12570 | // GenerateAlignmentException(); |
12571 | addr_t address = Rn; |
12572 | if ((address % alignment) != 0) |
12573 | return false; |
12574 | |
12575 | EmulateInstruction::Context context; |
12576 | // if wback then R[n] = R[n] + (if register_index then R[m] else ebytes); |
12577 | if (wback) { |
12578 | uint32_t Rm = ReadCoreReg(regnum: m, success: &success); |
12579 | if (!success) |
12580 | return false; |
12581 | |
12582 | uint32_t offset; |
12583 | if (register_index) |
12584 | offset = Rm; |
12585 | else |
12586 | offset = ebytes; |
12587 | |
12588 | context.type = eContextAdjustBaseRegister; |
12589 | std::optional<RegisterInfo> base_reg = |
12590 | GetRegisterInfo(reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n); |
12591 | context.SetRegisterPlusOffset(base_reg: *base_reg, signed_offset: offset); |
12592 | |
12593 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_r0 + n, |
12594 | reg_value: Rn + offset)) |
12595 | return false; |
12596 | } |
12597 | |
12598 | // replicated_element = Replicate(MemU[address,ebytes], elements); |
12599 | |
12600 | context.type = eContextRegisterLoad; |
12601 | uint64_t word = MemURead(context, address, size: ebytes, fail_value: 0, success_ptr: &success); |
12602 | if (!success) |
12603 | return false; |
12604 | |
12605 | uint64_t replicated_element = 0; |
12606 | uint32_t esize = ebytes * 8; |
12607 | for (uint32_t e = 0; e < elements; ++e) |
12608 | replicated_element = |
12609 | (replicated_element << esize) | Bits64(bits: word, msbit: esize - 1, lsbit: 0); |
12610 | |
12611 | // for r = 0 to regs-1 |
12612 | for (uint32_t r = 0; r < regs; ++r) { |
12613 | // D[d+r] = replicated_element; |
12614 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_d0 + d + r, |
12615 | reg_value: replicated_element)) |
12616 | return false; |
12617 | } |
12618 | } |
12619 | return true; |
12620 | } |
12621 | |
12622 | // B6.2.13 SUBS PC, LR and related instructions The SUBS PC, LR, #<const? |
12623 | // instruction provides an exception return without the use of the stack. It |
12624 | // subtracts the immediate constant from the LR, branches to the resulting |
12625 | // address, and also copies the SPSR to the CPSR. |
12626 | bool EmulateInstructionARM::EmulateSUBSPcLrEtc(const uint32_t opcode, |
12627 | const ARMEncoding encoding) { |
12628 | #if 0 |
12629 | if ConditionPassed() then |
12630 | EncodingSpecificOperations(); |
12631 | if CurrentInstrSet() == InstrSet_ThumbEE then |
12632 | UNPREDICTABLE; |
12633 | operand2 = if register_form then Shift(R[m], shift_t, shift_n, APSR.C) else imm32; |
12634 | case opcode of |
12635 | when '0000' result = R[n] AND operand2; // AND |
12636 | when '0001' result = R[n] EOR operand2; // EOR |
12637 | when '0010' (result, -, -) = AddWithCarry(R[n], NOT(operand2), '1'); // SUB |
12638 | when '0011' (result, -, -) = AddWithCarry(NOT(R[n]), operand2, '1'); // RSB |
12639 | when '0100' (result, -, -) = AddWithCarry(R[n], operand2, '0'); // ADD |
12640 | when '0101' (result, -, -) = AddWithCarry(R[n], operand2, APSR.c); // ADC |
12641 | when '0110' (result, -, -) = AddWithCarry(R[n], NOT(operand2), APSR.C); // SBC |
12642 | when '0111' (result, -, -) = AddWithCarry(NOT(R[n]), operand2, APSR.C); // RSC |
12643 | when '1100' result = R[n] OR operand2; // ORR |
12644 | when '1101' result = operand2; // MOV |
12645 | when '1110' result = R[n] AND NOT(operand2); // BIC |
12646 | when '1111' result = NOT(operand2); // MVN |
12647 | CPSRWriteByInstr(SPSR[], '1111', TRUE); |
12648 | BranchWritePC(result); |
12649 | #endif |
12650 | |
12651 | bool success = false; |
12652 | |
12653 | if (ConditionPassed(opcode)) { |
12654 | uint32_t n; |
12655 | uint32_t m; |
12656 | uint32_t imm32; |
12657 | bool register_form; |
12658 | ARM_ShifterType shift_t; |
12659 | uint32_t shift_n; |
12660 | uint32_t code; |
12661 | |
12662 | switch (encoding) { |
12663 | case eEncodingT1: |
12664 | // if CurrentInstrSet() == InstrSet_ThumbEE then UNPREDICTABLE n = 14; |
12665 | // imm32 = ZeroExtend(imm8, 32); register_form = FALSE; opcode = '0010'; |
12666 | // // = SUB |
12667 | n = 14; |
12668 | imm32 = Bits32(bits: opcode, msbit: 7, lsbit: 0); |
12669 | register_form = false; |
12670 | code = 2; |
12671 | |
12672 | // if InITBlock() && !LastInITBlock() then UNPREDICTABLE; |
12673 | if (InITBlock() && !LastInITBlock()) |
12674 | return false; |
12675 | |
12676 | break; |
12677 | |
12678 | case eEncodingA1: |
12679 | // n = UInt(Rn); imm32 = ARMExpandImm(imm12); register_form = FALSE; |
12680 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
12681 | imm32 = ARMExpandImm(opcode); |
12682 | register_form = false; |
12683 | code = Bits32(bits: opcode, msbit: 24, lsbit: 21); |
12684 | |
12685 | break; |
12686 | |
12687 | case eEncodingA2: |
12688 | // n = UInt(Rn); m = UInt(Rm); register_form = TRUE; |
12689 | n = Bits32(bits: opcode, msbit: 19, lsbit: 16); |
12690 | m = Bits32(bits: opcode, msbit: 3, lsbit: 0); |
12691 | register_form = true; |
12692 | |
12693 | // (shift_t, shift_n) = DecodeImmShift(type, imm5); |
12694 | shift_n = DecodeImmShiftARM(opcode, shift_t); |
12695 | |
12696 | break; |
12697 | |
12698 | default: |
12699 | return false; |
12700 | } |
12701 | |
12702 | // operand2 = if register_form then Shift(R[m], shift_t, shift_n, APSR.C) |
12703 | // else imm32; |
12704 | uint32_t operand2; |
12705 | if (register_form) { |
12706 | uint32_t Rm = ReadCoreReg(regnum: m, success: &success); |
12707 | if (!success) |
12708 | return false; |
12709 | |
12710 | operand2 = Shift(value: Rm, type: shift_t, amount: shift_n, APSR_C, success: &success); |
12711 | if (!success) |
12712 | return false; |
12713 | } else { |
12714 | operand2 = imm32; |
12715 | } |
12716 | |
12717 | uint32_t Rn = ReadCoreReg(regnum: n, success: &success); |
12718 | if (!success) |
12719 | return false; |
12720 | |
12721 | AddWithCarryResult result; |
12722 | |
12723 | // case opcode of |
12724 | switch (code) { |
12725 | case 0: // when '0000' |
12726 | // result = R[n] AND operand2; // AND |
12727 | result.result = Rn & operand2; |
12728 | break; |
12729 | |
12730 | case 1: // when '0001' |
12731 | // result = R[n] EOR operand2; // EOR |
12732 | result.result = Rn ^ operand2; |
12733 | break; |
12734 | |
12735 | case 2: // when '0010' |
12736 | // (result, -, -) = AddWithCarry(R[n], NOT(operand2), '1'); // SUB |
12737 | result = AddWithCarry(x: Rn, y: ~(operand2), carry_in: 1); |
12738 | break; |
12739 | |
12740 | case 3: // when '0011' |
12741 | // (result, -, -) = AddWithCarry(NOT(R[n]), operand2, '1'); // RSB |
12742 | result = AddWithCarry(x: ~(Rn), y: operand2, carry_in: 1); |
12743 | break; |
12744 | |
12745 | case 4: // when '0100' |
12746 | // (result, -, -) = AddWithCarry(R[n], operand2, '0'); // ADD |
12747 | result = AddWithCarry(x: Rn, y: operand2, carry_in: 0); |
12748 | break; |
12749 | |
12750 | case 5: // when '0101' |
12751 | // (result, -, -) = AddWithCarry(R[n], operand2, APSR.c); // ADC |
12752 | result = AddWithCarry(x: Rn, y: operand2, APSR_C); |
12753 | break; |
12754 | |
12755 | case 6: // when '0110' |
12756 | // (result, -, -) = AddWithCarry(R[n], NOT(operand2), APSR.C); // SBC |
12757 | result = AddWithCarry(x: Rn, y: ~(operand2), APSR_C); |
12758 | break; |
12759 | |
12760 | case 7: // when '0111' |
12761 | // (result, -, -) = AddWithCarry(NOT(R[n]), operand2, APSR.C); // RSC |
12762 | result = AddWithCarry(x: ~(Rn), y: operand2, APSR_C); |
12763 | break; |
12764 | |
12765 | case 10: // when '1100' |
12766 | // result = R[n] OR operand2; // ORR |
12767 | result.result = Rn | operand2; |
12768 | break; |
12769 | |
12770 | case 11: // when '1101' |
12771 | // result = operand2; // MOV |
12772 | result.result = operand2; |
12773 | break; |
12774 | |
12775 | case 12: // when '1110' |
12776 | // result = R[n] AND NOT(operand2); // BIC |
12777 | result.result = Rn & ~(operand2); |
12778 | break; |
12779 | |
12780 | case 15: // when '1111' |
12781 | // result = NOT(operand2); // MVN |
12782 | result.result = ~(operand2); |
12783 | break; |
12784 | |
12785 | default: |
12786 | return false; |
12787 | } |
12788 | // CPSRWriteByInstr(SPSR[], '1111', TRUE); |
12789 | |
12790 | // For now, in emulation mode, we don't have access to the SPSR, so we will |
12791 | // use the CPSR instead, and hope for the best. |
12792 | uint32_t spsr = |
12793 | ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_cpsr, fail_value: 0, success_ptr: &success); |
12794 | if (!success) |
12795 | return false; |
12796 | |
12797 | CPSRWriteByInstr(value: spsr, bytemask: 15, affect_execstate: true); |
12798 | |
12799 | // BranchWritePC(result); |
12800 | EmulateInstruction::Context context; |
12801 | context.type = eContextAdjustPC; |
12802 | context.SetImmediate(result.result); |
12803 | |
12804 | BranchWritePC(context, addr: result.result); |
12805 | } |
12806 | return true; |
12807 | } |
12808 | |
12809 | EmulateInstructionARM::ARMOpcode * |
12810 | EmulateInstructionARM::GetARMOpcodeForInstruction(const uint32_t opcode, |
12811 | uint32_t arm_isa) { |
12812 | static ARMOpcode g_arm_opcodes[] = { |
12813 | // Prologue instructions |
12814 | |
12815 | // push register(s) |
12816 | {.mask: 0x0fff0000, .value: 0x092d0000, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
12817 | .callback: &EmulateInstructionARM::EmulatePUSH, .name: "push <registers>" }, |
12818 | {.mask: 0x0fff0fff, .value: 0x052d0004, ARMvAll, .encoding: eEncodingA2, No_VFP, .size: eSize32, |
12819 | .callback: &EmulateInstructionARM::EmulatePUSH, .name: "push <register>" }, |
12820 | |
12821 | // set r7 to point to a stack offset |
12822 | {.mask: 0x0ffff000, .value: 0x028d7000, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
12823 | .callback: &EmulateInstructionARM::EmulateADDRdSPImm, .name: "add r7, sp, #<const>" }, |
12824 | {.mask: 0x0ffff000, .value: 0x024c7000, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
12825 | .callback: &EmulateInstructionARM::EmulateSUBR7IPImm, .name: "sub r7, ip, #<const>" }, |
12826 | // copy the stack pointer to ip |
12827 | {.mask: 0x0fffffff, .value: 0x01a0c00d, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
12828 | .callback: &EmulateInstructionARM::EmulateMOVRdSP, .name: "mov ip, sp" }, |
12829 | {.mask: 0x0ffff000, .value: 0x028dc000, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
12830 | .callback: &EmulateInstructionARM::EmulateADDRdSPImm, .name: "add ip, sp, #<const>" }, |
12831 | {.mask: 0x0ffff000, .value: 0x024dc000, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
12832 | .callback: &EmulateInstructionARM::EmulateSUBIPSPImm, .name: "sub ip, sp, #<const>" }, |
12833 | |
12834 | // adjust the stack pointer |
12835 | {.mask: 0x0ffff000, .value: 0x024dd000, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
12836 | .callback: &EmulateInstructionARM::EmulateSUBSPImm, .name: "sub sp, sp, #<const>" }, |
12837 | {.mask: 0x0fef0010, .value: 0x004d0000, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
12838 | .callback: &EmulateInstructionARM::EmulateSUBSPReg, |
12839 | .name: "sub{s}<c> <Rd>, sp, <Rm>{,<shift>}" }, |
12840 | |
12841 | // push one register |
12842 | // if Rn == '1101' && imm12 == '000000000100' then SEE PUSH; |
12843 | {.mask: 0x0e5f0000, .value: 0x040d0000, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
12844 | .callback: &EmulateInstructionARM::EmulateSTRRtSP, .name: "str Rt, [sp, #-imm12]!" }, |
12845 | |
12846 | // vector push consecutive extension register(s) |
12847 | {.mask: 0x0fbf0f00, .value: 0x0d2d0b00, ARMV6T2_ABOVE, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
12848 | .callback: &EmulateInstructionARM::EmulateVPUSH, .name: "vpush.64 <list>" }, |
12849 | {.mask: 0x0fbf0f00, .value: 0x0d2d0a00, ARMV6T2_ABOVE, .encoding: eEncodingA2, No_VFP, .size: eSize32, |
12850 | .callback: &EmulateInstructionARM::EmulateVPUSH, .name: "vpush.32 <list>" }, |
12851 | |
12852 | // Epilogue instructions |
12853 | |
12854 | {.mask: 0x0fff0000, .value: 0x08bd0000, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
12855 | .callback: &EmulateInstructionARM::EmulatePOP, .name: "pop <registers>" }, |
12856 | {.mask: 0x0fff0fff, .value: 0x049d0004, ARMvAll, .encoding: eEncodingA2, No_VFP, .size: eSize32, |
12857 | .callback: &EmulateInstructionARM::EmulatePOP, .name: "pop <register>" }, |
12858 | {.mask: 0x0fbf0f00, .value: 0x0cbd0b00, ARMV6T2_ABOVE, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
12859 | .callback: &EmulateInstructionARM::EmulateVPOP, .name: "vpop.64 <list>" }, |
12860 | {.mask: 0x0fbf0f00, .value: 0x0cbd0a00, ARMV6T2_ABOVE, .encoding: eEncodingA2, No_VFP, .size: eSize32, |
12861 | .callback: &EmulateInstructionARM::EmulateVPOP, .name: "vpop.32 <list>" }, |
12862 | |
12863 | // Supervisor Call (previously Software Interrupt) |
12864 | {.mask: 0x0f000000, .value: 0x0f000000, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
12865 | .callback: &EmulateInstructionARM::EmulateSVC, .name: "svc #imm24" }, |
12866 | |
12867 | // Branch instructions |
12868 | // To resolve ambiguity, "blx <label>" should come before "b #imm24" and |
12869 | // "bl <label>". |
12870 | {.mask: 0xfe000000, .value: 0xfa000000, ARMV5_ABOVE, .encoding: eEncodingA2, No_VFP, .size: eSize32, |
12871 | .callback: &EmulateInstructionARM::EmulateBLXImmediate, .name: "blx <label>" }, |
12872 | {.mask: 0x0f000000, .value: 0x0a000000, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
12873 | .callback: &EmulateInstructionARM::EmulateB, .name: "b #imm24" }, |
12874 | {.mask: 0x0f000000, .value: 0x0b000000, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
12875 | .callback: &EmulateInstructionARM::EmulateBLXImmediate, .name: "bl <label>" }, |
12876 | {.mask: 0x0ffffff0, .value: 0x012fff30, ARMV5_ABOVE, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
12877 | .callback: &EmulateInstructionARM::EmulateBLXRm, .name: "blx <Rm>" }, |
12878 | // for example, "bx lr" |
12879 | {.mask: 0x0ffffff0, .value: 0x012fff10, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
12880 | .callback: &EmulateInstructionARM::EmulateBXRm, .name: "bx <Rm>" }, |
12881 | // bxj |
12882 | {.mask: 0x0ffffff0, .value: 0x012fff20, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
12883 | .callback: &EmulateInstructionARM::EmulateBXJRm, .name: "bxj <Rm>" }, |
12884 | |
12885 | // Data-processing instructions |
12886 | // adc (immediate) |
12887 | {.mask: 0x0fe00000, .value: 0x02a00000, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
12888 | .callback: &EmulateInstructionARM::EmulateADCImm, .name: "adc{s}<c> <Rd>, <Rn>, #const" }, |
12889 | // adc (register) |
12890 | {.mask: 0x0fe00010, .value: 0x00a00000, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
12891 | .callback: &EmulateInstructionARM::EmulateADCReg, |
12892 | .name: "adc{s}<c> <Rd>, <Rn>, <Rm> {,<shift>}" }, |
12893 | // add (immediate) |
12894 | {.mask: 0x0fe00000, .value: 0x02800000, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
12895 | .callback: &EmulateInstructionARM::EmulateADDImmARM, |
12896 | .name: "add{s}<c> <Rd>, <Rn>, #const" }, |
12897 | // add (register) |
12898 | {.mask: 0x0fe00010, .value: 0x00800000, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
12899 | .callback: &EmulateInstructionARM::EmulateADDReg, |
12900 | .name: "add{s}<c> <Rd>, <Rn>, <Rm> {,<shift>}" }, |
12901 | // add (register-shifted register) |
12902 | {.mask: 0x0fe00090, .value: 0x00800010, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
12903 | .callback: &EmulateInstructionARM::EmulateADDRegShift, |
12904 | .name: "add{s}<c> <Rd>, <Rn>, <Rm>, <type> <RS>" }, |
12905 | // adr |
12906 | {.mask: 0x0fff0000, .value: 0x028f0000, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
12907 | .callback: &EmulateInstructionARM::EmulateADR, .name: "add<c> <Rd>, PC, #<const>" }, |
12908 | {.mask: 0x0fff0000, .value: 0x024f0000, ARMvAll, .encoding: eEncodingA2, No_VFP, .size: eSize32, |
12909 | .callback: &EmulateInstructionARM::EmulateADR, .name: "sub<c> <Rd>, PC, #<const>" }, |
12910 | // and (immediate) |
12911 | {.mask: 0x0fe00000, .value: 0x02000000, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
12912 | .callback: &EmulateInstructionARM::EmulateANDImm, .name: "and{s}<c> <Rd>, <Rn>, #const" }, |
12913 | // and (register) |
12914 | {.mask: 0x0fe00010, .value: 0x00000000, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
12915 | .callback: &EmulateInstructionARM::EmulateANDReg, |
12916 | .name: "and{s}<c> <Rd>, <Rn>, <Rm> {,<shift>}" }, |
12917 | // bic (immediate) |
12918 | {.mask: 0x0fe00000, .value: 0x03c00000, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
12919 | .callback: &EmulateInstructionARM::EmulateBICImm, .name: "bic{s}<c> <Rd>, <Rn>, #const" }, |
12920 | // bic (register) |
12921 | {.mask: 0x0fe00010, .value: 0x01c00000, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
12922 | .callback: &EmulateInstructionARM::EmulateBICReg, |
12923 | .name: "bic{s}<c> <Rd>, <Rn>, <Rm> {,<shift>}" }, |
12924 | // eor (immediate) |
12925 | {.mask: 0x0fe00000, .value: 0x02200000, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
12926 | .callback: &EmulateInstructionARM::EmulateEORImm, .name: "eor{s}<c> <Rd>, <Rn>, #const" }, |
12927 | // eor (register) |
12928 | {.mask: 0x0fe00010, .value: 0x00200000, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
12929 | .callback: &EmulateInstructionARM::EmulateEORReg, |
12930 | .name: "eor{s}<c> <Rd>, <Rn>, <Rm> {,<shift>}" }, |
12931 | // orr (immediate) |
12932 | {.mask: 0x0fe00000, .value: 0x03800000, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
12933 | .callback: &EmulateInstructionARM::EmulateORRImm, .name: "orr{s}<c> <Rd>, <Rn>, #const" }, |
12934 | // orr (register) |
12935 | {.mask: 0x0fe00010, .value: 0x01800000, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
12936 | .callback: &EmulateInstructionARM::EmulateORRReg, |
12937 | .name: "orr{s}<c> <Rd>, <Rn>, <Rm> {,<shift>}" }, |
12938 | // rsb (immediate) |
12939 | {.mask: 0x0fe00000, .value: 0x02600000, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
12940 | .callback: &EmulateInstructionARM::EmulateRSBImm, .name: "rsb{s}<c> <Rd>, <Rn>, #<const>" }, |
12941 | // rsb (register) |
12942 | {.mask: 0x0fe00010, .value: 0x00600000, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
12943 | .callback: &EmulateInstructionARM::EmulateRSBReg, |
12944 | .name: "rsb{s}<c> <Rd>, <Rn>, <Rm> {,<shift>}" }, |
12945 | // rsc (immediate) |
12946 | {.mask: 0x0fe00000, .value: 0x02e00000, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
12947 | .callback: &EmulateInstructionARM::EmulateRSCImm, .name: "rsc{s}<c> <Rd>, <Rn>, #<const>" }, |
12948 | // rsc (register) |
12949 | {.mask: 0x0fe00010, .value: 0x00e00000, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
12950 | .callback: &EmulateInstructionARM::EmulateRSCReg, |
12951 | .name: "rsc{s}<c> <Rd>, <Rn>, <Rm> {,<shift>}" }, |
12952 | // sbc (immediate) |
12953 | {.mask: 0x0fe00000, .value: 0x02c00000, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
12954 | .callback: &EmulateInstructionARM::EmulateSBCImm, .name: "sbc{s}<c> <Rd>, <Rn>, #<const>" }, |
12955 | // sbc (register) |
12956 | {.mask: 0x0fe00010, .value: 0x00c00000, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
12957 | .callback: &EmulateInstructionARM::EmulateSBCReg, |
12958 | .name: "sbc{s}<c> <Rd>, <Rn>, <Rm> {,<shift>}" }, |
12959 | // sub (immediate, ARM) |
12960 | {.mask: 0x0fe00000, .value: 0x02400000, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
12961 | .callback: &EmulateInstructionARM::EmulateSUBImmARM, |
12962 | .name: "sub{s}<c> <Rd>, <Rn>, #<const>" }, |
12963 | // sub (sp minus immediate) |
12964 | {.mask: 0x0fef0000, .value: 0x024d0000, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
12965 | .callback: &EmulateInstructionARM::EmulateSUBSPImm, .name: "sub{s}<c> <Rd>, sp, #<const>" }, |
12966 | // sub (register) |
12967 | {.mask: 0x0fe00010, .value: 0x00400000, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
12968 | .callback: &EmulateInstructionARM::EmulateSUBReg, |
12969 | .name: "sub{s}<c> <Rd>, <Rn>, <Rm>{,<shift>}" }, |
12970 | // teq (immediate) |
12971 | {.mask: 0x0ff0f000, .value: 0x03300000, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
12972 | .callback: &EmulateInstructionARM::EmulateTEQImm, .name: "teq<c> <Rn>, #const" }, |
12973 | // teq (register) |
12974 | {.mask: 0x0ff0f010, .value: 0x01300000, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
12975 | .callback: &EmulateInstructionARM::EmulateTEQReg, .name: "teq<c> <Rn>, <Rm> {,<shift>}" }, |
12976 | // tst (immediate) |
12977 | {.mask: 0x0ff0f000, .value: 0x03100000, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
12978 | .callback: &EmulateInstructionARM::EmulateTSTImm, .name: "tst<c> <Rn>, #const" }, |
12979 | // tst (register) |
12980 | {.mask: 0x0ff0f010, .value: 0x01100000, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
12981 | .callback: &EmulateInstructionARM::EmulateTSTReg, .name: "tst<c> <Rn>, <Rm> {,<shift>}" }, |
12982 | |
12983 | // mov (immediate) |
12984 | {.mask: 0x0fef0000, .value: 0x03a00000, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
12985 | .callback: &EmulateInstructionARM::EmulateMOVRdImm, .name: "mov{s}<c> <Rd>, #<const>" }, |
12986 | {.mask: 0x0ff00000, .value: 0x03000000, ARMV6T2_ABOVE, .encoding: eEncodingA2, No_VFP, .size: eSize32, |
12987 | .callback: &EmulateInstructionARM::EmulateMOVRdImm, .name: "movw<c> <Rd>, #<imm16>" }, |
12988 | // mov (register) |
12989 | {.mask: 0x0fef0ff0, .value: 0x01a00000, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
12990 | .callback: &EmulateInstructionARM::EmulateMOVRdRm, .name: "mov{s}<c> <Rd>, <Rm>" }, |
12991 | // mvn (immediate) |
12992 | {.mask: 0x0fef0000, .value: 0x03e00000, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
12993 | .callback: &EmulateInstructionARM::EmulateMVNImm, .name: "mvn{s}<c> <Rd>, #<const>" }, |
12994 | // mvn (register) |
12995 | {.mask: 0x0fef0010, .value: 0x01e00000, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
12996 | .callback: &EmulateInstructionARM::EmulateMVNReg, |
12997 | .name: "mvn{s}<c> <Rd>, <Rm> {,<shift>}" }, |
12998 | // cmn (immediate) |
12999 | {.mask: 0x0ff0f000, .value: 0x03700000, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
13000 | .callback: &EmulateInstructionARM::EmulateCMNImm, .name: "cmn<c> <Rn>, #<const>" }, |
13001 | // cmn (register) |
13002 | {.mask: 0x0ff0f010, .value: 0x01700000, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
13003 | .callback: &EmulateInstructionARM::EmulateCMNReg, .name: "cmn<c> <Rn>, <Rm> {,<shift>}" }, |
13004 | // cmp (immediate) |
13005 | {.mask: 0x0ff0f000, .value: 0x03500000, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
13006 | .callback: &EmulateInstructionARM::EmulateCMPImm, .name: "cmp<c> <Rn>, #<const>" }, |
13007 | // cmp (register) |
13008 | {.mask: 0x0ff0f010, .value: 0x01500000, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
13009 | .callback: &EmulateInstructionARM::EmulateCMPReg, .name: "cmp<c> <Rn>, <Rm> {,<shift>}" }, |
13010 | // asr (immediate) |
13011 | {.mask: 0x0fef0070, .value: 0x01a00040, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
13012 | .callback: &EmulateInstructionARM::EmulateASRImm, .name: "asr{s}<c> <Rd>, <Rm>, #imm" }, |
13013 | // asr (register) |
13014 | {.mask: 0x0fef00f0, .value: 0x01a00050, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
13015 | .callback: &EmulateInstructionARM::EmulateASRReg, .name: "asr{s}<c> <Rd>, <Rn>, <Rm>" }, |
13016 | // lsl (immediate) |
13017 | {.mask: 0x0fef0070, .value: 0x01a00000, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
13018 | .callback: &EmulateInstructionARM::EmulateLSLImm, .name: "lsl{s}<c> <Rd>, <Rm>, #imm" }, |
13019 | // lsl (register) |
13020 | {.mask: 0x0fef00f0, .value: 0x01a00010, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
13021 | .callback: &EmulateInstructionARM::EmulateLSLReg, .name: "lsl{s}<c> <Rd>, <Rn>, <Rm>" }, |
13022 | // lsr (immediate) |
13023 | {.mask: 0x0fef0070, .value: 0x01a00020, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
13024 | .callback: &EmulateInstructionARM::EmulateLSRImm, .name: "lsr{s}<c> <Rd>, <Rm>, #imm" }, |
13025 | // lsr (register) |
13026 | {.mask: 0x0fef00f0, .value: 0x01a00050, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
13027 | .callback: &EmulateInstructionARM::EmulateLSRReg, .name: "lsr{s}<c> <Rd>, <Rn>, <Rm>" }, |
13028 | // rrx is a special case encoding of ror (immediate) |
13029 | {.mask: 0x0fef0ff0, .value: 0x01a00060, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
13030 | .callback: &EmulateInstructionARM::EmulateRRX, .name: "rrx{s}<c> <Rd>, <Rm>" }, |
13031 | // ror (immediate) |
13032 | {.mask: 0x0fef0070, .value: 0x01a00060, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
13033 | .callback: &EmulateInstructionARM::EmulateRORImm, .name: "ror{s}<c> <Rd>, <Rm>, #imm" }, |
13034 | // ror (register) |
13035 | {.mask: 0x0fef00f0, .value: 0x01a00070, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
13036 | .callback: &EmulateInstructionARM::EmulateRORReg, .name: "ror{s}<c> <Rd>, <Rn>, <Rm>" }, |
13037 | // mul |
13038 | {.mask: 0x0fe000f0, .value: 0x00000090, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
13039 | .callback: &EmulateInstructionARM::EmulateMUL, .name: "mul{s}<c> <Rd>,<R>,<Rm>" }, |
13040 | |
13041 | // subs pc, lr and related instructions |
13042 | {.mask: 0x0e10f000, .value: 0x0210f000, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
13043 | .callback: &EmulateInstructionARM::EmulateSUBSPcLrEtc, |
13044 | .name: "<opc>S<c> PC,#<const> | <Rn>,#<const>" }, |
13045 | {.mask: 0x0e10f010, .value: 0x0010f000, ARMvAll, .encoding: eEncodingA2, No_VFP, .size: eSize32, |
13046 | .callback: &EmulateInstructionARM::EmulateSUBSPcLrEtc, |
13047 | .name: "<opc>S<c> PC,<Rn>,<Rm{,<shift>}" }, |
13048 | |
13049 | // Load instructions |
13050 | {.mask: 0x0fd00000, .value: 0x08900000, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
13051 | .callback: &EmulateInstructionARM::EmulateLDM, .name: "ldm<c> <Rn>{!} <registers>" }, |
13052 | {.mask: 0x0fd00000, .value: 0x08100000, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
13053 | .callback: &EmulateInstructionARM::EmulateLDMDA, .name: "ldmda<c> <Rn>{!} <registers>" }, |
13054 | {.mask: 0x0fd00000, .value: 0x09100000, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
13055 | .callback: &EmulateInstructionARM::EmulateLDMDB, .name: "ldmdb<c> <Rn>{!} <registers>" }, |
13056 | {.mask: 0x0fd00000, .value: 0x09900000, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
13057 | .callback: &EmulateInstructionARM::EmulateLDMIB, .name: "ldmib<c> <Rn<{!} <registers>" }, |
13058 | {.mask: 0x0e500000, .value: 0x04100000, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
13059 | .callback: &EmulateInstructionARM::EmulateLDRImmediateARM, |
13060 | .name: "ldr<c> <Rt> [<Rn> {#+/-<imm12>}]" }, |
13061 | {.mask: 0x0e500010, .value: 0x06100000, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
13062 | .callback: &EmulateInstructionARM::EmulateLDRRegister, |
13063 | .name: "ldr<c> <Rt> [<Rn> +/-<Rm> {<shift>}] {!}" }, |
13064 | {.mask: 0x0e5f0000, .value: 0x045f0000, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
13065 | .callback: &EmulateInstructionARM::EmulateLDRBLiteral, .name: "ldrb<c> <Rt>, [...]" }, |
13066 | {.mask: 0xfe500010, .value: 0x06500000, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
13067 | .callback: &EmulateInstructionARM::EmulateLDRBRegister, |
13068 | .name: "ldrb<c> <Rt>, [<Rn>,+/-<Rm>{, <shift>}]{!}" }, |
13069 | {.mask: 0x0e5f00f0, .value: 0x005f00b0, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
13070 | .callback: &EmulateInstructionARM::EmulateLDRHLiteral, .name: "ldrh<c> <Rt>, <label>" }, |
13071 | {.mask: 0x0e5000f0, .value: 0x001000b0, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
13072 | .callback: &EmulateInstructionARM::EmulateLDRHRegister, |
13073 | .name: "ldrh<c> <Rt>,[<Rn>,+/-<Rm>]{!}" }, |
13074 | {.mask: 0x0e5000f0, .value: 0x005000d0, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
13075 | .callback: &EmulateInstructionARM::EmulateLDRSBImmediate, |
13076 | .name: "ldrsb<c> <Rt>, [<Rn>{,#+/-<imm8>}]" }, |
13077 | {.mask: 0x0e5f00f0, .value: 0x005f00d0, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
13078 | .callback: &EmulateInstructionARM::EmulateLDRSBLiteral, .name: "ldrsb<c> <Rt> <label>" }, |
13079 | {.mask: 0x0e5000f0, .value: 0x001000d0, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
13080 | .callback: &EmulateInstructionARM::EmulateLDRSBRegister, |
13081 | .name: "ldrsb<c> <Rt>,[<Rn>,+/-<Rm>]{!}" }, |
13082 | {.mask: 0x0e5000f0, .value: 0x005000f0, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
13083 | .callback: &EmulateInstructionARM::EmulateLDRSHImmediate, |
13084 | .name: "ldrsh<c> <Rt>,[<Rn>{,#+/-<imm8>}]" }, |
13085 | {.mask: 0x0e5f00f0, .value: 0x005f00f0, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
13086 | .callback: &EmulateInstructionARM::EmulateLDRSHLiteral, .name: "ldrsh<c> <Rt>,<label>" }, |
13087 | {.mask: 0x0e5000f0, .value: 0x001000f0, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
13088 | .callback: &EmulateInstructionARM::EmulateLDRSHRegister, |
13089 | .name: "ldrsh<c> <Rt>,[<Rn>,+/-<Rm>]{!}" }, |
13090 | {.mask: 0x0e5000f0, .value: 0x004000d0, ARMV5TE_ABOVE, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
13091 | .callback: &EmulateInstructionARM::EmulateLDRDImmediate, |
13092 | .name: "ldrd<c> <Rt>, <Rt2>, [<Rn>,#+/-<imm8>]!" }, |
13093 | {.mask: 0x0e500ff0, .value: 0x000000d0, ARMV5TE_ABOVE, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
13094 | .callback: &EmulateInstructionARM::EmulateLDRDRegister, |
13095 | .name: "ldrd<c> <Rt>, <Rt2>, [<Rn>, +/-<Rm>]{!}" }, |
13096 | {.mask: 0x0e100f00, .value: 0x0c100b00, ARMvAll, .encoding: eEncodingA1, VFPv2_ABOVE, .size: eSize32, |
13097 | .callback: &EmulateInstructionARM::EmulateVLDM, .name: "vldm{mode}<c> <Rn>{!}, <list>" }, |
13098 | {.mask: 0x0e100f00, .value: 0x0c100a00, ARMvAll, .encoding: eEncodingA2, VFPv2v3, .size: eSize32, |
13099 | .callback: &EmulateInstructionARM::EmulateVLDM, .name: "vldm{mode}<c> <Rn>{!}, <list>" }, |
13100 | {.mask: 0x0f300f00, .value: 0x0d100b00, ARMvAll, .encoding: eEncodingA1, VFPv2_ABOVE, .size: eSize32, |
13101 | .callback: &EmulateInstructionARM::EmulateVLDR, .name: "vldr<c> <Dd>, [<Rn>{,#+/-<imm>}]" }, |
13102 | {.mask: 0x0f300f00, .value: 0x0d100a00, ARMvAll, .encoding: eEncodingA2, VFPv2v3, .size: eSize32, |
13103 | .callback: &EmulateInstructionARM::EmulateVLDR, .name: "vldr<c> <Sd>, [<Rn>{,#+/-<imm>}]" }, |
13104 | {.mask: 0xffb00000, .value: 0xf4200000, ARMvAll, .encoding: eEncodingA1, AdvancedSIMD, .size: eSize32, |
13105 | .callback: &EmulateInstructionARM::EmulateVLD1Multiple, |
13106 | .name: "vld1<c>.<size> <list>, [<Rn>{@<align>}], <Rm>" }, |
13107 | {.mask: 0xffb00300, .value: 0xf4a00000, ARMvAll, .encoding: eEncodingA1, AdvancedSIMD, .size: eSize32, |
13108 | .callback: &EmulateInstructionARM::EmulateVLD1Single, |
13109 | .name: "vld1<c>.<size> <list>, [<Rn>{@<align>}], <Rm>" }, |
13110 | {.mask: 0xffb00f00, .value: 0xf4a00c00, ARMvAll, .encoding: eEncodingA1, AdvancedSIMD, .size: eSize32, |
13111 | .callback: &EmulateInstructionARM::EmulateVLD1SingleAll, |
13112 | .name: "vld1<c>.<size> <list>, [<Rn>{@<align>}], <Rm>" }, |
13113 | |
13114 | // Store instructions |
13115 | {.mask: 0x0fd00000, .value: 0x08800000, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
13116 | .callback: &EmulateInstructionARM::EmulateSTM, .name: "stm<c> <Rn>{!} <registers>" }, |
13117 | {.mask: 0x0fd00000, .value: 0x08000000, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
13118 | .callback: &EmulateInstructionARM::EmulateSTMDA, .name: "stmda<c> <Rn>{!} <registers>" }, |
13119 | {.mask: 0x0fd00000, .value: 0x09000000, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
13120 | .callback: &EmulateInstructionARM::EmulateSTMDB, .name: "stmdb<c> <Rn>{!} <registers>" }, |
13121 | {.mask: 0x0fd00000, .value: 0x09800000, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
13122 | .callback: &EmulateInstructionARM::EmulateSTMIB, .name: "stmib<c> <Rn>{!} <registers>" }, |
13123 | {.mask: 0x0e500010, .value: 0x06000000, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
13124 | .callback: &EmulateInstructionARM::EmulateSTRRegister, |
13125 | .name: "str<c> <Rt> [<Rn> +/-<Rm> {<shift>}]{!}" }, |
13126 | {.mask: 0x0e5000f0, .value: 0x000000b0, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
13127 | .callback: &EmulateInstructionARM::EmulateSTRHRegister, |
13128 | .name: "strh<c> <Rt>,[<Rn>,+/-<Rm>[{!}" }, |
13129 | {.mask: 0x0ff00ff0, .value: 0x01800f90, ARMV6_ABOVE, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
13130 | .callback: &EmulateInstructionARM::EmulateSTREX, .name: "strex<c> <Rd>, <Rt>, [<Rn>]" }, |
13131 | {.mask: 0x0e500000, .value: 0x04400000, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
13132 | .callback: &EmulateInstructionARM::EmulateSTRBImmARM, |
13133 | .name: "strb<c> <Rt>,[<Rn>,#+/-<imm12>]!" }, |
13134 | {.mask: 0x0e500000, .value: 0x04000000, ARMvAll, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
13135 | .callback: &EmulateInstructionARM::EmulateSTRImmARM, |
13136 | .name: "str<c> <Rt>,[<Rn>,#+/-<imm12>]!" }, |
13137 | {.mask: 0x0e5000f0, .value: 0x004000f0, ARMV5TE_ABOVE, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
13138 | .callback: &EmulateInstructionARM::EmulateSTRDImm, |
13139 | .name: "strd<c> <Rt>, <Rt2>, [<Rn> #+/-<imm8>]!" }, |
13140 | {.mask: 0x0e500ff0, .value: 0x000000f0, ARMV5TE_ABOVE, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
13141 | .callback: &EmulateInstructionARM::EmulateSTRDReg, |
13142 | .name: "strd<c> <Rt>, <Rt2>, [<Rn>, +/-<Rm>]{!}" }, |
13143 | {.mask: 0x0e100f00, .value: 0x0c000b00, ARMvAll, .encoding: eEncodingA1, VFPv2_ABOVE, .size: eSize32, |
13144 | .callback: &EmulateInstructionARM::EmulateVSTM, .name: "vstm{mode}<c> <Rn>{!} <list>" }, |
13145 | {.mask: 0x0e100f00, .value: 0x0c000a00, ARMvAll, .encoding: eEncodingA2, VFPv2v3, .size: eSize32, |
13146 | .callback: &EmulateInstructionARM::EmulateVSTM, .name: "vstm{mode}<c> <Rn>{!} <list>" }, |
13147 | {.mask: 0x0f300f00, .value: 0x0d000b00, ARMvAll, .encoding: eEncodingA1, VFPv2_ABOVE, .size: eSize32, |
13148 | .callback: &EmulateInstructionARM::EmulateVSTR, .name: "vstr<c> <Dd> [<Rn>{,#+/-<imm>}]" }, |
13149 | {.mask: 0x0f300f00, .value: 0x0d000a00, ARMvAll, .encoding: eEncodingA2, VFPv2v3, .size: eSize32, |
13150 | .callback: &EmulateInstructionARM::EmulateVSTR, .name: "vstr<c> <Sd> [<Rn>{,#+/-<imm>}]" }, |
13151 | {.mask: 0xffb00000, .value: 0xf4000000, ARMvAll, .encoding: eEncodingA1, AdvancedSIMD, .size: eSize32, |
13152 | .callback: &EmulateInstructionARM::EmulateVST1Multiple, |
13153 | .name: "vst1<c>.<size> <list>, [<Rn>{@<align>}], <Rm>" }, |
13154 | {.mask: 0xffb00300, .value: 0xf4800000, ARMvAll, .encoding: eEncodingA1, AdvancedSIMD, .size: eSize32, |
13155 | .callback: &EmulateInstructionARM::EmulateVST1Single, |
13156 | .name: "vst1<c>.<size> <list>, [<Rn>{@<align>}], <Rm>" }, |
13157 | |
13158 | // Other instructions |
13159 | {.mask: 0x0fff00f0, .value: 0x06af00f0, ARMV6_ABOVE, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
13160 | .callback: &EmulateInstructionARM::EmulateSXTB, .name: "sxtb<c> <Rd>,<Rm>{,<rotation>}" }, |
13161 | {.mask: 0x0fff00f0, .value: 0x06bf0070, ARMV6_ABOVE, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
13162 | .callback: &EmulateInstructionARM::EmulateSXTH, .name: "sxth<c> <Rd>,<Rm>{,<rotation>}" }, |
13163 | {.mask: 0x0fff00f0, .value: 0x06ef0070, ARMV6_ABOVE, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
13164 | .callback: &EmulateInstructionARM::EmulateUXTB, .name: "uxtb<c> <Rd>,<Rm>{,<rotation>}" }, |
13165 | {.mask: 0x0fff00f0, .value: 0x06ff0070, ARMV6_ABOVE, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
13166 | .callback: &EmulateInstructionARM::EmulateUXTH, .name: "uxth<c> <Rd>,<Rm>{,<rotation>}" }, |
13167 | {.mask: 0xfe500000, .value: 0xf8100000, ARMV6_ABOVE, .encoding: eEncodingA1, No_VFP, .size: eSize32, |
13168 | .callback: &EmulateInstructionARM::EmulateRFE, .name: "rfe{<amode>} <Rn>{!}" } |
13169 | |
13170 | }; |
13171 | static const size_t k_num_arm_opcodes = std::size(g_arm_opcodes); |
13172 | |
13173 | for (size_t i = 0; i < k_num_arm_opcodes; ++i) { |
13174 | if ((g_arm_opcodes[i].mask & opcode) == g_arm_opcodes[i].value && |
13175 | (g_arm_opcodes[i].variants & arm_isa) != 0) |
13176 | return &g_arm_opcodes[i]; |
13177 | } |
13178 | return nullptr; |
13179 | } |
13180 | |
13181 | EmulateInstructionARM::ARMOpcode * |
13182 | EmulateInstructionARM::GetThumbOpcodeForInstruction(const uint32_t opcode, |
13183 | uint32_t arm_isa) { |
13184 | |
13185 | static ARMOpcode g_thumb_opcodes[] = { |
13186 | // Prologue instructions |
13187 | |
13188 | // push register(s) |
13189 | {.mask: 0xfffffe00, .value: 0x0000b400, ARMvAll, .encoding: eEncodingT1, No_VFP, .size: eSize16, |
13190 | .callback: &EmulateInstructionARM::EmulatePUSH, .name: "push <registers>" }, |
13191 | {.mask: 0xffff0000, .value: 0xe92d0000, ARMV6T2_ABOVE, .encoding: eEncodingT2, No_VFP, .size: eSize32, |
13192 | .callback: &EmulateInstructionARM::EmulatePUSH, .name: "push.w <registers>" }, |
13193 | {.mask: 0xffff0fff, .value: 0xf84d0d04, ARMV6T2_ABOVE, .encoding: eEncodingT3, No_VFP, .size: eSize32, |
13194 | .callback: &EmulateInstructionARM::EmulatePUSH, .name: "push.w <register>" }, |
13195 | |
13196 | // set r7 to point to a stack offset |
13197 | {.mask: 0xffffff00, .value: 0x0000af00, ARMvAll, .encoding: eEncodingT1, No_VFP, .size: eSize16, |
13198 | .callback: &EmulateInstructionARM::EmulateADDRdSPImm, .name: "add r7, sp, #imm" }, |
13199 | // copy the stack pointer to r7 |
13200 | {.mask: 0xffffffff, .value: 0x0000466f, ARMvAll, .encoding: eEncodingT1, No_VFP, .size: eSize16, |
13201 | .callback: &EmulateInstructionARM::EmulateMOVRdSP, .name: "mov r7, sp" }, |
13202 | // move from high register to low register (comes after "mov r7, sp" to |
13203 | // resolve ambiguity) |
13204 | {.mask: 0xffffffc0, .value: 0x00004640, ARMvAll, .encoding: eEncodingT1, No_VFP, .size: eSize16, |
13205 | .callback: &EmulateInstructionARM::EmulateMOVLowHigh, .name: "mov r0-r7, r8-r15" }, |
13206 | |
13207 | // PC-relative load into register (see also EmulateADDSPRm) |
13208 | {.mask: 0xfffff800, .value: 0x00004800, ARMvAll, .encoding: eEncodingT1, No_VFP, .size: eSize16, |
13209 | .callback: &EmulateInstructionARM::EmulateLDRRtPCRelative, .name: "ldr <Rt>, [PC, #imm]" }, |
13210 | |
13211 | // adjust the stack pointer |
13212 | {.mask: 0xffffff87, .value: 0x00004485, ARMvAll, .encoding: eEncodingT2, No_VFP, .size: eSize16, |
13213 | .callback: &EmulateInstructionARM::EmulateADDSPRm, .name: "add sp, <Rm>" }, |
13214 | {.mask: 0xffffff80, .value: 0x0000b080, ARMvAll, .encoding: eEncodingT1, No_VFP, .size: eSize16, |
13215 | .callback: &EmulateInstructionARM::EmulateSUBSPImm, .name: "sub sp, sp, #imm" }, |
13216 | {.mask: 0xfbef8f00, .value: 0xf1ad0d00, ARMV6T2_ABOVE, .encoding: eEncodingT2, No_VFP, .size: eSize32, |
13217 | .callback: &EmulateInstructionARM::EmulateSUBSPImm, .name: "sub.w sp, sp, #<const>" }, |
13218 | {.mask: 0xfbff8f00, .value: 0xf2ad0d00, ARMV6T2_ABOVE, .encoding: eEncodingT3, No_VFP, .size: eSize32, |
13219 | .callback: &EmulateInstructionARM::EmulateSUBSPImm, .name: "subw sp, sp, #imm12" }, |
13220 | {.mask: 0xffef8000, .value: 0xebad0000, ARMV6T2_ABOVE, .encoding: eEncodingT1, No_VFP, .size: eSize32, |
13221 | .callback: &EmulateInstructionARM::EmulateSUBSPReg, |
13222 | .name: "sub{s}<c> <Rd>, sp, <Rm>{,<shift>}" }, |
13223 | |
13224 | // vector push consecutive extension register(s) |
13225 | {.mask: 0xffbf0f00, .value: 0xed2d0b00, ARMV6T2_ABOVE, .encoding: eEncodingT1, No_VFP, .size: eSize32, |
13226 | .callback: &EmulateInstructionARM::EmulateVPUSH, .name: "vpush.64 <list>" }, |
13227 | {.mask: 0xffbf0f00, .value: 0xed2d0a00, ARMV6T2_ABOVE, .encoding: eEncodingT2, No_VFP, .size: eSize32, |
13228 | .callback: &EmulateInstructionARM::EmulateVPUSH, .name: "vpush.32 <list>" }, |
13229 | |
13230 | // Epilogue instructions |
13231 | |
13232 | {.mask: 0xfffff800, .value: 0x0000a800, ARMV4T_ABOVE, .encoding: eEncodingT1, No_VFP, .size: eSize16, |
13233 | .callback: &EmulateInstructionARM::EmulateADDSPImm, .name: "add<c> <Rd>, sp, #imm" }, |
13234 | {.mask: 0xffffff80, .value: 0x0000b000, ARMvAll, .encoding: eEncodingT2, No_VFP, .size: eSize16, |
13235 | .callback: &EmulateInstructionARM::EmulateADDSPImm, .name: "add sp, #imm" }, |
13236 | {.mask: 0xfffffe00, .value: 0x0000bc00, ARMvAll, .encoding: eEncodingT1, No_VFP, .size: eSize16, |
13237 | .callback: &EmulateInstructionARM::EmulatePOP, .name: "pop <registers>" }, |
13238 | {.mask: 0xffff0000, .value: 0xe8bd0000, ARMV6T2_ABOVE, .encoding: eEncodingT2, No_VFP, .size: eSize32, |
13239 | .callback: &EmulateInstructionARM::EmulatePOP, .name: "pop.w <registers>" }, |
13240 | {.mask: 0xffff0fff, .value: 0xf85d0d04, ARMV6T2_ABOVE, .encoding: eEncodingT3, No_VFP, .size: eSize32, |
13241 | .callback: &EmulateInstructionARM::EmulatePOP, .name: "pop.w <register>" }, |
13242 | {.mask: 0xffbf0f00, .value: 0xecbd0b00, ARMV6T2_ABOVE, .encoding: eEncodingT1, No_VFP, .size: eSize32, |
13243 | .callback: &EmulateInstructionARM::EmulateVPOP, .name: "vpop.64 <list>" }, |
13244 | {.mask: 0xffbf0f00, .value: 0xecbd0a00, ARMV6T2_ABOVE, .encoding: eEncodingT2, No_VFP, .size: eSize32, |
13245 | .callback: &EmulateInstructionARM::EmulateVPOP, .name: "vpop.32 <list>" }, |
13246 | |
13247 | // Supervisor Call (previously Software Interrupt) |
13248 | {.mask: 0xffffff00, .value: 0x0000df00, ARMvAll, .encoding: eEncodingT1, No_VFP, .size: eSize16, |
13249 | .callback: &EmulateInstructionARM::EmulateSVC, .name: "svc #imm8" }, |
13250 | |
13251 | // If Then makes up to four following instructions conditional. |
13252 | // The next 5 opcode _must_ come before the if then instruction |
13253 | {.mask: 0xffffffff, .value: 0x0000bf00, ARMV6T2_ABOVE, .encoding: eEncodingT1, No_VFP, .size: eSize16, |
13254 | .callback: &EmulateInstructionARM::EmulateNop, .name: "nop" }, |
13255 | {.mask: 0xffffffff, .value: 0x0000bf10, ARMV7_ABOVE, .encoding: eEncodingT1, No_VFP, .size: eSize16, |
13256 | .callback: &EmulateInstructionARM::EmulateNop, .name: "nop YIELD (yield hint)" }, |
13257 | {.mask: 0xffffffff, .value: 0x0000bf20, ARMV7_ABOVE, .encoding: eEncodingT1, No_VFP, .size: eSize16, |
13258 | .callback: &EmulateInstructionARM::EmulateNop, .name: "nop WFE (wait for event hint)" }, |
13259 | {.mask: 0xffffffff, .value: 0x0000bf30, ARMV7_ABOVE, .encoding: eEncodingT1, No_VFP, .size: eSize16, |
13260 | .callback: &EmulateInstructionARM::EmulateNop, .name: "nop WFI (wait for interrupt hint)" }, |
13261 | {.mask: 0xffffffff, .value: 0x0000bf40, ARMV7_ABOVE, .encoding: eEncodingT1, No_VFP, .size: eSize16, |
13262 | .callback: &EmulateInstructionARM::EmulateNop, .name: "nop SEV (send event hint)" }, |
13263 | {.mask: 0xffffff00, .value: 0x0000bf00, ARMV6T2_ABOVE, .encoding: eEncodingT1, No_VFP, .size: eSize16, |
13264 | .callback: &EmulateInstructionARM::EmulateIT, .name: "it{<x>{<y>{<z>}}} <firstcond>" }, |
13265 | |
13266 | // Branch instructions |
13267 | // To resolve ambiguity, "b<c> #imm8" should come after "svc #imm8". |
13268 | {.mask: 0xfffff000, .value: 0x0000d000, ARMvAll, .encoding: eEncodingT1, No_VFP, .size: eSize16, |
13269 | .callback: &EmulateInstructionARM::EmulateB, .name: "b<c> #imm8 (outside IT)" }, |
13270 | {.mask: 0xfffff800, .value: 0x0000e000, ARMvAll, .encoding: eEncodingT2, No_VFP, .size: eSize16, |
13271 | .callback: &EmulateInstructionARM::EmulateB, .name: "b<c> #imm11 (outside or last in IT)" }, |
13272 | {.mask: 0xf800d000, .value: 0xf0008000, ARMV6T2_ABOVE, .encoding: eEncodingT3, No_VFP, .size: eSize32, |
13273 | .callback: &EmulateInstructionARM::EmulateB, .name: "b<c>.w #imm8 (outside IT)" }, |
13274 | {.mask: 0xf800d000, .value: 0xf0009000, ARMV6T2_ABOVE, .encoding: eEncodingT4, No_VFP, .size: eSize32, |
13275 | .callback: &EmulateInstructionARM::EmulateB, |
13276 | .name: "b<c>.w #imm8 (outside or last in IT)" }, |
13277 | // J1 == J2 == 1 |
13278 | {.mask: 0xf800d000, .value: 0xf000d000, ARMV4T_ABOVE, .encoding: eEncodingT1, No_VFP, .size: eSize32, |
13279 | .callback: &EmulateInstructionARM::EmulateBLXImmediate, .name: "bl <label>" }, |
13280 | // J1 == J2 == 1 |
13281 | {.mask: 0xf800d001, .value: 0xf000c000, ARMV5_ABOVE, .encoding: eEncodingT2, No_VFP, .size: eSize32, |
13282 | .callback: &EmulateInstructionARM::EmulateBLXImmediate, .name: "blx <label>" }, |
13283 | {.mask: 0xffffff87, .value: 0x00004780, ARMV5_ABOVE, .encoding: eEncodingT1, No_VFP, .size: eSize16, |
13284 | .callback: &EmulateInstructionARM::EmulateBLXRm, .name: "blx <Rm>" }, |
13285 | // for example, "bx lr" |
13286 | {.mask: 0xffffff87, .value: 0x00004700, ARMvAll, .encoding: eEncodingT1, No_VFP, .size: eSize32, |
13287 | .callback: &EmulateInstructionARM::EmulateBXRm, .name: "bx <Rm>" }, |
13288 | // bxj |
13289 | {.mask: 0xfff0ffff, .value: 0xf3c08f00, ARMV5J_ABOVE, .encoding: eEncodingT1, No_VFP, .size: eSize32, |
13290 | .callback: &EmulateInstructionARM::EmulateBXJRm, .name: "bxj <Rm>" }, |
13291 | // compare and branch |
13292 | {.mask: 0xfffff500, .value: 0x0000b100, ARMV6T2_ABOVE, .encoding: eEncodingT1, No_VFP, .size: eSize16, |
13293 | .callback: &EmulateInstructionARM::EmulateCB, .name: "cb{n}z <Rn>, <label>" }, |
13294 | // table branch byte |
13295 | {.mask: 0xfff0fff0, .value: 0xe8d0f000, ARMV6T2_ABOVE, .encoding: eEncodingT1, No_VFP, .size: eSize32, |
13296 | .callback: &EmulateInstructionARM::EmulateTB, .name: "tbb<c> <Rn>, <Rm>" }, |
13297 | // table branch halfword |
13298 | {.mask: 0xfff0fff0, .value: 0xe8d0f010, ARMV6T2_ABOVE, .encoding: eEncodingT1, No_VFP, .size: eSize32, |
13299 | .callback: &EmulateInstructionARM::EmulateTB, .name: "tbh<c> <Rn>, <Rm>, lsl #1" }, |
13300 | |
13301 | // Data-processing instructions |
13302 | // adc (immediate) |
13303 | {.mask: 0xfbe08000, .value: 0xf1400000, ARMV6T2_ABOVE, .encoding: eEncodingT1, No_VFP, .size: eSize32, |
13304 | .callback: &EmulateInstructionARM::EmulateADCImm, .name: "adc{s}<c> <Rd>, <Rn>, #<const>" }, |
13305 | // adc (register) |
13306 | {.mask: 0xffffffc0, .value: 0x00004140, ARMvAll, .encoding: eEncodingT1, No_VFP, .size: eSize16, |
13307 | .callback: &EmulateInstructionARM::EmulateADCReg, .name: "adcs|adc<c> <Rdn>, <Rm>" }, |
13308 | {.mask: 0xffe08000, .value: 0xeb400000, ARMV6T2_ABOVE, .encoding: eEncodingT2, No_VFP, .size: eSize32, |
13309 | .callback: &EmulateInstructionARM::EmulateADCReg, |
13310 | .name: "adc{s}<c>.w <Rd>, <Rn>, <Rm> {,<shift>}" }, |
13311 | // add (register) |
13312 | {.mask: 0xfffffe00, .value: 0x00001800, ARMvAll, .encoding: eEncodingT1, No_VFP, .size: eSize16, |
13313 | .callback: &EmulateInstructionARM::EmulateADDReg, .name: "adds|add<c> <Rd>, <Rn>, <Rm>" }, |
13314 | // Make sure "add sp, <Rm>" comes before this instruction, so there's no |
13315 | // ambiguity decoding the two. |
13316 | {.mask: 0xffffff00, .value: 0x00004400, ARMvAll, .encoding: eEncodingT2, No_VFP, .size: eSize16, |
13317 | .callback: &EmulateInstructionARM::EmulateADDReg, .name: "add<c> <Rdn>, <Rm>" }, |
13318 | // adr |
13319 | {.mask: 0xfffff800, .value: 0x0000a000, ARMvAll, .encoding: eEncodingT1, No_VFP, .size: eSize16, |
13320 | .callback: &EmulateInstructionARM::EmulateADR, .name: "add<c> <Rd>, PC, #<const>" }, |
13321 | {.mask: 0xfbff8000, .value: 0xf2af0000, ARMV6T2_ABOVE, .encoding: eEncodingT2, No_VFP, .size: eSize32, |
13322 | .callback: &EmulateInstructionARM::EmulateADR, .name: "sub<c> <Rd>, PC, #<const>" }, |
13323 | {.mask: 0xfbff8000, .value: 0xf20f0000, ARMV6T2_ABOVE, .encoding: eEncodingT3, No_VFP, .size: eSize32, |
13324 | .callback: &EmulateInstructionARM::EmulateADR, .name: "add<c> <Rd>, PC, #<const>" }, |
13325 | // and (immediate) |
13326 | {.mask: 0xfbe08000, .value: 0xf0000000, ARMV6T2_ABOVE, .encoding: eEncodingT1, No_VFP, .size: eSize32, |
13327 | .callback: &EmulateInstructionARM::EmulateANDImm, .name: "and{s}<c> <Rd>, <Rn>, #<const>" }, |
13328 | // and (register) |
13329 | {.mask: 0xffffffc0, .value: 0x00004000, ARMvAll, .encoding: eEncodingT1, No_VFP, .size: eSize16, |
13330 | .callback: &EmulateInstructionARM::EmulateANDReg, .name: "ands|and<c> <Rdn>, <Rm>" }, |
13331 | {.mask: 0xffe08000, .value: 0xea000000, ARMV6T2_ABOVE, .encoding: eEncodingT2, No_VFP, .size: eSize32, |
13332 | .callback: &EmulateInstructionARM::EmulateANDReg, |
13333 | .name: "and{s}<c>.w <Rd>, <Rn>, <Rm> {,<shift>}" }, |
13334 | // bic (immediate) |
13335 | {.mask: 0xfbe08000, .value: 0xf0200000, ARMV6T2_ABOVE, .encoding: eEncodingT1, No_VFP, .size: eSize32, |
13336 | .callback: &EmulateInstructionARM::EmulateBICImm, .name: "bic{s}<c> <Rd>, <Rn>, #<const>" }, |
13337 | // bic (register) |
13338 | {.mask: 0xffffffc0, .value: 0x00004380, ARMvAll, .encoding: eEncodingT1, No_VFP, .size: eSize16, |
13339 | .callback: &EmulateInstructionARM::EmulateBICReg, .name: "bics|bic<c> <Rdn>, <Rm>" }, |
13340 | {.mask: 0xffe08000, .value: 0xea200000, ARMV6T2_ABOVE, .encoding: eEncodingT2, No_VFP, .size: eSize32, |
13341 | .callback: &EmulateInstructionARM::EmulateBICReg, |
13342 | .name: "bic{s}<c>.w <Rd>, <Rn>, <Rm> {,<shift>}" }, |
13343 | // eor (immediate) |
13344 | {.mask: 0xfbe08000, .value: 0xf0800000, ARMV6T2_ABOVE, .encoding: eEncodingT1, No_VFP, .size: eSize32, |
13345 | .callback: &EmulateInstructionARM::EmulateEORImm, .name: "eor{s}<c> <Rd>, <Rn>, #<const>" }, |
13346 | // eor (register) |
13347 | {.mask: 0xffffffc0, .value: 0x00004040, ARMvAll, .encoding: eEncodingT1, No_VFP, .size: eSize16, |
13348 | .callback: &EmulateInstructionARM::EmulateEORReg, .name: "eors|eor<c> <Rdn>, <Rm>" }, |
13349 | {.mask: 0xffe08000, .value: 0xea800000, ARMV6T2_ABOVE, .encoding: eEncodingT2, No_VFP, .size: eSize32, |
13350 | .callback: &EmulateInstructionARM::EmulateEORReg, |
13351 | .name: "eor{s}<c>.w <Rd>, <Rn>, <Rm> {,<shift>}" }, |
13352 | // orr (immediate) |
13353 | {.mask: 0xfbe08000, .value: 0xf0400000, ARMV6T2_ABOVE, .encoding: eEncodingT1, No_VFP, .size: eSize32, |
13354 | .callback: &EmulateInstructionARM::EmulateORRImm, .name: "orr{s}<c> <Rd>, <Rn>, #<const>" }, |
13355 | // orr (register) |
13356 | {.mask: 0xffffffc0, .value: 0x00004300, ARMvAll, .encoding: eEncodingT1, No_VFP, .size: eSize16, |
13357 | .callback: &EmulateInstructionARM::EmulateORRReg, .name: "orrs|orr<c> <Rdn>, <Rm>" }, |
13358 | {.mask: 0xffe08000, .value: 0xea400000, ARMV6T2_ABOVE, .encoding: eEncodingT2, No_VFP, .size: eSize32, |
13359 | .callback: &EmulateInstructionARM::EmulateORRReg, |
13360 | .name: "orr{s}<c>.w <Rd>, <Rn>, <Rm> {,<shift>}" }, |
13361 | // rsb (immediate) |
13362 | {.mask: 0xffffffc0, .value: 0x00004240, ARMvAll, .encoding: eEncodingT1, No_VFP, .size: eSize16, |
13363 | .callback: &EmulateInstructionARM::EmulateRSBImm, .name: "rsbs|rsb<c> <Rd>, <Rn>, #0" }, |
13364 | {.mask: 0xfbe08000, .value: 0xf1c00000, ARMV6T2_ABOVE, .encoding: eEncodingT2, No_VFP, .size: eSize32, |
13365 | .callback: &EmulateInstructionARM::EmulateRSBImm, |
13366 | .name: "rsb{s}<c>.w <Rd>, <Rn>, #<const>" }, |
13367 | // rsb (register) |
13368 | {.mask: 0xffe08000, .value: 0xea400000, ARMV6T2_ABOVE, .encoding: eEncodingT1, No_VFP, .size: eSize32, |
13369 | .callback: &EmulateInstructionARM::EmulateRSBReg, |
13370 | .name: "rsb{s}<c>.w <Rd>, <Rn>, <Rm> {,<shift>}" }, |
13371 | // sbc (immediate) |
13372 | {.mask: 0xfbe08000, .value: 0xf1600000, ARMV6T2_ABOVE, .encoding: eEncodingT1, No_VFP, .size: eSize32, |
13373 | .callback: &EmulateInstructionARM::EmulateSBCImm, .name: "sbc{s}<c> <Rd>, <Rn>, #<const>" }, |
13374 | // sbc (register) |
13375 | {.mask: 0xffffffc0, .value: 0x00004180, ARMvAll, .encoding: eEncodingT1, No_VFP, .size: eSize16, |
13376 | .callback: &EmulateInstructionARM::EmulateSBCReg, .name: "sbcs|sbc<c> <Rdn>, <Rm>" }, |
13377 | {.mask: 0xffe08000, .value: 0xeb600000, ARMV6T2_ABOVE, .encoding: eEncodingT2, No_VFP, .size: eSize32, |
13378 | .callback: &EmulateInstructionARM::EmulateSBCReg, |
13379 | .name: "sbc{s}<c>.w <Rd>, <Rn>, <Rm> {,<shift>}" }, |
13380 | // add (immediate, Thumb) |
13381 | {.mask: 0xfffffe00, .value: 0x00001c00, ARMV4T_ABOVE, .encoding: eEncodingT1, No_VFP, .size: eSize16, |
13382 | .callback: &EmulateInstructionARM::EmulateADDImmThumb, |
13383 | .name: "adds|add<c> <Rd>,<Rn>,#<imm3>" }, |
13384 | {.mask: 0xfffff800, .value: 0x00003000, ARMV4T_ABOVE, .encoding: eEncodingT2, No_VFP, .size: eSize16, |
13385 | .callback: &EmulateInstructionARM::EmulateADDImmThumb, .name: "adds|add<c> <Rdn>,#<imm8>" }, |
13386 | {.mask: 0xfbe08000, .value: 0xf1000000, ARMV6T2_ABOVE, .encoding: eEncodingT3, No_VFP, .size: eSize32, |
13387 | .callback: &EmulateInstructionARM::EmulateADDImmThumb, |
13388 | .name: "add{s}<c>.w <Rd>,<Rn>,#<const>" }, |
13389 | {.mask: 0xfbf08000, .value: 0xf2000000, ARMV6T2_ABOVE, .encoding: eEncodingT4, No_VFP, .size: eSize32, |
13390 | .callback: &EmulateInstructionARM::EmulateADDImmThumb, |
13391 | .name: "addw<c> <Rd>,<Rn>,#<imm12>" }, |
13392 | // sub (immediate, Thumb) |
13393 | {.mask: 0xfffffe00, .value: 0x00001e00, ARMvAll, .encoding: eEncodingT1, No_VFP, .size: eSize16, |
13394 | .callback: &EmulateInstructionARM::EmulateSUBImmThumb, |
13395 | .name: "subs|sub<c> <Rd>, <Rn> #imm3" }, |
13396 | {.mask: 0xfffff800, .value: 0x00003800, ARMvAll, .encoding: eEncodingT2, No_VFP, .size: eSize16, |
13397 | .callback: &EmulateInstructionARM::EmulateSUBImmThumb, .name: "subs|sub<c> <Rdn>, #imm8" }, |
13398 | {.mask: 0xfbe08000, .value: 0xf1a00000, ARMV6T2_ABOVE, .encoding: eEncodingT3, No_VFP, .size: eSize32, |
13399 | .callback: &EmulateInstructionARM::EmulateSUBImmThumb, |
13400 | .name: "sub{s}<c>.w <Rd>, <Rn>, #<const>" }, |
13401 | {.mask: 0xfbf08000, .value: 0xf2a00000, ARMV6T2_ABOVE, .encoding: eEncodingT4, No_VFP, .size: eSize32, |
13402 | .callback: &EmulateInstructionARM::EmulateSUBImmThumb, |
13403 | .name: "subw<c> <Rd>, <Rn>, #imm12" }, |
13404 | // sub (sp minus immediate) |
13405 | {.mask: 0xfbef8000, .value: 0xf1ad0000, ARMV6T2_ABOVE, .encoding: eEncodingT2, No_VFP, .size: eSize32, |
13406 | .callback: &EmulateInstructionARM::EmulateSUBSPImm, .name: "sub{s}.w <Rd>, sp, #<const>" }, |
13407 | {.mask: 0xfbff8000, .value: 0xf2ad0000, ARMV6T2_ABOVE, .encoding: eEncodingT3, No_VFP, .size: eSize32, |
13408 | .callback: &EmulateInstructionARM::EmulateSUBSPImm, .name: "subw<c> <Rd>, sp, #imm12" }, |
13409 | // sub (register) |
13410 | {.mask: 0xfffffe00, .value: 0x00001a00, ARMV4T_ABOVE, .encoding: eEncodingT1, No_VFP, .size: eSize16, |
13411 | .callback: &EmulateInstructionARM::EmulateSUBReg, .name: "subs|sub<c> <Rd>, <Rn>, <Rm>" }, |
13412 | {.mask: 0xffe08000, .value: 0xeba00000, ARMV6T2_ABOVE, .encoding: eEncodingT2, No_VFP, .size: eSize32, |
13413 | .callback: &EmulateInstructionARM::EmulateSUBReg, |
13414 | .name: "sub{s}<c>.w <Rd>, <Rn>, <Rm>{,<shift>}" }, |
13415 | // teq (immediate) |
13416 | {.mask: 0xfbf08f00, .value: 0xf0900f00, ARMV6T2_ABOVE, .encoding: eEncodingT1, No_VFP, .size: eSize32, |
13417 | .callback: &EmulateInstructionARM::EmulateTEQImm, .name: "teq<c> <Rn>, #<const>" }, |
13418 | // teq (register) |
13419 | {.mask: 0xfff08f00, .value: 0xea900f00, ARMV6T2_ABOVE, .encoding: eEncodingT1, No_VFP, .size: eSize32, |
13420 | .callback: &EmulateInstructionARM::EmulateTEQReg, .name: "teq<c> <Rn>, <Rm> {,<shift>}" }, |
13421 | // tst (immediate) |
13422 | {.mask: 0xfbf08f00, .value: 0xf0100f00, ARMV6T2_ABOVE, .encoding: eEncodingT1, No_VFP, .size: eSize32, |
13423 | .callback: &EmulateInstructionARM::EmulateTSTImm, .name: "tst<c> <Rn>, #<const>" }, |
13424 | // tst (register) |
13425 | {.mask: 0xffffffc0, .value: 0x00004200, ARMvAll, .encoding: eEncodingT1, No_VFP, .size: eSize16, |
13426 | .callback: &EmulateInstructionARM::EmulateTSTReg, .name: "tst<c> <Rdn>, <Rm>" }, |
13427 | {.mask: 0xfff08f00, .value: 0xea100f00, ARMV6T2_ABOVE, .encoding: eEncodingT2, No_VFP, .size: eSize32, |
13428 | .callback: &EmulateInstructionARM::EmulateTSTReg, .name: "tst<c>.w <Rn>, <Rm> {,<shift>}" }, |
13429 | |
13430 | // move from high register to high register |
13431 | {.mask: 0xffffff00, .value: 0x00004600, ARMvAll, .encoding: eEncodingT1, No_VFP, .size: eSize16, |
13432 | .callback: &EmulateInstructionARM::EmulateMOVRdRm, .name: "mov<c> <Rd>, <Rm>" }, |
13433 | // move from low register to low register |
13434 | {.mask: 0xffffffc0, .value: 0x00000000, ARMvAll, .encoding: eEncodingT2, No_VFP, .size: eSize16, |
13435 | .callback: &EmulateInstructionARM::EmulateMOVRdRm, .name: "movs <Rd>, <Rm>" }, |
13436 | // mov{s}<c>.w <Rd>, <Rm> |
13437 | {.mask: 0xffeff0f0, .value: 0xea4f0000, ARMV6T2_ABOVE, .encoding: eEncodingT3, No_VFP, .size: eSize32, |
13438 | .callback: &EmulateInstructionARM::EmulateMOVRdRm, .name: "mov{s}<c>.w <Rd>, <Rm>" }, |
13439 | // move immediate |
13440 | {.mask: 0xfffff800, .value: 0x00002000, ARMvAll, .encoding: eEncodingT1, No_VFP, .size: eSize16, |
13441 | .callback: &EmulateInstructionARM::EmulateMOVRdImm, .name: "movs|mov<c> <Rd>, #imm8" }, |
13442 | {.mask: 0xfbef8000, .value: 0xf04f0000, ARMV6T2_ABOVE, .encoding: eEncodingT2, No_VFP, .size: eSize32, |
13443 | .callback: &EmulateInstructionARM::EmulateMOVRdImm, .name: "mov{s}<c>.w <Rd>, #<const>" }, |
13444 | {.mask: 0xfbf08000, .value: 0xf2400000, ARMV6T2_ABOVE, .encoding: eEncodingT3, No_VFP, .size: eSize32, |
13445 | .callback: &EmulateInstructionARM::EmulateMOVRdImm, .name: "movw<c> <Rd>,#<imm16>" }, |
13446 | // mvn (immediate) |
13447 | {.mask: 0xfbef8000, .value: 0xf06f0000, ARMV6T2_ABOVE, .encoding: eEncodingT1, No_VFP, .size: eSize32, |
13448 | .callback: &EmulateInstructionARM::EmulateMVNImm, .name: "mvn{s} <Rd>, #<const>" }, |
13449 | // mvn (register) |
13450 | {.mask: 0xffffffc0, .value: 0x000043c0, ARMvAll, .encoding: eEncodingT1, No_VFP, .size: eSize16, |
13451 | .callback: &EmulateInstructionARM::EmulateMVNReg, .name: "mvns|mvn<c> <Rd>, <Rm>" }, |
13452 | {.mask: 0xffef8000, .value: 0xea6f0000, ARMV6T2_ABOVE, .encoding: eEncodingT2, No_VFP, .size: eSize32, |
13453 | .callback: &EmulateInstructionARM::EmulateMVNReg, |
13454 | .name: "mvn{s}<c>.w <Rd>, <Rm> {,<shift>}" }, |
13455 | // cmn (immediate) |
13456 | {.mask: 0xfbf08f00, .value: 0xf1100f00, ARMV6T2_ABOVE, .encoding: eEncodingT1, No_VFP, .size: eSize32, |
13457 | .callback: &EmulateInstructionARM::EmulateCMNImm, .name: "cmn<c> <Rn>, #<const>" }, |
13458 | // cmn (register) |
13459 | {.mask: 0xffffffc0, .value: 0x000042c0, ARMvAll, .encoding: eEncodingT1, No_VFP, .size: eSize16, |
13460 | .callback: &EmulateInstructionARM::EmulateCMNReg, .name: "cmn<c> <Rn>, <Rm>" }, |
13461 | {.mask: 0xfff08f00, .value: 0xeb100f00, ARMV6T2_ABOVE, .encoding: eEncodingT2, No_VFP, .size: eSize32, |
13462 | .callback: &EmulateInstructionARM::EmulateCMNReg, .name: "cmn<c> <Rn>, <Rm> {,<shift>}" }, |
13463 | // cmp (immediate) |
13464 | {.mask: 0xfffff800, .value: 0x00002800, ARMvAll, .encoding: eEncodingT1, No_VFP, .size: eSize16, |
13465 | .callback: &EmulateInstructionARM::EmulateCMPImm, .name: "cmp<c> <Rn>, #imm8" }, |
13466 | {.mask: 0xfbf08f00, .value: 0xf1b00f00, ARMV6T2_ABOVE, .encoding: eEncodingT2, No_VFP, .size: eSize32, |
13467 | .callback: &EmulateInstructionARM::EmulateCMPImm, .name: "cmp<c>.w <Rn>, #<const>" }, |
13468 | // cmp (register) (Rn and Rm both from r0-r7) |
13469 | {.mask: 0xffffffc0, .value: 0x00004280, ARMvAll, .encoding: eEncodingT1, No_VFP, .size: eSize16, |
13470 | .callback: &EmulateInstructionARM::EmulateCMPReg, .name: "cmp<c> <Rn>, <Rm>" }, |
13471 | // cmp (register) (Rn and Rm not both from r0-r7) |
13472 | {.mask: 0xffffff00, .value: 0x00004500, ARMvAll, .encoding: eEncodingT2, No_VFP, .size: eSize16, |
13473 | .callback: &EmulateInstructionARM::EmulateCMPReg, .name: "cmp<c> <Rn>, <Rm>" }, |
13474 | {.mask: 0xfff08f00, .value: 0xebb00f00, ARMvAll, .encoding: eEncodingT3, No_VFP, .size: eSize16, |
13475 | .callback: &EmulateInstructionARM::EmulateCMPReg, |
13476 | .name: "cmp<c>.w <Rn>, <Rm> {, <shift>}" }, |
13477 | // asr (immediate) |
13478 | {.mask: 0xfffff800, .value: 0x00001000, ARMvAll, .encoding: eEncodingT1, No_VFP, .size: eSize16, |
13479 | .callback: &EmulateInstructionARM::EmulateASRImm, .name: "asrs|asr<c> <Rd>, <Rm>, #imm" }, |
13480 | {.mask: 0xffef8030, .value: 0xea4f0020, ARMV6T2_ABOVE, .encoding: eEncodingT2, No_VFP, .size: eSize32, |
13481 | .callback: &EmulateInstructionARM::EmulateASRImm, .name: "asr{s}<c>.w <Rd>, <Rm>, #imm" }, |
13482 | // asr (register) |
13483 | {.mask: 0xffffffc0, .value: 0x00004100, ARMvAll, .encoding: eEncodingT1, No_VFP, .size: eSize16, |
13484 | .callback: &EmulateInstructionARM::EmulateASRReg, .name: "asrs|asr<c> <Rdn>, <Rm>" }, |
13485 | {.mask: 0xffe0f0f0, .value: 0xfa40f000, ARMV6T2_ABOVE, .encoding: eEncodingT2, No_VFP, .size: eSize32, |
13486 | .callback: &EmulateInstructionARM::EmulateASRReg, .name: "asr{s}<c>.w <Rd>, <Rn>, <Rm>" }, |
13487 | // lsl (immediate) |
13488 | {.mask: 0xfffff800, .value: 0x00000000, ARMvAll, .encoding: eEncodingT1, No_VFP, .size: eSize16, |
13489 | .callback: &EmulateInstructionARM::EmulateLSLImm, .name: "lsls|lsl<c> <Rd>, <Rm>, #imm" }, |
13490 | {.mask: 0xffef8030, .value: 0xea4f0000, ARMV6T2_ABOVE, .encoding: eEncodingT2, No_VFP, .size: eSize32, |
13491 | .callback: &EmulateInstructionARM::EmulateLSLImm, .name: "lsl{s}<c>.w <Rd>, <Rm>, #imm" }, |
13492 | // lsl (register) |
13493 | {.mask: 0xffffffc0, .value: 0x00004080, ARMvAll, .encoding: eEncodingT1, No_VFP, .size: eSize16, |
13494 | .callback: &EmulateInstructionARM::EmulateLSLReg, .name: "lsls|lsl<c> <Rdn>, <Rm>" }, |
13495 | {.mask: 0xffe0f0f0, .value: 0xfa00f000, ARMV6T2_ABOVE, .encoding: eEncodingT2, No_VFP, .size: eSize32, |
13496 | .callback: &EmulateInstructionARM::EmulateLSLReg, .name: "lsl{s}<c>.w <Rd>, <Rn>, <Rm>" }, |
13497 | // lsr (immediate) |
13498 | {.mask: 0xfffff800, .value: 0x00000800, ARMvAll, .encoding: eEncodingT1, No_VFP, .size: eSize16, |
13499 | .callback: &EmulateInstructionARM::EmulateLSRImm, .name: "lsrs|lsr<c> <Rd>, <Rm>, #imm" }, |
13500 | {.mask: 0xffef8030, .value: 0xea4f0010, ARMV6T2_ABOVE, .encoding: eEncodingT2, No_VFP, .size: eSize32, |
13501 | .callback: &EmulateInstructionARM::EmulateLSRImm, .name: "lsr{s}<c>.w <Rd>, <Rm>, #imm" }, |
13502 | // lsr (register) |
13503 | {.mask: 0xffffffc0, .value: 0x000040c0, ARMvAll, .encoding: eEncodingT1, No_VFP, .size: eSize16, |
13504 | .callback: &EmulateInstructionARM::EmulateLSRReg, .name: "lsrs|lsr<c> <Rdn>, <Rm>" }, |
13505 | {.mask: 0xffe0f0f0, .value: 0xfa20f000, ARMV6T2_ABOVE, .encoding: eEncodingT2, No_VFP, .size: eSize32, |
13506 | .callback: &EmulateInstructionARM::EmulateLSRReg, .name: "lsr{s}<c>.w <Rd>, <Rn>, <Rm>" }, |
13507 | // rrx is a special case encoding of ror (immediate) |
13508 | {.mask: 0xffeff0f0, .value: 0xea4f0030, ARMV6T2_ABOVE, .encoding: eEncodingT1, No_VFP, .size: eSize32, |
13509 | .callback: &EmulateInstructionARM::EmulateRRX, .name: "rrx{s}<c>.w <Rd>, <Rm>" }, |
13510 | // ror (immediate) |
13511 | {.mask: 0xffef8030, .value: 0xea4f0030, ARMV6T2_ABOVE, .encoding: eEncodingT1, No_VFP, .size: eSize32, |
13512 | .callback: &EmulateInstructionARM::EmulateRORImm, .name: "ror{s}<c>.w <Rd>, <Rm>, #imm" }, |
13513 | // ror (register) |
13514 | {.mask: 0xffffffc0, .value: 0x000041c0, ARMvAll, .encoding: eEncodingT1, No_VFP, .size: eSize16, |
13515 | .callback: &EmulateInstructionARM::EmulateRORReg, .name: "rors|ror<c> <Rdn>, <Rm>" }, |
13516 | {.mask: 0xffe0f0f0, .value: 0xfa60f000, ARMV6T2_ABOVE, .encoding: eEncodingT2, No_VFP, .size: eSize32, |
13517 | .callback: &EmulateInstructionARM::EmulateRORReg, .name: "ror{s}<c>.w <Rd>, <Rn>, <Rm>" }, |
13518 | // mul |
13519 | {.mask: 0xffffffc0, .value: 0x00004340, ARMV4T_ABOVE, .encoding: eEncodingT1, No_VFP, .size: eSize16, |
13520 | .callback: &EmulateInstructionARM::EmulateMUL, .name: "muls <Rdm>,<Rn>,<Rdm>" }, |
13521 | // mul |
13522 | {.mask: 0xfff0f0f0, .value: 0xfb00f000, ARMV6T2_ABOVE, .encoding: eEncodingT2, No_VFP, .size: eSize32, |
13523 | .callback: &EmulateInstructionARM::EmulateMUL, .name: "mul<c> <Rd>,<Rn>,<Rm>" }, |
13524 | |
13525 | // subs pc, lr and related instructions |
13526 | {.mask: 0xffffff00, .value: 0xf3de8f00, ARMV6T2_ABOVE, .encoding: eEncodingT1, No_VFP, .size: eSize32, |
13527 | .callback: &EmulateInstructionARM::EmulateSUBSPcLrEtc, .name: "SUBS<c> PC, LR, #<imm8>" }, |
13528 | |
13529 | // RFE instructions *** IMPORTANT *** THESE MUST BE LISTED **BEFORE** THE |
13530 | // LDM.. Instructions in this table; |
13531 | // otherwise the wrong instructions will be selected. |
13532 | |
13533 | {.mask: 0xffd0ffff, .value: 0xe810c000, ARMV6T2_ABOVE, .encoding: eEncodingT1, No_VFP, .size: eSize32, |
13534 | .callback: &EmulateInstructionARM::EmulateRFE, .name: "rfedb<c> <Rn>{!}" }, |
13535 | {.mask: 0xffd0ffff, .value: 0xe990c000, ARMV6T2_ABOVE, .encoding: eEncodingT2, No_VFP, .size: eSize32, |
13536 | .callback: &EmulateInstructionARM::EmulateRFE, .name: "rfe{ia}<c> <Rn>{!}" }, |
13537 | |
13538 | // Load instructions |
13539 | {.mask: 0xfffff800, .value: 0x0000c800, ARMV4T_ABOVE, .encoding: eEncodingT1, No_VFP, .size: eSize16, |
13540 | .callback: &EmulateInstructionARM::EmulateLDM, .name: "ldm<c> <Rn>{!} <registers>" }, |
13541 | {.mask: 0xffd02000, .value: 0xe8900000, ARMV6T2_ABOVE, .encoding: eEncodingT2, No_VFP, .size: eSize32, |
13542 | .callback: &EmulateInstructionARM::EmulateLDM, .name: "ldm<c>.w <Rn>{!} <registers>" }, |
13543 | {.mask: 0xffd00000, .value: 0xe9100000, ARMV6T2_ABOVE, .encoding: eEncodingT1, No_VFP, .size: eSize32, |
13544 | .callback: &EmulateInstructionARM::EmulateLDMDB, .name: "ldmdb<c> <Rn>{!} <registers>" }, |
13545 | {.mask: 0xfffff800, .value: 0x00006800, ARMV4T_ABOVE, .encoding: eEncodingT1, No_VFP, .size: eSize16, |
13546 | .callback: &EmulateInstructionARM::EmulateLDRRtRnImm, .name: "ldr<c> <Rt>, [<Rn>{,#imm}]" }, |
13547 | {.mask: 0xfffff800, .value: 0x00009800, ARMV4T_ABOVE, .encoding: eEncodingT2, No_VFP, .size: eSize16, |
13548 | .callback: &EmulateInstructionARM::EmulateLDRRtRnImm, .name: "ldr<c> <Rt>, [SP{,#imm}]" }, |
13549 | {.mask: 0xfff00000, .value: 0xf8d00000, ARMV6T2_ABOVE, .encoding: eEncodingT3, No_VFP, .size: eSize32, |
13550 | .callback: &EmulateInstructionARM::EmulateLDRRtRnImm, |
13551 | .name: "ldr<c>.w <Rt>, [<Rn>{,#imm12}]" }, |
13552 | {.mask: 0xfff00800, .value: 0xf8500800, ARMV6T2_ABOVE, .encoding: eEncodingT4, No_VFP, .size: eSize32, |
13553 | .callback: &EmulateInstructionARM::EmulateLDRRtRnImm, |
13554 | .name: "ldr<c> <Rt>, [<Rn>{,#+/-<imm8>}]{!}" }, |
13555 | // Thumb2 PC-relative load into register |
13556 | {.mask: 0xff7f0000, .value: 0xf85f0000, ARMV6T2_ABOVE, .encoding: eEncodingT2, No_VFP, .size: eSize32, |
13557 | .callback: &EmulateInstructionARM::EmulateLDRRtPCRelative, |
13558 | .name: "ldr<c>.w <Rt>, [PC, +/-#imm}]" }, |
13559 | {.mask: 0xfffffe00, .value: 0x00005800, ARMV4T_ABOVE, .encoding: eEncodingT1, No_VFP, .size: eSize16, |
13560 | .callback: &EmulateInstructionARM::EmulateLDRRegister, .name: "ldr<c> <Rt>, [<Rn>, <Rm>]" }, |
13561 | {.mask: 0xfff00fc0, .value: 0xf8500000, ARMV6T2_ABOVE, .encoding: eEncodingT2, No_VFP, .size: eSize32, |
13562 | .callback: &EmulateInstructionARM::EmulateLDRRegister, |
13563 | .name: "ldr<c>.w <Rt>, [<Rn>,<Rm>{,LSL #<imm2>}]" }, |
13564 | {.mask: 0xfffff800, .value: 0x00007800, ARMV4T_ABOVE, .encoding: eEncodingT1, No_VFP, .size: eSize16, |
13565 | .callback: &EmulateInstructionARM::EmulateLDRBImmediate, |
13566 | .name: "ldrb<c> <Rt>,[<Rn>{,#<imm5>}]" }, |
13567 | {.mask: 0xfff00000, .value: 0xf8900000, ARMV6T2_ABOVE, .encoding: eEncodingT2, No_VFP, .size: eSize32, |
13568 | .callback: &EmulateInstructionARM::EmulateLDRBImmediate, |
13569 | .name: "ldrb<c>.w <Rt>,[<Rn>{,#<imm12>}]" }, |
13570 | {.mask: 0xfff00800, .value: 0xf8100800, ARMV6T2_ABOVE, .encoding: eEncodingT3, No_VFP, .size: eSize32, |
13571 | .callback: &EmulateInstructionARM::EmulateLDRBImmediate, |
13572 | .name: "ldrb<c> <Rt>,[<Rn>, #+/-<imm8>]{!}" }, |
13573 | {.mask: 0xff7f0000, .value: 0xf81f0000, ARMV6T2_ABOVE, .encoding: eEncodingT1, No_VFP, .size: eSize32, |
13574 | .callback: &EmulateInstructionARM::EmulateLDRBLiteral, .name: "ldrb<c> <Rt>,[...]" }, |
13575 | {.mask: 0xfffffe00, .value: 0x00005c00, ARMV6T2_ABOVE, .encoding: eEncodingT1, No_VFP, .size: eSize16, |
13576 | .callback: &EmulateInstructionARM::EmulateLDRBRegister, .name: "ldrb<c> <Rt>,[<Rn>,<Rm>]" }, |
13577 | {.mask: 0xfff00fc0, .value: 0xf8100000, ARMV6T2_ABOVE, .encoding: eEncodingT2, No_VFP, .size: eSize32, |
13578 | .callback: &EmulateInstructionARM::EmulateLDRBRegister, |
13579 | .name: "ldrb<c>.w <Rt>,[<Rn>,<Rm>{,LSL #imm2>}]" }, |
13580 | {.mask: 0xfffff800, .value: 0x00008800, ARMV4T_ABOVE, .encoding: eEncodingT1, No_VFP, .size: eSize16, |
13581 | .callback: &EmulateInstructionARM::EmulateLDRHImmediate, |
13582 | .name: "ldrh<c> <Rt>, [<Rn>{,#<imm>}]" }, |
13583 | {.mask: 0xfff00000, .value: 0xf8b00000, ARMV6T2_ABOVE, .encoding: eEncodingT2, No_VFP, .size: eSize32, |
13584 | .callback: &EmulateInstructionARM::EmulateLDRHImmediate, |
13585 | .name: "ldrh<c>.w <Rt>,[<Rn>{,#<imm12>}]" }, |
13586 | {.mask: 0xfff00800, .value: 0xf8300800, ARMV6T2_ABOVE, .encoding: eEncodingT3, No_VFP, .size: eSize32, |
13587 | .callback: &EmulateInstructionARM::EmulateLDRHImmediate, |
13588 | .name: "ldrh<c> <Rt>,[<Rn>,#+/-<imm8>]{!}" }, |
13589 | {.mask: 0xff7f0000, .value: 0xf83f0000, ARMV6T2_ABOVE, .encoding: eEncodingT1, No_VFP, .size: eSize32, |
13590 | .callback: &EmulateInstructionARM::EmulateLDRHLiteral, .name: "ldrh<c> <Rt>, <label>" }, |
13591 | {.mask: 0xfffffe00, .value: 0x00005a00, ARMV4T_ABOVE, .encoding: eEncodingT1, No_VFP, .size: eSize16, |
13592 | .callback: &EmulateInstructionARM::EmulateLDRHRegister, |
13593 | .name: "ldrh<c> <Rt>, [<Rn>,<Rm>]" }, |
13594 | {.mask: 0xfff00fc0, .value: 0xf8300000, ARMV6T2_ABOVE, .encoding: eEncodingT2, No_VFP, .size: eSize32, |
13595 | .callback: &EmulateInstructionARM::EmulateLDRHRegister, |
13596 | .name: "ldrh<c>.w <Rt>,[<Rn>,<Rm>{,LSL #<imm2>}]" }, |
13597 | {.mask: 0xfff00000, .value: 0xf9900000, ARMV6T2_ABOVE, .encoding: eEncodingT1, No_VFP, .size: eSize32, |
13598 | .callback: &EmulateInstructionARM::EmulateLDRSBImmediate, |
13599 | .name: "ldrsb<c> <Rt>,[<Rn>,#<imm12>]" }, |
13600 | {.mask: 0xfff00800, .value: 0xf9100800, ARMV6T2_ABOVE, .encoding: eEncodingT2, No_VFP, .size: eSize32, |
13601 | .callback: &EmulateInstructionARM::EmulateLDRSBImmediate, |
13602 | .name: "ldrsb<c> <Rt>,[<Rn>,#+/-<imm8>]" }, |
13603 | {.mask: 0xff7f0000, .value: 0xf91f0000, ARMV6T2_ABOVE, .encoding: eEncodingT1, No_VFP, .size: eSize32, |
13604 | .callback: &EmulateInstructionARM::EmulateLDRSBLiteral, .name: "ldrsb<c> <Rt>, <label>" }, |
13605 | {.mask: 0xfffffe00, .value: 0x00005600, ARMV4T_ABOVE, .encoding: eEncodingT1, No_VFP, .size: eSize16, |
13606 | .callback: &EmulateInstructionARM::EmulateLDRSBRegister, |
13607 | .name: "ldrsb<c> <Rt>,[<Rn>,<Rm>]" }, |
13608 | {.mask: 0xfff00fc0, .value: 0xf9100000, ARMV6T2_ABOVE, .encoding: eEncodingT2, No_VFP, .size: eSize32, |
13609 | .callback: &EmulateInstructionARM::EmulateLDRSBRegister, |
13610 | .name: "ldrsb<c>.w <Rt>,[<Rn>,<Rm>{,LSL #imm2>}]" }, |
13611 | {.mask: 0xfff00000, .value: 0xf9b00000, ARMV6T2_ABOVE, .encoding: eEncodingT1, No_VFP, .size: eSize32, |
13612 | .callback: &EmulateInstructionARM::EmulateLDRSHImmediate, |
13613 | .name: "ldrsh<c> <Rt>,[<Rn>,#<imm12>]" }, |
13614 | {.mask: 0xfff00800, .value: 0xf9300800, ARMV6T2_ABOVE, .encoding: eEncodingT2, No_VFP, .size: eSize32, |
13615 | .callback: &EmulateInstructionARM::EmulateLDRSHImmediate, |
13616 | .name: "ldrsh<c> <Rt>,[<Rn>,#+/-<imm8>]" }, |
13617 | {.mask: 0xff7f0000, .value: 0xf93f0000, ARMV6T2_ABOVE, .encoding: eEncodingT1, No_VFP, .size: eSize32, |
13618 | .callback: &EmulateInstructionARM::EmulateLDRSHLiteral, .name: "ldrsh<c> <Rt>,<label>" }, |
13619 | {.mask: 0xfffffe00, .value: 0x00005e00, ARMV4T_ABOVE, .encoding: eEncodingT1, No_VFP, .size: eSize16, |
13620 | .callback: &EmulateInstructionARM::EmulateLDRSHRegister, |
13621 | .name: "ldrsh<c> <Rt>,[<Rn>,<Rm>]" }, |
13622 | {.mask: 0xfff00fc0, .value: 0xf9300000, ARMV6T2_ABOVE, .encoding: eEncodingT2, No_VFP, .size: eSize32, |
13623 | .callback: &EmulateInstructionARM::EmulateLDRSHRegister, |
13624 | .name: "ldrsh<c>.w <Rt>,[<Rn>,<Rm>{,LSL #<imm2>}]" }, |
13625 | {.mask: 0xfe500000, .value: 0xe8500000, ARMV6T2_ABOVE, .encoding: eEncodingT1, No_VFP, .size: eSize32, |
13626 | .callback: &EmulateInstructionARM::EmulateLDRDImmediate, |
13627 | .name: "ldrd<c> <Rt>, <Rt2>, [<Rn>,#+/-<imm>]!" }, |
13628 | {.mask: 0xfe100f00, .value: 0xec100b00, ARMvAll, .encoding: eEncodingT1, VFPv2_ABOVE, .size: eSize32, |
13629 | .callback: &EmulateInstructionARM::EmulateVLDM, .name: "vldm{mode}<c> <Rn>{!}, <list>" }, |
13630 | {.mask: 0xfe100f00, .value: 0xec100a00, ARMvAll, .encoding: eEncodingT2, VFPv2v3, .size: eSize32, |
13631 | .callback: &EmulateInstructionARM::EmulateVLDM, .name: "vldm{mode}<c> <Rn>{!}, <list>" }, |
13632 | {.mask: 0xffe00f00, .value: 0xed100b00, ARMvAll, .encoding: eEncodingT1, VFPv2_ABOVE, .size: eSize32, |
13633 | .callback: &EmulateInstructionARM::EmulateVLDR, .name: "vldr<c> <Dd>, [<Rn>{,#+/-<imm>}]" }, |
13634 | {.mask: 0xff300f00, .value: 0xed100a00, ARMvAll, .encoding: eEncodingT2, VFPv2v3, .size: eSize32, |
13635 | .callback: &EmulateInstructionARM::EmulateVLDR, .name: "vldr<c> <Sd>, {<Rn>{,#+/-<imm>}]" }, |
13636 | {.mask: 0xffb00000, .value: 0xf9200000, ARMvAll, .encoding: eEncodingT1, AdvancedSIMD, .size: eSize32, |
13637 | .callback: &EmulateInstructionARM::EmulateVLD1Multiple, |
13638 | .name: "vld1<c>.<size> <list>, [<Rn>{@<align>}],<Rm>" }, |
13639 | {.mask: 0xffb00300, .value: 0xf9a00000, ARMvAll, .encoding: eEncodingT1, AdvancedSIMD, .size: eSize32, |
13640 | .callback: &EmulateInstructionARM::EmulateVLD1Single, |
13641 | .name: "vld1<c>.<size> <list>, [<Rn>{@<align>}],<Rm>" }, |
13642 | {.mask: 0xffb00f00, .value: 0xf9a00c00, ARMvAll, .encoding: eEncodingT1, AdvancedSIMD, .size: eSize32, |
13643 | .callback: &EmulateInstructionARM::EmulateVLD1SingleAll, |
13644 | .name: "vld1<c>.<size> <list>, [<Rn>{@<align>}], <Rm>" }, |
13645 | |
13646 | // Store instructions |
13647 | {.mask: 0xfffff800, .value: 0x0000c000, ARMV4T_ABOVE, .encoding: eEncodingT1, No_VFP, .size: eSize16, |
13648 | .callback: &EmulateInstructionARM::EmulateSTM, .name: "stm<c> <Rn>{!} <registers>" }, |
13649 | {.mask: 0xffd00000, .value: 0xe8800000, ARMV6T2_ABOVE, .encoding: eEncodingT2, No_VFP, .size: eSize32, |
13650 | .callback: &EmulateInstructionARM::EmulateSTM, .name: "stm<c>.w <Rn>{!} <registers>" }, |
13651 | {.mask: 0xffd00000, .value: 0xe9000000, ARMV6T2_ABOVE, .encoding: eEncodingT1, No_VFP, .size: eSize32, |
13652 | .callback: &EmulateInstructionARM::EmulateSTMDB, .name: "stmdb<c> <Rn>{!} <registers>" }, |
13653 | {.mask: 0xfffff800, .value: 0x00006000, ARMV4T_ABOVE, .encoding: eEncodingT1, No_VFP, .size: eSize16, |
13654 | .callback: &EmulateInstructionARM::EmulateSTRThumb, .name: "str<c> <Rt>, [<Rn>{,#<imm>}]" }, |
13655 | {.mask: 0xfffff800, .value: 0x00009000, ARMV4T_ABOVE, .encoding: eEncodingT2, No_VFP, .size: eSize16, |
13656 | .callback: &EmulateInstructionARM::EmulateSTRThumb, .name: "str<c> <Rt>, [SP,#<imm>]" }, |
13657 | {.mask: 0xfff00000, .value: 0xf8c00000, ARMV6T2_ABOVE, .encoding: eEncodingT3, No_VFP, .size: eSize32, |
13658 | .callback: &EmulateInstructionARM::EmulateSTRThumb, |
13659 | .name: "str<c>.w <Rt>, [<Rn>,#<imm12>]" }, |
13660 | {.mask: 0xfff00800, .value: 0xf8400800, ARMV6T2_ABOVE, .encoding: eEncodingT4, No_VFP, .size: eSize32, |
13661 | .callback: &EmulateInstructionARM::EmulateSTRThumb, |
13662 | .name: "str<c> <Rt>, [<Rn>,#+/-<imm8>]" }, |
13663 | {.mask: 0xfffffe00, .value: 0x00005000, ARMV4T_ABOVE, .encoding: eEncodingT1, No_VFP, .size: eSize16, |
13664 | .callback: &EmulateInstructionARM::EmulateSTRRegister, .name: "str<c> <Rt> ,{<Rn>, <Rm>]" }, |
13665 | {.mask: 0xfff00fc0, .value: 0xf8400000, ARMV6T2_ABOVE, .encoding: eEncodingT2, No_VFP, .size: eSize32, |
13666 | .callback: &EmulateInstructionARM::EmulateSTRRegister, |
13667 | .name: "str<c>.w <Rt>, [<Rn>, <Rm> {lsl #imm2>}]" }, |
13668 | {.mask: 0xfffff800, .value: 0x00007000, ARMV4T_ABOVE, .encoding: eEncodingT1, No_VFP, .size: eSize16, |
13669 | .callback: &EmulateInstructionARM::EmulateSTRBThumb, |
13670 | .name: "strb<c> <Rt>, [<Rn>, #<imm5>]" }, |
13671 | {.mask: 0xfff00000, .value: 0xf8800000, ARMV6T2_ABOVE, .encoding: eEncodingT2, No_VFP, .size: eSize32, |
13672 | .callback: &EmulateInstructionARM::EmulateSTRBThumb, |
13673 | .name: "strb<c>.w <Rt>, [<Rn>, #<imm12>]" }, |
13674 | {.mask: 0xfff00800, .value: 0xf8000800, ARMV6T2_ABOVE, .encoding: eEncodingT3, No_VFP, .size: eSize32, |
13675 | .callback: &EmulateInstructionARM::EmulateSTRBThumb, |
13676 | .name: "strb<c> <Rt> ,[<Rn>, #+/-<imm8>]{!}" }, |
13677 | {.mask: 0xfffffe00, .value: 0x00005200, ARMV4T_ABOVE, .encoding: eEncodingT1, No_VFP, .size: eSize16, |
13678 | .callback: &EmulateInstructionARM::EmulateSTRHRegister, .name: "strh<c> <Rt>,[<Rn>,<Rm>]" }, |
13679 | {.mask: 0xfff00fc0, .value: 0xf8200000, ARMV6T2_ABOVE, .encoding: eEncodingT2, No_VFP, .size: eSize32, |
13680 | .callback: &EmulateInstructionARM::EmulateSTRHRegister, |
13681 | .name: "strh<c>.w <Rt>,[<Rn>,<Rm>{,LSL #<imm2>}]" }, |
13682 | {.mask: 0xfff00000, .value: 0xe8400000, ARMV6T2_ABOVE, .encoding: eEncodingT1, No_VFP, .size: eSize32, |
13683 | .callback: &EmulateInstructionARM::EmulateSTREX, |
13684 | .name: "strex<c> <Rd>, <Rt>, [<Rn{,#<imm>}]" }, |
13685 | {.mask: 0xfe500000, .value: 0xe8400000, ARMV6T2_ABOVE, .encoding: eEncodingT1, No_VFP, .size: eSize32, |
13686 | .callback: &EmulateInstructionARM::EmulateSTRDImm, |
13687 | .name: "strd<c> <Rt>, <Rt2>, [<Rn>, #+/-<imm>]!" }, |
13688 | {.mask: 0xfe100f00, .value: 0xec000b00, ARMvAll, .encoding: eEncodingT1, VFPv2_ABOVE, .size: eSize32, |
13689 | .callback: &EmulateInstructionARM::EmulateVSTM, .name: "vstm{mode}<c> <Rn>{!}, <list>" }, |
13690 | {.mask: 0xfea00f00, .value: 0xec000a00, ARMvAll, .encoding: eEncodingT2, VFPv2v3, .size: eSize32, |
13691 | .callback: &EmulateInstructionARM::EmulateVSTM, .name: "vstm{mode}<c> <Rn>{!}, <list>" }, |
13692 | {.mask: 0xff300f00, .value: 0xed000b00, ARMvAll, .encoding: eEncodingT1, VFPv2_ABOVE, .size: eSize32, |
13693 | .callback: &EmulateInstructionARM::EmulateVSTR, .name: "vstr<c> <Dd>, [<Rn>{,#+/-<imm>}]" }, |
13694 | {.mask: 0xff300f00, .value: 0xed000a00, ARMvAll, .encoding: eEncodingT2, VFPv2v3, .size: eSize32, |
13695 | .callback: &EmulateInstructionARM::EmulateVSTR, .name: "vstr<c> <Sd>, [<Rn>{,#+/-<imm>}]" }, |
13696 | {.mask: 0xffb00000, .value: 0xf9000000, ARMvAll, .encoding: eEncodingT1, AdvancedSIMD, .size: eSize32, |
13697 | .callback: &EmulateInstructionARM::EmulateVST1Multiple, |
13698 | .name: "vst1<c>.<size> <list>, [<Rn>{@<align>}], <Rm>" }, |
13699 | {.mask: 0xffb00300, .value: 0xf9800000, ARMvAll, .encoding: eEncodingT1, AdvancedSIMD, .size: eSize32, |
13700 | .callback: &EmulateInstructionARM::EmulateVST1Single, |
13701 | .name: "vst1<c>.<size> <list>, [<Rn>{@<align>}], <Rm>" }, |
13702 | |
13703 | // Other instructions |
13704 | {.mask: 0xffffffc0, .value: 0x0000b240, ARMV6_ABOVE, .encoding: eEncodingT1, No_VFP, .size: eSize16, |
13705 | .callback: &EmulateInstructionARM::EmulateSXTB, .name: "sxtb<c> <Rd>,<Rm>" }, |
13706 | {.mask: 0xfffff080, .value: 0xfa4ff080, ARMV6_ABOVE, .encoding: eEncodingT2, No_VFP, .size: eSize32, |
13707 | .callback: &EmulateInstructionARM::EmulateSXTB, .name: "sxtb<c>.w <Rd>,<Rm>{,<rotation>}" }, |
13708 | {.mask: 0xffffffc0, .value: 0x0000b200, ARMV6_ABOVE, .encoding: eEncodingT1, No_VFP, .size: eSize16, |
13709 | .callback: &EmulateInstructionARM::EmulateSXTH, .name: "sxth<c> <Rd>,<Rm>" }, |
13710 | {.mask: 0xfffff080, .value: 0xfa0ff080, ARMV6T2_ABOVE, .encoding: eEncodingT2, No_VFP, .size: eSize32, |
13711 | .callback: &EmulateInstructionARM::EmulateSXTH, .name: "sxth<c>.w <Rd>,<Rm>{,<rotation>}" }, |
13712 | {.mask: 0xffffffc0, .value: 0x0000b2c0, ARMV6_ABOVE, .encoding: eEncodingT1, No_VFP, .size: eSize16, |
13713 | .callback: &EmulateInstructionARM::EmulateUXTB, .name: "uxtb<c> <Rd>,<Rm>" }, |
13714 | {.mask: 0xfffff080, .value: 0xfa5ff080, ARMV6T2_ABOVE, .encoding: eEncodingT2, No_VFP, .size: eSize32, |
13715 | .callback: &EmulateInstructionARM::EmulateUXTB, .name: "uxtb<c>.w <Rd>,<Rm>{,<rotation>}" }, |
13716 | {.mask: 0xffffffc0, .value: 0x0000b280, ARMV6_ABOVE, .encoding: eEncodingT1, No_VFP, .size: eSize16, |
13717 | .callback: &EmulateInstructionARM::EmulateUXTH, .name: "uxth<c> <Rd>,<Rm>" }, |
13718 | {.mask: 0xfffff080, .value: 0xfa1ff080, ARMV6T2_ABOVE, .encoding: eEncodingT2, No_VFP, .size: eSize32, |
13719 | .callback: &EmulateInstructionARM::EmulateUXTH, .name: "uxth<c>.w <Rd>,<Rm>{,<rotation>}" }, |
13720 | }; |
13721 | |
13722 | const size_t k_num_thumb_opcodes = std::size(g_thumb_opcodes); |
13723 | for (size_t i = 0; i < k_num_thumb_opcodes; ++i) { |
13724 | if ((g_thumb_opcodes[i].mask & opcode) == g_thumb_opcodes[i].value && |
13725 | (g_thumb_opcodes[i].variants & arm_isa) != 0) |
13726 | return &g_thumb_opcodes[i]; |
13727 | } |
13728 | return nullptr; |
13729 | } |
13730 | |
13731 | bool EmulateInstructionARM::SetArchitecture(const ArchSpec &arch) { |
13732 | m_arch = arch; |
13733 | m_arm_isa = 0; |
13734 | llvm::StringRef arch_cstr = arch.GetArchitectureName(); |
13735 | if (arch_cstr.equals_insensitive(RHS: "armv4t" )) |
13736 | m_arm_isa = ARMv4T; |
13737 | else if (arch_cstr.equals_insensitive(RHS: "armv5tej" )) |
13738 | m_arm_isa = ARMv5TEJ; |
13739 | else if (arch_cstr.equals_insensitive(RHS: "armv5te" )) |
13740 | m_arm_isa = ARMv5TE; |
13741 | else if (arch_cstr.equals_insensitive(RHS: "armv5t" )) |
13742 | m_arm_isa = ARMv5T; |
13743 | else if (arch_cstr.equals_insensitive(RHS: "armv6k" )) |
13744 | m_arm_isa = ARMv6K; |
13745 | else if (arch_cstr.equals_insensitive(RHS: "armv6t2" )) |
13746 | m_arm_isa = ARMv6T2; |
13747 | else if (arch_cstr.equals_insensitive(RHS: "armv7s" )) |
13748 | m_arm_isa = ARMv7S; |
13749 | else if (arch_cstr.equals_insensitive(RHS: "arm" )) |
13750 | m_arm_isa = ARMvAll; |
13751 | else if (arch_cstr.equals_insensitive(RHS: "thumb" )) |
13752 | m_arm_isa = ARMvAll; |
13753 | else if (arch_cstr.starts_with_insensitive(Prefix: "armv4" )) |
13754 | m_arm_isa = ARMv4; |
13755 | else if (arch_cstr.starts_with_insensitive(Prefix: "armv6" )) |
13756 | m_arm_isa = ARMv6; |
13757 | else if (arch_cstr.starts_with_insensitive(Prefix: "armv7" )) |
13758 | m_arm_isa = ARMv7; |
13759 | else if (arch_cstr.starts_with_insensitive(Prefix: "armv8" )) |
13760 | m_arm_isa = ARMv8; |
13761 | return m_arm_isa != 0; |
13762 | } |
13763 | |
13764 | bool EmulateInstructionARM::SetInstruction(const Opcode &insn_opcode, |
13765 | const Address &inst_addr, |
13766 | Target *target) { |
13767 | if (EmulateInstruction::SetInstruction(insn_opcode, inst_addr, target)) { |
13768 | if (m_arch.GetTriple().getArch() == llvm::Triple::thumb || |
13769 | m_arch.IsAlwaysThumbInstructions()) |
13770 | m_opcode_mode = eModeThumb; |
13771 | else { |
13772 | AddressClass addr_class = inst_addr.GetAddressClass(); |
13773 | |
13774 | if ((addr_class == AddressClass::eCode) || |
13775 | (addr_class == AddressClass::eUnknown)) |
13776 | m_opcode_mode = eModeARM; |
13777 | else if (addr_class == AddressClass::eCodeAlternateISA) |
13778 | m_opcode_mode = eModeThumb; |
13779 | else |
13780 | return false; |
13781 | } |
13782 | if (m_opcode_mode == eModeThumb || m_arch.IsAlwaysThumbInstructions()) |
13783 | m_opcode_cpsr = CPSR_MODE_USR | MASK_CPSR_T; |
13784 | else |
13785 | m_opcode_cpsr = CPSR_MODE_USR; |
13786 | return true; |
13787 | } |
13788 | return false; |
13789 | } |
13790 | |
13791 | bool EmulateInstructionARM::ReadInstruction() { |
13792 | bool success = false; |
13793 | m_opcode_cpsr = ReadRegisterUnsigned(reg_kind: eRegisterKindGeneric, |
13794 | LLDB_REGNUM_GENERIC_FLAGS, fail_value: 0, success_ptr: &success); |
13795 | if (success) { |
13796 | addr_t pc = |
13797 | ReadRegisterUnsigned(reg_kind: eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, |
13798 | LLDB_INVALID_ADDRESS, success_ptr: &success); |
13799 | if (success) { |
13800 | Context read_inst_context; |
13801 | read_inst_context.type = eContextReadOpcode; |
13802 | read_inst_context.SetNoArgs(); |
13803 | |
13804 | if ((m_opcode_cpsr & MASK_CPSR_T) || m_arch.IsAlwaysThumbInstructions()) { |
13805 | m_opcode_mode = eModeThumb; |
13806 | uint32_t thumb_opcode = MemARead(context&: read_inst_context, address: pc, size: 2, fail_value: 0, success_ptr: &success); |
13807 | |
13808 | if (success) { |
13809 | if ((thumb_opcode & 0xe000) != 0xe000 || |
13810 | ((thumb_opcode & 0x1800u) == 0)) { |
13811 | m_opcode.SetOpcode16(inst: thumb_opcode, order: GetByteOrder()); |
13812 | } else { |
13813 | m_opcode.SetOpcode32( |
13814 | inst: (thumb_opcode << 16) | |
13815 | MemARead(context&: read_inst_context, address: pc + 2, size: 2, fail_value: 0, success_ptr: &success), |
13816 | order: GetByteOrder()); |
13817 | } |
13818 | } |
13819 | } else { |
13820 | m_opcode_mode = eModeARM; |
13821 | m_opcode.SetOpcode32(inst: MemARead(context&: read_inst_context, address: pc, size: 4, fail_value: 0, success_ptr: &success), |
13822 | order: GetByteOrder()); |
13823 | } |
13824 | |
13825 | if (!m_ignore_conditions) { |
13826 | // If we are not ignoreing the conditions then init the it session from |
13827 | // the current value of cpsr. |
13828 | uint32_t it = (Bits32(bits: m_opcode_cpsr, msbit: 15, lsbit: 10) << 2) | |
13829 | Bits32(bits: m_opcode_cpsr, msbit: 26, lsbit: 25); |
13830 | if (it != 0) |
13831 | m_it_session.InitIT(bits7_0: it); |
13832 | } |
13833 | } |
13834 | } |
13835 | if (!success) { |
13836 | m_opcode_mode = eModeInvalid; |
13837 | m_addr = LLDB_INVALID_ADDRESS; |
13838 | } |
13839 | return success; |
13840 | } |
13841 | |
13842 | uint32_t EmulateInstructionARM::ArchVersion() { return m_arm_isa; } |
13843 | |
13844 | bool EmulateInstructionARM::ConditionPassed(const uint32_t opcode) { |
13845 | // If we are ignoring conditions, then always return true. this allows us to |
13846 | // iterate over disassembly code and still emulate an instruction even if we |
13847 | // don't have all the right bits set in the CPSR register... |
13848 | if (m_ignore_conditions) |
13849 | return true; |
13850 | |
13851 | const uint32_t cond = CurrentCond(opcode); |
13852 | if (cond == UINT32_MAX) |
13853 | return false; |
13854 | |
13855 | bool result = false; |
13856 | switch (UnsignedBits(value: cond, msbit: 3, lsbit: 1)) { |
13857 | case 0: |
13858 | if (m_opcode_cpsr == 0) |
13859 | result = true; |
13860 | else |
13861 | result = (m_opcode_cpsr & MASK_CPSR_Z) != 0; |
13862 | break; |
13863 | case 1: |
13864 | if (m_opcode_cpsr == 0) |
13865 | result = true; |
13866 | else |
13867 | result = (m_opcode_cpsr & MASK_CPSR_C) != 0; |
13868 | break; |
13869 | case 2: |
13870 | if (m_opcode_cpsr == 0) |
13871 | result = true; |
13872 | else |
13873 | result = (m_opcode_cpsr & MASK_CPSR_N) != 0; |
13874 | break; |
13875 | case 3: |
13876 | if (m_opcode_cpsr == 0) |
13877 | result = true; |
13878 | else |
13879 | result = (m_opcode_cpsr & MASK_CPSR_V) != 0; |
13880 | break; |
13881 | case 4: |
13882 | if (m_opcode_cpsr == 0) |
13883 | result = true; |
13884 | else |
13885 | result = ((m_opcode_cpsr & MASK_CPSR_C) != 0) && |
13886 | ((m_opcode_cpsr & MASK_CPSR_Z) == 0); |
13887 | break; |
13888 | case 5: |
13889 | if (m_opcode_cpsr == 0) |
13890 | result = true; |
13891 | else { |
13892 | bool n = (m_opcode_cpsr & MASK_CPSR_N); |
13893 | bool v = (m_opcode_cpsr & MASK_CPSR_V); |
13894 | result = n == v; |
13895 | } |
13896 | break; |
13897 | case 6: |
13898 | if (m_opcode_cpsr == 0) |
13899 | result = true; |
13900 | else { |
13901 | bool n = (m_opcode_cpsr & MASK_CPSR_N); |
13902 | bool v = (m_opcode_cpsr & MASK_CPSR_V); |
13903 | result = n == v && ((m_opcode_cpsr & MASK_CPSR_Z) == 0); |
13904 | } |
13905 | break; |
13906 | case 7: |
13907 | // Always execute (cond == 0b1110, or the special 0b1111 which gives |
13908 | // opcodes different meanings, but always means execution happens. |
13909 | return true; |
13910 | } |
13911 | |
13912 | if (cond & 1) |
13913 | result = !result; |
13914 | return result; |
13915 | } |
13916 | |
13917 | uint32_t EmulateInstructionARM::CurrentCond(const uint32_t opcode) { |
13918 | switch (m_opcode_mode) { |
13919 | case eModeInvalid: |
13920 | break; |
13921 | |
13922 | case eModeARM: |
13923 | return UnsignedBits(value: opcode, msbit: 31, lsbit: 28); |
13924 | |
13925 | case eModeThumb: |
13926 | // For T1 and T3 encodings of the Branch instruction, it returns the 4-bit |
13927 | // 'cond' field of the encoding. |
13928 | { |
13929 | const uint32_t byte_size = m_opcode.GetByteSize(); |
13930 | if (byte_size == 2) { |
13931 | if (Bits32(bits: opcode, msbit: 15, lsbit: 12) == 0x0d && Bits32(bits: opcode, msbit: 11, lsbit: 8) != 0x0f) |
13932 | return Bits32(bits: opcode, msbit: 11, lsbit: 8); |
13933 | } else if (byte_size == 4) { |
13934 | if (Bits32(bits: opcode, msbit: 31, lsbit: 27) == 0x1e && Bits32(bits: opcode, msbit: 15, lsbit: 14) == 0x02 && |
13935 | Bits32(bits: opcode, msbit: 12, lsbit: 12) == 0x00 && Bits32(bits: opcode, msbit: 25, lsbit: 22) <= 0x0d) { |
13936 | return Bits32(bits: opcode, msbit: 25, lsbit: 22); |
13937 | } |
13938 | } else |
13939 | // We have an invalid thumb instruction, let's bail out. |
13940 | break; |
13941 | |
13942 | return m_it_session.GetCond(); |
13943 | } |
13944 | } |
13945 | return UINT32_MAX; // Return invalid value |
13946 | } |
13947 | |
13948 | bool EmulateInstructionARM::InITBlock() { |
13949 | return CurrentInstrSet() == eModeThumb && m_it_session.InITBlock(); |
13950 | } |
13951 | |
13952 | bool EmulateInstructionARM::LastInITBlock() { |
13953 | return CurrentInstrSet() == eModeThumb && m_it_session.LastInITBlock(); |
13954 | } |
13955 | |
13956 | bool EmulateInstructionARM::BadMode(uint32_t mode) { |
13957 | |
13958 | switch (mode) { |
13959 | case 16: |
13960 | return false; // '10000' |
13961 | case 17: |
13962 | return false; // '10001' |
13963 | case 18: |
13964 | return false; // '10010' |
13965 | case 19: |
13966 | return false; // '10011' |
13967 | case 22: |
13968 | return false; // '10110' |
13969 | case 23: |
13970 | return false; // '10111' |
13971 | case 27: |
13972 | return false; // '11011' |
13973 | case 31: |
13974 | return false; // '11111' |
13975 | default: |
13976 | return true; |
13977 | } |
13978 | return true; |
13979 | } |
13980 | |
13981 | bool EmulateInstructionARM::CurrentModeIsPrivileged() { |
13982 | uint32_t mode = Bits32(bits: m_opcode_cpsr, msbit: 4, lsbit: 0); |
13983 | |
13984 | if (BadMode(mode)) |
13985 | return false; |
13986 | |
13987 | if (mode == 16) |
13988 | return false; |
13989 | |
13990 | return true; |
13991 | } |
13992 | |
13993 | void EmulateInstructionARM::CPSRWriteByInstr(uint32_t value, uint32_t bytemask, |
13994 | bool affect_execstate) { |
13995 | bool privileged = CurrentModeIsPrivileged(); |
13996 | |
13997 | uint32_t tmp_cpsr = Bits32(bits: m_opcode_cpsr, msbit: 23, lsbit: 20) << 20; |
13998 | |
13999 | if (BitIsSet(value: bytemask, bit: 3)) { |
14000 | tmp_cpsr = tmp_cpsr | (Bits32(bits: value, msbit: 31, lsbit: 27) << 27); |
14001 | if (affect_execstate) |
14002 | tmp_cpsr = tmp_cpsr | (Bits32(bits: value, msbit: 26, lsbit: 24) << 24); |
14003 | } |
14004 | |
14005 | if (BitIsSet(value: bytemask, bit: 2)) { |
14006 | tmp_cpsr = tmp_cpsr | (Bits32(bits: value, msbit: 19, lsbit: 16) << 16); |
14007 | } |
14008 | |
14009 | if (BitIsSet(value: bytemask, bit: 1)) { |
14010 | if (affect_execstate) |
14011 | tmp_cpsr = tmp_cpsr | (Bits32(bits: value, msbit: 15, lsbit: 10) << 10); |
14012 | tmp_cpsr = tmp_cpsr | (Bit32(bits: value, bit: 9) << 9); |
14013 | if (privileged) |
14014 | tmp_cpsr = tmp_cpsr | (Bit32(bits: value, bit: 8) << 8); |
14015 | } |
14016 | |
14017 | if (BitIsSet(value: bytemask, bit: 0)) { |
14018 | if (privileged) |
14019 | tmp_cpsr = tmp_cpsr | (Bits32(bits: value, msbit: 7, lsbit: 6) << 6); |
14020 | if (affect_execstate) |
14021 | tmp_cpsr = tmp_cpsr | (Bit32(bits: value, bit: 5) << 5); |
14022 | if (privileged) |
14023 | tmp_cpsr = tmp_cpsr | Bits32(bits: value, msbit: 4, lsbit: 0); |
14024 | } |
14025 | |
14026 | m_opcode_cpsr = tmp_cpsr; |
14027 | } |
14028 | |
14029 | bool EmulateInstructionARM::BranchWritePC(const Context &context, |
14030 | uint32_t addr) { |
14031 | addr_t target; |
14032 | |
14033 | // Check the current instruction set. |
14034 | if (CurrentInstrSet() == eModeARM) |
14035 | target = addr & 0xfffffffc; |
14036 | else |
14037 | target = addr & 0xfffffffe; |
14038 | |
14039 | return WriteRegisterUnsigned(context, reg_kind: eRegisterKindGeneric, |
14040 | LLDB_REGNUM_GENERIC_PC, reg_value: target); |
14041 | } |
14042 | |
14043 | // As a side effect, BXWritePC sets context.arg2 to eModeARM or eModeThumb by |
14044 | // inspecting addr. |
14045 | bool EmulateInstructionARM::BXWritePC(Context &context, uint32_t addr) { |
14046 | addr_t target; |
14047 | // If the CPSR is changed due to switching between ARM and Thumb ISETSTATE, |
14048 | // we want to record it and issue a WriteRegister callback so the clients can |
14049 | // track the mode changes accordingly. |
14050 | bool cpsr_changed = false; |
14051 | |
14052 | if (BitIsSet(value: addr, bit: 0)) { |
14053 | if (CurrentInstrSet() != eModeThumb) { |
14054 | SelectInstrSet(arm_or_thumb: eModeThumb); |
14055 | cpsr_changed = true; |
14056 | } |
14057 | target = addr & 0xfffffffe; |
14058 | context.SetISA(eModeThumb); |
14059 | } else if (BitIsClear(value: addr, bit: 1)) { |
14060 | if (CurrentInstrSet() != eModeARM) { |
14061 | SelectInstrSet(arm_or_thumb: eModeARM); |
14062 | cpsr_changed = true; |
14063 | } |
14064 | target = addr & 0xfffffffc; |
14065 | context.SetISA(eModeARM); |
14066 | } else |
14067 | return false; // address<1:0> == '10' => UNPREDICTABLE |
14068 | |
14069 | if (cpsr_changed) { |
14070 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindGeneric, |
14071 | LLDB_REGNUM_GENERIC_FLAGS, reg_value: m_new_inst_cpsr)) |
14072 | return false; |
14073 | } |
14074 | return WriteRegisterUnsigned(context, reg_kind: eRegisterKindGeneric, |
14075 | LLDB_REGNUM_GENERIC_PC, reg_value: target); |
14076 | } |
14077 | |
14078 | // Dispatches to either BXWritePC or BranchWritePC based on architecture |
14079 | // versions. |
14080 | bool EmulateInstructionARM::LoadWritePC(Context &context, uint32_t addr) { |
14081 | if (ArchVersion() >= ARMv5T) |
14082 | return BXWritePC(context, addr); |
14083 | else |
14084 | return BranchWritePC(context: (const Context)context, addr); |
14085 | } |
14086 | |
14087 | // Dispatches to either BXWritePC or BranchWritePC based on architecture |
14088 | // versions and current instruction set. |
14089 | bool EmulateInstructionARM::ALUWritePC(Context &context, uint32_t addr) { |
14090 | if (ArchVersion() >= ARMv7 && CurrentInstrSet() == eModeARM) |
14091 | return BXWritePC(context, addr); |
14092 | else |
14093 | return BranchWritePC(context: (const Context)context, addr); |
14094 | } |
14095 | |
14096 | EmulateInstructionARM::Mode EmulateInstructionARM::CurrentInstrSet() { |
14097 | return m_opcode_mode; |
14098 | } |
14099 | |
14100 | // Set the 'T' bit of our CPSR. The m_opcode_mode gets updated when the next |
14101 | // ReadInstruction() is performed. This function has a side effect of updating |
14102 | // the m_new_inst_cpsr member variable if necessary. |
14103 | bool EmulateInstructionARM::SelectInstrSet(Mode arm_or_thumb) { |
14104 | m_new_inst_cpsr = m_opcode_cpsr; |
14105 | switch (arm_or_thumb) { |
14106 | default: |
14107 | return false; |
14108 | case eModeARM: |
14109 | // Clear the T bit. |
14110 | m_new_inst_cpsr &= ~MASK_CPSR_T; |
14111 | break; |
14112 | case eModeThumb: |
14113 | // Set the T bit. |
14114 | m_new_inst_cpsr |= MASK_CPSR_T; |
14115 | break; |
14116 | } |
14117 | return true; |
14118 | } |
14119 | |
14120 | // This function returns TRUE if the processor currently provides support for |
14121 | // unaligned memory accesses, or FALSE otherwise. This is always TRUE in ARMv7, |
14122 | // controllable by the SCTLR.U bit in ARMv6, and always FALSE before ARMv6. |
14123 | bool EmulateInstructionARM::UnalignedSupport() { |
14124 | return (ArchVersion() >= ARMv7); |
14125 | } |
14126 | |
14127 | // The main addition and subtraction instructions can produce status |
14128 | // information about both unsigned carry and signed overflow conditions. This |
14129 | // status information can be used to synthesize multi-word additions and |
14130 | // subtractions. |
14131 | EmulateInstructionARM::AddWithCarryResult |
14132 | EmulateInstructionARM::AddWithCarry(uint32_t x, uint32_t y, uint8_t carry_in) { |
14133 | uint32_t result; |
14134 | uint8_t carry_out; |
14135 | uint8_t overflow; |
14136 | |
14137 | uint64_t unsigned_sum = x + y + carry_in; |
14138 | int64_t signed_sum = (int32_t)x + (int32_t)y + (int32_t)carry_in; |
14139 | |
14140 | result = UnsignedBits(value: unsigned_sum, msbit: 31, lsbit: 0); |
14141 | // carry_out = (result == unsigned_sum ? 0 : 1); |
14142 | overflow = ((int32_t)result == signed_sum ? 0 : 1); |
14143 | |
14144 | if (carry_in) |
14145 | carry_out = ((int32_t)x >= (int32_t)(~y)) ? 1 : 0; |
14146 | else |
14147 | carry_out = ((int32_t)x > (int32_t)y) ? 1 : 0; |
14148 | |
14149 | AddWithCarryResult res = {.result: result, .carry_out: carry_out, .overflow: overflow}; |
14150 | return res; |
14151 | } |
14152 | |
14153 | uint32_t EmulateInstructionARM::ReadCoreReg(uint32_t num, bool *success) { |
14154 | lldb::RegisterKind reg_kind; |
14155 | uint32_t reg_num; |
14156 | switch (num) { |
14157 | case SP_REG: |
14158 | reg_kind = eRegisterKindGeneric; |
14159 | reg_num = LLDB_REGNUM_GENERIC_SP; |
14160 | break; |
14161 | case LR_REG: |
14162 | reg_kind = eRegisterKindGeneric; |
14163 | reg_num = LLDB_REGNUM_GENERIC_RA; |
14164 | break; |
14165 | case PC_REG: |
14166 | reg_kind = eRegisterKindGeneric; |
14167 | reg_num = LLDB_REGNUM_GENERIC_PC; |
14168 | break; |
14169 | default: |
14170 | if (num < SP_REG) { |
14171 | reg_kind = eRegisterKindDWARF; |
14172 | reg_num = dwarf_r0 + num; |
14173 | } else { |
14174 | // assert(0 && "Invalid register number"); |
14175 | *success = false; |
14176 | return UINT32_MAX; |
14177 | } |
14178 | break; |
14179 | } |
14180 | |
14181 | // Read our register. |
14182 | uint32_t val = ReadRegisterUnsigned(reg_kind, reg_num, fail_value: 0, success_ptr: success); |
14183 | |
14184 | // When executing an ARM instruction , PC reads as the address of the current |
14185 | // instruction plus 8. When executing a Thumb instruction , PC reads as the |
14186 | // address of the current instruction plus 4. |
14187 | if (num == 15) { |
14188 | if (CurrentInstrSet() == eModeARM) |
14189 | val += 8; |
14190 | else |
14191 | val += 4; |
14192 | } |
14193 | |
14194 | return val; |
14195 | } |
14196 | |
14197 | // Write the result to the ARM core register Rd, and optionally update the |
14198 | // condition flags based on the result. |
14199 | // |
14200 | // This helper method tries to encapsulate the following pseudocode from the |
14201 | // ARM Architecture Reference Manual: |
14202 | // |
14203 | // if d == 15 then // Can only occur for encoding A1 |
14204 | // ALUWritePC(result); // setflags is always FALSE here |
14205 | // else |
14206 | // R[d] = result; |
14207 | // if setflags then |
14208 | // APSR.N = result<31>; |
14209 | // APSR.Z = IsZeroBit(result); |
14210 | // APSR.C = carry; |
14211 | // // APSR.V unchanged |
14212 | // |
14213 | // In the above case, the API client does not pass in the overflow arg, which |
14214 | // defaults to ~0u. |
14215 | bool EmulateInstructionARM::WriteCoreRegOptionalFlags( |
14216 | Context &context, const uint32_t result, const uint32_t Rd, bool setflags, |
14217 | const uint32_t carry, const uint32_t overflow) { |
14218 | if (Rd == 15) { |
14219 | if (!ALUWritePC(context, addr: result)) |
14220 | return false; |
14221 | } else { |
14222 | lldb::RegisterKind reg_kind; |
14223 | uint32_t reg_num; |
14224 | switch (Rd) { |
14225 | case SP_REG: |
14226 | reg_kind = eRegisterKindGeneric; |
14227 | reg_num = LLDB_REGNUM_GENERIC_SP; |
14228 | break; |
14229 | case LR_REG: |
14230 | reg_kind = eRegisterKindGeneric; |
14231 | reg_num = LLDB_REGNUM_GENERIC_RA; |
14232 | break; |
14233 | default: |
14234 | reg_kind = eRegisterKindDWARF; |
14235 | reg_num = dwarf_r0 + Rd; |
14236 | } |
14237 | if (!WriteRegisterUnsigned(context, reg_kind, reg_num, reg_value: result)) |
14238 | return false; |
14239 | if (setflags) |
14240 | return WriteFlags(context, result, carry, overflow); |
14241 | } |
14242 | return true; |
14243 | } |
14244 | |
14245 | // This helper method tries to encapsulate the following pseudocode from the |
14246 | // ARM Architecture Reference Manual: |
14247 | // |
14248 | // APSR.N = result<31>; |
14249 | // APSR.Z = IsZeroBit(result); |
14250 | // APSR.C = carry; |
14251 | // APSR.V = overflow |
14252 | // |
14253 | // Default arguments can be specified for carry and overflow parameters, which |
14254 | // means not to update the respective flags. |
14255 | bool EmulateInstructionARM::WriteFlags(Context &context, const uint32_t result, |
14256 | const uint32_t carry, |
14257 | const uint32_t overflow) { |
14258 | m_new_inst_cpsr = m_opcode_cpsr; |
14259 | SetBit32(bits&: m_new_inst_cpsr, CPSR_N_POS, val: Bit32(bits: result, CPSR_N_POS)); |
14260 | SetBit32(bits&: m_new_inst_cpsr, CPSR_Z_POS, val: result == 0 ? 1 : 0); |
14261 | if (carry != ~0u) |
14262 | SetBit32(bits&: m_new_inst_cpsr, CPSR_C_POS, val: carry); |
14263 | if (overflow != ~0u) |
14264 | SetBit32(bits&: m_new_inst_cpsr, CPSR_V_POS, val: overflow); |
14265 | if (m_new_inst_cpsr != m_opcode_cpsr) { |
14266 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindGeneric, |
14267 | LLDB_REGNUM_GENERIC_FLAGS, reg_value: m_new_inst_cpsr)) |
14268 | return false; |
14269 | } |
14270 | return true; |
14271 | } |
14272 | |
14273 | bool EmulateInstructionARM::EvaluateInstruction(uint32_t evaluate_options) { |
14274 | ARMOpcode *opcode_data = nullptr; |
14275 | |
14276 | if (m_opcode_mode == eModeThumb) |
14277 | opcode_data = |
14278 | GetThumbOpcodeForInstruction(opcode: m_opcode.GetOpcode32(), arm_isa: m_arm_isa); |
14279 | else if (m_opcode_mode == eModeARM) |
14280 | opcode_data = GetARMOpcodeForInstruction(opcode: m_opcode.GetOpcode32(), arm_isa: m_arm_isa); |
14281 | |
14282 | const bool auto_advance_pc = |
14283 | evaluate_options & eEmulateInstructionOptionAutoAdvancePC; |
14284 | m_ignore_conditions = |
14285 | evaluate_options & eEmulateInstructionOptionIgnoreConditions; |
14286 | |
14287 | bool success = false; |
14288 | if (m_opcode_cpsr == 0 || !m_ignore_conditions) { |
14289 | m_opcode_cpsr = |
14290 | ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_cpsr, fail_value: 0, success_ptr: &success); |
14291 | } |
14292 | |
14293 | // Only return false if we are unable to read the CPSR if we care about |
14294 | // conditions |
14295 | if (!success && !m_ignore_conditions) |
14296 | return false; |
14297 | |
14298 | uint32_t orig_pc_value = 0; |
14299 | if (auto_advance_pc) { |
14300 | orig_pc_value = |
14301 | ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_pc, fail_value: 0, success_ptr: &success); |
14302 | if (!success) |
14303 | return false; |
14304 | } |
14305 | |
14306 | // Call the Emulate... function if we managed to decode the opcode. |
14307 | if (opcode_data) { |
14308 | success = (this->*opcode_data->callback)(m_opcode.GetOpcode32(), |
14309 | opcode_data->encoding); |
14310 | if (!success) |
14311 | return false; |
14312 | } |
14313 | |
14314 | // Advance the ITSTATE bits to their values for the next instruction if we |
14315 | // haven't just executed an IT instruction what initialized it. |
14316 | if (m_opcode_mode == eModeThumb && m_it_session.InITBlock() && |
14317 | (opcode_data == nullptr || |
14318 | opcode_data->callback != &EmulateInstructionARM::EmulateIT)) |
14319 | m_it_session.ITAdvance(); |
14320 | |
14321 | if (auto_advance_pc) { |
14322 | uint32_t after_pc_value = |
14323 | ReadRegisterUnsigned(reg_kind: eRegisterKindDWARF, reg_num: dwarf_pc, fail_value: 0, success_ptr: &success); |
14324 | if (!success) |
14325 | return false; |
14326 | |
14327 | if (after_pc_value == orig_pc_value) { |
14328 | after_pc_value += m_opcode.GetByteSize(); |
14329 | |
14330 | EmulateInstruction::Context context; |
14331 | context.type = eContextAdvancePC; |
14332 | context.SetNoArgs(); |
14333 | if (!WriteRegisterUnsigned(context, reg_kind: eRegisterKindDWARF, reg_num: dwarf_pc, |
14334 | reg_value: after_pc_value)) |
14335 | return false; |
14336 | } |
14337 | } |
14338 | return true; |
14339 | } |
14340 | |
14341 | EmulateInstruction::InstructionCondition |
14342 | EmulateInstructionARM::GetInstructionCondition() { |
14343 | const uint32_t cond = CurrentCond(opcode: m_opcode.GetOpcode32()); |
14344 | if (cond == 0xe || cond == 0xf || cond == UINT32_MAX) |
14345 | return EmulateInstruction::UnconditionalCondition; |
14346 | return cond; |
14347 | } |
14348 | |
14349 | bool EmulateInstructionARM::TestEmulation(Stream &out_stream, ArchSpec &arch, |
14350 | OptionValueDictionary *test_data) { |
14351 | if (!test_data) { |
14352 | out_stream.Printf(format: "TestEmulation: Missing test data.\n" ); |
14353 | return false; |
14354 | } |
14355 | |
14356 | static constexpr llvm::StringLiteral opcode_key("opcode" ); |
14357 | static constexpr llvm::StringLiteral before_key("before_state" ); |
14358 | static constexpr llvm::StringLiteral after_key("after_state" ); |
14359 | |
14360 | OptionValueSP value_sp = test_data->GetValueForKey(key: opcode_key); |
14361 | |
14362 | uint32_t test_opcode; |
14363 | if ((value_sp.get() == nullptr) || |
14364 | (value_sp->GetType() != OptionValue::eTypeUInt64)) { |
14365 | out_stream.Printf(format: "TestEmulation: Error reading opcode from test file.\n" ); |
14366 | return false; |
14367 | } |
14368 | test_opcode = value_sp->GetValueAs<uint64_t>().value_or(u: 0); |
14369 | |
14370 | if (arch.GetTriple().getArch() == llvm::Triple::thumb || |
14371 | arch.IsAlwaysThumbInstructions()) { |
14372 | m_opcode_mode = eModeThumb; |
14373 | if (test_opcode < 0x10000) |
14374 | m_opcode.SetOpcode16(inst: test_opcode, order: endian::InlHostByteOrder()); |
14375 | else |
14376 | m_opcode.SetOpcode32(inst: test_opcode, order: endian::InlHostByteOrder()); |
14377 | } else if (arch.GetTriple().getArch() == llvm::Triple::arm) { |
14378 | m_opcode_mode = eModeARM; |
14379 | m_opcode.SetOpcode32(inst: test_opcode, order: endian::InlHostByteOrder()); |
14380 | } else { |
14381 | out_stream.Printf(format: "TestEmulation: Invalid arch.\n" ); |
14382 | return false; |
14383 | } |
14384 | |
14385 | EmulationStateARM before_state; |
14386 | EmulationStateARM after_state; |
14387 | |
14388 | value_sp = test_data->GetValueForKey(key: before_key); |
14389 | if ((value_sp.get() == nullptr) || |
14390 | (value_sp->GetType() != OptionValue::eTypeDictionary)) { |
14391 | out_stream.Printf(format: "TestEmulation: Failed to find 'before' state.\n" ); |
14392 | return false; |
14393 | } |
14394 | |
14395 | OptionValueDictionary *state_dictionary = value_sp->GetAsDictionary(); |
14396 | if (!before_state.LoadStateFromDictionary(test_data: state_dictionary)) { |
14397 | out_stream.Printf(format: "TestEmulation: Failed loading 'before' state.\n" ); |
14398 | return false; |
14399 | } |
14400 | |
14401 | value_sp = test_data->GetValueForKey(key: after_key); |
14402 | if ((value_sp.get() == nullptr) || |
14403 | (value_sp->GetType() != OptionValue::eTypeDictionary)) { |
14404 | out_stream.Printf(format: "TestEmulation: Failed to find 'after' state.\n" ); |
14405 | return false; |
14406 | } |
14407 | |
14408 | state_dictionary = value_sp->GetAsDictionary(); |
14409 | if (!after_state.LoadStateFromDictionary(test_data: state_dictionary)) { |
14410 | out_stream.Printf(format: "TestEmulation: Failed loading 'after' state.\n" ); |
14411 | return false; |
14412 | } |
14413 | |
14414 | SetBaton((void *)&before_state); |
14415 | SetCallbacks(read_mem_callback: &EmulationStateARM::ReadPseudoMemory, |
14416 | write_mem_callback: &EmulationStateARM::WritePseudoMemory, |
14417 | read_reg_callback: &EmulationStateARM::ReadPseudoRegister, |
14418 | write_reg_callback: &EmulationStateARM::WritePseudoRegister); |
14419 | |
14420 | bool success = EvaluateInstruction(evaluate_options: eEmulateInstructionOptionAutoAdvancePC); |
14421 | if (!success) { |
14422 | out_stream.Printf(format: "TestEmulation: EvaluateInstruction() failed.\n" ); |
14423 | return false; |
14424 | } |
14425 | |
14426 | success = before_state.CompareState(other_state&: after_state, out_stream); |
14427 | if (!success) |
14428 | out_stream.Printf(format: "TestEmulation: State after emulation does not match " |
14429 | "'after' state.\n" ); |
14430 | |
14431 | return success; |
14432 | } |
14433 | // |
14434 | // |
14435 | // const char * |
14436 | // EmulateInstructionARM::GetRegisterName (uint32_t reg_kind, uint32_t reg_num) |
14437 | //{ |
14438 | // if (reg_kind == eRegisterKindGeneric) |
14439 | // { |
14440 | // switch (reg_num) |
14441 | // { |
14442 | // case LLDB_REGNUM_GENERIC_PC: return "pc"; |
14443 | // case LLDB_REGNUM_GENERIC_SP: return "sp"; |
14444 | // case LLDB_REGNUM_GENERIC_FP: return "fp"; |
14445 | // case LLDB_REGNUM_GENERIC_RA: return "lr"; |
14446 | // case LLDB_REGNUM_GENERIC_FLAGS: return "cpsr"; |
14447 | // default: return NULL; |
14448 | // } |
14449 | // } |
14450 | // else if (reg_kind == eRegisterKindDWARF) |
14451 | // { |
14452 | // return GetARMDWARFRegisterName (reg_num); |
14453 | // } |
14454 | // return NULL; |
14455 | //} |
14456 | // |
14457 | bool EmulateInstructionARM::CreateFunctionEntryUnwind(UnwindPlan &unwind_plan) { |
14458 | unwind_plan.Clear(); |
14459 | unwind_plan.SetRegisterKind(eRegisterKindDWARF); |
14460 | |
14461 | UnwindPlan::RowSP row(new UnwindPlan::Row); |
14462 | |
14463 | // Our previous Call Frame Address is the stack pointer |
14464 | row->GetCFAValue().SetIsRegisterPlusOffset(reg_num: dwarf_sp, offset: 0); |
14465 | |
14466 | unwind_plan.AppendRow(row_sp: row); |
14467 | unwind_plan.SetSourceName("EmulateInstructionARM" ); |
14468 | unwind_plan.SetSourcedFromCompiler(eLazyBoolNo); |
14469 | unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolYes); |
14470 | unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo); |
14471 | unwind_plan.SetReturnAddressRegister(dwarf_lr); |
14472 | return true; |
14473 | } |
14474 | |