original source from gpsp09-2xb_src.tar.bz2
[gpsp.git] / cpu_threaded.c
CommitLineData
2823a4c8 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// Not-so-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
27u8 rom_translation_cache[ROM_TRANSLATION_CACHE_SIZE];
28u8 *rom_translation_ptr = rom_translation_cache;
29
30u8 ram_translation_cache[RAM_TRANSLATION_CACHE_SIZE];
31u8 *ram_translation_ptr = ram_translation_cache;
32u32 iwram_code_min = 0xFFFFFFFF;
33u32 iwram_code_max = 0xFFFFFFFF;
34u32 ewram_code_min = 0xFFFFFFFF;
35u32 ewram_code_max = 0xFFFFFFFF;
36
37u8 bios_translation_cache[BIOS_TRANSLATION_CACHE_SIZE];
38u8 *bios_translation_ptr = bios_translation_cache;
39
40u32 *rom_branch_hash[ROM_BRANCH_HASH_SIZE];
41
42// Default
43u32 idle_loop_target_pc = 0xFFFFFFFF;
44u32 force_pc_update_target = 0xFFFFFFFF;
45u32 translation_gate_target_pc[MAX_TRANSLATION_GATES];
46u32 translation_gate_targets = 0;
47u32 iwram_stack_optimize = 1;
48u32 allow_smc_ram_u8 = 1;
49u32 allow_smc_ram_u16 = 1;
50u32 allow_smc_ram_u32 = 1;
51
52typedef struct
53{
54 u8 *block_offset;
55 u16 flag_data;
56 u8 condition;
57 u8 update_cycles;
58} block_data_type;
59
60typedef struct
61{
62 u32 branch_target;
63 u8 *branch_source;
64} block_exit_type;
65
66extern u8 bit_count[256];
67
68#define arm_decode_data_proc_reg() \
69 u32 rn = (opcode >> 16) & 0x0F; \
70 u32 rd = (opcode >> 12) & 0x0F; \
71 u32 rm = opcode & 0x0F \
72
73#define arm_decode_data_proc_imm() \
74 u32 rn = (opcode >> 16) & 0x0F; \
75 u32 rd = (opcode >> 12) & 0x0F; \
76 u32 imm = opcode & 0xFF; \
77 u32 imm_ror = ((opcode >> 8) & 0x0F) * 2 \
78
79#define arm_decode_psr_reg() \
80 u32 psr_field = (opcode >> 16) & 0x0F; \
81 u32 rd = (opcode >> 12) & 0x0F; \
82 u32 rm = opcode & 0x0F \
83
84#define arm_decode_psr_imm() \
85 u32 psr_field = (opcode >> 16) & 0x0F; \
86 u32 rd = (opcode >> 12) & 0x0F; \
87 u32 imm = opcode & 0xFF; \
88 u32 imm_ror = ((opcode >> 8) & 0x0F) * 2 \
89
90#define arm_decode_branchx() \
91 u32 rn = opcode & 0x0F \
92
93#define arm_decode_multiply() \
94 u32 rd = (opcode >> 16) & 0x0F; \
95 u32 rn = (opcode >> 12) & 0x0F; \
96 u32 rs = (opcode >> 8) & 0x0F; \
97 u32 rm = opcode & 0x0F \
98
99#define arm_decode_multiply_long() \
100 u32 rdhi = (opcode >> 16) & 0x0F; \
101 u32 rdlo = (opcode >> 12) & 0x0F; \
102 u32 rs = (opcode >> 8) & 0x0F; \
103 u32 rm = opcode & 0x0F \
104
105#define arm_decode_swap() \
106 u32 rn = (opcode >> 16) & 0x0F; \
107 u32 rd = (opcode >> 12) & 0x0F; \
108 u32 rm = opcode & 0x0F \
109
110#define arm_decode_half_trans_r() \
111 u32 rn = (opcode >> 16) & 0x0F; \
112 u32 rd = (opcode >> 12) & 0x0F; \
113 u32 rm = opcode & 0x0F \
114
115#define arm_decode_half_trans_of() \
116 u32 rn = (opcode >> 16) & 0x0F; \
117 u32 rd = (opcode >> 12) & 0x0F; \
118 u32 offset = ((opcode >> 4) & 0xF0) | (opcode & 0x0F) \
119
120#define arm_decode_data_trans_imm() \
121 u32 rn = (opcode >> 16) & 0x0F; \
122 u32 rd = (opcode >> 12) & 0x0F; \
123 u32 offset = opcode & 0x0FFF \
124
125#define arm_decode_data_trans_reg() \
126 u32 rn = (opcode >> 16) & 0x0F; \
127 u32 rd = (opcode >> 12) & 0x0F; \
128 u32 rm = opcode & 0x0F \
129
130#define arm_decode_block_trans() \
131 u32 rn = (opcode >> 16) & 0x0F; \
132 u32 reg_list = opcode & 0xFFFF \
133
134#define arm_decode_branch() \
135 s32 offset = ((s32)(opcode & 0xFFFFFF) << 8) >> 6 \
136
137#define thumb_decode_shift() \
138 u32 imm = (opcode >> 6) & 0x1F; \
139 u32 rs = (opcode >> 3) & 0x07; \
140 u32 rd = opcode & 0x07 \
141
142#define thumb_decode_add_sub() \
143 u32 rn = (opcode >> 6) & 0x07; \
144 u32 rs = (opcode >> 3) & 0x07; \
145 u32 rd = opcode & 0x07 \
146
147#define thumb_decode_add_sub_imm() \
148 u32 imm = (opcode >> 6) & 0x07; \
149 u32 rs = (opcode >> 3) & 0x07; \
150 u32 rd = opcode & 0x07 \
151
152#define thumb_decode_imm() \
153 u32 imm = opcode & 0xFF \
154
155#define thumb_decode_alu_op() \
156 u32 rs = (opcode >> 3) & 0x07; \
157 u32 rd = opcode & 0x07 \
158
159#define thumb_decode_hireg_op() \
160 u32 rs = (opcode >> 3) & 0x0F; \
161 u32 rd = ((opcode >> 4) & 0x08) | (opcode & 0x07) \
162
163#define thumb_decode_mem_reg() \
164 u32 ro = (opcode >> 6) & 0x07; \
165 u32 rb = (opcode >> 3) & 0x07; \
166 u32 rd = opcode & 0x07 \
167
168#define thumb_decode_mem_imm() \
169 u32 imm = (opcode >> 6) & 0x1F; \
170 u32 rb = (opcode >> 3) & 0x07; \
171 u32 rd = opcode & 0x07 \
172
173#define thumb_decode_add_sp() \
174 u32 imm = opcode & 0x7F \
175
176#define thumb_decode_rlist() \
177 u32 reg_list = opcode & 0xFF \
178
179#define thumb_decode_branch_cond() \
180 s32 offset = (s8)(opcode & 0xFF) \
181
182#define thumb_decode_swi() \
183 u32 comment = opcode & 0xFF \
184
185#define thumb_decode_branch() \
186 u32 offset = opcode & 0x07FF \
187
188
189#ifdef PSP_BUILD
190
191#include "psp/mips_emit.h"
192
193#elif defined(GP2X_BUILD)
194
195#include "gp2x/arm_emit.h"
196
197#elif defined(GIZ_BUILD)
198
199#include "giz/arm_emit.h"
200
201#else
202
203#include "x86/x86_emit.h"
204
205#endif
206
207
208#define check_pc_region(pc) \
209 new_pc_region = (pc >> 15); \
210 if(new_pc_region != pc_region) \
211 { \
212 pc_region = new_pc_region; \
213 pc_address_block = memory_map_read[new_pc_region]; \
214 \
215 if(pc_address_block == NULL) \
216 pc_address_block = load_gamepak_page(pc_region & 0x3FF); \
217 } \
218
219#define translate_arm_instruction() \
220 check_pc_region(pc); \
221 opcode = address32(pc_address_block, (pc & 0x7FFF)); \
222 condition = block_data[block_data_position].condition; \
223 \
224 if((condition != last_condition) || (condition >= 0x20)) \
225 { \
226 if((last_condition & 0x0F) != 0x0E) \
227 { \
228 generate_branch_patch_conditional(backpatch_address, translation_ptr); \
229 } \
230 \
231 last_condition = condition; \
232 \
233 condition &= 0x0F; \
234 \
235 if(condition != 0x0E) \
236 { \
237 arm_conditional_block_header(); \
238 } \
239 } \
240 \
241 switch((opcode >> 20) & 0xFF) \
242 { \
243 case 0x00: \
244 if((opcode & 0x90) == 0x90) \
245 { \
246 if(opcode & 0x20) \
247 { \
248 /* STRH rd, [rn], -rm */ \
249 arm_access_memory(store, down, post, u16, half_reg); \
250 } \
251 else \
252 { \
253 /* MUL rd, rm, rs */ \
254 arm_multiply(no, no); \
255 } \
256 } \
257 else \
258 { \
259 /* AND rd, rn, reg_op */ \
260 arm_data_proc(and, reg, no_flags); \
261 } \
262 break; \
263 \
264 case 0x01: \
265 if((opcode & 0x90) == 0x90) \
266 { \
267 switch((opcode >> 5) & 0x03) \
268 { \
269 case 0: \
270 /* MULS rd, rm, rs */ \
271 arm_multiply(no, yes); \
272 break; \
273 \
274 case 1: \
275 /* LDRH rd, [rn], -rm */ \
276 arm_access_memory(load, down, post, u16, half_reg); \
277 break; \
278 \
279 case 2: \
280 /* LDRSB rd, [rn], -rm */ \
281 arm_access_memory(load, down, post, s8, half_reg); \
282 break; \
283 \
284 case 3: \
285 /* LDRSH rd, [rn], -rm */ \
286 arm_access_memory(load, down, post, s16, half_reg); \
287 break; \
288 } \
289 } \
290 else \
291 { \
292 /* ANDS rd, rn, reg_op */ \
293 arm_data_proc(ands, reg_flags, flags); \
294 } \
295 break; \
296 \
297 case 0x02: \
298 if((opcode & 0x90) == 0x90) \
299 { \
300 if(opcode & 0x20) \
301 { \
302 /* STRH rd, [rn], -rm */ \
303 arm_access_memory(store, down, post, u16, half_reg); \
304 } \
305 else \
306 { \
307 /* MLA rd, rm, rs, rn */ \
308 arm_multiply(yes, no); \
309 } \
310 } \
311 else \
312 { \
313 /* EOR rd, rn, reg_op */ \
314 arm_data_proc(eor, reg, no_flags); \
315 } \
316 break; \
317 \
318 case 0x03: \
319 if((opcode & 0x90) == 0x90) \
320 { \
321 switch((opcode >> 5) & 0x03) \
322 { \
323 case 0: \
324 /* MLAS rd, rm, rs, rn */ \
325 arm_multiply(yes, yes); \
326 break; \
327 \
328 case 1: \
329 /* LDRH rd, [rn], -rm */ \
330 arm_access_memory(load, down, post, u16, half_reg); \
331 break; \
332 \
333 case 2: \
334 /* LDRSB rd, [rn], -rm */ \
335 arm_access_memory(load, down, post, s8, half_reg); \
336 break; \
337 \
338 case 3: \
339 /* LDRSH rd, [rn], -rm */ \
340 arm_access_memory(load, down, post, s16, half_reg); \
341 break; \
342 } \
343 } \
344 else \
345 { \
346 /* EORS rd, rn, reg_op */ \
347 arm_data_proc(eors, reg_flags, flags); \
348 } \
349 break; \
350 \
351 case 0x04: \
352 if((opcode & 0x90) == 0x90) \
353 { \
354 /* STRH rd, [rn], -imm */ \
355 arm_access_memory(store, down, post, u16, half_imm); \
356 } \
357 else \
358 { \
359 /* SUB rd, rn, reg_op */ \
360 arm_data_proc(sub, reg, no_flags); \
361 } \
362 break; \
363 \
364 case 0x05: \
365 if((opcode & 0x90) == 0x90) \
366 { \
367 switch((opcode >> 5) & 0x03) \
368 { \
369 case 1: \
370 /* LDRH rd, [rn], -imm */ \
371 arm_access_memory(load, down, post, u16, half_imm); \
372 break; \
373 \
374 case 2: \
375 /* LDRSB rd, [rn], -imm */ \
376 arm_access_memory(load, down, post, s8, half_imm); \
377 break; \
378 \
379 case 3: \
380 /* LDRSH rd, [rn], -imm */ \
381 arm_access_memory(load, down, post, s16, half_imm); \
382 break; \
383 } \
384 } \
385 else \
386 { \
387 /* SUBS rd, rn, reg_op */ \
388 arm_data_proc(subs, reg, flags); \
389 } \
390 break; \
391 \
392 case 0x06: \
393 if((opcode & 0x90) == 0x90) \
394 { \
395 /* STRH rd, [rn], -imm */ \
396 arm_access_memory(store, down, post, u16, half_imm); \
397 } \
398 else \
399 { \
400 /* RSB rd, rn, reg_op */ \
401 arm_data_proc(rsb, reg, no_flags); \
402 } \
403 break; \
404 \
405 case 0x07: \
406 if((opcode & 0x90) == 0x90) \
407 { \
408 switch((opcode >> 5) & 0x03) \
409 { \
410 case 1: \
411 /* LDRH rd, [rn], -imm */ \
412 arm_access_memory(load, down, post, u16, half_imm); \
413 break; \
414 \
415 case 2: \
416 /* LDRSB rd, [rn], -imm */ \
417 arm_access_memory(load, down, post, s8, half_imm); \
418 break; \
419 \
420 case 3: \
421 /* LDRSH rd, [rn], -imm */ \
422 arm_access_memory(load, down, post, s16, half_imm); \
423 break; \
424 } \
425 } \
426 else \
427 { \
428 /* RSBS rd, rn, reg_op */ \
429 arm_data_proc(rsbs, reg, flags); \
430 } \
431 break; \
432 \
433 case 0x08: \
434 if((opcode & 0x90) == 0x90) \
435 { \
436 if(opcode & 0x20) \
437 { \
438 /* STRH rd, [rn], +rm */ \
439 arm_access_memory(store, up, post, u16, half_reg); \
440 } \
441 else \
442 { \
443 /* UMULL rd, rm, rs */ \
444 arm_multiply_long(u64, no, no); \
445 } \
446 } \
447 else \
448 { \
449 /* ADD rd, rn, reg_op */ \
450 arm_data_proc(add, reg, no_flags); \
451 } \
452 break; \
453 \
454 case 0x09: \
455 if((opcode & 0x90) == 0x90) \
456 { \
457 switch((opcode >> 5) & 0x03) \
458 { \
459 case 0: \
460 /* UMULLS rdlo, rdhi, rm, rs */ \
461 arm_multiply_long(u64, no, yes); \
462 break; \
463 \
464 case 1: \
465 /* LDRH rd, [rn], +rm */ \
466 arm_access_memory(load, up, post, u16, half_reg); \
467 break; \
468 \
469 case 2: \
470 /* LDRSB rd, [rn], +rm */ \
471 arm_access_memory(load, up, post, s8, half_reg); \
472 break; \
473 \
474 case 3: \
475 /* LDRSH rd, [rn], +rm */ \
476 arm_access_memory(load, up, post, s16, half_reg); \
477 break; \
478 } \
479 } \
480 else \
481 { \
482 /* ADDS rd, rn, reg_op */ \
483 arm_data_proc(adds, reg, flags); \
484 } \
485 break; \
486 \
487 case 0x0A: \
488 if((opcode & 0x90) == 0x90) \
489 { \
490 if(opcode & 0x20) \
491 { \
492 /* STRH rd, [rn], +rm */ \
493 arm_access_memory(store, up, post, u16, half_reg); \
494 } \
495 else \
496 { \
497 /* UMLAL rd, rm, rs */ \
498 arm_multiply_long(u64_add, yes, no); \
499 } \
500 } \
501 else \
502 { \
503 /* ADC rd, rn, reg_op */ \
504 arm_data_proc(adc, reg, no_flags); \
505 } \
506 break; \
507 \
508 case 0x0B: \
509 if((opcode & 0x90) == 0x90) \
510 { \
511 switch((opcode >> 5) & 0x03) \
512 { \
513 case 0: \
514 /* UMLALS rdlo, rdhi, rm, rs */ \
515 arm_multiply_long(u64_add, yes, yes); \
516 break; \
517 \
518 case 1: \
519 /* LDRH rd, [rn], +rm */ \
520 arm_access_memory(load, up, post, u16, half_reg); \
521 break; \
522 \
523 case 2: \
524 /* LDRSB rd, [rn], +rm */ \
525 arm_access_memory(load, up, post, s8, half_reg); \
526 break; \
527 \
528 case 3: \
529 /* LDRSH rd, [rn], +rm */ \
530 arm_access_memory(load, up, post, s16, half_reg); \
531 break; \
532 } \
533 } \
534 else \
535 { \
536 /* ADCS rd, rn, reg_op */ \
537 arm_data_proc(adcs, reg, flags); \
538 } \
539 break; \
540 \
541 case 0x0C: \
542 if((opcode & 0x90) == 0x90) \
543 { \
544 if(opcode & 0x20) \
545 { \
546 /* STRH rd, [rn], +imm */ \
547 arm_access_memory(store, up, post, u16, half_imm); \
548 } \
549 else \
550 { \
551 /* SMULL rd, rm, rs */ \
552 arm_multiply_long(s64, no, no); \
553 } \
554 } \
555 else \
556 { \
557 /* SBC rd, rn, reg_op */ \
558 arm_data_proc(sbc, reg, no_flags); \
559 } \
560 break; \
561 \
562 case 0x0D: \
563 if((opcode & 0x90) == 0x90) \
564 { \
565 switch((opcode >> 5) & 0x03) \
566 { \
567 case 0: \
568 /* SMULLS rdlo, rdhi, rm, rs */ \
569 arm_multiply_long(s64, no, yes); \
570 break; \
571 \
572 case 1: \
573 /* LDRH rd, [rn], +imm */ \
574 arm_access_memory(load, up, post, u16, half_imm); \
575 break; \
576 \
577 case 2: \
578 /* LDRSB rd, [rn], +imm */ \
579 arm_access_memory(load, up, post, s8, half_imm); \
580 break; \
581 \
582 case 3: \
583 /* LDRSH rd, [rn], +imm */ \
584 arm_access_memory(load, up, post, s16, half_imm); \
585 break; \
586 } \
587 } \
588 else \
589 { \
590 /* SBCS rd, rn, reg_op */ \
591 arm_data_proc(sbcs, reg, flags); \
592 } \
593 break; \
594 \
595 case 0x0E: \
596 if((opcode & 0x90) == 0x90) \
597 { \
598 if(opcode & 0x20) \
599 { \
600 /* STRH rd, [rn], +imm */ \
601 arm_access_memory(store, up, post, u16, half_imm); \
602 } \
603 else \
604 { \
605 /* SMLAL rd, rm, rs */ \
606 arm_multiply_long(s64_add, yes, no); \
607 } \
608 } \
609 else \
610 { \
611 /* RSC rd, rn, reg_op */ \
612 arm_data_proc(rsc, reg, no_flags); \
613 } \
614 break; \
615 \
616 case 0x0F: \
617 if((opcode & 0x90) == 0x90) \
618 { \
619 switch((opcode >> 5) & 0x03) \
620 { \
621 case 0: \
622 /* SMLALS rdlo, rdhi, rm, rs */ \
623 arm_multiply_long(s64_add, yes, yes); \
624 break; \
625 \
626 case 1: \
627 /* LDRH rd, [rn], +imm */ \
628 arm_access_memory(load, up, post, u16, half_imm); \
629 break; \
630 \
631 case 2: \
632 /* LDRSB rd, [rn], +imm */ \
633 arm_access_memory(load, up, post, s8, half_imm); \
634 break; \
635 \
636 case 3: \
637 /* LDRSH rd, [rn], +imm */ \
638 arm_access_memory(load, up, post, s16, half_imm); \
639 break; \
640 } \
641 } \
642 else \
643 { \
644 /* RSCS rd, rn, reg_op */ \
645 arm_data_proc(rscs, reg, flags); \
646 } \
647 break; \
648 \
649 case 0x10: \
650 if((opcode & 0x90) == 0x90) \
651 { \
652 if(opcode & 0x20) \
653 { \
654 /* STRH rd, [rn - rm] */ \
655 arm_access_memory(store, down, pre, u16, half_reg); \
656 } \
657 else \
658 { \
659 /* SWP rd, rm, [rn] */ \
660 arm_swap(u32); \
661 } \
662 } \
663 else \
664 { \
665 /* MRS rd, cpsr */ \
666 arm_psr(reg, read, cpsr); \
667 } \
668 break; \
669 \
670 case 0x11: \
671 if((opcode & 0x90) == 0x90) \
672 { \
673 switch((opcode >> 5) & 0x03) \
674 { \
675 case 1: \
676 /* LDRH rd, [rn - rm] */ \
677 arm_access_memory(load, down, pre, u16, half_reg); \
678 break; \
679 \
680 case 2: \
681 /* LDRSB rd, [rn - rm] */ \
682 arm_access_memory(load, down, pre, s8, half_reg); \
683 break; \
684 \
685 case 3: \
686 /* LDRSH rd, [rn - rm] */ \
687 arm_access_memory(load, down, pre, s16, half_reg); \
688 break; \
689 } \
690 } \
691 else \
692 { \
693 /* TST rd, rn, reg_op */ \
694 arm_data_proc_test(tst, reg_flags); \
695 } \
696 break; \
697 \
698 case 0x12: \
699 if((opcode & 0x90) == 0x90) \
700 { \
701 /* STRH rd, [rn - rm]! */ \
702 arm_access_memory(store, down, pre_wb, u16, half_reg); \
703 } \
704 else \
705 { \
706 if(opcode & 0x10) \
707 { \
708 /* BX rn */ \
709 arm_bx(); \
710 } \
711 else \
712 { \
713 /* MSR cpsr, rm */ \
714 arm_psr(reg, store, cpsr); \
715 } \
716 } \
717 break; \
718 \
719 case 0x13: \
720 if((opcode & 0x90) == 0x90) \
721 { \
722 switch((opcode >> 5) & 0x03) \
723 { \
724 case 1: \
725 /* LDRH rd, [rn - rm]! */ \
726 arm_access_memory(load, down, pre_wb, u16, half_reg); \
727 break; \
728 \
729 case 2: \
730 /* LDRSB rd, [rn - rm]! */ \
731 arm_access_memory(load, down, pre_wb, s8, half_reg); \
732 break; \
733 \
734 case 3: \
735 /* LDRSH rd, [rn - rm]! */ \
736 arm_access_memory(load, down, pre_wb, s16, half_reg); \
737 break; \
738 } \
739 } \
740 else \
741 { \
742 /* TEQ rd, rn, reg_op */ \
743 arm_data_proc_test(teq, reg_flags); \
744 } \
745 break; \
746 \
747 case 0x14: \
748 if((opcode & 0x90) == 0x90) \
749 { \
750 if(opcode & 0x20) \
751 { \
752 /* STRH rd, [rn - imm] */ \
753 arm_access_memory(store, down, pre, u16, half_imm); \
754 } \
755 else \
756 { \
757 /* SWPB rd, rm, [rn] */ \
758 arm_swap(u8); \
759 } \
760 } \
761 else \
762 { \
763 /* MRS rd, spsr */ \
764 arm_psr(reg, read, spsr); \
765 } \
766 break; \
767 \
768 case 0x15: \
769 if((opcode & 0x90) == 0x90) \
770 { \
771 switch((opcode >> 5) & 0x03) \
772 { \
773 case 1: \
774 /* LDRH rd, [rn - imm] */ \
775 arm_access_memory(load, down, pre, u16, half_imm); \
776 break; \
777 \
778 case 2: \
779 /* LDRSB rd, [rn - imm] */ \
780 arm_access_memory(load, down, pre, s8, half_imm); \
781 break; \
782 \
783 case 3: \
784 /* LDRSH rd, [rn - imm] */ \
785 arm_access_memory(load, down, pre, s16, half_imm); \
786 break; \
787 } \
788 } \
789 else \
790 { \
791 /* CMP rn, reg_op */ \
792 arm_data_proc_test(cmp, reg); \
793 } \
794 break; \
795 \
796 case 0x16: \
797 if((opcode & 0x90) == 0x90) \
798 { \
799 /* STRH rd, [rn - imm]! */ \
800 arm_access_memory(store, down, pre_wb, u16, half_imm); \
801 } \
802 else \
803 { \
804 /* MSR spsr, rm */ \
805 arm_psr(reg, store, spsr); \
806 } \
807 break; \
808 \
809 case 0x17: \
810 if((opcode & 0x90) == 0x90) \
811 { \
812 switch((opcode >> 5) & 0x03) \
813 { \
814 case 1: \
815 /* LDRH rd, [rn - imm]! */ \
816 arm_access_memory(load, down, pre_wb, u16, half_imm); \
817 break; \
818 \
819 case 2: \
820 /* LDRSB rd, [rn - imm]! */ \
821 arm_access_memory(load, down, pre_wb, s8, half_imm); \
822 break; \
823 \
824 case 3: \
825 /* LDRSH rd, [rn - imm]! */ \
826 arm_access_memory(load, down, pre_wb, s16, half_imm); \
827 break; \
828 } \
829 } \
830 else \
831 { \
832 /* CMN rd, rn, reg_op */ \
833 arm_data_proc_test(cmn, reg); \
834 } \
835 break; \
836 \
837 case 0x18: \
838 if((opcode & 0x90) == 0x90) \
839 { \
840 /* STRH rd, [rn + rm] */ \
841 arm_access_memory(store, up, pre, u16, half_reg); \
842 } \
843 else \
844 { \
845 /* ORR rd, rn, reg_op */ \
846 arm_data_proc(orr, reg, no_flags); \
847 } \
848 break; \
849 \
850 case 0x19: \
851 if((opcode & 0x90) == 0x90) \
852 { \
853 switch((opcode >> 5) & 0x03) \
854 { \
855 case 1: \
856 /* LDRH rd, [rn + rm] */ \
857 arm_access_memory(load, up, pre, u16, half_reg); \
858 break; \
859 \
860 case 2: \
861 /* LDRSB rd, [rn + rm] */ \
862 arm_access_memory(load, up, pre, s8, half_reg); \
863 break; \
864 \
865 case 3: \
866 /* LDRSH rd, [rn + rm] */ \
867 arm_access_memory(load, up, pre, s16, half_reg); \
868 break; \
869 } \
870 } \
871 else \
872 { \
873 /* ORRS rd, rn, reg_op */ \
874 arm_data_proc(orrs, reg_flags, flags); \
875 } \
876 break; \
877 \
878 case 0x1A: \
879 if((opcode & 0x90) == 0x90) \
880 { \
881 /* STRH rd, [rn + rm]! */ \
882 arm_access_memory(store, up, pre_wb, u16, half_reg); \
883 } \
884 else \
885 { \
886 /* MOV rd, reg_op */ \
887 arm_data_proc_unary(mov, reg, no_flags); \
888 } \
889 break; \
890 \
891 case 0x1B: \
892 if((opcode & 0x90) == 0x90) \
893 { \
894 switch((opcode >> 5) & 0x03) \
895 { \
896 case 1: \
897 /* LDRH rd, [rn + rm]! */ \
898 arm_access_memory(load, up, pre_wb, u16, half_reg); \
899 break; \
900 \
901 case 2: \
902 /* LDRSB rd, [rn + rm]! */ \
903 arm_access_memory(load, up, pre_wb, s8, half_reg); \
904 break; \
905 \
906 case 3: \
907 /* LDRSH rd, [rn + rm]! */ \
908 arm_access_memory(load, up, pre_wb, s16, half_reg); \
909 break; \
910 } \
911 } \
912 else \
913 { \
914 /* MOVS rd, reg_op */ \
915 arm_data_proc_unary(movs, reg_flags, flags); \
916 } \
917 break; \
918 \
919 case 0x1C: \
920 if((opcode & 0x90) == 0x90) \
921 { \
922 /* STRH rd, [rn + imm] */ \
923 arm_access_memory(store, up, pre, u16, half_imm); \
924 } \
925 else \
926 { \
927 /* BIC rd, rn, reg_op */ \
928 arm_data_proc(bic, reg, no_flags); \
929 } \
930 break; \
931 \
932 case 0x1D: \
933 if((opcode & 0x90) == 0x90) \
934 { \
935 switch((opcode >> 5) & 0x03) \
936 { \
937 case 1: \
938 /* LDRH rd, [rn + imm] */ \
939 arm_access_memory(load, up, pre, u16, half_imm); \
940 break; \
941 \
942 case 2: \
943 /* LDRSB rd, [rn + imm] */ \
944 arm_access_memory(load, up, pre, s8, half_imm); \
945 break; \
946 \
947 case 3: \
948 /* LDRSH rd, [rn + imm] */ \
949 arm_access_memory(load, up, pre, s16, half_imm); \
950 break; \
951 } \
952 } \
953 else \
954 { \
955 /* BICS rd, rn, reg_op */ \
956 arm_data_proc(bics, reg_flags, flags); \
957 } \
958 break; \
959 \
960 case 0x1E: \
961 if((opcode & 0x90) == 0x90) \
962 { \
963 /* STRH rd, [rn + imm]! */ \
964 arm_access_memory(store, up, pre_wb, u16, half_imm); \
965 } \
966 else \
967 { \
968 /* MVN rd, reg_op */ \
969 arm_data_proc_unary(mvn, reg, no_flags); \
970 } \
971 break; \
972 \
973 case 0x1F: \
974 if((opcode & 0x90) == 0x90) \
975 { \
976 switch((opcode >> 5) & 0x03) \
977 { \
978 case 1: \
979 /* LDRH rd, [rn + imm]! */ \
980 arm_access_memory(load, up, pre_wb, u16, half_imm); \
981 break; \
982 \
983 case 2: \
984 /* LDRSB rd, [rn + imm]! */ \
985 arm_access_memory(load, up, pre_wb, s8, half_imm); \
986 break; \
987 \
988 case 3: \
989 /* LDRSH rd, [rn + imm]! */ \
990 arm_access_memory(load, up, pre_wb, s16, half_imm); \
991 break; \
992 } \
993 } \
994 else \
995 { \
996 /* MVNS rd, rn, reg_op */ \
997 arm_data_proc_unary(mvns, reg_flags, flags); \
998 } \
999 break; \
1000 \
1001 case 0x20: \
1002 /* AND rd, rn, imm */ \
1003 arm_data_proc(and, imm, no_flags); \
1004 break; \
1005 \
1006 case 0x21: \
1007 /* ANDS rd, rn, imm */ \
1008 arm_data_proc(ands, imm_flags, flags); \
1009 break; \
1010 \
1011 case 0x22: \
1012 /* EOR rd, rn, imm */ \
1013 arm_data_proc(eor, imm, no_flags); \
1014 break; \
1015 \
1016 case 0x23: \
1017 /* EORS rd, rn, imm */ \
1018 arm_data_proc(eors, imm_flags, flags); \
1019 break; \
1020 \
1021 case 0x24: \
1022 /* SUB rd, rn, imm */ \
1023 arm_data_proc(sub, imm, no_flags); \
1024 break; \
1025 \
1026 case 0x25: \
1027 /* SUBS rd, rn, imm */ \
1028 arm_data_proc(subs, imm, flags); \
1029 break; \
1030 \
1031 case 0x26: \
1032 /* RSB rd, rn, imm */ \
1033 arm_data_proc(rsb, imm, no_flags); \
1034 break; \
1035 \
1036 case 0x27: \
1037 /* RSBS rd, rn, imm */ \
1038 arm_data_proc(rsbs, imm, flags); \
1039 break; \
1040 \
1041 case 0x28: \
1042 /* ADD rd, rn, imm */ \
1043 arm_data_proc(add, imm, no_flags); \
1044 break; \
1045 \
1046 case 0x29: \
1047 /* ADDS rd, rn, imm */ \
1048 arm_data_proc(adds, imm, flags); \
1049 break; \
1050 \
1051 case 0x2A: \
1052 /* ADC rd, rn, imm */ \
1053 arm_data_proc(adc, imm, no_flags); \
1054 break; \
1055 \
1056 case 0x2B: \
1057 /* ADCS rd, rn, imm */ \
1058 arm_data_proc(adcs, imm, flags); \
1059 break; \
1060 \
1061 case 0x2C: \
1062 /* SBC rd, rn, imm */ \
1063 arm_data_proc(sbc, imm, no_flags); \
1064 break; \
1065 \
1066 case 0x2D: \
1067 /* SBCS rd, rn, imm */ \
1068 arm_data_proc(sbcs, imm, flags); \
1069 break; \
1070 \
1071 case 0x2E: \
1072 /* RSC rd, rn, imm */ \
1073 arm_data_proc(rsc, imm, no_flags); \
1074 break; \
1075 \
1076 case 0x2F: \
1077 /* RSCS rd, rn, imm */ \
1078 arm_data_proc(rscs, imm, flags); \
1079 break; \
1080 \
1081 case 0x30 ... 0x31: \
1082 /* TST rn, imm */ \
1083 arm_data_proc_test(tst, imm); \
1084 break; \
1085 \
1086 case 0x32: \
1087 /* MSR cpsr, imm */ \
1088 arm_psr(imm, store, cpsr); \
1089 break; \
1090 \
1091 case 0x33: \
1092 /* TEQ rn, imm */ \
1093 arm_data_proc_test(teq, imm); \
1094 break; \
1095 \
1096 case 0x34 ... 0x35: \
1097 /* CMP rn, imm */ \
1098 arm_data_proc_test(cmp, imm); \
1099 break; \
1100 \
1101 case 0x36: \
1102 /* MSR spsr, imm */ \
1103 arm_psr(imm, store, spsr); \
1104 break; \
1105 \
1106 case 0x37: \
1107 /* CMN rn, imm */ \
1108 arm_data_proc_test(cmn, imm); \
1109 break; \
1110 \
1111 case 0x38: \
1112 /* ORR rd, rn, imm */ \
1113 arm_data_proc(orr, imm, no_flags); \
1114 break; \
1115 \
1116 case 0x39: \
1117 /* ORRS rd, rn, imm */ \
1118 arm_data_proc(orrs, imm_flags, flags); \
1119 break; \
1120 \
1121 case 0x3A: \
1122 /* MOV rd, imm */ \
1123 arm_data_proc_unary(mov, imm, no_flags); \
1124 break; \
1125 \
1126 case 0x3B: \
1127 /* MOVS rd, imm */ \
1128 arm_data_proc_unary(movs, imm_flags, flags); \
1129 break; \
1130 \
1131 case 0x3C: \
1132 /* BIC rd, rn, imm */ \
1133 arm_data_proc(bic, imm, no_flags); \
1134 break; \
1135 \
1136 case 0x3D: \
1137 /* BICS rd, rn, imm */ \
1138 arm_data_proc(bics, imm_flags, flags); \
1139 break; \
1140 \
1141 case 0x3E: \
1142 /* MVN rd, imm */ \
1143 arm_data_proc_unary(mvn, imm, no_flags); \
1144 break; \
1145 \
1146 case 0x3F: \
1147 /* MVNS rd, imm */ \
1148 arm_data_proc_unary(mvns, imm_flags, flags); \
1149 break; \
1150 \
1151 case 0x40: \
1152 /* STR rd, [rn], -imm */ \
1153 arm_access_memory(store, down, post, u32, imm); \
1154 break; \
1155 \
1156 case 0x41: \
1157 /* LDR rd, [rn], -imm */ \
1158 arm_access_memory(load, down, post, u32, imm); \
1159 break; \
1160 \
1161 case 0x42: \
1162 /* STRT rd, [rn], -imm */ \
1163 arm_access_memory(store, down, post, u32, imm); \
1164 break; \
1165 \
1166 case 0x43: \
1167 /* LDRT rd, [rn], -imm */ \
1168 arm_access_memory(load, down, post, u32, imm); \
1169 break; \
1170 \
1171 case 0x44: \
1172 /* STRB rd, [rn], -imm */ \
1173 arm_access_memory(store, down, post, u8, imm); \
1174 break; \
1175 \
1176 case 0x45: \
1177 /* LDRB rd, [rn], -imm */ \
1178 arm_access_memory(load, down, post, u8, imm); \
1179 break; \
1180 \
1181 case 0x46: \
1182 /* STRBT rd, [rn], -imm */ \
1183 arm_access_memory(store, down, post, u8, imm); \
1184 break; \
1185 \
1186 case 0x47: \
1187 /* LDRBT rd, [rn], -imm */ \
1188 arm_access_memory(load, down, post, u8, imm); \
1189 break; \
1190 \
1191 case 0x48: \
1192 /* STR rd, [rn], +imm */ \
1193 arm_access_memory(store, up, post, u32, imm); \
1194 break; \
1195 \
1196 case 0x49: \
1197 /* LDR rd, [rn], +imm */ \
1198 arm_access_memory(load, up, post, u32, imm); \
1199 break; \
1200 \
1201 case 0x4A: \
1202 /* STRT rd, [rn], +imm */ \
1203 arm_access_memory(store, up, post, u32, imm); \
1204 break; \
1205 \
1206 case 0x4B: \
1207 /* LDRT rd, [rn], +imm */ \
1208 arm_access_memory(load, up, post, u32, imm); \
1209 break; \
1210 \
1211 case 0x4C: \
1212 /* STRB rd, [rn], +imm */ \
1213 arm_access_memory(store, up, post, u8, imm); \
1214 break; \
1215 \
1216 case 0x4D: \
1217 /* LDRB rd, [rn], +imm */ \
1218 arm_access_memory(load, up, post, u8, imm); \
1219 break; \
1220 \
1221 case 0x4E: \
1222 /* STRBT rd, [rn], +imm */ \
1223 arm_access_memory(store, up, post, u8, imm); \
1224 break; \
1225 \
1226 case 0x4F: \
1227 /* LDRBT rd, [rn], +imm */ \
1228 arm_access_memory(load, up, post, u8, imm); \
1229 break; \
1230 \
1231 case 0x50: \
1232 /* STR rd, [rn - imm] */ \
1233 arm_access_memory(store, down, pre, u32, imm); \
1234 break; \
1235 \
1236 case 0x51: \
1237 /* LDR rd, [rn - imm] */ \
1238 arm_access_memory(load, down, pre, u32, imm); \
1239 break; \
1240 \
1241 case 0x52: \
1242 /* STR rd, [rn - imm]! */ \
1243 arm_access_memory(store, down, pre_wb, u32, imm); \
1244 break; \
1245 \
1246 case 0x53: \
1247 /* LDR rd, [rn - imm]! */ \
1248 arm_access_memory(load, down, pre_wb, u32, imm); \
1249 break; \
1250 \
1251 case 0x54: \
1252 /* STRB rd, [rn - imm] */ \
1253 arm_access_memory(store, down, pre, u8, imm); \
1254 break; \
1255 \
1256 case 0x55: \
1257 /* LDRB rd, [rn - imm] */ \
1258 arm_access_memory(load, down, pre, u8, imm); \
1259 break; \
1260 \
1261 case 0x56: \
1262 /* STRB rd, [rn - imm]! */ \
1263 arm_access_memory(store, down, pre_wb, u8, imm); \
1264 break; \
1265 \
1266 case 0x57: \
1267 /* LDRB rd, [rn - imm]! */ \
1268 arm_access_memory(load, down, pre_wb, u8, imm); \
1269 break; \
1270 \
1271 case 0x58: \
1272 /* STR rd, [rn + imm] */ \
1273 arm_access_memory(store, up, pre, u32, imm); \
1274 break; \
1275 \
1276 case 0x59: \
1277 /* LDR rd, [rn + imm] */ \
1278 arm_access_memory(load, up, pre, u32, imm); \
1279 break; \
1280 \
1281 case 0x5A: \
1282 /* STR rd, [rn + imm]! */ \
1283 arm_access_memory(store, up, pre_wb, u32, imm); \
1284 break; \
1285 \
1286 case 0x5B: \
1287 /* LDR rd, [rn + imm]! */ \
1288 arm_access_memory(load, up, pre_wb, u32, imm); \
1289 break; \
1290 \
1291 case 0x5C: \
1292 /* STRB rd, [rn + imm] */ \
1293 arm_access_memory(store, up, pre, u8, imm); \
1294 break; \
1295 \
1296 case 0x5D: \
1297 /* LDRB rd, [rn + imm] */ \
1298 arm_access_memory(load, up, pre, u8, imm); \
1299 break; \
1300 \
1301 case 0x5E: \
1302 /* STRB rd, [rn + imm]! */ \
1303 arm_access_memory(store, up, pre_wb, u8, imm); \
1304 break; \
1305 \
1306 case 0x5F: \
1307 /* LDRBT rd, [rn + imm]! */ \
1308 arm_access_memory(load, up, pre_wb, u8, imm); \
1309 break; \
1310 \
1311 case 0x60: \
1312 /* STR rd, [rn], -rm */ \
1313 arm_access_memory(store, down, post, u32, reg); \
1314 break; \
1315 \
1316 case 0x61: \
1317 /* LDR rd, [rn], -rm */ \
1318 arm_access_memory(load, down, post, u32, reg); \
1319 break; \
1320 \
1321 case 0x62: \
1322 /* STRT rd, [rn], -rm */ \
1323 arm_access_memory(store, down, post, u32, reg); \
1324 break; \
1325 \
1326 case 0x63: \
1327 /* LDRT rd, [rn], -rm */ \
1328 arm_access_memory(load, down, post, u32, reg); \
1329 break; \
1330 \
1331 case 0x64: \
1332 /* STRB rd, [rn], -rm */ \
1333 arm_access_memory(store, down, post, u8, reg); \
1334 break; \
1335 \
1336 case 0x65: \
1337 /* LDRB rd, [rn], -rm */ \
1338 arm_access_memory(load, down, post, u8, reg); \
1339 break; \
1340 \
1341 case 0x66: \
1342 /* STRBT rd, [rn], -rm */ \
1343 arm_access_memory(store, down, post, u8, reg); \
1344 break; \
1345 \
1346 case 0x67: \
1347 /* LDRBT rd, [rn], -rm */ \
1348 arm_access_memory(load, down, post, u8, reg); \
1349 break; \
1350 \
1351 case 0x68: \
1352 /* STR rd, [rn], +rm */ \
1353 arm_access_memory(store, up, post, u32, reg); \
1354 break; \
1355 \
1356 case 0x69: \
1357 /* LDR rd, [rn], +rm */ \
1358 arm_access_memory(load, up, post, u32, reg); \
1359 break; \
1360 \
1361 case 0x6A: \
1362 /* STRT rd, [rn], +rm */ \
1363 arm_access_memory(store, up, post, u32, reg); \
1364 break; \
1365 \
1366 case 0x6B: \
1367 /* LDRT rd, [rn], +rm */ \
1368 arm_access_memory(load, up, post, u32, reg); \
1369 break; \
1370 \
1371 case 0x6C: \
1372 /* STRB rd, [rn], +rm */ \
1373 arm_access_memory(store, up, post, u8, reg); \
1374 break; \
1375 \
1376 case 0x6D: \
1377 /* LDRB rd, [rn], +rm */ \
1378 arm_access_memory(load, up, post, u8, reg); \
1379 break; \
1380 \
1381 case 0x6E: \
1382 /* STRBT rd, [rn], +rm */ \
1383 arm_access_memory(store, up, post, u8, reg); \
1384 break; \
1385 \
1386 case 0x6F: \
1387 /* LDRBT rd, [rn], +rm */ \
1388 arm_access_memory(load, up, post, u8, reg); \
1389 break; \
1390 \
1391 case 0x70: \
1392 /* STR rd, [rn - rm] */ \
1393 arm_access_memory(store, down, pre, u32, reg); \
1394 break; \
1395 \
1396 case 0x71: \
1397 /* LDR rd, [rn - rm] */ \
1398 arm_access_memory(load, down, pre, u32, reg); \
1399 break; \
1400 \
1401 case 0x72: \
1402 /* STR rd, [rn - rm]! */ \
1403 arm_access_memory(store, down, pre_wb, u32, reg); \
1404 break; \
1405 \
1406 case 0x73: \
1407 /* LDR rd, [rn - rm]! */ \
1408 arm_access_memory(load, down, pre_wb, u32, reg); \
1409 break; \
1410 \
1411 case 0x74: \
1412 /* STRB rd, [rn - rm] */ \
1413 arm_access_memory(store, down, pre, u8, reg); \
1414 break; \
1415 \
1416 case 0x75: \
1417 /* LDRB rd, [rn - rm] */ \
1418 arm_access_memory(load, down, pre, u8, reg); \
1419 break; \
1420 \
1421 case 0x76: \
1422 /* STRB rd, [rn - rm]! */ \
1423 arm_access_memory(store, down, pre_wb, u8, reg); \
1424 break; \
1425 \
1426 case 0x77: \
1427 /* LDRB rd, [rn - rm]! */ \
1428 arm_access_memory(load, down, pre_wb, u8, reg); \
1429 break; \
1430 \
1431 case 0x78: \
1432 /* STR rd, [rn + rm] */ \
1433 arm_access_memory(store, up, pre, u32, reg); \
1434 break; \
1435 \
1436 case 0x79: \
1437 /* LDR rd, [rn + rm] */ \
1438 arm_access_memory(load, up, pre, u32, reg); \
1439 break; \
1440 \
1441 case 0x7A: \
1442 /* STR rd, [rn + rm]! */ \
1443 arm_access_memory(store, up, pre_wb, u32, reg); \
1444 break; \
1445 \
1446 case 0x7B: \
1447 /* LDR rd, [rn + rm]! */ \
1448 arm_access_memory(load, up, pre_wb, u32, reg); \
1449 break; \
1450 \
1451 case 0x7C: \
1452 /* STRB rd, [rn + rm] */ \
1453 arm_access_memory(store, up, pre, u8, reg); \
1454 break; \
1455 \
1456 case 0x7D: \
1457 /* LDRB rd, [rn + rm] */ \
1458 arm_access_memory(load, up, pre, u8, reg); \
1459 break; \
1460 \
1461 case 0x7E: \
1462 /* STRB rd, [rn + rm]! */ \
1463 arm_access_memory(store, up, pre_wb, u8, reg); \
1464 break; \
1465 \
1466 case 0x7F: \
1467 /* LDRBT rd, [rn + rm]! */ \
1468 arm_access_memory(load, up, pre_wb, u8, reg); \
1469 break; \
1470 \
1471 case 0x80: \
1472 /* STMDA rn, rlist */ \
1473 arm_block_memory(store, down_a, no, no); \
1474 break; \
1475 \
1476 case 0x81: \
1477 /* LDMDA rn, rlist */ \
1478 arm_block_memory(load, down_a, no, no); \
1479 break; \
1480 \
1481 case 0x82: \
1482 /* STMDA rn!, rlist */ \
1483 arm_block_memory(store, down_a, down, no); \
1484 break; \
1485 \
1486 case 0x83: \
1487 /* LDMDA rn!, rlist */ \
1488 arm_block_memory(load, down_a, down, no); \
1489 break; \
1490 \
1491 case 0x84: \
1492 /* STMDA rn, rlist^ */ \
1493 arm_block_memory(store, down_a, no, yes); \
1494 break; \
1495 \
1496 case 0x85: \
1497 /* LDMDA rn, rlist^ */ \
1498 arm_block_memory(load, down_a, no, yes); \
1499 break; \
1500 \
1501 case 0x86: \
1502 /* STMDA rn!, rlist^ */ \
1503 arm_block_memory(store, down_a, down, yes); \
1504 break; \
1505 \
1506 case 0x87: \
1507 /* LDMDA rn!, rlist^ */ \
1508 arm_block_memory(load, down_a, down, yes); \
1509 break; \
1510 \
1511 case 0x88: \
1512 /* STMIA rn, rlist */ \
1513 arm_block_memory(store, no, no, no); \
1514 break; \
1515 \
1516 case 0x89: \
1517 /* LDMIA rn, rlist */ \
1518 arm_block_memory(load, no, no, no); \
1519 break; \
1520 \
1521 case 0x8A: \
1522 /* STMIA rn!, rlist */ \
1523 arm_block_memory(store, no, up, no); \
1524 break; \
1525 \
1526 case 0x8B: \
1527 /* LDMIA rn!, rlist */ \
1528 arm_block_memory(load, no, up, no); \
1529 break; \
1530 \
1531 case 0x8C: \
1532 /* STMIA rn, rlist^ */ \
1533 arm_block_memory(store, no, no, yes); \
1534 break; \
1535 \
1536 case 0x8D: \
1537 /* LDMIA rn, rlist^ */ \
1538 arm_block_memory(load, no, no, yes); \
1539 break; \
1540 \
1541 case 0x8E: \
1542 /* STMIA rn!, rlist^ */ \
1543 arm_block_memory(store, no, up, yes); \
1544 break; \
1545 \
1546 case 0x8F: \
1547 /* LDMIA rn!, rlist^ */ \
1548 arm_block_memory(load, no, up, yes); \
1549 break; \
1550 \
1551 case 0x90: \
1552 /* STMDB rn, rlist */ \
1553 arm_block_memory(store, down_b, no, no); \
1554 break; \
1555 \
1556 case 0x91: \
1557 /* LDMDB rn, rlist */ \
1558 arm_block_memory(load, down_b, no, no); \
1559 break; \
1560 \
1561 case 0x92: \
1562 /* STMDB rn!, rlist */ \
1563 arm_block_memory(store, down_b, down, no); \
1564 break; \
1565 \
1566 case 0x93: \
1567 /* LDMDB rn!, rlist */ \
1568 arm_block_memory(load, down_b, down, no); \
1569 break; \
1570 \
1571 case 0x94: \
1572 /* STMDB rn, rlist^ */ \
1573 arm_block_memory(store, down_b, no, yes); \
1574 break; \
1575 \
1576 case 0x95: \
1577 /* LDMDB rn, rlist^ */ \
1578 arm_block_memory(load, down_b, no, yes); \
1579 break; \
1580 \
1581 case 0x96: \
1582 /* STMDB rn!, rlist^ */ \
1583 arm_block_memory(store, down_b, down, yes); \
1584 break; \
1585 \
1586 case 0x97: \
1587 /* LDMDB rn!, rlist^ */ \
1588 arm_block_memory(load, down_b, down, yes); \
1589 break; \
1590 \
1591 case 0x98: \
1592 /* STMIB rn, rlist */ \
1593 arm_block_memory(store, up, no, no); \
1594 break; \
1595 \
1596 case 0x99: \
1597 /* LDMIB rn, rlist */ \
1598 arm_block_memory(load, up, no, no); \
1599 break; \
1600 \
1601 case 0x9A: \
1602 /* STMIB rn!, rlist */ \
1603 arm_block_memory(store, up, up, no); \
1604 break; \
1605 \
1606 case 0x9B: \
1607 /* LDMIB rn!, rlist */ \
1608 arm_block_memory(load, up, up, no); \
1609 break; \
1610 \
1611 case 0x9C: \
1612 /* STMIB rn, rlist^ */ \
1613 arm_block_memory(store, up, no, yes); \
1614 break; \
1615 \
1616 case 0x9D: \
1617 /* LDMIB rn, rlist^ */ \
1618 arm_block_memory(load, up, no, yes); \
1619 break; \
1620 \
1621 case 0x9E: \
1622 /* STMIB rn!, rlist^ */ \
1623 arm_block_memory(store, up, up, yes); \
1624 break; \
1625 \
1626 case 0x9F: \
1627 /* LDMIB rn!, rlist^ */ \
1628 arm_block_memory(load, up, up, yes); \
1629 break; \
1630 \
1631 case 0xA0 ... 0xAF: \
1632 { \
1633 /* B offset */ \
1634 arm_b(); \
1635 break; \
1636 } \
1637 \
1638 case 0xB0 ... 0xBF: \
1639 { \
1640 /* BL offset */ \
1641 arm_bl(); \
1642 break; \
1643 } \
1644 \
1645 case 0xC0 ... 0xEF: \
1646 /* coprocessor instructions, reserved on GBA */ \
1647 break; \
1648 \
1649 case 0xF0 ... 0xFF: \
1650 { \
1651 /* SWI comment */ \
1652 arm_swi(); \
1653 break; \
1654 } \
1655 } \
1656 \
1657 pc += 4 \
1658
1659#define arm_flag_status() \
1660
1661#define translate_thumb_instruction() \
1662 flag_status = block_data[block_data_position].flag_data; \
1663 check_pc_region(pc); \
1664 last_opcode = opcode; \
1665 opcode = address16(pc_address_block, (pc & 0x7FFF)); \
1666 \
1667 switch((opcode >> 8) & 0xFF) \
1668 { \
1669 case 0x00 ... 0x07: \
1670 /* LSL rd, rs, imm */ \
1671 thumb_shift(shift, lsl, imm); \
1672 break; \
1673 \
1674 case 0x08 ... 0x0F: \
1675 /* LSR rd, rs, imm */ \
1676 thumb_shift(shift, lsr, imm); \
1677 break; \
1678 \
1679 case 0x10 ... 0x17: \
1680 /* ASR rd, rs, imm */ \
1681 thumb_shift(shift, asr, imm); \
1682 break; \
1683 \
1684 case 0x18 ... 0x19: \
1685 /* ADD rd, rs, rn */ \
1686 thumb_data_proc(add_sub, adds, reg, rd, rs, rn); \
1687 break; \
1688 \
1689 case 0x1A ... 0x1B: \
1690 /* SUB rd, rs, rn */ \
1691 thumb_data_proc(add_sub, subs, reg, rd, rs, rn); \
1692 break; \
1693 \
1694 case 0x1C ... 0x1D: \
1695 /* ADD rd, rs, imm */ \
1696 thumb_data_proc(add_sub_imm, adds, imm, rd, rs, imm); \
1697 break; \
1698 \
1699 case 0x1E ... 0x1F: \
1700 /* SUB rd, rs, imm */ \
1701 thumb_data_proc(add_sub_imm, subs, imm, rd, rs, imm); \
1702 break; \
1703 \
1704 case 0x20: \
1705 /* MOV r0, imm */ \
1706 thumb_data_proc_unary(imm, movs, imm, 0, imm); \
1707 break; \
1708 \
1709 case 0x21: \
1710 /* MOV r1, imm */ \
1711 thumb_data_proc_unary(imm, movs, imm, 1, imm); \
1712 break; \
1713 \
1714 case 0x22: \
1715 /* MOV r2, imm */ \
1716 thumb_data_proc_unary(imm, movs, imm, 2, imm); \
1717 break; \
1718 \
1719 case 0x23: \
1720 /* MOV r3, imm */ \
1721 thumb_data_proc_unary(imm, movs, imm, 3, imm); \
1722 break; \
1723 \
1724 case 0x24: \
1725 /* MOV r4, imm */ \
1726 thumb_data_proc_unary(imm, movs, imm, 4, imm); \
1727 break; \
1728 \
1729 case 0x25: \
1730 /* MOV r5, imm */ \
1731 thumb_data_proc_unary(imm, movs, imm, 5, imm); \
1732 break; \
1733 \
1734 case 0x26: \
1735 /* MOV r6, imm */ \
1736 thumb_data_proc_unary(imm, movs, imm, 6, imm); \
1737 break; \
1738 \
1739 case 0x27: \
1740 /* MOV r7, imm */ \
1741 thumb_data_proc_unary(imm, movs, imm, 7, imm); \
1742 break; \
1743 \
1744 case 0x28: \
1745 /* CMP r0, imm */ \
1746 thumb_data_proc_test(imm, cmp, imm, 0, imm); \
1747 break; \
1748 \
1749 case 0x29: \
1750 /* CMP r1, imm */ \
1751 thumb_data_proc_test(imm, cmp, imm, 1, imm); \
1752 break; \
1753 \
1754 case 0x2A: \
1755 /* CMP r2, imm */ \
1756 thumb_data_proc_test(imm, cmp, imm, 2, imm); \
1757 break; \
1758 \
1759 case 0x2B: \
1760 /* CMP r3, imm */ \
1761 thumb_data_proc_test(imm, cmp, imm, 3, imm); \
1762 break; \
1763 \
1764 case 0x2C: \
1765 /* CMP r4, imm */ \
1766 thumb_data_proc_test(imm, cmp, imm, 4, imm); \
1767 break; \
1768 \
1769 case 0x2D: \
1770 /* CMP r5, imm */ \
1771 thumb_data_proc_test(imm, cmp, imm, 5, imm); \
1772 break; \
1773 \
1774 case 0x2E: \
1775 /* CMP r6, imm */ \
1776 thumb_data_proc_test(imm, cmp, imm, 6, imm); \
1777 break; \
1778 \
1779 case 0x2F: \
1780 /* CMP r7, imm */ \
1781 thumb_data_proc_test(imm, cmp, imm, 7, imm); \
1782 break; \
1783 \
1784 case 0x30: \
1785 /* ADD r0, imm */ \
1786 thumb_data_proc(imm, adds, imm, 0, 0, imm); \
1787 break; \
1788 \
1789 case 0x31: \
1790 /* ADD r1, imm */ \
1791 thumb_data_proc(imm, adds, imm, 1, 1, imm); \
1792 break; \
1793 \
1794 case 0x32: \
1795 /* ADD r2, imm */ \
1796 thumb_data_proc(imm, adds, imm, 2, 2, imm); \
1797 break; \
1798 \
1799 case 0x33: \
1800 /* ADD r3, imm */ \
1801 thumb_data_proc(imm, adds, imm, 3, 3, imm); \
1802 break; \
1803 \
1804 case 0x34: \
1805 /* ADD r4, imm */ \
1806 thumb_data_proc(imm, adds, imm, 4, 4, imm); \
1807 break; \
1808 \
1809 case 0x35: \
1810 /* ADD r5, imm */ \
1811 thumb_data_proc(imm, adds, imm, 5, 5, imm); \
1812 break; \
1813 \
1814 case 0x36: \
1815 /* ADD r6, imm */ \
1816 thumb_data_proc(imm, adds, imm, 6, 6, imm); \
1817 break; \
1818 \
1819 case 0x37: \
1820 /* ADD r7, imm */ \
1821 thumb_data_proc(imm, adds, imm, 7, 7, imm); \
1822 break; \
1823 \
1824 case 0x38: \
1825 /* SUB r0, imm */ \
1826 thumb_data_proc(imm, subs, imm, 0, 0, imm); \
1827 break; \
1828 \
1829 case 0x39: \
1830 /* SUB r1, imm */ \
1831 thumb_data_proc(imm, subs, imm, 1, 1, imm); \
1832 break; \
1833 \
1834 case 0x3A: \
1835 /* SUB r2, imm */ \
1836 thumb_data_proc(imm, subs, imm, 2, 2, imm); \
1837 break; \
1838 \
1839 case 0x3B: \
1840 /* SUB r3, imm */ \
1841 thumb_data_proc(imm, subs, imm, 3, 3, imm); \
1842 break; \
1843 \
1844 case 0x3C: \
1845 /* SUB r4, imm */ \
1846 thumb_data_proc(imm, subs, imm, 4, 4, imm); \
1847 break; \
1848 \
1849 case 0x3D: \
1850 /* SUB r5, imm */ \
1851 thumb_data_proc(imm, subs, imm, 5, 5, imm); \
1852 break; \
1853 \
1854 case 0x3E: \
1855 /* SUB r6, imm */ \
1856 thumb_data_proc(imm, subs, imm, 6, 6, imm); \
1857 break; \
1858 \
1859 case 0x3F: \
1860 /* SUB r7, imm */ \
1861 thumb_data_proc(imm, subs, imm, 7, 7, imm); \
1862 break; \
1863 \
1864 case 0x40: \
1865 switch((opcode >> 6) & 0x03) \
1866 { \
1867 case 0x00: \
1868 /* AND rd, rs */ \
1869 thumb_data_proc(alu_op, ands, reg, rd, rd, rs); \
1870 break; \
1871 \
1872 case 0x01: \
1873 /* EOR rd, rs */ \
1874 thumb_data_proc(alu_op, eors, reg, rd, rd, rs); \
1875 break; \
1876 \
1877 case 0x02: \
1878 /* LSL rd, rs */ \
1879 thumb_shift(alu_op, lsl, reg); \
1880 break; \
1881 \
1882 case 0x03: \
1883 /* LSR rd, rs */ \
1884 thumb_shift(alu_op, lsr, reg); \
1885 break; \
1886 } \
1887 break; \
1888 \
1889 case 0x41: \
1890 switch((opcode >> 6) & 0x03) \
1891 { \
1892 case 0x00: \
1893 /* ASR rd, rs */ \
1894 thumb_shift(alu_op, asr, reg); \
1895 break; \
1896 \
1897 case 0x01: \
1898 /* ADC rd, rs */ \
1899 thumb_data_proc(alu_op, adcs, reg, rd, rd, rs); \
1900 break; \
1901 \
1902 case 0x02: \
1903 /* SBC rd, rs */ \
1904 thumb_data_proc(alu_op, sbcs, reg, rd, rd, rs); \
1905 break; \
1906 \
1907 case 0x03: \
1908 /* ROR rd, rs */ \
1909 thumb_shift(alu_op, ror, reg); \
1910 break; \
1911 } \
1912 break; \
1913 \
1914 case 0x42: \
1915 switch((opcode >> 6) & 0x03) \
1916 { \
1917 case 0x00: \
1918 /* TST rd, rs */ \
1919 thumb_data_proc_test(alu_op, tst, reg, rd, rs); \
1920 break; \
1921 \
1922 case 0x01: \
1923 /* NEG rd, rs */ \
1924 thumb_data_proc_unary(alu_op, neg, reg, rd, rs); \
1925 break; \
1926 \
1927 case 0x02: \
1928 /* CMP rd, rs */ \
1929 thumb_data_proc_test(alu_op, cmp, reg, rd, rs); \
1930 break; \
1931 \
1932 case 0x03: \
1933 /* CMN rd, rs */ \
1934 thumb_data_proc_test(alu_op, cmn, reg, rd, rs); \
1935 break; \
1936 } \
1937 break; \
1938 \
1939 case 0x43: \
1940 switch((opcode >> 6) & 0x03) \
1941 { \
1942 case 0x00: \
1943 /* ORR rd, rs */ \
1944 thumb_data_proc(alu_op, orrs, reg, rd, rd, rs); \
1945 break; \
1946 \
1947 case 0x01: \
1948 /* MUL rd, rs */ \
1949 thumb_data_proc(alu_op, muls, reg, rd, rd, rs); \
1950 break; \
1951 \
1952 case 0x02: \
1953 /* BIC rd, rs */ \
1954 thumb_data_proc(alu_op, bics, reg, rd, rd, rs); \
1955 break; \
1956 \
1957 case 0x03: \
1958 /* MVN rd, rs */ \
1959 thumb_data_proc_unary(alu_op, mvns, reg, rd, rs); \
1960 break; \
1961 } \
1962 break; \
1963 \
1964 case 0x44: \
1965 /* ADD rd, rs */ \
1966 thumb_data_proc_hi(add); \
1967 break; \
1968 \
1969 case 0x45: \
1970 /* CMP rd, rs */ \
1971 thumb_data_proc_test_hi(cmp); \
1972 break; \
1973 \
1974 case 0x46: \
1975 /* MOV rd, rs */ \
1976 thumb_data_proc_mov_hi(); \
1977 break; \
1978 \
1979 case 0x47: \
1980 /* BX rs */ \
1981 thumb_bx(); \
1982 break; \
1983 \
1984 case 0x48: \
1985 /* LDR r0, [pc + imm] */ \
1986 thumb_access_memory(load, imm, 0, 0, 0, pc_relative, \
1987 (pc & ~2) + (imm * 4) + 4, u32); \
1988 break; \
1989 \
1990 case 0x49: \
1991 /* LDR r1, [pc + imm] */ \
1992 thumb_access_memory(load, imm, 1, 0, 0, pc_relative, \
1993 (pc & ~2) + (imm * 4) + 4, u32); \
1994 break; \
1995 \
1996 case 0x4A: \
1997 /* LDR r2, [pc + imm] */ \
1998 thumb_access_memory(load, imm, 2, 0, 0, pc_relative, \
1999 (pc & ~2) + (imm * 4) + 4, u32); \
2000 break; \
2001 \
2002 case 0x4B: \
2003 /* LDR r3, [pc + imm] */ \
2004 thumb_access_memory(load, imm, 3, 0, 0, pc_relative, \
2005 (pc & ~2) + (imm * 4) + 4, u32); \
2006 break; \
2007 \
2008 case 0x4C: \
2009 /* LDR r4, [pc + imm] */ \
2010 thumb_access_memory(load, imm, 4, 0, 0, pc_relative, \
2011 (pc & ~2) + (imm * 4) + 4, u32); \
2012 break; \
2013 \
2014 case 0x4D: \
2015 /* LDR r5, [pc + imm] */ \
2016 thumb_access_memory(load, imm, 5, 0, 0, pc_relative, \
2017 (pc & ~2) + (imm * 4) + 4, u32); \
2018 break; \
2019 \
2020 case 0x4E: \
2021 /* LDR r6, [pc + imm] */ \
2022 thumb_access_memory(load, imm, 6, 0, 0, pc_relative, \
2023 (pc & ~2) + (imm * 4) + 4, u32); \
2024 break; \
2025 \
2026 case 0x4F: \
2027 /* LDR r7, [pc + imm] */ \
2028 thumb_access_memory(load, imm, 7, 0, 0, pc_relative, \
2029 (pc & ~2) + (imm * 4) + 4, u32); \
2030 break; \
2031 \
2032 case 0x50 ... 0x51: \
2033 /* STR rd, [rb + ro] */ \
2034 thumb_access_memory(store, mem_reg, rd, rb, ro, reg_reg, 0, u32); \
2035 break; \
2036 \
2037 case 0x52 ... 0x53: \
2038 /* STRH rd, [rb + ro] */ \
2039 thumb_access_memory(store, mem_reg, rd, rb, ro, reg_reg, 0, u16); \
2040 break; \
2041 \
2042 case 0x54 ... 0x55: \
2043 /* STRB rd, [rb + ro] */ \
2044 thumb_access_memory(store, mem_reg, rd, rb, ro, reg_reg, 0, u8); \
2045 break; \
2046 \
2047 case 0x56 ... 0x57: \
2048 /* LDSB rd, [rb + ro] */ \
2049 thumb_access_memory(load, mem_reg, rd, rb, ro, reg_reg, 0, s8); \
2050 break; \
2051 \
2052 case 0x58 ... 0x59: \
2053 /* LDR rd, [rb + ro] */ \
2054 thumb_access_memory(load, mem_reg, rd, rb, ro, reg_reg, 0, u32); \
2055 break; \
2056 \
2057 case 0x5A ... 0x5B: \
2058 /* LDRH rd, [rb + ro] */ \
2059 thumb_access_memory(load, mem_reg, rd, rb, ro, reg_reg, 0, u16); \
2060 break; \
2061 \
2062 case 0x5C ... 0x5D: \
2063 /* LDRB rd, [rb + ro] */ \
2064 thumb_access_memory(load, mem_reg, rd, rb, ro, reg_reg, 0, u8); \
2065 break; \
2066 \
2067 case 0x5E ... 0x5F: \
2068 /* LDSH rd, [rb + ro] */ \
2069 thumb_access_memory(load, mem_reg, rd, rb, ro, reg_reg, 0, s16); \
2070 break; \
2071 \
2072 case 0x60 ... 0x67: \
2073 /* STR rd, [rb + imm] */ \
2074 thumb_access_memory(store, mem_imm, rd, rb, 0, reg_imm, (imm * 4), \
2075 u32); \
2076 break; \
2077 \
2078 case 0x68 ... 0x6F: \
2079 /* LDR rd, [rb + imm] */ \
2080 thumb_access_memory(load, mem_imm, rd, rb, 0, reg_imm, (imm * 4), u32); \
2081 break; \
2082 \
2083 case 0x70 ... 0x77: \
2084 /* STRB rd, [rb + imm] */ \
2085 thumb_access_memory(store, mem_imm, rd, rb, 0, reg_imm, imm, u8); \
2086 break; \
2087 \
2088 case 0x78 ... 0x7F: \
2089 /* LDRB rd, [rb + imm] */ \
2090 thumb_access_memory(load, mem_imm, rd, rb, 0, reg_imm, imm, u8); \
2091 break; \
2092 \
2093 case 0x80 ... 0x87: \
2094 /* STRH rd, [rb + imm] */ \
2095 thumb_access_memory(store, mem_imm, rd, rb, 0, reg_imm, \
2096 (imm * 2), u16); \
2097 break; \
2098 \
2099 case 0x88 ... 0x8F: \
2100 /* LDRH rd, [rb + imm] */ \
2101 thumb_access_memory(load, mem_imm, rd, rb, 0, reg_imm, (imm * 2), u16); \
2102 break; \
2103 \
2104 case 0x90: \
2105 /* STR r0, [sp + imm] */ \
2106 thumb_access_memory(store, imm, 0, 13, 0, reg_imm_sp, imm, u32); \
2107 break; \
2108 \
2109 case 0x91: \
2110 /* STR r1, [sp + imm] */ \
2111 thumb_access_memory(store, imm, 1, 13, 0, reg_imm_sp, imm, u32); \
2112 break; \
2113 \
2114 case 0x92: \
2115 /* STR r2, [sp + imm] */ \
2116 thumb_access_memory(store, imm, 2, 13, 0, reg_imm_sp, imm, u32); \
2117 break; \
2118 \
2119 case 0x93: \
2120 /* STR r3, [sp + imm] */ \
2121 thumb_access_memory(store, imm, 3, 13, 0, reg_imm_sp, imm, u32); \
2122 break; \
2123 \
2124 case 0x94: \
2125 /* STR r4, [sp + imm] */ \
2126 thumb_access_memory(store, imm, 4, 13, 0, reg_imm_sp, imm, u32); \
2127 break; \
2128 \
2129 case 0x95: \
2130 /* STR r5, [sp + imm] */ \
2131 thumb_access_memory(store, imm, 5, 13, 0, reg_imm_sp, imm, u32); \
2132 break; \
2133 \
2134 case 0x96: \
2135 /* STR r6, [sp + imm] */ \
2136 thumb_access_memory(store, imm, 6, 13, 0, reg_imm_sp, imm, u32); \
2137 break; \
2138 \
2139 case 0x97: \
2140 /* STR r7, [sp + imm] */ \
2141 thumb_access_memory(store, imm, 7, 13, 0, reg_imm_sp, imm, u32); \
2142 break; \
2143 \
2144 case 0x98: \
2145 /* LDR r0, [sp + imm] */ \
2146 thumb_access_memory(load, imm, 0, 13, 0, reg_imm_sp, imm, u32); \
2147 break; \
2148 \
2149 case 0x99: \
2150 /* LDR r1, [sp + imm] */ \
2151 thumb_access_memory(load, imm, 1, 13, 0, reg_imm_sp, imm, u32); \
2152 break; \
2153 \
2154 case 0x9A: \
2155 /* LDR r2, [sp + imm] */ \
2156 thumb_access_memory(load, imm, 2, 13, 0, reg_imm_sp, imm, u32); \
2157 break; \
2158 \
2159 case 0x9B: \
2160 /* LDR r3, [sp + imm] */ \
2161 thumb_access_memory(load, imm, 3, 13, 0, reg_imm_sp, imm, u32); \
2162 break; \
2163 \
2164 case 0x9C: \
2165 /* LDR r4, [sp + imm] */ \
2166 thumb_access_memory(load, imm, 4, 13, 0, reg_imm_sp, imm, u32); \
2167 break; \
2168 \
2169 case 0x9D: \
2170 /* LDR r5, [sp + imm] */ \
2171 thumb_access_memory(load, imm, 5, 13, 0, reg_imm_sp, imm, u32); \
2172 break; \
2173 \
2174 case 0x9E: \
2175 /* LDR r6, [sp + imm] */ \
2176 thumb_access_memory(load, imm, 6, 13, 0, reg_imm_sp, imm, u32); \
2177 break; \
2178 \
2179 case 0x9F: \
2180 /* LDR r7, [sp + imm] */ \
2181 thumb_access_memory(load, imm, 7, 13, 0, reg_imm_sp, imm, u32); \
2182 break; \
2183 \
2184 case 0xA0: \
2185 /* ADD r0, pc, +imm */ \
2186 thumb_load_pc(0); \
2187 break; \
2188 \
2189 case 0xA1: \
2190 /* ADD r1, pc, +imm */ \
2191 thumb_load_pc(1); \
2192 break; \
2193 \
2194 case 0xA2: \
2195 /* ADD r2, pc, +imm */ \
2196 thumb_load_pc(2); \
2197 break; \
2198 \
2199 case 0xA3: \
2200 /* ADD r3, pc, +imm */ \
2201 thumb_load_pc(3); \
2202 break; \
2203 \
2204 case 0xA4: \
2205 /* ADD r4, pc, +imm */ \
2206 thumb_load_pc(4); \
2207 break; \
2208 \
2209 case 0xA5: \
2210 /* ADD r5, pc, +imm */ \
2211 thumb_load_pc(5); \
2212 break; \
2213 \
2214 case 0xA6: \
2215 /* ADD r6, pc, +imm */ \
2216 thumb_load_pc(6); \
2217 break; \
2218 \
2219 case 0xA7: \
2220 /* ADD r7, pc, +imm */ \
2221 thumb_load_pc(7); \
2222 break; \
2223 \
2224 case 0xA8: \
2225 /* ADD r0, sp, +imm */ \
2226 thumb_load_sp(0); \
2227 break; \
2228 \
2229 case 0xA9: \
2230 /* ADD r1, sp, +imm */ \
2231 thumb_load_sp(1); \
2232 break; \
2233 \
2234 case 0xAA: \
2235 /* ADD r2, sp, +imm */ \
2236 thumb_load_sp(2); \
2237 break; \
2238 \
2239 case 0xAB: \
2240 /* ADD r3, sp, +imm */ \
2241 thumb_load_sp(3); \
2242 break; \
2243 \
2244 case 0xAC: \
2245 /* ADD r4, sp, +imm */ \
2246 thumb_load_sp(4); \
2247 break; \
2248 \
2249 case 0xAD: \
2250 /* ADD r5, sp, +imm */ \
2251 thumb_load_sp(5); \
2252 break; \
2253 \
2254 case 0xAE: \
2255 /* ADD r6, sp, +imm */ \
2256 thumb_load_sp(6); \
2257 break; \
2258 \
2259 case 0xAF: \
2260 /* ADD r7, sp, +imm */ \
2261 thumb_load_sp(7); \
2262 break; \
2263 \
2264 case 0xB0 ... 0xB3: \
2265 if((opcode >> 7) & 0x01) \
2266 { \
2267 /* ADD sp, -imm */ \
2268 thumb_adjust_sp(down); \
2269 } \
2270 else \
2271 { \
2272 /* ADD sp, +imm */ \
2273 thumb_adjust_sp(up); \
2274 } \
2275 break; \
2276 \
2277 case 0xB4: \
2278 /* PUSH rlist */ \
2279 thumb_block_memory(store, down, no, 13); \
2280 break; \
2281 \
2282 case 0xB5: \
2283 /* PUSH rlist, lr */ \
2284 thumb_block_memory(store, push_lr, push_lr, 13); \
2285 break; \
2286 \
2287 case 0xBC: \
2288 /* POP rlist */ \
2289 thumb_block_memory(load, no, up, 13); \
2290 break; \
2291 \
2292 case 0xBD: \
2293 /* POP rlist, pc */ \
2294 thumb_block_memory(load, no, pop_pc, 13); \
2295 break; \
2296 \
2297 case 0xC0: \
2298 /* STMIA r0!, rlist */ \
2299 thumb_block_memory(store, no, up, 0); \
2300 break; \
2301 \
2302 case 0xC1: \
2303 /* STMIA r1!, rlist */ \
2304 thumb_block_memory(store, no, up, 1); \
2305 break; \
2306 \
2307 case 0xC2: \
2308 /* STMIA r2!, rlist */ \
2309 thumb_block_memory(store, no, up, 2); \
2310 break; \
2311 \
2312 case 0xC3: \
2313 /* STMIA r3!, rlist */ \
2314 thumb_block_memory(store, no, up, 3); \
2315 break; \
2316 \
2317 case 0xC4: \
2318 /* STMIA r4!, rlist */ \
2319 thumb_block_memory(store, no, up, 4); \
2320 break; \
2321 \
2322 case 0xC5: \
2323 /* STMIA r5!, rlist */ \
2324 thumb_block_memory(store, no, up, 5); \
2325 break; \
2326 \
2327 case 0xC6: \
2328 /* STMIA r6!, rlist */ \
2329 thumb_block_memory(store, no, up, 6); \
2330 break; \
2331 \
2332 case 0xC7: \
2333 /* STMIA r7!, rlist */ \
2334 thumb_block_memory(store, no, up, 7); \
2335 break; \
2336 \
2337 case 0xC8: \
2338 /* LDMIA r0!, rlist */ \
2339 thumb_block_memory(load, no, up, 0); \
2340 break; \
2341 \
2342 case 0xC9: \
2343 /* LDMIA r1!, rlist */ \
2344 thumb_block_memory(load, no, up, 1); \
2345 break; \
2346 \
2347 case 0xCA: \
2348 /* LDMIA r2!, rlist */ \
2349 thumb_block_memory(load, no, up, 2); \
2350 break; \
2351 \
2352 case 0xCB: \
2353 /* LDMIA r3!, rlist */ \
2354 thumb_block_memory(load, no, up, 3); \
2355 break; \
2356 \
2357 case 0xCC: \
2358 /* LDMIA r4!, rlist */ \
2359 thumb_block_memory(load, no, up, 4); \
2360 break; \
2361 \
2362 case 0xCD: \
2363 /* LDMIA r5!, rlist */ \
2364 thumb_block_memory(load, no, up, 5); \
2365 break; \
2366 \
2367 case 0xCE: \
2368 /* LDMIA r6!, rlist */ \
2369 thumb_block_memory(load, no, up, 6); \
2370 break; \
2371 \
2372 case 0xCF: \
2373 /* LDMIA r7!, rlist */ \
2374 thumb_block_memory(load, no, up, 7); \
2375 break; \
2376 \
2377 case 0xD0: \
2378 /* BEQ label */ \
2379 thumb_conditional_branch(eq); \
2380 break; \
2381 \
2382 case 0xD1: \
2383 /* BNE label */ \
2384 thumb_conditional_branch(ne); \
2385 break; \
2386 \
2387 case 0xD2: \
2388 /* BCS label */ \
2389 thumb_conditional_branch(cs); \
2390 break; \
2391 \
2392 case 0xD3: \
2393 /* BCC label */ \
2394 thumb_conditional_branch(cc); \
2395 break; \
2396 \
2397 case 0xD4: \
2398 /* BMI label */ \
2399 thumb_conditional_branch(mi); \
2400 break; \
2401 \
2402 case 0xD5: \
2403 /* BPL label */ \
2404 thumb_conditional_branch(pl); \
2405 break; \
2406 \
2407 case 0xD6: \
2408 /* BVS label */ \
2409 thumb_conditional_branch(vs); \
2410 break; \
2411 \
2412 case 0xD7: \
2413 /* BVC label */ \
2414 thumb_conditional_branch(vc); \
2415 break; \
2416 \
2417 case 0xD8: \
2418 /* BHI label */ \
2419 thumb_conditional_branch(hi); \
2420 break; \
2421 \
2422 case 0xD9: \
2423 /* BLS label */ \
2424 thumb_conditional_branch(ls); \
2425 break; \
2426 \
2427 case 0xDA: \
2428 /* BGE label */ \
2429 thumb_conditional_branch(ge); \
2430 break; \
2431 \
2432 case 0xDB: \
2433 /* BLT label */ \
2434 thumb_conditional_branch(lt); \
2435 break; \
2436 \
2437 case 0xDC: \
2438 /* BGT label */ \
2439 thumb_conditional_branch(gt); \
2440 break; \
2441 \
2442 case 0xDD: \
2443 /* BLE label */ \
2444 thumb_conditional_branch(le); \
2445 break; \
2446 \
2447 case 0xDF: \
2448 { \
2449 /* SWI comment */ \
2450 thumb_swi(); \
2451 break; \
2452 } \
2453 \
2454 case 0xE0 ... 0xE7: \
2455 { \
2456 /* B label */ \
2457 thumb_b(); \
2458 break; \
2459 } \
2460 \
2461 case 0xF0 ... 0xF7: \
2462 { \
2463 /* (low word) BL label */ \
2464 /* This should possibly generate code if not in conjunction with a BLH \
2465 next, but I don't think anyone will do that. */ \
2466 break; \
2467 } \
2468 \
2469 case 0xF8 ... 0xFF: \
2470 { \
2471 /* (high word) BL label */ \
2472 /* This might not be preceeding a BL low word (Golden Sun 2), if so \
2473 it must be handled like an indirect branch. */ \
2474 if((last_opcode >= 0xF000) && (last_opcode < 0xF800)) \
2475 { \
2476 thumb_bl(); \
2477 } \
2478 else \
2479 { \
2480 thumb_blh(); \
2481 } \
2482 break; \
2483 } \
2484 } \
2485 \
2486 pc += 2 \
2487
2488#define thumb_flag_modifies_all() \
2489 flag_status |= 0xFF \
2490
2491#define thumb_flag_modifies_zn() \
2492 flag_status |= 0xCC \
2493
2494#define thumb_flag_modifies_znc() \
2495 flag_status |= 0xEE \
2496
2497#define thumb_flag_modifies_zn_maybe_c() \
2498 flag_status |= 0xCE \
2499
2500#define thumb_flag_modifies_c() \
2501 flag_status |= 0x22 \
2502
2503#define thumb_flag_requires_c() \
2504 flag_status |= 0x200 \
2505
2506#define thumb_flag_requires_all() \
2507 flag_status |= 0xF00 \
2508
2509#define thumb_flag_status() \
2510{ \
2511 u16 flag_status = 0; \
2512 switch((opcode >> 8) & 0xFF) \
2513 { \
2514 /* left shift by imm */ \
2515 case 0x00 ... 0x07: \
2516 thumb_flag_modifies_zn(); \
2517 if(((opcode >> 6) & 0x1F) != 0) \
2518 { \
2519 thumb_flag_modifies_c(); \
2520 } \
2521 break; \
2522 \
2523 /* right shift by imm */ \
2524 case 0x08 ... 0x17: \
2525 thumb_flag_modifies_znc(); \
2526 break; \
2527 \
2528 /* add, subtract */ \
2529 case 0x18 ... 0x1F: \
2530 thumb_flag_modifies_all(); \
2531 break; \
2532 \
2533 /* mov reg, imm */ \
2534 case 0x20 ... 0x27: \
2535 thumb_flag_modifies_zn(); \
2536 break; \
2537 \
2538 /* cmp reg, imm; add, subtract */ \
2539 case 0x28 ... 0x3F: \
2540 thumb_flag_modifies_all(); \
2541 break; \
2542 \
2543 case 0x40: \
2544 switch((opcode >> 6) & 0x03) \
2545 { \
2546 case 0x00: \
2547 /* AND rd, rs */ \
2548 thumb_flag_modifies_zn(); \
2549 break; \
2550 \
2551 case 0x01: \
2552 /* EOR rd, rs */ \
2553 thumb_flag_modifies_zn(); \
2554 break; \
2555 \
2556 case 0x02: \
2557 /* LSL rd, rs */ \
2558 thumb_flag_modifies_zn_maybe_c(); \
2559 break; \
2560 \
2561 case 0x03: \
2562 /* LSR rd, rs */ \
2563 thumb_flag_modifies_zn_maybe_c(); \
2564 break; \
2565 } \
2566 break; \
2567 \
2568 case 0x41: \
2569 switch((opcode >> 6) & 0x03) \
2570 { \
2571 case 0x00: \
2572 /* ASR rd, rs */ \
2573 thumb_flag_modifies_zn_maybe_c(); \
2574 break; \
2575 \
2576 case 0x01: \
2577 /* ADC rd, rs */ \
2578 thumb_flag_modifies_all(); \
2579 thumb_flag_requires_c(); \
2580 break; \
2581 \
2582 case 0x02: \
2583 /* SBC rd, rs */ \
2584 thumb_flag_modifies_all(); \
2585 thumb_flag_requires_c(); \
2586 break; \
2587 \
2588 case 0x03: \
2589 /* ROR rd, rs */ \
2590 thumb_flag_modifies_zn_maybe_c(); \
2591 break; \
2592 } \
2593 break; \
2594 \
2595 /* TST, NEG, CMP, CMN */ \
2596 case 0x42: \
2597 thumb_flag_modifies_all(); \
2598 break; \
2599 \
2600 /* ORR, MUL, BIC, MVN */ \
2601 case 0x43: \
2602 thumb_flag_modifies_zn(); \
2603 break; \
2604 \
2605 case 0x45: \
2606 /* CMP rd, rs */ \
2607 thumb_flag_modifies_all(); \
2608 break; \
2609 \
2610 /* mov might change PC (fall through if so) */ \
2611 case 0x46: \
2612 if((opcode & 0xFF87) != 0x4687) \
2613 break; \
2614 \
2615 /* branches (can change PC) */ \
2616 case 0x47: \
2617 case 0xBD: \
2618 case 0xD0 ... 0xE7: \
2619 case 0xF0 ... 0xFF: \
2620 thumb_flag_requires_all(); \
2621 break; \
2622 } \
2623 block_data[block_data_position].flag_data = flag_status; \
2624} \
2625
2626u8 *ram_block_ptrs[1024 * 64];
2627u32 ram_block_tag_top = 0x0101;
2628
2629u8 *bios_block_ptrs[1024 * 8];
2630u32 bios_block_tag_top = 0x0101;
2631
2632// This function will return a pointer to a translated block of code. If it
2633// doesn't exist it will translate it, if it does it will pass it back.
2634
2635// type should be "arm", "thumb", or "dual." For arm or thumb the PC should
2636// be a real PC, for dual the least significant bit will determine if it's
2637// ARM or Thumb mode.
2638
2639#define block_lookup_address_pc_arm() \
2640 pc &= ~0x03
2641
2642#define block_lookup_address_pc_thumb() \
2643 pc &= ~0x01 \
2644
2645#define block_lookup_address_pc_dual() \
2646 u32 thumb = pc & 0x01; \
2647 \
2648 if(thumb) \
2649 { \
2650 pc--; \
2651 reg[REG_CPSR] |= 0x20; \
2652 } \
2653 else \
2654 { \
2655 pc = (pc + 2) & ~0x03; \
2656 reg[REG_CPSR] &= ~0x20; \
2657 } \
2658
2659#define ram_translation_region TRANSLATION_REGION_RAM
2660#define rom_translation_region TRANSLATION_REGION_ROM
2661#define bios_translation_region TRANSLATION_REGION_BIOS
2662
2663#define block_lookup_translate_arm(mem_type, smc_enable) \
2664 translation_result = translate_block_arm(pc, mem_type##_translation_region, \
2665 smc_enable) \
2666
2667#define block_lookup_translate_thumb(mem_type, smc_enable) \
2668 translation_result = translate_block_thumb(pc, \
2669 mem_type##_translation_region, smc_enable) \
2670
2671#define block_lookup_translate_dual(mem_type, smc_enable) \
2672 if(thumb) \
2673 { \
2674 translation_result = translate_block_thumb(pc, \
2675 mem_type##_translation_region, smc_enable); \
2676 } \
2677 else \
2678 { \
2679 translation_result = translate_block_arm(pc, \
2680 mem_type##_translation_region, smc_enable); \
2681 } \
2682
2683// 0x0101 is the smallest tag that can be used. 0xFFFF is marked
2684// in the middle of blocks and used for write guarding, it doesn't
2685// indicate a valid block either (it's okay to compile a new block
2686// that overlaps the earlier one, although this should be relatively
2687// uncommon)
2688
2689#define fill_tag_arm(mem_type) \
2690 location[0] = mem_type##_block_tag_top; \
2691 location[1] = 0xFFFF \
2692
2693#define fill_tag_thumb(mem_type) \
2694 *location = mem_type##_block_tag_top \
2695
2696#define fill_tag_dual(mem_type) \
2697 if(thumb) \
2698 fill_tag_thumb(mem_type); \
2699 else \
2700 fill_tag_arm(mem_type) \
2701
2702#define block_lookup_translate(instruction_type, mem_type, smc_enable) \
2703 block_tag = *location; \
2704 if((block_tag < 0x0101) || (block_tag == 0xFFFF)) \
2705 { \
2706 __label__ redo; \
2707 s32 translation_result; \
2708 \
2709 redo: \
2710 \
2711 translation_recursion_level++; \
2712 block_address = mem_type##_translation_ptr + block_prologue_size; \
2713 mem_type##_block_ptrs[mem_type##_block_tag_top] = block_address; \
2714 fill_tag_##instruction_type(mem_type); \
2715 mem_type##_block_tag_top++; \
2716 \
2717 block_lookup_translate_##instruction_type(mem_type, smc_enable); \
2718 translation_recursion_level--; \
2719 \
2720 /* If the translation failed then pass that failure on if we're in \
2721 a recursive level, or try again if we've hit the bottom. */ \
2722 if(translation_result == -1) \
2723 { \
2724 if(translation_recursion_level) \
2725 return NULL; \
2726 \
2727 goto redo; \
2728 } \
2729 \
2730 if(translation_recursion_level == 0) \
2731 translate_invalidate_dcache(); \
2732 } \
2733 else \
2734 { \
2735 block_address = mem_type##_block_ptrs[block_tag]; \
2736 } \
2737
2738u32 translation_recursion_level = 0;
2739u32 translation_flush_count = 0;
2740
2741
2742#define block_lookup_address_builder(type) \
2743u8 function_cc *block_lookup_address_##type(u32 pc) \
2744{ \
2745 u16 *location; \
2746 u32 block_tag; \
2747 u8 *block_address; \
2748 \
2749 /* Starting at the beginning, we allow for one translation cache flush. */ \
2750 if(translation_recursion_level == 0) \
2751 translation_flush_count = 0; \
2752 block_lookup_address_pc_##type(); \
2753 \
2754 switch(pc >> 24) \
2755 { \
2756 case 0x0: \
2757 bios_region_read_allow(); \
2758 location = (u16 *)(bios_rom + pc + 0x4000); \
2759 block_lookup_translate(type, bios, 0); \
2760 if(translation_recursion_level == 0) \
2761 bios_region_read_allow(); \
2762 break; \
2763 \
2764 case 0x2: \
2765 location = (u16 *)(ewram + (pc & 0x7FFF) + ((pc & 0x38000) * 2)); \
2766 block_lookup_translate(type, ram, 1); \
2767 if(translation_recursion_level == 0) \
2768 bios_region_read_protect(); \
2769 break; \
2770 \
2771 case 0x3: \
2772 location = (u16 *)(iwram + (pc & 0x7FFF)); \
2773 block_lookup_translate(type, ram, 1); \
2774 if(translation_recursion_level == 0) \
2775 bios_region_read_protect(); \
2776 break; \
2777 \
2778 case 0x8 ... 0xD: \
2779 { \
2780 u32 hash_target = ((pc * 2654435761U) >> 16) & \
2781 (ROM_BRANCH_HASH_SIZE - 1); \
2782 u32 *block_ptr = rom_branch_hash[hash_target]; \
2783 u32 **block_ptr_address = rom_branch_hash + hash_target; \
2784 \
2785 while(block_ptr) \
2786 { \
2787 if(block_ptr[0] == pc) \
2788 { \
2789 block_address = (u8 *)(block_ptr + 2) + block_prologue_size; \
2790 break; \
2791 } \
2792 \
2793 block_ptr_address = (u32 **)(block_ptr + 1); \
2794 block_ptr = (u32 *)block_ptr[1]; \
2795 } \
2796 \
2797 if(block_ptr == NULL) \
2798 { \
2799 __label__ redo; \
2800 s32 translation_result; \
2801 \
2802 redo: \
2803 \
2804 translation_recursion_level++; \
2805 ((u32 *)rom_translation_ptr)[0] = pc; \
2806 ((u32 **)rom_translation_ptr)[1] = NULL; \
2807 *block_ptr_address = (u32 *)rom_translation_ptr; \
2808 rom_translation_ptr += 8; \
2809 block_address = rom_translation_ptr + block_prologue_size; \
2810 block_lookup_translate_##type(rom, 0); \
2811 translation_recursion_level--; \
2812 \
2813 /* If the translation failed then pass that failure on if we're in \
2814 a recursive level, or try again if we've hit the bottom. */ \
2815 if(translation_result == -1) \
2816 { \
2817 if(translation_recursion_level) \
2818 return NULL; \
2819 \
2820 goto redo; \
2821 } \
2822 \
2823 if(translation_recursion_level == 0) \
2824 translate_invalidate_dcache(); \
2825 } \
2826 if(translation_recursion_level == 0) \
2827 bios_region_read_protect(); \
2828 break; \
2829 } \
2830 \
2831 default: \
2832 /* If we're at the bottom, it means we're actually trying to jump to an \
2833 address that we can't handle. Otherwise, it means that code scanned \
2834 has reached an address that can't be handled, which means that we \
2835 have most likely hit an area that doesn't contain code yet (for \
2836 instance, in RAM). If such a thing happens, return -1 and the \
2837 block translater will naively link it (it'll be okay, since it \
2838 should never be hit) */ \
2839 if(translation_recursion_level == 0) \
2840 { \
2841 char buffer[256]; \
2842 sprintf(buffer, "bad jump %x (%x) (%x)\n", pc, reg[REG_PC], \
2843 last_instruction); \
2844 printf(buffer); \
2845 quit(); \
2846 } \
2847 block_address = (u8 *)(-1); \
2848 break; \
2849 } \
2850 \
2851 return block_address; \
2852} \
2853
2854block_lookup_address_builder(arm);
2855block_lookup_address_builder(thumb);
2856block_lookup_address_builder(dual);
2857
2858// Potential exit point: If the rd field is pc for instructions is 0x0F,
2859// the instruction is b/bl/bx, or the instruction is ldm with PC in the
2860// register list.
2861// All instructions with upper 3 bits less than 100b have an rd field
2862// except bx, where the bits must be 0xF there anyway, multiplies,
2863// which cannot have 0xF in the corresponding fields, and msr, which
2864// has 0x0F there but doesn't end things (therefore must be special
2865// checked against). Because MSR and BX overlap both are checked for.
2866
2867#define arm_exit_point \
2868 (((opcode < 0x8000000) && ((opcode & 0x000F000) == 0x000F000) && \
2869 ((opcode & 0xDB0F000) != 0x120F000)) || \
2870 ((opcode & 0x12FFF10) == 0x12FFF10) || \
2871 ((opcode & 0x8108000) == 0x8108000) || \
2872 ((opcode >= 0xA000000) && (opcode < 0xF000000)) || \
2873 ((opcode > 0xF000000) && (!swi_hle_handle[((opcode >> 16) & 0xFF)]))) \
2874
2875#define arm_opcode_branch \
2876 ((opcode & 0xE000000) == 0xA000000) \
2877
2878#define arm_opcode_swi \
2879 ((opcode & 0xF000000) == 0xF000000) \
2880
2881#define arm_opcode_unconditional_branch \
2882 (condition == 0x0E) \
2883
2884#define arm_load_opcode() \
2885 opcode = address32(pc_address_block, (block_end_pc & 0x7FFF)); \
2886 condition = opcode >> 28; \
2887 \
2888 opcode &= 0xFFFFFFF; \
2889 \
2890 block_end_pc += 4 \
2891
2892#define arm_branch_target() \
2893 branch_target = (block_end_pc + 4 + (((s32)(opcode & 0xFFFFFF) << 8) >> 6)) \
2894
2895// Contiguous conditional block flags modification - it will set 0x20 in the
2896// condition's bits if this instruction modifies flags. Taken from the CPU
2897// switch so it'd better be right this time.
2898
2899#define arm_set_condition(_condition) \
2900 block_data[block_data_position].condition = _condition; \
2901 switch((opcode >> 20) & 0xFF) \
2902 { \
2903 case 0x01: \
2904 case 0x03: \
2905 case 0x09: \
2906 case 0x0B: \
2907 case 0x0D: \
2908 case 0x0F: \
2909 if((((opcode >> 5) & 0x03) == 0) || ((opcode & 0x90) != 0x90)) \
2910 block_data[block_data_position].condition |= 0x20; \
2911 break; \
2912 \
2913 case 0x05: \
2914 case 0x07: \
2915 case 0x11: \
2916 case 0x13: \
2917 case 0x15 ... 0x17: \
2918 case 0x19: \
2919 case 0x1B: \
2920 case 0x1D: \
2921 case 0x1F: \
2922 if((opcode & 0x90) != 0x90) \
2923 block_data[block_data_position].condition |= 0x20; \
2924 break; \
2925 \
2926 case 0x12: \
2927 if(((opcode & 0x90) != 0x90) && !(opcode & 0x10)) \
2928 block_data[block_data_position].condition |= 0x20; \
2929 break; \
2930 \
2931 case 0x21: \
2932 case 0x23: \
2933 case 0x25: \
2934 case 0x27: \
2935 case 0x29: \
2936 case 0x2B: \
2937 case 0x2D: \
2938 case 0x2F ... 0x37: \
2939 case 0x39: \
2940 case 0x3B: \
2941 case 0x3D: \
2942 case 0x3F: \
2943 block_data[block_data_position].condition |= 0x20; \
2944 break; \
2945 } \
2946
2947#define arm_link_block() \
2948 translation_target = block_lookup_address_arm(branch_target) \
2949
2950#define arm_instruction_width 4
2951
2952#define arm_base_cycles() \
2953 cycle_count += waitstate_cycles_sequential[pc >> 24][2] \
2954
2955// For now this just sets a variable that says flags should always be
2956// computed.
2957
2958#define arm_dead_flag_eliminate() \
2959 flag_status = 0xF \
2960
2961// The following Thumb instructions can exit:
2962// b, bl, bx, swi, pop {... pc}, and mov pc, ..., the latter being a hireg
2963// op only. Rather simpler to identify than the ARM set.
2964
2965#define thumb_exit_point \
2966 (((opcode >= 0xD000) && (opcode < 0xDF00)) || \
2967 (((opcode & 0xFF00) == 0xDF00) && \
2968 (!swi_hle_handle[opcode & 0xFF])) || \
2969 ((opcode >= 0xE000) && (opcode < 0xE800)) || \
2970 ((opcode & 0xFF00) == 0x4700) || \
2971 ((opcode & 0xFF00) == 0xBD00) || \
2972 ((opcode & 0xFF87) == 0x4687) || \
2973 ((opcode >= 0xF800))) \
2974
2975#define thumb_opcode_branch \
2976 (((opcode >= 0xD000) && (opcode < 0xDF00)) || \
2977 ((opcode >= 0xE000) && (opcode < 0xE800)) || \
2978 (opcode >= 0xF800)) \
2979
2980#define thumb_opcode_swi \
2981 ((opcode & 0xFF00) == 0xDF00) \
2982
2983#define thumb_opcode_unconditional_branch \
2984 ((opcode < 0xD000) || (opcode >= 0xDF00)) \
2985
2986#define thumb_load_opcode() \
2987 last_opcode = opcode; \
2988 opcode = address16(pc_address_block, (block_end_pc & 0x7FFF)); \
2989 \
2990 block_end_pc += 2 \
2991
2992#define thumb_branch_target() \
2993 if(opcode < 0xE000) \
2994 { \
2995 branch_target = block_end_pc + 2 + ((s8)(opcode & 0xFF) * 2); \
2996 } \
2997 else \
2998 \
2999 if(opcode < 0xF800) \
3000 { \
3001 branch_target = block_end_pc + 2 + ((s32)((opcode & 0x7FF) << 21) >> 20); \
3002 } \
3003 else \
3004 { \
3005 if((last_opcode >= 0xF000) && (last_opcode < 0xF800)) \
3006 { \
3007 branch_target = \
3008 (block_end_pc + ((s32)((last_opcode & 0x07FF) << 21) >> 9) + \
3009 ((opcode & 0x07FF) * 2)); \
3010 } \
3011 else \
3012 { \
3013 goto no_direct_branch; \
3014 } \
3015 } \
3016
3017#define thumb_set_condition(_condition) \
3018
3019#define thumb_link_block() \
3020 if(branch_target != 0x00000008) \
3021 translation_target = block_lookup_address_thumb(branch_target); \
3022 else \
3023 translation_target = block_lookup_address_arm(branch_target) \
3024
3025#define thumb_instruction_width 2
3026
3027#define thumb_base_cycles() \
3028 cycle_count += waitstate_cycles_sequential[pc >> 24][1] \
3029
3030// Here's how this works: each instruction has three different sets of flag
3031// attributes, each consisiting of a 4bit mask describing how that instruction
3032// interacts with the 4 main flags (N/Z/C/V).
3033// The first set, in bits 0:3, is the set of flags the instruction may
3034// modify. After this pass this is changed to the set of flags the instruction
3035// should modify - if the bit for the corresponding flag is not set then code
3036// does not have to be generated to calculate the flag for that instruction.
3037
3038// The second set, in bits 7:4, is the set of flags that the instruction must
3039// modify (ie, for shifts by the register values the instruction may not
3040// always modify the C flag, and thus the C bit won't be set here).
3041
3042// The third set, in bits 11:8, is the set of flags that the instruction uses
3043// in its computation, or the set of flags that will be needed after the
3044// instruction is done. For any instructions that change the PC all of the
3045// bits should be set because it is (for now) unknown what flags will be
3046// needed after it arrives at its destination. Instructions that use the
3047// carry flag as input will have it set as well.
3048
3049// The algorithm is a simple liveness analysis procedure: It starts at the
3050// bottom of the instruction stream and sets a "currently needed" mask to
3051// the flags needed mask of the current instruction. Then it moves down
3052// an instruction, ANDs that instructions "should generate" mask by the
3053// "currently needed" mask, then ANDs the "currently needed" mask by
3054// the 1's complement of the instruction's "must generate" mask, and ORs
3055// the "currently needed" mask by the instruction's "flags needed" mask.
3056
3057#define thumb_dead_flag_eliminate() \
3058{ \
3059 u32 needed_mask; \
3060 needed_mask = block_data[block_data_position].flag_data >> 8; \
3061 \
3062 block_data_position--; \
3063 while(block_data_position >= 0) \
3064 { \
3065 flag_status = block_data[block_data_position].flag_data; \
3066 block_data[block_data_position].flag_data = \
3067 (flag_status & needed_mask); \
3068 needed_mask &= ~((flag_status >> 4) & 0x0F); \
3069 needed_mask |= flag_status >> 8; \
3070 block_data_position--; \
3071 } \
3072} \
3073
3074#define MAX_BLOCK_SIZE 8192
3075#define MAX_EXITS 256
3076
3077block_data_type block_data[MAX_BLOCK_SIZE];
3078block_exit_type block_exits[MAX_EXITS];
3079
3080#define smc_write_arm_yes() \
3081 if(address32(pc_address_block, (block_end_pc & 0x7FFF) - 0x8000) == 0x0000) \
3082 { \
3083 address32(pc_address_block, (block_end_pc & 0x7FFF) - 0x8000) = \
3084 0xFFFFFFFF; \
3085 } \
3086
3087#define smc_write_thumb_yes() \
3088 if(address16(pc_address_block, (block_end_pc & 0x7FFF) - 0x8000) == 0x0000) \
3089 { \
3090 address16(pc_address_block, (block_end_pc & 0x7FFF) - 0x8000) = 0xFFFF; \
3091 } \
3092
3093#define smc_write_arm_no() \
3094
3095#define smc_write_thumb_no() \
3096
3097#define scan_block(type, smc_write_op) \
3098{ \
3099 __label__ block_end; \
3100 /* Find the end of the block */ \
3101 do \
3102 { \
3103 check_pc_region(block_end_pc); \
3104 smc_write_##type##_##smc_write_op(); \
3105 type##_load_opcode(); \
3106 type##_flag_status(); \
3107 \
3108 if(type##_exit_point) \
3109 { \
3110 /* Branch/branch with link */ \
3111 if(type##_opcode_branch) \
3112 { \
3113 __label__ no_direct_branch; \
3114 type##_branch_target(); \
3115 block_exits[block_exit_position].branch_target = branch_target; \
3116 block_exit_position++; \
3117 \
3118 /* Give the branch target macro somewhere to bail if it turns out to \
3119 be an indirect branch (ala malformed Thumb bl) */ \
3120 no_direct_branch:; \
3121 } \
3122 \
3123 /* SWI branches to the BIOS, this will likely change when \
3124 some HLE BIOS is implemented. */ \
3125 if(type##_opcode_swi) \
3126 { \
3127 block_exits[block_exit_position].branch_target = 0x00000008; \
3128 block_exit_position++; \
3129 } \
3130 \
3131 type##_set_condition(condition | 0x10); \
3132 \
3133 /* Only unconditional branches can end the block. */ \
3134 if(type##_opcode_unconditional_branch) \
3135 { \
3136 /* Check to see if any prior block exits branch after here, \
3137 if so don't end the block. Starts from the top and works \
3138 down because the most recent branch is most likely to \
3139 join after the end (if/then form) */ \
3140 for(i = block_exit_position - 2; i >= 0; i--) \
3141 { \
3142 if(block_exits[i].branch_target == block_end_pc) \
3143 break; \
3144 } \
3145 \
3146 if(i < 0) \
3147 break; \
3148 } \
3149 if(block_exit_position == MAX_EXITS) \
3150 break; \
3151 } \
3152 else \
3153 { \
3154 type##_set_condition(condition); \
3155 } \
3156 \
3157 for(i = 0; i < translation_gate_targets; i++) \
3158 { \
3159 if(block_end_pc == translation_gate_target_pc[i]) \
3160 goto block_end; \
3161 } \
3162 \
3163 block_data[block_data_position].update_cycles = 0; \
3164 block_data_position++; \
3165 if((block_data_position == MAX_BLOCK_SIZE) || \
3166 (block_end_pc == 0x3007FF0) || (block_end_pc == 0x203FFFF0)) \
3167 { \
3168 break; \
3169 } \
3170 } while(1); \
3171 \
3172 block_end:; \
3173} \
3174
3175#define arm_fix_pc() \
3176 pc &= ~0x03 \
3177
3178#define thumb_fix_pc() \
3179 pc &= ~0x01 \
3180
3181#define translate_block_builder(type) \
3182s32 translate_block_##type(u32 pc, translation_region_type \
3183 translation_region, u32 smc_enable) \
3184{ \
3185 u32 opcode; \
3186 u32 last_opcode; \
3187 u32 condition; \
3188 u32 last_condition; \
3189 u32 pc_region = (pc >> 15); \
3190 u32 new_pc_region; \
3191 u8 *pc_address_block = memory_map_read[pc_region]; \
3192 u32 block_start_pc = pc; \
3193 u32 block_end_pc = pc; \
3194 u32 block_exit_position = 0; \
3195 s32 block_data_position = 0; \
3196 u32 external_block_exit_position = 0; \
3197 u32 branch_target; \
3198 u32 cycle_count = 0; \
3199 u8 *translation_target; \
3200 u8 *backpatch_address; \
3201 u8 *translation_ptr; \
3202 u8 *translation_cache_limit; \
3203 s32 i; \
3204 u32 flag_status; \
3205 block_exit_type external_block_exits[MAX_EXITS]; \
3206 generate_block_extra_vars_##type(); \
3207 type##_fix_pc(); \
3208 \
3209 if(pc_address_block == NULL) \
3210 pc_address_block = load_gamepak_page(pc_region & 0x3FF); \
3211 \
3212 switch(translation_region) \
3213 { \
3214 case TRANSLATION_REGION_RAM: \
3215 if(pc >= 0x3000000) \
3216 { \
3217 if((pc < iwram_code_min) || (iwram_code_min == 0xFFFFFFFF)) \
3218 iwram_code_min = pc; \
3219 } \
3220 else \
3221 \
3222 if(pc >= 0x2000000) \
3223 { \
3224 if((pc < ewram_code_min) || (ewram_code_min == 0xFFFFFFFF)) \
3225 ewram_code_min = pc; \
3226 } \
3227 \
3228 translation_ptr = ram_translation_ptr; \
3229 translation_cache_limit = \
3230 ram_translation_cache + RAM_TRANSLATION_CACHE_SIZE - \
3231 TRANSLATION_CACHE_LIMIT_THRESHOLD; \
3232 break; \
3233 \
3234 case TRANSLATION_REGION_ROM: \
3235 translation_ptr = rom_translation_ptr; \
3236 translation_cache_limit = \
3237 rom_translation_cache + ROM_TRANSLATION_CACHE_SIZE - \
3238 TRANSLATION_CACHE_LIMIT_THRESHOLD; \
3239 break; \
3240 \
3241 case TRANSLATION_REGION_BIOS: \
3242 translation_ptr = bios_translation_ptr; \
3243 translation_cache_limit = bios_translation_cache + \
3244 BIOS_TRANSLATION_CACHE_SIZE; \
3245 break; \
3246 } \
3247 \
3248 generate_block_prologue(); \
3249 \
3250 /* This is a function because it's used a lot more than it might seem (all \
3251 of the data processing functions can access it), and its expansion was \
3252 massacreing the compiler. */ \
3253 \
3254 if(smc_enable) \
3255 { \
3256 scan_block(type, yes); \
3257 } \
3258 else \
3259 { \
3260 scan_block(type, no); \
3261 } \
3262 \
3263 for(i = 0; i < block_exit_position; i++) \
3264 { \
3265 branch_target = block_exits[i].branch_target; \
3266 \
3267 if((branch_target > block_start_pc) && \
3268 (branch_target < block_end_pc)) \
3269 { \
3270 block_data[(branch_target - block_start_pc) / \
3271 type##_instruction_width].update_cycles = 1; \
3272 } \
3273 } \
3274 \
3275 type##_dead_flag_eliminate(); \
3276 \
3277 block_exit_position = 0; \
3278 block_data_position = 0; \
3279 \
3280 last_condition = 0x0E; \
3281 \
3282 while(pc != block_end_pc) \
3283 { \
3284 block_data[block_data_position].block_offset = translation_ptr; \
3285 type##_base_cycles(); \
3286 /*generate_step_debug();*/ \
3287 \
3288 translate_##type##_instruction(); \
3289 block_data_position++; \
3290 \
3291 /* If it went too far the cache needs to be flushed and the process \
3292 restarted. Because we might already be nested several stages in \
3293 a simple recursive call here won't work, it has to pedal out to \
3294 the beginning. */ \
3295 \
3296 if(translation_ptr > translation_cache_limit) \
3297 { \
3298 translation_flush_count++; \
3299 \
3300 switch(translation_region) \
3301 { \
3302 case TRANSLATION_REGION_RAM: \
3303 flush_translation_cache_ram(); \
3304 break; \
3305 \
3306 case TRANSLATION_REGION_ROM: \
3307 flush_translation_cache_rom(); \
3308 break; \
3309 \
3310 case TRANSLATION_REGION_BIOS: \
3311 flush_translation_cache_bios(); \
3312 break; \
3313 } \
3314 \
3315 return -1; \
3316 } \
3317 \
3318 /* If the next instruction is a block entry point update the \
3319 cycle counter and update */ \
3320 if(block_data[block_data_position].update_cycles == 1) \
3321 { \
3322 generate_cycle_update(); \
3323 } \
3324 } \
3325 for(i = 0; i < translation_gate_targets; i++) \
3326 { \
3327 if(pc == translation_gate_target_pc[i]) \
3328 { \
3329 generate_translation_gate(type); \
3330 break; \
3331 } \
3332 } \
3333 \
3334 for(i = 0; i < block_exit_position; i++) \
3335 { \
3336 branch_target = block_exits[i].branch_target; \
3337 \
3338 if((branch_target >= block_start_pc) && (branch_target < block_end_pc)) \
3339 { \
3340 /* Internal branch, patch to recorded address */ \
3341 translation_target = \
3342 block_data[(branch_target - block_start_pc) / \
3343 type##_instruction_width].block_offset; \
3344 \
3345 generate_branch_patch_unconditional(block_exits[i].branch_source, \
3346 translation_target); \
3347 } \
3348 else \
3349 { \
3350 /* External branch, save for later */ \
3351 external_block_exits[external_block_exit_position].branch_target = \
3352 branch_target; \
3353 external_block_exits[external_block_exit_position].branch_source = \
3354 block_exits[i].branch_source; \
3355 external_block_exit_position++; \
3356 } \
3357 } \
3358 \
3359 switch(translation_region) \
3360 { \
3361 case TRANSLATION_REGION_RAM: \
3362 if(pc >= 0x3000000) \
3363 { \
3364 if((pc > iwram_code_max) || (iwram_code_max == 0xFFFFFFFF)) \
3365 iwram_code_max = pc; \
3366 } \
3367 else \
3368 \
3369 if(pc >= 0x2000000) \
3370 { \
3371 if((pc > ewram_code_max) || (ewram_code_max == 0xFFFFFFFF)) \
3372 ewram_code_max = pc; \
3373 } \
3374 \
3375 ram_translation_ptr = translation_ptr; \
3376 break; \
3377 \
3378 case TRANSLATION_REGION_ROM: \
3379 rom_translation_ptr = translation_ptr; \
3380 break; \
3381 \
3382 case TRANSLATION_REGION_BIOS: \
3383 bios_translation_ptr = translation_ptr; \
3384 break; \
3385 } \
3386 \
3387 for(i = 0; i < external_block_exit_position; i++) \
3388 { \
3389 branch_target = external_block_exits[i].branch_target; \
3390 type##_link_block(); \
3391 if(translation_target == NULL) \
3392 return -1; \
3393 generate_branch_patch_unconditional( \
3394 external_block_exits[i].branch_source, translation_target); \
3395 } \
3396 \
3397 return 0; \
3398} \
3399
3400translate_block_builder(arm);
3401translate_block_builder(thumb);
3402
3403void flush_translation_cache_ram()
3404{
3405 flush_ram_count++;
3406/* printf("ram flush %d (pc %x), %x to %x, %x to %x\n",
3407 flush_ram_count, reg[REG_PC], iwram_code_min, iwram_code_max,
3408 ewram_code_min, ewram_code_max); */
3409
3410#ifndef PC_BUILD
3411 invalidate_icache_region(ram_translation_cache,
3412 (ram_translation_ptr - ram_translation_cache) + 0x100);
3413#endif
3414 ram_translation_ptr = ram_translation_cache;
3415 ram_block_tag_top = 0x0101;
3416 if(iwram_code_min != 0xFFFFFFFF)
3417 {
3418 iwram_code_min &= 0x7FFF;
3419 iwram_code_max &= 0x7FFF;
3420 memset(iwram + iwram_code_min, 0, iwram_code_max - iwram_code_min);
3421 }
3422
3423 if(ewram_code_min != 0xFFFFFFFF)
3424 {
3425 u32 ewram_code_min_page;
3426 u32 ewram_code_max_page;
3427 u32 ewram_code_min_offset;
3428 u32 ewram_code_max_offset;
3429 u32 i;
3430
3431 ewram_code_min &= 0x3FFFF;
3432 ewram_code_max &= 0x3FFFF;
3433
3434 ewram_code_min_page = ewram_code_min >> 15;
3435 ewram_code_max_page = ewram_code_max >> 15;
3436 ewram_code_min_offset = ewram_code_min & 0x7FFF;
3437 ewram_code_max_offset = ewram_code_max & 0x7FFF;
3438
3439 if(ewram_code_min_page == ewram_code_max_page)
3440 {
3441 memset(ewram + (ewram_code_min_page * 0x10000) +
3442 ewram_code_min_offset, 0,
3443 ewram_code_max_offset - ewram_code_min_offset);
3444 }
3445 else
3446 {
3447 for(i = ewram_code_min_page + 1; i < ewram_code_max_page; i++)
3448 {
3449 memset(ewram + (i * 0x10000), 0, 0x8000);
3450 }
3451
3452 memset(ewram, 0, ewram_code_max_offset);
3453 }
3454 }
3455
3456 iwram_code_min = 0xFFFFFFFF;
3457 iwram_code_max = 0xFFFFFFFF;
3458 ewram_code_min = 0xFFFFFFFF;
3459 ewram_code_max = 0xFFFFFFFF;
3460}
3461
3462void flush_translation_cache_rom()
3463{
3464#ifndef PC_BUILD
3465 invalidate_icache_region(rom_translation_cache,
3466 rom_translation_ptr - rom_translation_cache + 0x100);
3467#endif
3468
3469 rom_translation_ptr = rom_translation_cache;
3470 memset(rom_branch_hash, 0, sizeof(rom_branch_hash));
3471}
3472
3473void flush_translation_cache_bios()
3474{
3475#ifndef PC_BUILD
3476 invalidate_icache_region(bios_translation_cache,
3477 bios_translation_ptr - bios_translation_cache + 0x100);
3478#endif
3479
3480 bios_block_tag_top = 0x0101;
3481 bios_translation_ptr = bios_translation_cache;
3482 memset(bios_rom + 0x4000, 0, 0x4000);
3483}
3484
3485#ifdef GP2X_BUILD
3486 #define cache_dump_prefix "/mnt/nand/"
3487#else
3488 #define cache_dump_prefix ""
3489#endif
3490
3491void dump_translation_cache()
3492{
3493 file_open(ram_cache, cache_dump_prefix "ram_cache.bin", write);
3494 file_write(ram_cache, ram_translation_cache,
3495 ram_translation_ptr - ram_translation_cache);
3496 file_close(ram_cache);
3497
3498 file_open(rom_cache, cache_dump_prefix "rom_cache.bin", write);
3499 file_write(rom_cache, rom_translation_cache,
3500 rom_translation_ptr - rom_translation_cache);
3501 file_close(rom_cache);
3502
3503 file_open(bios_cache, cache_dump_prefix "bios_cache.bin", write);
3504 file_write(bios_cache, bios_translation_cache,
3505 bios_translation_ptr - bios_translation_cache);
3506 file_close(bios_cache);
3507}
3508