public
Description: A Nintendo Gameboy Advance emulator for the Apple iPhone and iPod Touch.
Homepage: http://www.zodttd.com
Clone URL: git://github.com/zodttd/gpsphone.git
Click here to lend your support to: gpsphone and make a donation at www.pledgie.com !
gpsphone / cpu.c
fc787e4d » ME 2008-05-13 First commit of gpSPhone at... 1 /* gameplaySP
2 *
3 * Copyright (C) 2006 Exophase <exophase@gmail.com>
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of
8 * the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20 // Important todo:
21 // - stm reglist writeback when base is in the list needs adjustment
22 // - block memory needs psr swapping and user mode reg swapping
23
24 #include <stdio.h>
25 #include "common.h"
26
27 u32 memory_region_access_read_u8[16];
28 u32 memory_region_access_read_s8[16];
29 u32 memory_region_access_read_u16[16];
30 u32 memory_region_access_read_s16[16];
31 u32 memory_region_access_read_u32[16];
32 u32 memory_region_access_write_u8[16];
33 u32 memory_region_access_write_u16[16];
34 u32 memory_region_access_write_u32[16];
35 u32 memory_reads_u8;
36 u32 memory_reads_s8;
37 u32 memory_reads_u16;
38 u32 memory_reads_s16;
39 u32 memory_reads_u32;
40 u32 memory_writes_u8;
41 u32 memory_writes_u16;
42 u32 memory_writes_u32;
43
44 static const u8 bit_count[256] =
45 {
46 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3,
47 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4,
48 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 1, 2, 2, 3, 2,
49 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5,
50 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4,
51 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3,
52 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2,
53 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6,
54 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5,
55 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 3, 4, 4, 5, 4, 5,
56 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6,
57 7, 7, 8
58 };
59
60
61 #ifdef REGISTER_USAGE_ANALYZE
62
63 u64 instructions_total = 0;
64
65 u64 arm_reg_freq[16];
66 u64 arm_reg_access_total = 0;
67 u64 arm_instructions_total = 0;
68
69 u64 thumb_reg_freq[16];
70 u64 thumb_reg_access_total = 0;
71 u64 thumb_instructions_total = 0;
72
73 // mla/long mla's addition operand are not counted yet.
74
75 #define using_register(instruction_set, register, type) \
76 instruction_set##_reg_freq[register]++; \
77 instruction_set##_reg_access_total++ \
78
79 #define using_register_list(instruction_set, rlist, count) \
80 { \
81 u32 i; \
82 for(i = 0; i < count; i++) \
83 { \
84 if((reg_list >> i) & 0x01) \
85 { \
86 using_register(instruction_set, i, memory_target); \
87 } \
88 } \
89 } \
90
91 #define using_instruction(instruction_set) \
92 instruction_set##_instructions_total++; \
93 instructions_total++ \
94
95 int sort_tagged_element(const void *_a, const void *_b)
96 {
97 const u64 *a = _a;
98 const u64 *b = _b;
99
100 return (int)(b[1] - a[1]);
101 }
102
103 void print_register_usage()
104 {
105 u32 i;
106 u64 arm_reg_freq_tagged[32];
107 u64 thumb_reg_freq_tagged[32];
108 double percent;
109 double percent_total = 0.0;
110
111 for(i = 0; i < 16; i++)
112 {
113 arm_reg_freq_tagged[i * 2] = i;
114 arm_reg_freq_tagged[(i * 2) + 1] = arm_reg_freq[i];
115 thumb_reg_freq_tagged[i * 2] = i;
116 thumb_reg_freq_tagged[(i * 2) + 1] = thumb_reg_freq[i];
117 }
118
119 qsort(arm_reg_freq_tagged, 16, sizeof(u64) * 2, sort_tagged_element);
120 qsort(thumb_reg_freq_tagged, 16, sizeof(u64) * 2, sort_tagged_element);
121
122 printf("ARM register usage (%lf%% ARM instructions):\n",
123 (arm_instructions_total * 100.0) / instructions_total);
124 for(i = 0; i < 16; i++)
125 {
126 percent = (arm_reg_freq_tagged[(i * 2) + 1] * 100.0) /
127 arm_reg_access_total;
128 percent_total += percent;
129 printf("r%02d: %lf%% (-- %lf%%)\n",
130 (u32)arm_reg_freq_tagged[(i * 2)], percent, percent_total);
131 }
132
133 percent_total = 0.0;
134
135 printf("\nThumb register usage (%lf%% Thumb instructions):\n",
136 (thumb_instructions_total * 100.0) / instructions_total);
137 for(i = 0; i < 16; i++)
138 {
139 percent = (thumb_reg_freq_tagged[(i * 2) + 1] * 100.0) /
140 thumb_reg_access_total;
141 percent_total += percent;
142 printf("r%02d: %lf%% (-- %lf%%)\n",
143 (u32)thumb_reg_freq_tagged[(i * 2)], percent, percent_total);
144 }
145
146 memset(arm_reg_freq, 0, sizeof(u64) * 16);
147 memset(thumb_reg_freq, 0, sizeof(u64) * 16);
148 arm_reg_access_total = 0;
149 thumb_reg_access_total = 0;
150 }
151
152 #else
153
154 #define using_register(instruction_set, register, type) \
155
156 #define using_register_list(instruction_set, rlist, count) \
157
158 #define using_instruction(instruction_set) \
159
160 #endif
161
162
163 #define arm_decode_data_proc_reg() \
164 u32 rn = (opcode >> 16) & 0x0F; \
165 u32 rd = (opcode >> 12) & 0x0F; \
166 u32 rm = opcode & 0x0F; \
167 using_register(arm, rd, op_dest); \
168 using_register(arm, rn, op_src); \
169 using_register(arm, rm, op_src) \
170
171 #define arm_decode_data_proc_imm() \
172 u32 rn = (opcode >> 16) & 0x0F; \
173 u32 rd = (opcode >> 12) & 0x0F; \
174 u32 imm; \
175 ror(imm, opcode & 0xFF, ((opcode >> 8) & 0x0F) * 2); \
176 using_register(arm, rd, op_dest); \
177 using_register(arm, rn, op_src) \
178
179 #define arm_decode_psr_reg() \
180 u32 psr_field = (opcode >> 16) & 0x0F; \
181 u32 rd = (opcode >> 12) & 0x0F; \
182 u32 rm = opcode & 0x0F; \
183 using_register(arm, rd, op_dest); \
184 using_register(arm, rm, op_src) \
185
186 #define arm_decode_psr_imm() \
187 u32 psr_field = (opcode >> 16) & 0x0F; \
188 u32 rd = (opcode >> 12) & 0x0F; \
189 u32 imm; \
190 ror(imm, opcode & 0xFF, ((opcode >> 8) & 0x0F) * 2); \
191 using_register(arm, rd, op_dest) \
192
193 #define arm_decode_branchx() \
194 u32 rn = opcode & 0x0F; \
195 using_register(arm, rn, branch_target) \
196
197 #define arm_decode_multiply() \
198 u32 rd = (opcode >> 16) & 0x0F; \
199 u32 rn = (opcode >> 12) & 0x0F; \
200 u32 rs = (opcode >> 8) & 0x0F; \
201 u32 rm = opcode & 0x0F; \
202 using_register(arm, rd, op_dest); \
203 using_register(arm, rn, op_src); \
204 using_register(arm, rm, op_src) \
205
206 #define arm_decode_multiply_long() \
207 u32 rdhi = (opcode >> 16) & 0x0F; \
208 u32 rdlo = (opcode >> 12) & 0x0F; \
209 u32 rn = (opcode >> 8) & 0x0F; \
210 u32 rm = opcode & 0x0F; \
211 using_register(arm, rdhi, op_dest); \
212 using_register(arm, rdlo, op_dest); \
213 using_register(arm, rn, op_src); \
214 using_register(arm, rm, op_src) \
215
216 #define arm_decode_swap() \
217 u32 rn = (opcode >> 16) & 0x0F; \
218 u32 rd = (opcode >> 12) & 0x0F; \
219 u32 rm = opcode & 0x0F; \
220 using_register(arm, rd, memory_target); \
221 using_register(arm, rn, memory_base); \
222 using_register(arm, rm, memory_target) \
223
224 #define arm_decode_half_trans_r() \
225 u32 rn = (opcode >> 16) & 0x0F; \
226 u32 rd = (opcode >> 12) & 0x0F; \
227 u32 rm = opcode & 0x0F; \
228 using_register(arm, rd, memory_target); \
229 using_register(arm, rn, memory_base); \
230 using_register(arm, rm, memory_offset) \
231
232 #define arm_decode_half_trans_of() \
233 u32 rn = (opcode >> 16) & 0x0F; \
234 u32 rd = (opcode >> 12) & 0x0F; \
235 u32 offset = ((opcode >> 4) & 0xF0) | (opcode & 0x0F); \
236 using_register(arm, rd, memory_target); \
237 using_register(arm, rn, memory_base) \
238
239 #define arm_decode_data_trans_imm() \
240 u32 rn = (opcode >> 16) & 0x0F; \
241 u32 rd = (opcode >> 12) & 0x0F; \
242 u32 offset = opcode & 0x0FFF; \
243 using_register(arm, rd, memory_target); \
244 using_register(arm, rn, memory_base) \
245
246 #define arm_decode_data_trans_reg() \
247 u32 rn = (opcode >> 16) & 0x0F; \
248 u32 rd = (opcode >> 12) & 0x0F; \
249 u32 rm = opcode & 0x0F; \
250 using_register(arm, rd, memory_target); \
251 using_register(arm, rn, memory_base); \
252 using_register(arm, rm, memory_offset) \
253
254 #define arm_decode_block_trans() \
255 u32 rn = (opcode >> 16) & 0x0F; \
256 u32 reg_list = opcode & 0xFFFF; \
257 using_register(arm, rn, memory_base); \
258 using_register_list(arm, reg_list, 16) \
259
260 #define arm_decode_branch() \
261 s32 offset = ((s32)(opcode & 0xFFFFFF) << 8) >> 6 \
262
263
264 #define thumb_decode_shift() \
265 u32 imm = (opcode >> 6) & 0x1F; \
266 u32 rs = (opcode >> 3) & 0x07; \
267 u32 rd = opcode & 0x07; \
268 using_register(thumb, rd, op_dest); \
269 using_register(thumb, rs, op_shift) \
270
271 #define thumb_decode_add_sub() \
272 u32 rn = (opcode >> 6) & 0x07; \
273 u32 rs = (opcode >> 3) & 0x07; \
274 u32 rd = opcode & 0x07; \
275 using_register(thumb, rd, op_dest); \
276 using_register(thumb, rn, op_src); \
277 using_register(thumb, rn, op_src) \
278
279 #define thumb_decode_add_sub_imm() \
280 u32 imm = (opcode >> 6) & 0x07; \
281 u32 rs = (opcode >> 3) & 0x07; \
282 u32 rd = opcode & 0x07; \
283 using_register(thumb, rd, op_src_dest); \
284 using_register(thumb, rs, op_src) \
285
286 #define thumb_decode_imm() \
287 u32 imm = opcode & 0xFF; \
288 using_register(thumb, ((opcode >> 8) & 0x07), op_dest) \
289
290 #define thumb_decode_alu_op() \
291 u32 rs = (opcode >> 3) & 0x07; \
292 u32 rd = opcode & 0x07; \
293 using_register(thumb, rd, op_src_dest); \
294 using_register(thumb, rs, op_src) \
295
296 #define thumb_decode_hireg_op() \
297 u32 rs = (opcode >> 3) & 0x0F; \
298 u32 rd = ((opcode >> 4) & 0x08) | (opcode & 0x07); \
299 using_register(thumb, rd, op_src_dest); \
300 using_register(thumb, rs, op_src) \
301
302
303 #define thumb_decode_mem_reg() \
304 u32 ro = (opcode >> 6) & 0x07; \
305 u32 rb = (opcode >> 3) & 0x07; \
306 u32 rd = opcode & 0x07; \
307 using_register(thumb, rd, memory_target); \
308 using_register(thumb, rb, memory_base); \
309 using_register(thumb, ro, memory_offset) \
310
311
312 #define thumb_decode_mem_imm() \
313 u32 imm = (opcode >> 6) & 0x1F; \
314 u32 rb = (opcode >> 3) & 0x07; \
315 u32 rd = opcode & 0x07; \
316 using_register(thumb, rd, memory_target); \
317 using_register(thumb, rb, memory_base) \
318
319
320 #define thumb_decode_add_sp() \
321 u32 imm = opcode & 0x7F; \
322 using_register(thumb, REG_SP, op_dest) \
323
324 #define thumb_decode_rlist() \
325 u32 reg_list = opcode & 0xFF; \
326 using_register_list(thumb, rlist, 8) \
327
328 #define thumb_decode_branch_cond() \
329 s32 offset = (s8)(opcode & 0xFF) \
330
331 #define thumb_decode_swi() \
332 u32 comment = opcode & 0xFF \
333
334 #define thumb_decode_branch() \
335 u32 offset = opcode & 0x07FF \
336
337
338 #define get_shift_register(dest) \
339 u32 shift = reg[(opcode >> 8) & 0x0F]; \
340 using_register(arm, ((opcode >> 8) & 0x0F), op_shift); \
341 dest = reg[rm]; \
342 if(rm == 15) \
343 dest += 4 \
344
345
346 #define calculate_z_flag(dest) \
347 z_flag = (dest == 0) \
348
349 #define calculate_n_flag(dest) \
350 n_flag = ((signed)dest < 0) \
351
352 #define calculate_c_flag_sub(dest, src_a, src_b) \
353 c_flag = ((unsigned)src_b <= (unsigned)src_a) \
354
355 #define calculate_v_flag_sub(dest, src_a, src_b) \
356 v_flag = ((signed)src_b > (signed)src_a) != ((signed)dest < 0) \
357
358 #define calculate_c_flag_add(dest, src_a, src_b) \
359 c_flag = ((unsigned)dest < (unsigned)src_a) \
360
361 #define calculate_v_flag_add(dest, src_a, src_b) \
362 v_flag = ((signed)dest < (signed)src_a) != ((signed)src_b < 0) \
363
364
365 #define calculate_reg_sh() \
366 u32 reg_sh; \
367 switch((opcode >> 4) & 0x07) \
368 { \
369 /* LSL imm */ \
370 case 0x0: \
371 { \
372 reg_sh = reg[rm] << ((opcode >> 7) & 0x1F); \
373 break; \
374 } \
375 \
376 /* LSL reg */ \
377 case 0x1: \
378 { \
379 get_shift_register(reg_sh); \
380 if(shift <= 31) \
381 reg_sh = reg_sh << shift; \
382 else \
383 reg_sh = 0; \
384 break; \
385 } \
386 \
387 /* LSR imm */ \
388 case 0x2: \
389 { \
390 u32 imm = (opcode >> 7) & 0x1F; \
391 if(imm == 0) \
392 reg_sh = 0; \
393 else \
394 reg_sh = reg[rm] >> imm; \
395 break; \
396 } \
397 \
398 /* LSR reg */ \
399 case 0x3: \
400 { \
401 get_shift_register(reg_sh); \
402 if(shift <= 31) \
403 reg_sh = reg_sh >> shift; \
404 else \
405 reg_sh = 0; \
406 break; \
407 } \
408 \
409 /* ASR imm */ \
410 case 0x4: \
411 { \
412 u32 imm = (opcode >> 7) & 0x1F; \
413 reg_sh = reg[rm]; \
414 \
415 if(imm == 0) \
416 reg_sh = (s32)reg_sh >> 31; \
417 else \
418 reg_sh = (s32)reg_sh >> imm; \
419 break; \
420 } \
421 \
422 /* ASR reg */ \
423 case 0x5: \
424 { \
425 get_shift_register(reg_sh); \
426 if(shift <= 31) \
427 reg_sh = (s32)reg_sh >> shift; \
428 else \
429 reg_sh = (s32)reg_sh >> 31; \
430 break; \
431 } \
432 \
433 /* ROR imm */ \
434 case 0x6: \
435 { \
436 u32 imm = (opcode >> 7) & 0x1F; \
437 \
438 if(imm == 0) \
439 reg_sh = (reg[rm] >> 1) | (c_flag << 31); \
440 else \
441 ror(reg_sh, reg[rm], imm); \
442 break; \
443 } \
444 \
445 /* ROR reg */ \
446 case 0x7: \
447 { \
448 get_shift_register(reg_sh); \
449 ror(reg_sh, reg_sh, shift); \
450 break; \
451 } \
452 } \
453
454 #define calculate_reg_sh_flags() \
455 u32 reg_sh; \
456 switch((opcode >> 4) & 0x07) \
457 { \
458 /* LSL imm */ \
459 case 0x0: \
460 { \
461 u32 imm = (opcode >> 7) & 0x1F; \
462 reg_sh = reg[rm]; \
463 \
464 if(imm != 0) \
465 { \
466 c_flag = (reg_sh >> (32 - imm)) & 0x01; \
467 reg_sh <<= imm; \
468 } \
469 \
470 break; \
471 } \
472 \
473 /* LSL reg */ \
474 case 0x1: \
475 { \
476 get_shift_register(reg_sh); \
477 if(shift != 0) \
478 { \
479 if(shift > 31) \
480 { \
481 if(shift == 32) \
482 c_flag = reg_sh & 0x01; \
483 else \
484 c_flag = 0; \
485 reg_sh = 0; \
486 } \
487 else \
488 { \
489 c_flag = (reg_sh >> (32 - shift)) & 0x01; \
490 reg_sh <<= shift; \
491 } \
492 } \
493 break; \
494 } \
495 \
496 /* LSR imm */ \
497 case 0x2: \
498 { \
499 u32 imm = (opcode >> 7) & 0x1F; \
500 reg_sh = reg[rm]; \
501 if(imm == 0) \
502 { \
503 c_flag = reg_sh >> 31; \
504 reg_sh = 0; \
505 } \
506 else \
507 { \
508 c_flag = (reg_sh >> (imm - 1)) & 0x01; \
509 reg_sh >>= imm; \
510 } \
511 break; \
512 } \
513 \
514 /* LSR reg */ \
515 case 0x3: \
516 { \
517 get_shift_register(reg_sh); \
518 if(shift != 0) \
519 { \
520 if(shift > 31) \
521 { \
522 if(shift == 32) \
523 c_flag = (reg_sh >> 31) & 0x01; \
524 else \
525 c_flag = 0; \
526 reg_sh = 0; \
527 } \
528 else \
529 { \
530 c_flag = (reg_sh >> (shift - 1)) & 0x01; \
531 reg_sh >>= shift; \
532 } \
533 } \
534 break; \
535 } \
536 \
537 /* ASR imm */ \
538 case 0x4: \
539 { \
540 u32 imm = (opcode >> 7) & 0x1F; \
541 reg_sh = reg[rm]; \
542 if(imm == 0) \
543 { \
544 reg_sh = (s32)reg_sh >> 31; \
545 c_flag = reg_sh & 0x01; \
546 } \
547 else \
548 { \
549 c_flag = (reg_sh >> (imm - 1)) & 0x01; \
550 reg_sh = (s32)reg_sh >> imm; \
551 } \
552 break; \
553 } \
554 \
555 /* ASR reg */ \
556 case 0x5: \
557 { \
558 get_shift_register(reg_sh); \
559 if(shift != 0) \
560 { \
561 if(shift > 31) \
562 { \
563 reg_sh = (s32)reg_sh >> 31; \
564 c_flag = reg_sh & 0x01; \
565 } \
566 else \
567 { \
568 c_flag = (reg_sh >> (shift - 1)) & 0x01; \
569 reg_sh = (s32)reg_sh >> shift; \
570 } \
571 } \
572 break; \
573 } \
574 \
575 /* ROR imm */ \
576 case 0x6: \
577 { \
578 u32 imm = (opcode >> 7) & 0x1F; \
579 reg_sh = reg[rm]; \
580 if(imm == 0) \
581 { \
582 u32 old_c_flag = c_flag; \
583 c_flag = reg_sh & 0x01; \
584 reg_sh = (reg_sh >> 1) | (old_c_flag << 31); \
585 } \
586 else \
587 { \
588 c_flag = (reg_sh >> (imm - 1)) & 0x01; \
589 ror(reg_sh, reg_sh, imm); \
590 } \
591 break; \
592 } \
593 \
594 /* ROR reg */ \
595 case 0x7: \
596 { \
597 get_shift_register(reg_sh); \
598 if(shift != 0) \
599 { \
600 c_flag = (reg_sh >> (shift - 1)) & 0x01; \
601 ror(reg_sh, reg_sh, shift); \
602 } \
603 break; \
604 } \
605 } \
606
607 #define calculate_reg_offset() \
608 u32 reg_offset; \
609 switch((opcode >> 5) & 0x03) \
610 { \
611 /* LSL imm */ \
612 case 0x0: \
613 { \
614 reg_offset = reg[rm] << ((opcode >> 7) & 0x1F); \
615 break; \
616 } \
617 \
618 /* LSR imm */ \
619 case 0x1: \
620 { \
621 u32 imm = (opcode >> 7) & 0x1F; \
622 if(imm == 0) \
623 reg_offset = 0; \
624 else \
625 reg_offset = reg[rm] >> imm; \
626 break; \
627 } \
628 \
629 /* ASR imm */ \
630 case 0x2: \
631 { \
632 u32 imm = (opcode >> 7) & 0x1F; \
633 if(imm == 0) \
634 reg_offset = (s32)reg[rm] >> 31; \
635 else \
636 reg_offset = (s32)reg[rm] >> imm; \
637 break; \
638 } \
639 \
640 /* ROR imm */ \
641 case 0x3: \
642 { \
643 u32 imm = (opcode >> 7) & 0x1F; \
644 if(imm == 0) \
645 reg_offset = (reg[rm] >> 1) | (c_flag << 31); \
646 else \
647 ror(reg_offset, reg[rm], imm); \
648 break; \
649 } \
650 } \
651
652 #define calculate_flags_add(dest, src_a, src_b) \
653 calculate_z_flag(dest); \
654 calculate_n_flag(dest); \
655 calculate_c_flag_add(dest, src_a, src_b); \
656 calculate_v_flag_add(dest, src_a, src_b) \
657
658 #define calculate_flags_sub(dest, src_a, src_b) \
659 calculate_z_flag(dest); \
660 calculate_n_flag(dest); \
661 calculate_c_flag_sub(dest, src_a, src_b); \
662 calculate_v_flag_sub(dest, src_a, src_b) \
663
664 #define calculate_flags_logic(dest) \
665 calculate_z_flag(dest); \
666 calculate_n_flag(dest) \
667
668 #define extract_flags() \
669 n_flag = reg[REG_CPSR] >> 31; \
670 z_flag = (reg[REG_CPSR] >> 30) & 0x01; \
671 c_flag = (reg[REG_CPSR] >> 29) & 0x01; \
672 v_flag = (reg[REG_CPSR] >> 28) & 0x01; \
673
674 #define collapse_flags() \
675 reg[REG_CPSR] = (n_flag << 31) | (z_flag << 30) | (c_flag << 29) | \
676 (v_flag << 28) | (reg[REG_CPSR] & 0xFF) \
677
678 #define memory_region(r_dest, l_dest, address) \
679 r_dest = memory_regions[address >> 24]; \
680 l_dest = memory_limits[address >> 24] \
681
682
683 #define pc_region() \
684 memory_region(pc_region, pc_limit, pc) \
685
686 #define check_pc_region() \
687 new_pc_region = (pc >> 15); \
688 if(new_pc_region != pc_region) \
689 { \
690 pc_region = new_pc_region; \
691 pc_address_block = memory_map_read[new_pc_region]; \
692 \
693 if(pc_address_block == NULL) \
694 pc_address_block = load_gamepak_page(pc_region & 0x3FF); \
695 } \
696
697 u32 branch_targets = 0;
698 u32 high_frequency_branch_targets = 0;
699
700 #define BRANCH_ACTIVITY_THRESHOLD 50
701
702 #define arm_update_pc() \
703 pc = reg[REG_PC] \
704
705 #define arm_pc_offset(val) \
706 pc += val; \
707 reg[REG_PC] = pc \
708
709 #define arm_pc_offset_update(val) \
710 pc += val; \
711 reg[REG_PC] = pc \
712
713 #define arm_pc_offset_update_direct(val) \
714 pc = val; \
715 reg[REG_PC] = pc \
716
717
718 // It should be okay to still generate result flags, spsr will overwrite them.
719 // This is pretty infrequent (returning from interrupt handlers, et al) so
720 // probably not worth optimizing for.
721
722 #define check_for_interrupts() \
723 if((io_registers[REG_IE] & io_registers[REG_IF]) && \
724 io_registers[REG_IME] && ((reg[REG_CPSR] & 0x80) == 0)) \
725 { \
726 reg_mode[MODE_IRQ][6] = reg[REG_PC] + 4; \
727 spsr[MODE_IRQ] = reg[REG_CPSR]; \
728 reg[REG_CPSR] = 0xD2; \
729 reg[REG_PC] = 0x00000018; \
730 arm_update_pc(); \
731 set_cpu_mode(MODE_IRQ); \
732 goto arm_loop; \
733 } \
734
735 #define arm_spsr_restore() \
736 if(rd == 15) \
737 { \
738 if(reg[CPU_MODE] != MODE_USER) \
739 { \
740 reg[REG_CPSR] = spsr[reg[CPU_MODE]]; \
741 extract_flags(); \
742 set_cpu_mode(cpu_modes[reg[REG_CPSR] & 0x1F]); \
743 check_for_interrupts(); \
744 } \
745 arm_update_pc(); \
746 \
747 if(reg[REG_CPSR] & 0x20) \
748 goto thumb_loop; \
749 } \
750
751 #define arm_data_proc_flags_reg() \
752 arm_decode_data_proc_reg(); \
753 calculate_reg_sh_flags() \
754
755 #define arm_data_proc_reg() \
756 arm_decode_data_proc_reg(); \
757 calculate_reg_sh() \
758
759 #define arm_data_proc_flags_imm() \
760 arm_decode_data_proc_imm() \
761
762 #define arm_data_proc_imm() \
763 arm_decode_data_proc_imm() \
764
765 #define arm_data_proc(expr, type) \
766 { \
767 u32 dest; \
768 arm_pc_offset(8); \
769 arm_data_proc_##type(); \
770 dest = expr; \
771 arm_pc_offset(-4); \
772 reg[rd] = dest; \
773 \
774 if(rd == 15) \
775 { \
776 arm_update_pc(); \
777 } \
778 } \
779
780 #define flags_vars(src_a, src_b) \
781 u32 dest; \
782 const u32 _sa = src_a; \
783 const u32 _sb = src_b \
784
785 #define arm_data_proc_logic_flags(expr, type) \
786 { \
787 arm_pc_offset(8); \
788 arm_data_proc_flags_##type(); \
789 u32 dest = expr; \
790 calculate_flags_logic(dest); \
791 arm_pc_offset(-4); \
792 reg[rd] = dest; \
793 arm_spsr_restore(); \
794 } \
795
796 #define arm_data_proc_add_flags(src_a, src_b, type) \
797 { \
798 arm_pc_offset(8); \
799 arm_data_proc_##type(); \
800 flags_vars(src_a, src_b); \
801 dest = _sa + _sb; \
802 calculate_flags_add(dest, _sa, _sb); \
803 arm_pc_offset(-4); \
804 reg[rd] = dest; \
805 arm_spsr_restore(); \
806 }
807
808 #define arm_data_proc_sub_flags(src_a, src_b, type) \
809 { \
810 arm_pc_offset(8); \
811 arm_data_proc_##type(); \
812 flags_vars(src_a, src_b); \
813 dest = _sa - _sb; \
814 calculate_flags_sub(dest, _sa, _sb); \
815 arm_pc_offset(-4); \
816 reg[rd] = dest; \
817 arm_spsr_restore(); \
818 } \
819
820 #define arm_data_proc_test_logic(expr, type) \
821 { \
822 arm_pc_offset(8); \
823 arm_data_proc_flags_##type(); \
824 u32 dest = expr; \
825 calculate_flags_logic(dest); \
826 arm_pc_offset(-4); \
827 } \
828
829 #define arm_data_proc_test_add(src_a, src_b, type) \
830 { \
831 arm_pc_offset(8); \
832 arm_data_proc_##type(); \
833 flags_vars(src_a, src_b); \
834 dest = _sa + _sb; \
835 calculate_flags_add(dest, _sa, _sb); \
836 arm_pc_offset(-4); \
837 } \
838
839 #define arm_data_proc_test_sub(src_a, src_b, type) \
840 { \
841 arm_pc_offset(8); \
842 arm_data_proc_##type(); \
843 flags_vars(src_a, src_b); \
844 dest = _sa - _sb; \
845 calculate_flags_sub(dest, _sa, _sb); \
846 arm_pc_offset(-4); \
847 } \
848
849 #define arm_multiply_flags_yes(_dest) \
850 calculate_z_flag(_dest); \
851 calculate_n_flag(_dest); \
852
853 #define arm_multiply_flags_no(_dest) \
854
855 #define arm_multiply_long_flags_yes(_dest_lo, _dest_hi) \
856 z_flag = (_dest_lo == 0) & (_dest_hi == 0); \
857 calculate_n_flag(_dest_hi) \
858
859 #define arm_multiply_long_flags_no(_dest_lo, _dest_hi) \
860
861 #define arm_multiply(add_op, flags) \
862 { \
863 u32 dest; \
864 arm_decode_multiply(); \
865 dest = (reg[rm] * reg[rs]) add_op; \
866 arm_multiply_flags_##flags(dest); \
867 reg[rd] = dest; \
868 arm_pc_offset(4); \
869 } \
870
871 #define arm_multiply_long_addop(type) \
872 + ((type##64)((((type##64)reg[rdhi]) << 32) | reg[rdlo])); \
873
874 #define arm_multiply_long(add_op, flags, type) \
875 { \
876 type##64 dest; \
877 u32 dest_lo; \
878 u32 dest_hi; \
879 arm_decode_multiply_long(); \
880 dest = ((type##64)((type##32)reg[rm]) * \
881 (type##64)((type##32)reg[rn])) add_op; \
882 dest_lo = (u32)dest; \
883 dest_hi = (u32)(dest >> 32); \
884 arm_multiply_long_flags_##flags(dest_lo, dest_hi); \
885 reg[rdlo] = dest_lo; \
886 reg[rdhi] = dest_hi; \
887 arm_pc_offset(4); \
888 } \
889
890 const u32 psr_masks[16] =
891 {
892 0x00000000, 0x000000FF, 0x0000FF00, 0x0000FFFF, 0x00FF0000,
893 0x00FF00FF, 0x00FFFF00, 0x00FFFFFF, 0xFF000000, 0xFF0000FF,
894 0xFF00FF00, 0xFF00FFFF, 0xFFFF0000, 0xFFFF00FF, 0xFFFFFF00,
895 0xFFFFFFFF
896 };
897
898 #define arm_psr_read(dummy, psr_reg) \
899 collapse_flags(); \
900 reg[rd] = psr_reg \
901
902 #define arm_psr_store_cpsr(source) \
903 reg[REG_CPSR] = (source & store_mask) | (reg[REG_CPSR] & (~store_mask)); \
904 extract_flags(); \
905 if(store_mask & 0xFF) \
906 { \
907 set_cpu_mode(cpu_modes[reg[REG_CPSR] & 0x1F]); \
908 check_for_interrupts(); \
909 } \
910
911 #define arm_psr_store_spsr(source) \
912 u32 _psr = spsr[reg[CPU_MODE]]; \
913 spsr[reg[CPU_MODE]] = (source & store_mask) | (_psr & (~store_mask)) \
914
915 #define arm_psr_store(source, psr_reg) \
916 const u32 store_mask = psr_masks[psr_field]; \
917 arm_psr_store_##psr_reg(source) \
918
919 #define arm_psr_src_reg reg[rm]
920
921 #define arm_psr_src_imm imm
922
923 #define arm_psr(op_type, transfer_type, psr_reg) \
924 { \
925 arm_decode_psr_##op_type(); \
926 arm_pc_offset(4); \
927 arm_psr_##transfer_type(arm_psr_src_##op_type, psr_reg); \
928 } \
929
930 #define arm_data_trans_reg() \
931 arm_decode_data_trans_reg(); \
932 calculate_reg_offset() \
933
934 #define arm_data_trans_imm() \
935 arm_decode_data_trans_imm() \
936
937 #define arm_data_trans_half_reg() \
938 arm_decode_half_trans_r() \
939
940 #define arm_data_trans_half_imm() \
941 arm_decode_half_trans_of() \
942
943 #define aligned_address_mask8 0xF0000000
944 #define aligned_address_mask16 0xF0000001
945 #define aligned_address_mask32 0xF0000003
946
947 #define fast_read_memory(size, type, address, dest) \
948 { \
949 u8 *map; \
950 u32 _address = address; \
951 \
952 if(_address < 0x10000000) \
953 { \
954 memory_region_access_read_##type[_address >> 24]++; \
955 memory_reads_##type++; \
956 } \
957 if(((_address >> 24) == 0) && (pc >= 0x4000)) \
958 { \
959 dest = *((type *)((u8 *)&bios_read_protect + (_address & 0x03))); \
960 } \
961 else \
962 \
963 if(((_address & aligned_address_mask##size) == 0) && \
964 (map = memory_map_read[address >> 15])) \
965 { \
966 dest = *((type *)((u8 *)map + (_address & 0x7FFF))); \
967 } \
968 else \
969 { \
970 dest = (type)read_memory##size(_address); \
971 } \
972 } \
973
974 #define fast_read_memory_s16(address, dest) \
975 { \
976 u8 *map; \
977 u32 _address = address; \
978 if(_address < 0x10000000) \
979 { \
980 memory_region_access_read_s16[_address >> 24]++; \
981 memory_reads_s16++; \
982 } \
983 if(((_address & aligned_address_mask16) == 0) && \
984 (map = memory_map_read[_address >> 15])) \
985 { \
986 dest = *((s16 *)((u8 *)map + (_address & 0x7FFF))); \
987 } \
988 else \
989 { \
990 dest = (s16)read_memory16_signed(_address); \
991 } \
992 } \
993
994
995 #define fast_write_memory(size, type, address, value) \
996 { \
997 u8 *map; \
998 u32 _address = (address) & ~(aligned_address_mask##size & 0x03); \
999 if(_address < 0x10000000) \
1000 { \
1001 memory_region_access_write_##type[_address >> 24]++; \
1002 memory_writes_##type++; \
1003 } \
1004 \
1005 if(((_address & aligned_address_mask##size) == 0) && \
1006 (map = memory_map_write[_address >> 15])) \
1007 { \
1008 *((type *)((u8 *)map + (_address & 0x7FFF))) = value; \
1009 } \
1010 else \
1011 { \
1012 cpu_alert = write_memory##size(_address, value); \
1013 if(cpu_alert) \
1014 goto alert; \
1015 } \
1016 } \
1017
1018 #define load_aligned32(address, dest) \
1019 { \
1020 u8 *map = memory_map_read[address >> 15]; \
1021 if(address < 0x10000000) \
1022 { \
1023 memory_region_access_read_u32[address >> 24]++; \
1024 memory_reads_u32++; \
1025 } \
1026 if(map) \
1027 { \
1028 dest = address32(map, address & 0x7FFF); \
1029 } \
1030 else \
1031 { \
1032 dest = read_memory32(address); \
1033 } \
1034 } \
1035
1036 #define store_aligned32(address, value) \
1037 { \
1038 u8 *map = memory_map_write[address >> 15]; \
1039 if(address < 0x10000000) \
1040 { \
1041 memory_region_access_write_u32[address >> 24]++; \
1042 memory_writes_u32++; \
1043 } \
1044 if(map) \
1045 { \
1046 address32(map, address & 0x7FFF) = value; \
1047 } \
1048 else \
1049 { \
1050 cpu_alert = write_memory32(address, value); \
1051 if(cpu_alert) \
1052 goto alert; \
1053 } \
1054 } \
1055
1056 #define load_memory_u8(address, dest) \
1057 fast_read_memory(8, u8, address, dest) \
1058
1059 #define load_memory_u16(address, dest) \
1060 fast_read_memory(16, u16, address, dest) \
1061
1062 #define load_memory_u32(address, dest) \
1063 fast_read_memory(32, u32, address, dest) \
1064
1065 #define load_memory_s8(address, dest) \
1066 fast_read_memory(8, s8, address, dest) \
1067
1068 #define load_memory_s16(address, dest) \
1069 fast_read_memory_s16(address, dest) \
1070
1071 #define store_memory_u8(address, value) \
1072 fast_write_memory(8, u8, address, value) \
1073
1074 #define store_memory_u16(address, value) \
1075 fast_write_memory(16, u16, address, value) \
1076
1077 #define store_memory_u32(address, value) \
1078 fast_write_memory(32, u32, address, value) \
1079
1080 #define no_op \
1081
1082 #define arm_access_memory_writeback_yes(off_op) \
1083 reg[rn] = address off_op \
1084
1085 #define arm_access_memory_writeback_no(off_op) \
1086
1087 #define arm_access_memory_pc_preadjust_load() \
1088
1089 #define arm_access_memory_pc_preadjust_store() \
1090 u32 reg_op = reg[rd]; \
1091 if(rd == 15) \
1092 reg_op += 4 \
1093
1094 #define arm_access_memory_pc_postadjust_load() \
1095 arm_update_pc() \
1096
1097 #define arm_access_memory_pc_postadjust_store() \
1098
1099 #define load_reg_op reg[rd] \
1100
1101 #define store_reg_op reg_op \
1102
1103 #define arm_access_memory(access_type, off_op, off_type, mem_type, \
1104 wb, wb_off_op) \
1105 { \
1106 arm_pc_offset(8); \
1107 arm_data_trans_##off_type(); \
1108 u32 address = reg[rn] off_op; \
1109 arm_access_memory_pc_preadjust_##access_type(); \
1110 \
1111 arm_pc_offset(-4); \
1112 arm_access_memory_writeback_##wb(wb_off_op); \
1113 access_type##_memory_##mem_type(address, access_type##_reg_op); \
1114 arm_access_memory_pc_postadjust_##access_type(); \
1115 } \
1116
1117 #define word_bit_count(word) \
1118 (bit_count[word >> 8] + bit_count[word & 0xFF]) \
1119
1120 #define sprint_no(access_type, offset_type, writeback_type) \
1121
1122 #define sprint_yes(access_type, offset_type, writeback_type) \
1123 printf("sbit on %s %s %s\n", #access_type, #offset_type, #writeback_type) \
1124
1125 #define arm_block_writeback_load() \
1126 if(!((reg_list >> rn) & 0x01)) \
1127 { \
1128 reg[rn] = address; \
1129 } \
1130
1131 #define arm_block_writeback_store() \
1132 reg[rn] = address \
1133
1134 #define arm_block_writeback_yes(access_type) \
1135 arm_block_writeback_##access_type() \
1136
1137 #define arm_block_writeback_no(access_type) \
1138
1139 #define load_block_memory(address, dest) \
1140 dest = address32(address_region, (address + offset) & 0x7FFF) \
1141
1142 #define store_block_memory(address, dest) \
1143 address32(address_region, (address + offset) & 0x7FFF) = dest \
1144
1145 #define arm_block_memory_offset_down_a() \
1146 (base - (word_bit_count(reg_list) * 4) + 4) \
1147
1148 #define arm_block_memory_offset_down_b() \
1149 (base - (word_bit_count(reg_list) * 4)) \
1150
1151 #define arm_block_memory_offset_no() \
1152 (base) \
1153
1154 #define arm_block_memory_offset_up() \
1155 (base + 4) \
1156
1157 #define arm_block_memory_writeback_down() \
1158 reg[rn] = base - (word_bit_count(reg_list) * 4) \
1159
1160 #define arm_block_memory_writeback_up() \
1161 reg[rn] = base + (word_bit_count(reg_list) * 4) \
1162
1163 #define arm_block_memory_writeback_no() \
1164
1165 #define arm_block_memory_load_pc() \
1166 load_aligned32(address, pc); \
1167 reg[REG_PC] = pc \
1168
1169 #define arm_block_memory_store_pc() \
1170 store_aligned32(address, pc + 4) \
1171
1172 #define arm_block_memory(access_type, offset_type, writeback_type, s_bit) \
1173 { \
1174 arm_decode_block_trans(); \
1175 u32 base = reg[rn]; \
1176 u32 address = arm_block_memory_offset_##offset_type() & 0xFFFFFFFC; \
1177 u32 i; \
1178 \
1179 arm_block_memory_writeback_##writeback_type(); \
1180 \
1181 for(i = 0; i < 15; i++) \
1182 { \
1183 if((reg_list >> i) & 0x01) \
1184 { \
1185 access_type##_aligned32(address, reg[i]); \
1186 address += 4; \
1187 } \
1188 } \
1189 \
1190 arm_pc_offset(4); \
1191 if(reg_list & 0x8000) \
1192 { \
1193 arm_block_memory_##access_type##_pc(); \
1194 } \
1195 } \
1196
1197 #define arm_swap(type) \
1198 { \
1199 arm_decode_swap(); \
1200 u32 temp; \
1201 load_memory_##type(reg[rn], temp); \
1202 store_memory_##type(reg[rn], reg[rm]); \
1203 reg[rd] = temp; \
1204 arm_pc_offset(4); \
1205 } \
1206
1207 #define arm_next_instruction() \
1208 { \
1209 arm_pc_offset(4); \
1210 goto skip_instruction; \
1211 } \
1212
1213 #define thumb_update_pc() \
1214 pc = reg[REG_PC] \
1215
1216 #define thumb_pc_offset(val) \
1217 pc += val; \
1218 reg[REG_PC] = pc \
1219
1220 #define thumb_pc_offset_update(val) \
1221 pc += val; \
1222 reg[REG_PC] = pc \
1223
1224 #define thumb_pc_offset_update_direct(val) \
1225 pc = val; \
1226 reg[REG_PC] = pc \
1227
1228 // Types: add_sub, add_sub_imm, alu_op, imm
1229 // Affects N/Z/C/V flags
1230
1231 #define thumb_add(type, dest_reg, src_a, src_b) \
1232 { \
1233 thumb_decode_##type(); \
1234 const u32 _sa = src_a; \
1235 const u32 _sb = src_b; \
1236 u32 dest = _sa + _sb; \
1237 calculate_flags_add(dest, src_a, src_b); \
1238 reg[dest_reg] = dest; \
1239 thumb_pc_offset(2); \
1240 } \
1241
1242 #define thumb_add_noflags(type, dest_reg, src_a, src_b) \
1243 { \
1244 thumb_decode_##type(); \
1245 u32 dest = src_a + src_b; \
1246 reg[dest_reg] = dest; \
1247 thumb_pc_offset(2); \
1248 } \
1249
1250 #define thumb_sub(type, dest_reg, src_a, src_b) \
1251 { \
1252 thumb_decode_##type(); \
1253 const u32 _sa = src_a; \
1254 const u32 _sb = src_b; \
1255 u32 dest = _sa - _sb; \
1256 calculate_flags_sub(dest, src_a, src_b); \
1257 reg[dest_reg] = dest; \
1258 thumb_pc_offset(2); \
1259 } \
1260
1261 // Affects N/Z flags
1262
1263 #define thumb_logic(type, dest_reg, expr) \
1264 { \
1265 thumb_decode_##type(); \
1266 u32 dest = expr; \
1267 calculate_flags_logic(dest); \
1268 reg[dest_reg] = dest; \
1269 thumb_pc_offset(2); \
1270 } \
1271
1272 // Decode types: shift, alu_op
1273 // Operation types: lsl, lsr, asr, ror
1274 // Affects N/Z/C flags
1275
1276 #define thumb_shift_lsl_reg() \
1277 u32 shift = reg[rs]; \
1278 u32 dest = reg[rd]; \
1279 if(shift != 0) \
1280 { \
1281 if(shift > 31) \
1282 { \
1283 if(shift == 32) \
1284 c_flag = dest & 0x01; \
1285 else \
1286 c_flag = 0; \
1287 dest = 0; \
1288 } \
1289 else \
1290 { \
1291 c_flag = (dest >> (32 - shift)) & 0x01; \
1292 dest <<= shift; \
1293 } \
1294 } \
1295
1296 #define thumb_shift_lsr_reg() \
1297 u32 shift = reg[rs]; \
1298 u32 dest = reg[rd]; \
1299 if(shift != 0) \
1300 { \
1301 if(shift > 31) \
1302 { \
1303 if(shift == 32) \
1304 c_flag = dest >> 31; \
1305 else \
1306 c_flag = 0; \
1307 dest = 0; \
1308 } \
1309 else \
1310 { \
1311 c_flag = (dest >> (shift - 1)) & 0x01; \
1312 dest >>= shift; \
1313 } \
1314 } \
1315
1316 #define thumb_shift_asr_reg() \
1317 u32 shift = reg[rs]; \
1318 u32 dest = reg[rd]; \
1319 if(shift != 0) \
1320 { \
1321 if(shift > 31) \
1322 { \
1323 dest = (s32)dest >> 31; \
1324 c_flag = dest & 0x01; \
1325 } \
1326 else \
1327 { \
1328 c_flag = (dest >> (shift - 1)) & 0x01; \
1329 dest = (s32)dest >> shift; \
1330 } \
1331 } \
1332
1333 #define thumb_shift_ror_reg() \
1334 u32 shift = reg[rs]; \
1335 u32 dest = reg[rd]; \
1336 if(shift != 0) \
1337 { \
1338 c_flag = (dest >> (shift - 1)) & 0x01; \
1339 ror(dest, dest, shift); \
1340 } \
1341
1342 #define thumb_shift_lsl_imm() \
1343 u32 dest = reg[rs]; \
1344 if(imm != 0) \
1345 { \
1346 c_flag = (dest >> (32 - imm)) & 0x01; \
1347 dest <<= imm; \
1348 } \
1349
1350 #define thumb_shift_lsr_imm() \
1351 u32 dest; \
1352 if(imm == 0) \
1353 { \
1354 dest = 0; \
1355 c_flag = reg[rs] >> 31; \
1356 } \
1357 else \
1358 { \
1359 dest = reg[rs]; \
1360 c_flag = (dest >> (imm - 1)) & 0x01; \
1361 dest >>= imm; \
1362 } \
1363
1364 #define thumb_shift_asr_imm() \
1365 u32 dest; \
1366 if(imm == 0) \
1367 { \
1368 dest = (s32)reg[rs] >> 31; \
1369 c_flag = dest & 0x01; \
1370 } \
1371 else \
1372 { \
1373 dest = reg[rs]; \
1374 c_flag = (dest >> (imm - 1)) & 0x01; \
1375 dest = (s32)dest >> imm; \
1376 } \
1377
1378 #define thumb_shift_ror_imm() \
1379 u32 dest = reg[rs]; \
1380 if(imm == 0) \
1381 { \
1382 u32 old_c_flag = c_flag; \
1383 c_flag = dest & 0x01; \
1384 dest = (dest >> 1) | (old_c_flag << 31); \
1385 } \
1386 else \
1387 { \
1388 c_flag = (dest >> (imm - 1)) & 0x01; \
1389 ror(dest, dest, imm); \
1390 } \
1391
1392 #define thumb_shift(decode_type, op_type, value_type) \
1393 { \
1394 thumb_decode_##decode_type(); \
1395 thumb_shift_##op_type##_##value_type(); \
1396 calculate_flags_logic(dest); \
1397 reg[rd] = dest; \
1398 thumb_pc_offset(2); \
1399 } \
1400
1401 #define thumb_test_add(type, src_a, src_b) \
1402 { \
1403 thumb_decode_##type(); \
1404 const u32 _sa = src_a; \
1405 const u32 _sb = src_b; \
1406 u32 dest = _sa + _sb; \
1407 calculate_flags_add(dest, src_a, src_b); \
1408 thumb_pc_offset(2); \
1409 } \
1410
1411 #define thumb_test_sub(type, src_a, src_b) \
1412 { \
1413 thumb_decode_##type(); \
1414 const u32 _sa = src_a; \
1415 const u32 _sb = src_b; \
1416 u32 dest = _sa - _sb; \
1417 calculate_flags_sub(dest, src_a, src_b); \
1418 thumb_pc_offset(2); \
1419 } \
1420
1421 #define thumb_test_logic(type, expr) \
1422 { \
1423 thumb_decode_##type(); \
1424 u32 dest = expr; \
1425 calculate_flags_logic(dest); \
1426 thumb_pc_offset(2); \
1427 }
1428
1429 #define thumb_hireg_op(expr) \
1430 { \
1431 thumb_pc_offset(4); \
1432 thumb_decode_hireg_op(); \
1433 u32 dest = expr; \
1434 thumb_pc_offset(-2); \
1435 if(rd == 15) \
1436 { \
1437 reg[REG_PC] = dest & ~0x01; \
1438 thumb_update_pc(); \
1439 } \
1440 else \
1441 { \
1442 reg[rd] = dest; \
1443 } \
1444 } \
1445
1446 // Operation types: imm, mem_reg, mem_imm
1447
1448 #define thumb_access_memory(access_type, op_type, address, reg_op, \
1449 mem_type) \
1450 { \
1451 thumb_decode_##op_type(); \
1452 access_type##_memory_##mem_type(address, reg_op); \
1453 thumb_pc_offset(2); \
1454 } \
1455
1456 #define thumb_block_address_preadjust_no_op() \
1457
1458 #define thumb_block_address_preadjust_up() \
1459 address += bit_count[reg_list] * 4 \
1460
1461 #define thumb_block_address_preadjust_down() \
1462 address -= bit_count[reg_list] * 4 \
1463
1464 #define thumb_block_address_preadjust_push_lr() \
1465 address -= (bit_count[reg_list] + 1) * 4 \
1466
1467 #define thumb_block_address_postadjust_no_op() \
1468
1469 #define thumb_block_address_postadjust_up() \
1470 address += offset \
1471
1472 #define thumb_block_address_postadjust_down() \
1473 address -= offset \
1474
1475 #define thumb_block_address_postadjust_pop_pc() \
1476 load_memory_u32(address + offset, pc); \
1477 pc &= ~0x01; \
1478 reg[REG_PC] = pc; \
1479 address += offset + 4 \
1480
1481 #define thumb_block_address_postadjust_push_lr() \
1482 store_memory_u32(address + offset, reg[REG_LR]); \
1483
1484 #define thumb_block_memory_wb_load(base_reg) \
1485 if(!((reg_list >> base_reg) & 0x01)) \
1486 { \
1487 reg[base_reg] = address; \
1488 } \
1489
1490 #define thumb_block_memory_wb_store(base_reg) \
1491 reg[base_reg] = address \
1492
1493 #define thumb_block_memory(access_type, pre_op, post_op, base_reg) \
1494 { \
1495 u32 i; \
1496 u32 offset = 0; \
1497 thumb_decode_rlist(); \
1498 using_register(thumb, base_reg, memory_base); \
1499 u32 address = reg[base_reg] & ~0x03; \
1500 thumb_block_address_preadjust_##pre_op(); \
1501 \
1502 for(i = 0; i < 8; i++) \
1503 { \
1504 if((reg_list >> i) & 1) \
1505 { \
1506 access_type##_aligned32(address + offset, reg[i]); \
1507 offset += 4; \
1508 } \
1509 } \
1510 \
1511 thumb_pc_offset(2); \
1512 \
1513 thumb_block_address_postadjust_##post_op(); \
1514 thumb_block_memory_wb_##access_type(base_reg); \
1515 } \
1516
1517 #define thumb_conditional_branch(condition) \
1518 { \
1519 thumb_decode_branch_cond(); \
1520 if(condition) \
1521 { \
1522 thumb_pc_offset((offset * 2) + 4); \
1523 } \
1524 else \
1525 { \
1526 thumb_pc_offset(2); \
1527 } \
1528 } \
1529
1530 // When a mode change occurs from non-FIQ to non-FIQ retire the current
1531 // reg[13] and reg[14] into reg_mode[cpu_mode][5] and reg_mode[cpu_mode][6]
1532 // respectively and load into reg[13] and reg[14] reg_mode[new_mode][5] and
1533 // reg_mode[new_mode][6]. When swapping to/from FIQ retire/load reg[8]
1534 // through reg[14] to/from reg_mode[MODE_FIQ][0] through reg_mode[MODE_FIQ][6].
1535
1536 u32 reg_mode[7][7];
1537
1538 u32 cpu_modes[32] =
1539 {
1540 MODE_INVALID, MODE_INVALID, MODE_INVALID, MODE_INVALID, MODE_INVALID,
1541 MODE_INVALID, MODE_INVALID, MODE_INVALID, MODE_INVALID, MODE_INVALID,
1542 MODE_INVALID, MODE_INVALID, MODE_INVALID, MODE_INVALID, MODE_INVALID,
1543 MODE_INVALID, MODE_USER, MODE_FIQ, MODE_IRQ, MODE_SUPERVISOR, MODE_INVALID,
1544 MODE_INVALID, MODE_INVALID, MODE_ABORT, MODE_INVALID, MODE_INVALID,
1545 MODE_INVALID, MODE_INVALID, MODE_UNDEFINED, MODE_INVALID, MODE_INVALID,
1546 MODE_USER
1547 };
1548
1549 u32 cpu_modes_cpsr[7] = { 0x10, 0x11, 0x12, 0x13, 0x17, 0x1B, 0x1F };
1550
1551 // When switching modes set spsr[new_mode] to cpsr. Modifying PC as the
1552 // target of a data proc instruction will set cpsr to spsr[cpu_mode].
1553
1554 u32 initial_reg[64];
1555 u32 *reg = initial_reg;
1556 u32 spsr[6];
1557
1558 // ARM/Thumb mode is stored in the flags directly, this is simpler than
1559 // shadowing it since it has a constant 1bit represenation.
1560
1561 char *reg_names[16] =
1562 {
1563 " r0", " r1", " r2", " r3", " r4", " r5", " r6", " r7",
1564 " r8", " r9", "r10", " fp", " ip", " sp", " lr", " pc"
1565 };
1566
1567 char *cpu_mode_names[] =
1568 {
1569 "user", "irq", "fiq", "svsr", "abrt", "undf", "invd"
1570 };
1571
1572
1573 #define execute_arm_instruction() \
1574 using_instruction(arm); \
1575 check_pc_region(); \
1576 pc &= ~0x03; \
1577 opcode = address32(pc_address_block, (pc & 0x7FFF)); \
1578 condition = opcode >> 28; \
1579 \
1580 switch(condition) \
1581 { \
1582 case 0x0: \
1583 /* EQ */ \
1584 if(!z_flag) \
1585 arm_next_instruction(); \
1586 break; \
1587 \
1588 case 0x1: \
1589 /* NE */ \
1590 if(z_flag) \
1591 arm_next_instruction(); \
1592 break; \
1593 \
1594 case 0x2: \
1595 /* CS */ \
1596 if(!c_flag) \
1597 arm_next_instruction(); \
1598 break; \
1599 \
1600 case 0x3: \
1601 /* CC */ \
1602 if(c_flag) \
1603 arm_next_instruction(); \
1604 break; \
1605 \
1606 case 0x4: \
1607 /* MI */ \
1608 if(!n_flag) \
1609 arm_next_instruction(); \
1610 break; \
1611 \
1612 case 0x5: \
1613 /* PL */ \
1614 if(n_flag) \
1615 arm_next_instruction(); \
1616 break; \
1617 \
1618 case 0x6: \
1619 /* VS */ \
1620 if(!v_flag) \
1621 arm_next_instruction(); \
1622 break; \
1623 \
1624 case 0x7: \
1625 /* VC */ \
1626 if(v_flag) \
1627 arm_next_instruction(); \
1628 break; \
1629 \
1630 case 0x8: \
1631 /* HI */ \
1632 if((c_flag == 0) | z_flag) \
1633 arm_next_instruction(); \
1634 break; \
1635 \
1636 case 0x9: \
1637 /* LS */ \
1638 if(c_flag & (z_flag ^ 1)) \
1639 arm_next_instruction(); \
1640 break; \
1641 \
1642 case 0xA: \
1643 /* GE */ \
1644 if(n_flag != v_flag) \
1645 arm_next_instruction(); \
1646 break; \
1647 \
1648 case 0xB: \
1649 /* LT */ \
1650 if(n_flag == v_flag) \
1651 arm_next_instruction(); \
1652 break; \
1653 \
1654 case 0xC: \
1655 /* GT */ \
1656 if(z_flag | (n_flag != v_flag)) \
1657 arm_next_instruction(); \
1658 break; \
1659 \
1660 case 0xD: \
1661 /* LE */ \
1662 if((z_flag == 0) & (n_flag == v_flag)) \
1663 arm_next_instruction(); \
1664 break; \
1665 \
1666 case 0xE: \
1667 /* AL */ \
1668 break; \
1669 \
1670 case 0xF: \
1671 /* Reserved - treat as "never" */ \
1672 quit(); \
1673 arm_next_instruction(); \
1674 break; \
1675 } \
1676 \
1677 switch((opcode >> 20) & 0xFF) \
1678 { \
1679 case 0x00: \
1680 if((opcode & 0x90) == 0x90) \
1681 { \
1682 if(opcode & 0x20) \
1683 { \
1684 /* STRH rd, [rn], -rm */ \
1685 arm_access_memory(store, no_op, half_reg, u16, yes, - reg[rm]); \
1686 } \
1687 else \
1688 { \
1689 /* MUL rd, rm, rs */ \
1690 arm_multiply(no_op, no); \
1691 } \
1692 } \
1693 else \
1694 { \
1695 /* AND rd, rn, reg_op */ \
1696 arm_data_proc(reg[rn] & reg_sh, reg); \
1697 } \
1698 break; \
1699 \
1700 case 0x01: \
1701 if((opcode & 0x90) == 0x90) \
1702 { \
1703 switch((opcode >> 5) & 0x03) \
1704 { \
1705 case 0: \
1706 /* MULS rd, rm, rs */ \
1707 arm_multiply(no_op, yes); \
1708 break; \
1709 \
1710 case 1: \
1711 /* LDRH rd, [rn], -rm */ \
1712 arm_access_memory(load, no_op, half_reg, u16, yes, - reg[rm]); \
1713 break; \
1714 \
1715 case 2: \
1716 /* LDRSB rd, [rn], -rm */ \
1717 arm_access_memory(load, no_op, half_reg, s8, yes, - reg[rm]); \
1718 break; \
1719 \
1720 case 3: \
1721 /* LDRSH rd, [rn], -rm */ \
1722 arm_access_memory(load, no_op, half_reg, s16, yes, - reg[rm]); \
1723 break; \
1724 } \
1725 } \
1726 else \
1727 { \
1728 /* ANDS rd, rn, reg_op */ \
1729 arm_data_proc_logic_flags(reg[rn] & reg_sh, reg); \
1730 } \
1731 break; \
1732 \
1733 case 0x02: \
1734 if((opcode & 0x90) == 0x90) \
1735 { \
1736 if(opcode & 0x20) \
1737 { \
1738 /* STRH rd, [rn], -rm */ \
1739 arm_access_memory(store, no_op, half_reg, u16, yes, - reg[rm]); \
1740 } \
1741 else \
1742 { \
1743 /* MLA rd, rm, rs, rn */ \
1744 arm_multiply(+ reg[rn], no); \
1745 } \
1746 } \
1747 else \
1748 { \
1749 /* EOR rd, rn, reg_op */ \
1750 arm_data_proc(reg[rn] ^ reg_sh, reg); \
1751 } \
1752 break; \
1753 \
1754 case 0x03: \
1755 if((opcode & 0x90) == 0x90) \
1756 { \
1757 switch((opcode >> 5) & 0x03) \
1758 { \
1759 case 0: \
1760 /* MLAS rd, rm, rs, rn */ \
1761 arm_multiply(+ reg[rn], yes); \
1762 break; \
1763 \
1764 case 1: \
1765 /* LDRH rd, [rn], -rm */ \
1766 arm_access_memory(load, no_op, half_reg, u16, yes, - reg[rm]); \
1767 break; \
1768 \
1769 case 2: \
1770 /* LDRSB rd, [rn], -rm */ \
1771 arm_access_memory(load, no_op, half_reg, s8, yes, - reg[rm]); \
1772 break; \
1773 \
1774 case 3: \
1775 /* LDRSH rd, [rn], -rm */ \
1776 arm_access_memory(load, no_op, half_reg, s16, yes, - reg[rm]); \
1777 break; \
1778 } \
1779 } \
1780 else \
1781 { \
1782 /* EORS rd, rn, reg_op */ \
1783 arm_data_proc_logic_flags(reg[rn] ^ reg_sh, reg); \
1784 } \
1785 break; \
1786 \
1787 case 0x04: \
1788 if((opcode & 0x90) == 0x90) \
1789 { \
1790 /* STRH rd, [rn], -imm */ \
1791 arm_access_memory(store, no_op, half_imm, u16, yes, - offset); \
1792 } \
1793 else \
1794 { \
1795 /* SUB rd, rn, reg_op */ \
1796 arm_data_proc(reg[rn] - reg_sh, reg); \
1797 } \
1798 break; \
1799 \
1800 case 0x05: \
1801 if((opcode & 0x90) == 0x90) \
1802 { \
1803 switch((opcode >> 5) & 0x03) \
1804 { \
1805 case 1: \
1806 /* LDRH rd, [rn], -imm */ \
1807 arm_access_memory(load, no_op, half_imm, u16, yes, - offset); \
1808 break; \
1809 \
1810 case 2: \
1811 /* LDRSB rd, [rn], -imm */ \
1812 arm_access_memory(load, no_op, half_imm, s8, yes, - offset); \
1813 break; \
1814 \
1815 case 3: \
1816 /* LDRSH rd, [rn], -imm */ \
1817 arm_access_memory(load, no_op, half_imm, s16, yes, - offset); \
1818 break; \
1819 } \
1820 } \
1821 else \
1822 { \
1823 /* SUBS rd, rn, reg_op */ \
1824 arm_data_proc_sub_flags(reg[rn], reg_sh, reg); \
1825 } \
1826 break; \
1827 \
1828 case 0x06: \
1829 if((opcode & 0x90) == 0x90) \
1830 { \
1831 /* STRH rd, [rn], -imm */ \
1832 arm_access_memory(store, no_op, half_imm, u16, yes, - offset); \
1833 } \
1834 else \
1835 { \
1836 /* RSB rd, rn, reg_op */ \
1837 arm_data_proc(reg_sh - reg[rn], reg); \
1838 } \
1839 break; \
1840 \
1841 case 0x07: \
1842 if((opcode & 0x90) == 0x90) \
1843 { \
1844 switch((opcode >> 5) & 0x03) \
1845 { \
1846 case 1: \
1847 /* LDRH rd, [rn], -imm */ \
1848 arm_access_memory(load, no_op, half_imm, u16, yes, - offset); \
1849 break; \
1850 \
1851 case 2: \
1852 /* LDRSB rd, [rn], -imm */ \
1853 arm_access_memory(load, no_op, half_imm, s8, yes, - offset); \
1854 break; \
1855 \
1856 case 3: \
1857 /* LDRSH rd, [rn], -imm */ \
1858 arm_access_memory(load, no_op, half_imm, s16, yes, - offset); \
1859 break; \
1860 } \
1861 } \
1862 else \
1863 { \
1864 /* RSBS rd, rn, reg_op */ \
1865 arm_data_proc_sub_flags(reg_sh, reg[rn], reg); \
1866 } \
1867 break; \
1868 \
1869 case 0x08: \
1870 if((opcode & 0x90) == 0x90) \
1871 { \
1872 if(opcode & 0x20) \
1873 { \
1874 /* STRH rd, [rn], +rm */ \
1875 arm_access_memory(store, no_op, half_reg, u16, yes, + reg[rm]); \
1876 } \
1877 else \
1878 { \
1879 /* UMULL rd, rm, rs */ \
1880 arm_multiply_long(no_op, no, u); \
1881 } \
1882 } \
1883 else \
1884 { \
1885 /* ADD rd, rn, reg_op */ \
1886 arm_data_proc(reg[rn] + reg_sh, reg); \
1887 } \
1888 break; \
1889 \
1890 case 0x09: \
1891 if((opcode & 0x90) == 0x90) \
1892 { \
1893 switch((opcode >> 5) & 0x03) \
1894 { \
1895 case 0: \
1896 /* UMULLS rdlo, rdhi, rm, rs */ \
1897 arm_multiply_long(no_op, yes, u); \
1898 break; \
1899 \
1900 case 1: \
1901 /* LDRH rd, [rn], +rm */ \
1902 arm_access_memory(load, no_op, half_reg, u16, yes, + reg[rm]); \
1903 break; \
1904 \
1905 case 2: \
1906 /* LDRSB rd, [rn], +rm */ \
1907 arm_access_memory(load, no_op, half_reg, s8, yes, + reg[rm]); \
1908 break; \
1909 \
1910 case 3: \
1911 /* LDRSH rd, [rn], +rm */ \
1912 arm_access_memory(load, no_op, half_reg, s16, yes, + reg[rm]); \
1913 break; \
1914 } \
1915 } \
1916 else \
1917 { \
1918 /* ADDS rd, rn, reg_op */ \
1919 arm_data_proc_add_flags(reg[rn], reg_sh, reg); \
1920 } \
1921 break; \
1922 \
1923 case 0x0A: \
1924 if((opcode & 0x90) == 0x90) \
1925 { \
1926 if(opcode & 0x20) \
1927 { \
1928 /* STRH rd, [rn], +rm */ \
1929 arm_access_memory(store, no_op, half_reg, u16, yes, + reg[rm]); \
1930 } \
1931 else \
1932 { \
1933 /* UMLAL rd, rm, rs */ \
1934 arm_multiply_long(arm_multiply_long_addop(u), no, u); \
1935 } \
1936 } \
1937 else \
1938 { \
1939 /* ADC rd, rn, reg_op */ \
1940 arm_data_proc(reg[rn] + reg_sh + c_flag, reg); \
1941 } \
1942 break; \
1943 \
1944 case 0x0B: \
1945 if((opcode & 0x90) == 0x90) \
1946 { \
1947 switch((opcode >> 5) & 0x03) \
1948 { \
1949 case 0: \
1950 /* UMLALS rdlo, rdhi, rm, rs */ \
1951 arm_multiply_long(arm_multiply_long_addop(u), yes, u); \
1952 break; \
1953 \
1954 case 1: \
1955 /* LDRH rd, [rn], +rm */ \
1956 arm_access_memory(load, no_op, half_reg, u16, yes, + reg[rm]); \
1957 break; \
1958 \
1959 case 2: \
1960 /* LDRSB rd, [rn], +rm */ \
1961 arm_access_memory(load, no_op, half_reg, s8, yes, + reg[rm]); \
1962 break; \
1963 \
1964 case 3: \
1965 /* LDRSH rd, [rn], +rm */ \
1966 arm_access_memory(load, no_op, half_reg, s16, yes, + reg[rm]); \
1967 break; \
1968 } \
1969 } \
1970 else \
1971 { \
1972 /* ADCS rd, rn, reg_op */ \
1973 arm_data_proc_add_flags(reg[rn], reg_sh + c_flag, reg); \
1974 } \
1975 break; \
1976 \
1977 case 0x0C: \
1978 if((opcode & 0x90) == 0x90) \
1979 { \
1980 if(opcode & 0x20) \
1981 { \
1982 /* STRH rd, [rn], +imm */ \
1983 arm_access_memory(store, no_op, half_imm, u16, yes, + offset); \
1984 } \
1985 else \
1986 { \
1987 /* SMULL rd, rm, rs */ \
1988 arm_multiply_long(no_op, no, s); \
1989 } \
1990 } \
1991 else \
1992 { \
1993 /* SBC rd, rn, reg_op */ \
1994 arm_data_proc(reg[rn] - (reg_sh + (c_flag ^ 1)), reg); \
1995 } \
1996 break; \
1997 \
1998 case 0x0D: \
1999 if((opcode & 0x90) == 0x90) \
2000 { \
2001 switch((opcode >> 5) & 0x03) \
2002 { \
2003 case 0: \
2004 /* SMULLS rdlo, rdhi, rm, rs */ \
2005 arm_multiply_long(no_op, yes, s); \
2006 break; \
2007 \
2008 case 1: \
2009 /* LDRH rd, [rn], +imm */ \
2010 arm_access_memory(load, no_op, half_imm, u16, yes, + offset); \
2011 break; \
2012 \
2013 case 2: \
2014 /* LDRSB rd, [rn], +imm */ \
2015 arm_access_memory(load, no_op, half_imm, s8, yes, + offset); \
2016 break; \
2017 \
2018 case 3: \
2019 /* LDRSH rd, [rn], +imm */ \
2020 arm_access_memory(load, no_op, half_imm, s16, yes, + offset); \
2021 break; \
2022 } \
2023 } \
2024 else \
2025 { \
2026 /* SBCS rd, rn, reg_op */ \
2027 arm_data_proc_sub_flags(reg[rn], (reg_sh + (c_flag ^ 1)), reg); \
2028 } \
2029 break; \
2030 \
2031 case 0x0E: \
2032 if((opcode & 0x90) == 0x90) \
2033 { \
2034 if(opcode & 0x20) \
2035 { \
2036 /* STRH rd, [rn], +imm */ \
2037 arm_access_memory(store, no_op, half_imm, u16, yes, + offset); \
2038 } \
2039 else \
2040 { \
2041 /* SMLAL rd, rm, rs */ \
2042 arm_multiply_long(arm_multiply_long_addop(s), no, s); \
2043 } \
2044 } \
2045 else \
2046 { \
2047 /* RSC rd, rn, reg_op */ \
2048 arm_data_proc(reg_sh - reg[rn] + c_flag - 1, reg); \
2049 } \
2050 break; \
2051 \
2052 case 0x0F: \
2053 if((opcode & 0x90) == 0x90) \
2054 { \
2055 switch((opcode >> 5) & 0x03) \
2056 { \
2057 case 0: \
2058 /* SMLALS rdlo, rdhi, rm, rs */ \
2059 arm_multiply_long(arm_multiply_long_addop(s), yes, s); \
2060 break; \
2061 \
2062 case 1: \
2063 /* LDRH rd, [rn], +imm */ \
2064 arm_access_memory(load, no_op, half_imm, u16, yes, + offset); \
2065 break; \
2066 \
2067 case 2: \
2068 /* LDRSB rd, [rn], +imm */ \
2069 arm_access_memory(load, no_op, half_imm, s8, yes, + offset); \
2070 break; \
2071 \
2072 case 3: \
2073 /* LDRSH rd, [rn], +imm */ \
2074 arm_access_memory(load, no_op, half_imm, s16, yes, + offset); \
2075 break; \
2076 } \
2077 } \
2078 else \
2079 { \
2080 /* RSCS rd, rn, reg_op */ \
2081 arm_data_proc_sub_flags((reg_sh + c_flag - 1), reg[rn], reg); \
2082 } \
2083 break; \
2084 \
2085 case 0x10: \
2086 if((opcode & 0x90) == 0x90) \
2087 { \
2088 if(opcode & 0x20) \
2089 { \
2090 /* STRH rd, [rn - rm] */ \
2091 arm_access_memory(store, - reg[rm], half_reg, u16, no, no_op); \
2092 } \
2093 else \
2094 { \
2095 /* SWP rd, rm, [rn] */ \
2096 arm_swap(u32); \
2097 } \
2098 } \
2099 else \
2100 { \
2101 /* MRS rd, cpsr */ \
2102 arm_psr(reg, read, reg[REG_CPSR]); \
2103 } \
2104 break; \
2105 \
2106 case 0x11: \
2107 if((opcode & 0x90) == 0x90) \
2108 { \
2109 switch((opcode >> 5) & 0x03) \
2110 { \
2111 case 1: \
2112 /* LDRH rd, [rn - rm] */ \
2113 arm_access_memory(load, - reg[rm], half_reg, u16, no, no_op); \
2114 break; \
2115 \
2116 case 2: \
2117 /* LDRSB rd, [rn - rm] */ \
2118 arm_access_memory(load, - reg[rm], half_reg, s8, no, no_op); \
2119 break; \
2120 \
2121 case 3: \
2122 /* LDRSH rd, [rn - rm] */ \
2123 arm_access_memory(load, - reg[rm], half_reg, s16, no, no_op); \
2124 break; \
2125 } \
2126 } \
2127 else \
2128 { \
2129 /* TST rd, rn, reg_op */ \
2130 arm_data_proc_test_logic(reg[rn] & reg_sh, reg); \
2131 } \
2132 break; \
2133 \
2134 case 0x12: \
2135 if((opcode & 0x90) == 0x90) \
2136 { \
2137 /* STRH rd, [rn - rm]! */ \
2138 arm_access_memory(store, - reg[rm], half_reg, u16, yes, no_op); \
2139 } \
2140 else \
2141 { \
2142 if(opcode & 0x10) \
2143 { \
2144 /* BX rn */ \
2145 arm_decode_branchx(); \
2146 u32 src = reg[rn]; \
2147 if(src & 0x01) \
2148 { \
2149 src -= 1; \
2150 arm_pc_offset_update_direct(src); \
2151 reg[REG_CPSR] |= 0x20; \
2152 goto thumb_loop; \
2153 } \
2154 else \
2155 { \
2156 arm_pc_offset_update_direct(src); \
2157 } \
2158 } \
2159 else \
2160 { \
2161 /* MSR cpsr, rm */ \
2162 arm_psr(reg, store, cpsr); \
2163 } \
2164 } \
2165 break; \
2166 \
2167 case 0x13: \
2168 if((opcode & 0x90) == 0x90) \
2169 { \
2170 switch((opcode >> 5) & 0x03) \
2171 { \
2172 case 1: \
2173 /* LDRH rd, [rn - rm]! */ \
2174 arm_access_memory(load, - reg[rm], half_reg, u16, yes, no_op); \
2175 break; \
2176 \
2177 case 2: \
2178 /* LDRSB rd, [rn - rm]! */ \
2179 arm_access_memory(load, - reg[rm], half_reg, s8, yes, no_op); \
2180 break; \
2181 \
2182 case 3: \
2183 /* LDRSH rd, [rn - rm]! */ \
2184 arm_access_memory(load, - reg[rm], half_reg, s16, yes, no_op); \
2185 break; \
2186 } \
2187 } \
2188 else \
2189 { \
2190 /* TEQ rd, rn, reg_op */ \
2191 arm_data_proc_test_logic(reg[rn] ^ reg_sh, reg); \
2192 } \
2193 break; \
2194 \
2195 case 0x14: \
2196 if((opcode & 0x90) == 0x90) \
2197 { \
2198 if(opcode & 0x20) \
2199 { \
2200 /* STRH rd, [rn - imm] */ \
2201 arm_access_memory(store, - offset, half_imm, u16, no, no_op); \
2202 } \
2203 else \
2204 { \
2205 /* SWPB rd, rm, [rn] */ \
2206 arm_swap(u8); \
2207 } \
2208 } \
2209 else \
2210 { \
2211 /* MRS rd, spsr */ \
2212 arm_psr(reg, read, spsr[reg[CPU_MODE]]); \
2213 } \
2214 break; \
2215 \
2216 case 0x15: \
2217 if((opcode & 0x90) == 0x90) \
2218 { \
2219 switch((opcode >> 5) & 0x03) \
2220 { \
2221 case 1: \
2222 /* LDRH rd, [rn - imm] */ \
2223 arm_access_memory(load, - offset, half_imm, u16, no, no_op); \
2224 break; \
2225 \
2226 case 2: \
2227 /* LDRSB rd, [rn - imm] */ \
2228 arm_access_memory(load, - offset, half_imm, s8, no, no_op); \
2229 break; \
2230 \
2231 case 3: \
2232 /* LDRSH rd, [rn - imm] */ \
2233 arm_access_memory(load, - offset, half_imm, s16, no, no_op); \
2234 break; \
2235 } \
2236 } \
2237 else \
2238 { \
2239 /* CMP rn, reg_op */ \
2240 arm_data_proc_test_sub(reg[rn], reg_sh, reg); \
2241 } \
2242 break; \
2243 \
2244 case 0x16: \
2245 if((opcode & 0x90) == 0x90) \
2246 { \
2247 /* STRH rd, [rn - imm]! */ \
2248 arm_access_memory(store, - offset, half_imm, u16, yes, no_op); \
2249 } \
2250 else \
2251 { \
2252 /* MSR spsr, rm */ \
2253 arm_psr(reg, store, spsr); \
2254 } \
2255 break; \
2256 \
2257 case 0x17: \
2258 if((opcode & 0x90) == 0x90) \
2259 { \
2260 switch((opcode >> 5) & 0x03) \
2261 { \
2262 case 1: \
2263 /* LDRH rd, [rn - imm]! */ \
2264 arm_access_memory(load, - offset, half_imm, u16, yes, no_op); \
2265 break; \
2266 \
2267 case 2: \
2268 /* LDRSB rd, [rn - imm]! */ \
2269 arm_access_memory(load, - offset, half_imm, s8, yes, no_op); \
2270 break; \
2271 \
2272 case 3: \
2273 /* LDRSH rd, [rn - imm]! */ \
2274 arm_access_memory(load, - offset, half_imm, s16, yes, no_op); \
2275 break; \
2276 } \
2277 } \
2278 else \
2279 { \
2280 /* CMN rd, rn, reg_op */ \
2281 arm_data_proc_test_add(reg[rn], reg_sh, reg); \
2282 } \
2283 break; \
2284 \
2285 case 0x18: \
2286 if((opcode & 0x90) == 0x90) \
2287 { \
2288 /* STRH rd, [rn + rm] */ \
2289 arm_access_memory(store, + reg[rm], half_reg, u16, no, no_op); \
2290 } \
2291 else \
2292 { \
2293 /* ORR rd, rn, reg_op */ \
2294 arm_data_proc(reg[rn] | reg_sh, reg); \
2295 } \
2296 break; \
2297 \
2298 case 0x19: \
2299 if((opcode & 0x90) == 0x90) \
2300 { \
2301 switch((opcode >> 5) & 0x03) \
2302 { \
2303 case 1: \
2304 /* LDRH rd, [rn + rm] */ \
2305 arm_access_memory(load, + reg[rm], half_reg, u16, no, no_op); \
2306 break; \
2307 \
2308 case 2: \
2309 /* LDRSB rd, [rn + rm] */ \
2310 arm_access_memory(load, + reg[rm], half_reg, s8, no, no_op); \
2311 break; \
2312 \
2313 case 3: \
2314 /* LDRSH rd, [rn + rm] */ \
2315 arm_access_memory(load, + reg[rm], half_reg, s16, no, no_op); \
2316 break; \
2317 } \
2318 } \
2319 else \
2320 { \
2321 /* ORRS rd, rn, reg_op */ \
2322 arm_data_proc_logic_flags(reg[rn] | reg_sh, reg); \
2323 } \
2324 break; \
2325 \
2326 case 0x1A: \
2327 if((opcode & 0x90) == 0x90) \
2328 { \
2329 /* STRH rd, [rn + rm]! */ \
2330 arm_access_memory(store, + reg[rm], half_reg, u16, yes, no_op); \
2331 } \
2332 else \
2333 { \
2334 /* MOV rd, reg_op */ \
2335 arm_data_proc(reg_sh, reg); \
2336 } \
2337 break; \
2338 \
2339 case 0x1B: \
2340 if((opcode & 0x90) == 0x90) \
2341 { \
2342 switch((opcode >> 5) & 0x03) \
2343 { \
2344 case 1: \
2345 /* LDRH rd, [rn + rm]! */ \
2346 arm_access_memory(load, + reg[rm], half_reg, u16, yes, no_op); \
2347 break; \
2348 \
2349 case 2: \
2350 /* LDRSB rd, [rn + rm]! */ \
2351 arm_access_memory(load, + reg[rm], half_reg, s8, yes, no_op); \
2352 break; \
2353 \
2354 case 3: \
2355 /* LDRSH rd, [rn + rm]! */ \
2356 arm_access_memory(load, + reg[rm], half_reg, s16, yes, no_op); \
2357 break; \
2358 } \
2359 } \
2360 else \
2361 { \
2362 /* MOVS rd, reg_op */ \
2363 arm_data_proc_logic_flags(reg_sh, reg); \
2364 } \
2365 break; \
2366 \
2367 case 0x1C: \
2368 if((opcode & 0x90) == 0x90) \
2369 { \
2370 /* STRH rd, [rn + imm] */ \
2371 arm_access_memory(store, + offset, half_imm, u16, no, no_op); \
2372 } \
2373 else \
2374 { \
2375 /* BIC rd, rn, reg_op */ \
2376 arm_data_proc(reg[rn] & (~reg_sh), reg); \
2377 } \
2378 break; \
2379 \
2380 case 0x1D: \
2381 if((opcode & 0x90) == 0x90) \
2382 { \
2383 switch((opcode >> 5) & 0x03) \
2384 { \
2385 case 1: \
2386 /* LDRH rd, [rn + imm] */ \
2387 arm_access_memory(load, + offset, half_imm, u16, no, no_op); \
2388 break; \
2389 \
2390 case 2: \
2391 /* LDRSB rd, [rn + imm] */ \
2392 arm_access_memory(load, + offset, half_imm, s8, no, no_op); \
2393 break; \
2394 \
2395 case 3: \
2396 /* LDRSH rd, [rn + imm] */ \
2397 arm_access_memory(load, + offset, half_imm, s16, no, no_op); \
2398 break; \
2399 } \
2400 } \
2401 else \
2402 { \
2403 /* BICS rd, rn, reg_op */ \
2404 arm_data_proc_logic_flags(reg[rn] & (~reg_sh), reg); \
2405 } \
2406 break; \
2407 \
2408 case 0x1E: \
2409 if((opcode & 0x90) == 0x90) \
2410 { \
2411 /* STRH rd, [rn + imm]! */ \
2412 arm_access_memory(store, + offset, half_imm, u16, yes, no_op); \
2413 } \
2414 else \
2415 { \
2416 /* MVN rd, reg_op */ \
2417 arm_data_proc(~reg_sh, reg); \
2418 } \
2419 break; \
2420 \
2421 case 0x1F: \
2422 if((opcode & 0x90) == 0x90) \
2423 { \
2424 switch((opcode >> 5) & 0x03) \
2425 { \
2426 case 1: \
2427 /* LDRH rd, [rn + imm]! */ \
2428 arm_access_memory(load, + offset, half_imm, u16, yes, no_op); \
2429 break; \
2430 \
2431 case 2: \
2432 /* LDRSB rd, [rn + imm]! */ \
2433 arm_access_memory(load, + offset, half_imm, s8, yes, no_op); \
2434 break; \
2435 \
2436 case 3: \
2437 /* LDRSH rd, [rn + imm]! */ \
2438 arm_access_memory(load, + offset, half_imm, s16, yes, no_op); \
2439 break; \
2440 } \
2441 } \
2442 else \
2443 { \
2444 /* MVNS rd, rn, reg_op */ \
2445 arm_data_proc_logic_flags(~reg_sh, reg); \
2446 } \
2447 break; \
2448 \
2449 case 0x20: \
2450 /* AND rd, rn, imm */ \
2451 arm_data_proc(reg[rn] & imm, imm); \
2452 break; \
2453 \
2454 case 0x21: \
2455 /* ANDS rd, rn, imm */ \
2456 arm_data_proc_logic_flags(reg[rn] & imm, imm); \
2457 break; \
2458 \
2459 case 0x22: \
2460 /* EOR rd, rn, imm */ \
2461 arm_data_proc(reg[rn] ^ imm, imm); \
2462 break; \
2463 \
2464 case 0x23: \
2465 /* EORS rd, rn, imm */ \
2466 arm_data_proc_logic_flags(reg[rn] ^ imm, imm); \
2467 break; \
2468 \
2469 case 0x24: \
2470 /* SUB rd, rn, imm */ \
2471 arm_data_proc(reg[rn] - imm, imm); \
2472 break; \
2473 \
2474 case 0x25: \
2475 /* SUBS rd, rn, imm */ \
2476 arm_data_proc_sub_flags(reg[rn], imm, imm); \
2477 break; \
2478 \
2479 case 0x26: \
2480 /* RSB rd, rn, imm */ \
2481 arm_data_proc(imm - reg[rn], imm); \
2482 break; \
2483 \
2484 case 0x27: \
2485 /* RSBS rd, rn, imm */ \
2486 arm_data_proc_sub_flags(imm, reg[rn], imm); \
2487 break; \
2488 \
2489 case 0x28: \
2490 /* ADD rd, rn, imm */ \
2491 arm_data_proc(reg[rn] + imm, imm); \
2492 break; \
2493 \
2494 case 0x29: \
2495 /* ADDS rd, rn, imm */ \
2496 arm_data_proc_add_flags(reg[rn], imm, imm); \
2497 break; \
2498 \
2499 case 0x2A: \
2500 /* ADC rd, rn, imm */ \
2501 arm_data_proc(reg[rn] + imm + c_flag, imm); \
2502 break; \
2503 \
2504 case 0x2B: \
2505 /* ADCS rd, rn, imm */ \
2506 arm_data_proc_add_flags(reg[rn] + imm, c_flag, imm); \
2507 break; \
2508 \
2509 case 0x2C: \
2510 /* SBC rd, rn, imm */ \
2511 arm_data_proc(reg[rn] - imm + c_flag - 1, imm); \
2512 break; \
2513 \
2514 case 0x2D: \
2515 /* SBCS rd, rn, imm */ \
2516 arm_data_proc_sub_flags(reg[rn], (imm + (c_flag ^ 1)), imm); \
2517 break; \
2518 \
2519 case 0x2E: \
2520 /* RSC rd, rn, imm */ \
2521 arm_data_proc(imm - reg[rn] + c_flag - 1, imm); \
2522 break; \
2523 \
2524 case 0x2F: \
2525 /* RSCS rd, rn, imm */ \
2526 arm_data_proc_sub_flags((imm + c_flag - 1), reg[rn], imm); \
2527 break; \
2528 \
2529 case 0x30 ... 0x31: \
2530 /* TST rn, imm */ \
2531 arm_data_proc_test_logic(reg[rn] & imm, imm); \
2532 break; \
2533 \
2534 case 0x32: \
2535 /* MSR cpsr, imm */ \
2536 arm_psr(imm, store, cpsr); \
2537 break; \
2538 \
2539 case 0x33: \
2540 /* TEQ rn, imm */ \
2541 arm_data_proc_test_logic(reg[rn] ^ imm, imm); \
2542 break; \
2543 \
2544 case 0x34 ... 0x35: \
2545 /* CMP rn, imm */ \
2546 arm_data_proc_test_sub(reg[rn], imm, imm); \
2547 break; \
2548 \
2549 case 0x36: \
2550 /* MSR spsr, imm */ \
2551 arm_psr(imm, store, spsr); \
2552 break; \
2553 \
2554 case 0x37: \
2555 /* CMN rn, imm */ \
2556 arm_data_proc_test_add(reg[rn], imm, imm); \
2557 break; \
2558 \
2559 case 0x38: \
2560 /* ORR rd, rn, imm */ \
2561 arm_data_proc(reg[rn] | imm, imm); \
2562 break; \
2563 \
2564 case 0x39: \
2565 /* ORRS rd, rn, imm */ \
2566 arm_data_proc_logic_flags(reg[rn] | imm, imm); \
2567 break; \
2568 \
2569 case 0x3A: \
2570 /* MOV rd, imm */ \
2571 arm_data_proc(imm, imm); \
2572 break; \
2573 \
2574 case 0x3B: \
2575 /* MOVS rd, imm */ \
2576 arm_data_proc_logic_flags(imm, imm); \
2577 break; \
2578 \
2579 case 0x3C: \
2580 /* BIC rd, rn, imm */ \
2581 arm_data_proc(reg[rn] & (~imm), imm); \
2582 break; \
2583 \
2584 case 0x3D: \
2585 /* BICS rd, rn, imm */ \
2586 arm_data_proc_logic_flags(reg[rn] & (~imm), imm); \
2587 break; \
2588 \
2589 case 0x3E: \
2590 /* MVN rd, imm */ \
2591 arm_data_proc(~imm, imm); \
2592 break; \
2593 \
2594 case 0x3F: \
2595 /* MVNS rd, imm */ \
2596 arm_data_proc_logic_flags(~imm, imm); \
2597 break; \
2598 \
2599 case 0x40: \
2600 /* STR rd, [rn], -imm */ \
2601 arm_access_memory(store, no_op, imm, u32, yes, - offset); \
2602 break; \
2603 \
2604 case 0x41: \
2605 /* LDR rd, [rn], -imm */ \
2606 arm_access_memory(load, no_op, imm, u32, yes, - offset); \
2607 break; \
2608 \
2609 case 0x42: \
2610 /* STRT rd, [rn], -imm */ \
2611 arm_access_memory(store, no_op, imm, u32, yes, - offset); \
2612 break; \
2613 \
2614 case 0x43: \
2615 /* LDRT rd, [rn], -imm */ \
2616 arm_access_memory(load, no_op, imm, u32, yes, - offset); \
2617 break; \
2618 \
2619 case 0x44: \
2620 /* STRB rd, [rn], -imm */ \
2621 arm_access_memory(store, no_op, imm, u8, yes, - offset); \
2622 break; \
2623 \
2624 case 0x45: \
2625 /* LDRB rd, [rn], -imm */ \
2626 arm_access_memory(load, no_op, imm, u8, yes, - offset); \
2627 break; \
2628 \
2629 case 0x46: \
2630 /* STRBT rd, [rn], -imm */ \
2631 arm_access_memory(store, no_op, imm, u8, yes, - offset); \
2632 break; \
2633 \
2634 case 0x47: \
2635 /* LDRBT rd, [rn], -imm */ \
2636 arm_access_memory(load, no_op, imm, u8, yes, - offset); \
2637 break; \
2638 \
2639 case 0x48: \
2640 /* STR rd, [rn], +imm */ \
2641 arm_access_memory(store, no_op, imm, u32, yes, + offset); \
2642 break; \
2643 \
2644 case 0x49: \
2645 /* LDR rd, [rn], +imm */ \
2646 arm_access_memory(load, no_op, imm, u32, yes, + offset); \
2647 break; \
2648 \
2649 case 0x4A: \
2650 /* STRT rd, [rn], +imm */ \
2651 arm_access_memory(store, no_op, imm, u32, yes, + offset); \
2652 break; \
2653 \
2654 case 0x4B: \
2655 /* LDRT rd, [rn], +imm */ \
2656 arm_access_memory(load, no_op, imm, u32, yes, + offset); \
2657 break; \
2658 \
2659 case 0x4C: \
2660 /* STRB rd, [rn], +imm */ \
2661 arm_access_memory(store, no_op, imm, u8, yes, + offset); \
2662 break; \
2663 \
2664 case 0x4D: \
2665 /* LDRB rd, [rn], +imm */ \
2666 arm_access_memory(load, no_op, imm, u8, yes, + offset); \
2667 break; \
2668 \
2669 case 0x4E: \
2670 /* STRBT rd, [rn], +imm */ \
2671 arm_access_memory(store, no_op, imm, u8, yes, + offset); \
2672 break; \
2673 \
2674 case 0x4F: \
2675 /* LDRBT rd, [rn], +imm */ \
2676 arm_access_memory(load, no_op, imm, u8, yes, + offset); \
2677 break; \
2678 \
2679 case 0x50: \
2680 /* STR rd, [rn - imm] */ \
2681 arm_access_memory(store, - offset, imm, u32, no, no_op); \
2682 break; \
2683 \
2684 case 0x51: \
2685 /* LDR rd, [rn - imm] */ \
2686 arm_access_memory(load, - offset, imm, u32, no, no_op); \
2687 break; \
2688 \
2689 case 0x52: \
2690 /* STR rd, [rn - imm]! */ \
2691 arm_access_memory(store, - offset, imm, u32, yes, no_op); \
2692 break; \
2693 \
2694 case 0x53: \
2695 /* LDR rd, [rn - imm]! */ \
2696 arm_access_memory(load, - offset, imm, u32, yes, no_op); \
2697 break; \
2698 \
2699 case 0x54: \
2700 /* STRB rd, [rn - imm] */ \
2701 arm_access_memory(store, - offset, imm, u8, no, no_op); \
2702 break; \
2703 \
2704 case 0x55: \
2705 /* LDRB rd, [rn - imm] */ \
2706 arm_access_memory(load, - offset, imm, u8, no, no_op); \
2707 break; \
2708 \
2709 case 0x56: \
2710 /* STRB rd, [rn - imm]! */ \
2711 arm_access_memory(store, - offset, imm, u8, yes, no_op); \
2712 break; \
2713 \
2714 case 0x57: \
2715 /* LDRB rd, [rn - imm]! */ \
2716 arm_access_memory(load, - offset, imm, u8, yes, no_op); \
2717 break; \
2718 \
2719 case 0x58: \
2720 /* STR rd, [rn + imm] */ \
2721 arm_access_memory(store, + offset, imm, u32, no, no_op); \
2722 break; \
2723 \
2724 case 0x59: \
2725 /* LDR rd, [rn + imm] */ \
2726 arm_access_memory(load, + offset, imm, u32, no, no_op); \
2727 break; \
2728 \
2729 case 0x5A: \
2730 /* STR rd, [rn + imm]! */ \
2731 arm_access_memory(store, + offset, imm, u32, yes, no_op); \
2732 break; \
2733 \
2734 case 0x5B: \
2735 /* LDR rd, [rn + imm]! */ \
2736 arm_access_memory(load, + offset, imm, u32, yes, no_op); \
2737 break; \
2738 \
2739 case 0x5C: \
2740 /* STRB rd, [rn + imm] */ \
2741 arm_access_memory(store, + offset, imm, u8, no, no_op); \
2742 break; \
2743 \
2744 case 0x5D: \
2745 /* LDRB rd, [rn + imm] */ \
2746 arm_access_memory(load, + offset, imm, u8, no, no_op); \
2747 break; \
2748 \
2749 case 0x5E: \
2750 /* STRB rd, [rn + imm]! */ \
2751 arm_access_memory(store, + offset, imm, u8, yes, no_op); \
2752 break; \
2753 \
2754 case 0x5F: \
2755 /* LDRBT rd, [rn + imm]! */ \
2756 arm_access_memory(load, + offset, imm, u8, yes, no_op); \
2757 break; \
2758 \
2759 case 0x60: \
2760 /* STR rd, [rn], -reg_op */ \
2761 arm_access_memory(store, no_op, reg, u32, yes, - reg_offset); \
2762 break; \
2763 \
2764 case 0x61: \
2765 /* LDR rd, [rn], -reg_op */ \
2766 arm_access_memory(load, no_op, reg, u32, yes, - reg_offset); \
2767 break; \
2768 \
2769 case 0x62: \
2770 /* STRT rd, [rn], -reg_op */ \
2771 arm_access_memory(store, no_op, reg, u32, yes, - reg_offset); \
2772 break; \
2773 \
2774 case 0x63: \
2775 /* LDRT rd, [rn], -reg_op */ \
2776 arm_access_memory(load, no_op, reg, u32, yes, - reg_offset); \
2777 break; \
2778 \
2779 case 0x64: \
2780 /* STRB rd, [rn], -reg_op */ \
2781 arm_access_memory(store, no_op, reg, u8, yes, - reg_offset); \
2782 break; \
2783 \
2784 case 0x65: \
2785 /* LDRB rd, [rn], -reg_op */ \
2786 arm_access_memory(load, no_op, reg, u8, yes, - reg_offset); \
2787 break; \
2788 \
2789 case 0x66: \
2790 /* STRBT rd, [rn], -reg_op */ \
2791 arm_access_memory(store, no_op, reg, u8, yes, - reg_offset); \
2792 break; \
2793 \
2794 case 0x67: \
2795 /* LDRBT rd, [rn], -reg_op */ \
2796 arm_access_memory(load, no_op, reg, u8, yes, - reg_offset); \
2797 break; \
2798 \
2799 case 0x68: \
2800 /* STR rd, [rn], +reg_op */ \
2801 arm_access_memory(store, no_op, reg, u32, yes, + reg_offset); \
2802 break; \
2803 \
2804 case 0x69: \
2805 /* LDR rd, [rn], +reg_op */ \
2806 arm_access_memory(load, no_op, reg, u32, yes, + reg_offset); \
2807 break; \
2808 \
2809 case 0x6A: \
2810 /* STRT rd, [rn], +reg_op */ \
2811 arm_access_memory(store, no_op, reg, u32, yes, + reg_offset); \
2812 break; \
2813 \
2814 case 0x6B: \
2815 /* LDRT rd, [rn], +reg_op */ \
2816 arm_access_memory(load, no_op, reg, u32, yes, + reg_offset); \
2817 break; \
2818 \
2819 case 0x6C: \
2820 /* STRB rd, [rn], +reg_op */ \
2821 arm_access_memory(store, no_op, reg, u8, yes, + reg_offset); \
2822 break; \
2823 \
2824 case 0x6D: \
2825 /* LDRB rd, [rn], +reg_op */ \
2826 arm_access_memory(load, no_op, reg, u8, yes, + reg_offset); \
2827 break; \
2828 \
2829 case 0x6E: \
2830 /* STRBT rd, [rn], +reg_op */ \
2831 arm_access_memory(store, no_op, reg, u8, yes, + reg_offset); \
2832 break; \
2833 \
2834 case 0x6F: \
2835 /* LDRBT rd, [rn], +reg_op */ \
2836 arm_access_memory(load, no_op, reg, u8, yes, + reg_offset); \
2837 break; \
2838 \
2839 case 0x70: \
2840 /* STR rd, [rn - reg_op] */ \
2841 arm_access_memory(store, - reg_offset, reg, u32, no, no_op); \
2842 break; \
2843 \
2844 case 0x71: \
2845 /* LDR rd, [rn - reg_op] */ \
2846 arm_access_memory(load, - reg_offset, reg, u32, no, no_op); \
2847 break; \
2848 \
2849 case 0x72: \
2850 /* STR rd, [rn - reg_op]! */ \
2851 arm_access_memory(store, - reg_offset, reg, u32, yes, no_op); \
2852 break; \
2853 \
2854 case 0x73: \
2855 /* LDR rd, [rn - reg_op]! */ \
2856 arm_access_memory(load, - reg_offset, reg, u32, yes, no_op); \
2857 break; \
2858 \
2859 case 0x74: \
2860 /* STRB rd, [rn - reg_op] */ \
2861 arm_access_memory(store, - reg_offset, reg, u8, no, no_op); \
2862 break; \
2863 \
2864 case 0x75: \
2865 /* LDRB rd, [rn - reg_op] */ \
2866 arm_access_memory(load, - reg_offset, reg, u8, no, no_op); \
2867 break; \
2868 \
2869 case 0x76: \
2870 /* STRB rd, [rn - reg_op]! */ \
2871 arm_access_memory(store, - reg_offset, reg, u8, yes, no_op); \
2872 break; \
2873 \
2874 case 0x77: \
2875 /* LDRB rd, [rn - reg_op]! */ \
2876 arm_access_memory(load, - reg_offset, reg, u8, yes, no_op); \
2877 break; \
2878 \
2879 case 0x78: \
2880 /* STR rd, [rn + reg_op] */ \
2881 arm_access_memory(store, + reg_offset, reg, u32, no, no_op); \
2882 break; \
2883 \
2884 case 0x79: \
2885 /* LDR rd, [rn + reg_op] */ \
2886 arm_access_memory(load, + reg_offset, reg, u32, no, no_op); \
2887 break; \
2888 \
2889 case 0x7A: \
2890 /* STR rd, [rn + reg_op]! */ \
2891 arm_access_memory(store, + reg_offset, reg, u32, yes, no_op); \
2892 break; \
2893 \
2894 case 0x7B: \
2895 /* LDR rd, [rn + reg_op]! */ \
2896 arm_access_memory(load, + reg_offset, reg, u32, yes, no_op); \
2897 break; \
2898 \
2899 case 0x7C: \
2900 /* STRB rd, [rn + reg_op] */ \
2901 arm_access_memory(store, + reg_offset, reg, u8, no, no_op); \
2902 break; \
2903 \
2904 case 0x7D: \
2905 /* LDRB rd, [rn + reg_op] */ \
2906 arm_access_memory(load, + reg_offset, reg, u8, no, no_op); \
2907 break; \
2908 \
2909 case 0x7E: \
2910 /* STRB rd, [rn + reg_op]! */ \
2911 arm_access_memory(store, + reg_offset, reg, u8, yes, no_op); \
2912 break; \
2913 \
2914 case 0x7F: \
2915 /* LDRBT rd, [rn + reg_op]! */ \
2916 arm_access_memory(load, + reg_offset, reg, u8, yes, no_op); \
2917 break; \
2918 \
2919 case 0x80: \
2920 /* STMDA rn, rlist */ \
2921 arm_block_memory(store, down_a, no, no); \
2922 break; \
2923 \
2924 case 0x81: \
2925 /* LDMDA rn, rlist */ \
2926 arm_block_memory(load, down_a, no, no); \
2927 break; \
2928 \
2929 case 0x82: \
2930 /* STMDA rn!, rlist */ \
2931 arm_block_memory(store, down_a, down, no); \
2932 break; \
2933 \
2934 case 0x83: \
2935 /* LDMDA rn!, rlist */ \
2936 arm_block_memory(load, down_a, down, no); \
2937 break; \
2938 \
2939 case 0x84: \
2940 /* STMDA rn, rlist^ */ \
2941 arm_block_memory(store, down_a, no, yes); \
2942 break; \
2943 \
2944 case 0x85: \
2945 /* LDMDA rn, rlist^ */ \
2946 arm_block_memory(load, down_a, no, yes); \
2947 break; \
2948 \
2949 case 0x86: \
2950 /* STMDA rn!, rlist^ */ \
2951 arm_block_memory(store, down_a, down, yes); \
2952 break; \
2953 \
2954 case 0x87: \
2955 /* LDMDA rn!, rlist^ */ \
2956 arm_block_memory(load, down_a, down, yes); \
2957 break; \
2958 \
2959 case 0x88: \
2960 /* STMIA rn, rlist */ \
2961 arm_block_memory(store, no, no, no); \
2962 break; \
2963 \
2964 case 0x89: \
2965 /* LDMIA rn, rlist */ \
2966 arm_block_memory(load, no, no, no); \
2967 break; \
2968 \
2969 case 0x8A: \
2970 /* STMIA rn!, rlist */ \
2971 arm_block_memory(store, no, up, no); \
2972 break; \
2973 \
2974 case 0x8B: \
2975 /* LDMIA rn!, rlist */ \
2976 arm_block_memory(load, no, up, no); \
2977 break; \
2978 \
2979 case 0x8C: \
2980 /* STMIA rn, rlist^ */ \
2981 arm_block_memory(store, no, no, yes); \
2982 break; \
2983 \
2984 case 0x8D: \
2985 /* LDMIA rn, rlist^ */ \
2986 arm_block_memory(load, no, no, yes); \
2987 break; \
2988 \
2989 case 0x8E: \
2990 /* STMIA rn!, rlist^ */ \
2991 arm_block_memory(store, no, up, yes); \
2992 break; \
2993 \
2994 case 0x8F: \
2995 /* LDMIA rn!, rlist^ */ \
2996 arm_block_memory(load, no, up, yes); \
2997 break; \
2998 \
2999 case 0x90: \
3000 /* STMDB rn, rlist */ \
3001 arm_block_memory(store, down_b, no, no); \
3002 break; \
3003 \
3004 case 0x91: \
3005 /* LDMDB rn, rlist */ \
3006 arm_block_memory(load, down_b, no, no); \
3007 break; \
3008 \
3009 case 0x92: \
3010 /* STMDB rn!, rlist */ \
3011 arm_block_memory(store, down_b, down, no); \
3012 break; \
3013 \
3014 case 0x93: \
3015 /* LDMDB rn!, rlist */ \
3016 arm_block_memory(load, down_b, down, no); \
3017 break; \
3018 \
3019 case 0x94: \
3020 /* STMDB rn, rlist^ */ \
3021 arm_block_memory(store, down_b, no, yes); \
3022 break; \
3023 \
3024 case 0x95: \
3025 /* LDMDB rn, rlist^ */