3 * Copyright (C) 2006 Exophase <exophase@gmail.com>
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.
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.
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
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
27 u8 rom_translation_cache[ROM_TRANSLATION_CACHE_SIZE];
28 u8 *rom_translation_ptr = rom_translation_cache;
30 u8 ram_translation_cache[RAM_TRANSLATION_CACHE_SIZE];
31 u8 *ram_translation_ptr = ram_translation_cache;
32 u32 iwram_code_min = 0xFFFFFFFF;
33 u32 iwram_code_max = 0xFFFFFFFF;
34 u32 ewram_code_min = 0xFFFFFFFF;
35 u32 ewram_code_max = 0xFFFFFFFF;
37 u8 bios_translation_cache[BIOS_TRANSLATION_CACHE_SIZE];
38 u8 *bios_translation_ptr = bios_translation_cache;
40 u32 *rom_branch_hash[ROM_BRANCH_HASH_SIZE];
43 u32 idle_loop_target_pc = 0xFFFFFFFF;
44 u32 force_pc_update_target = 0xFFFFFFFF;
45 u32 translation_gate_target_pc[MAX_TRANSLATION_GATES];
46 u32 translation_gate_targets = 0;
47 u32 iwram_stack_optimize = 1;
48 u32 allow_smc_ram_u8 = 1;
49 u32 allow_smc_ram_u16 = 1;
50 u32 allow_smc_ram_u32 = 1;
66 extern u8 bit_count[256];
68 #define arm_decode_data_proc_reg() \
69 u32 rn = (opcode >> 16) & 0x0F; \
70 u32 rd = (opcode >> 12) & 0x0F; \
71 u32 rm = opcode & 0x0F \
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 \
79 #define arm_decode_psr_reg() \
80 u32 psr_field = (opcode >> 16) & 0x0F; \
81 u32 rd = (opcode >> 12) & 0x0F; \
82 u32 rm = opcode & 0x0F \
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 \
90 #define arm_decode_branchx() \
91 u32 rn = opcode & 0x0F \
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 \
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 \
105 #define arm_decode_swap() \
106 u32 rn = (opcode >> 16) & 0x0F; \
107 u32 rd = (opcode >> 12) & 0x0F; \
108 u32 rm = opcode & 0x0F \
110 #define arm_decode_half_trans_r() \
111 u32 rn = (opcode >> 16) & 0x0F; \
112 u32 rd = (opcode >> 12) & 0x0F; \
113 u32 rm = opcode & 0x0F \
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) \
120 #define arm_decode_data_trans_imm() \
121 u32 rn = (opcode >> 16) & 0x0F; \
122 u32 rd = (opcode >> 12) & 0x0F; \
123 u32 offset = opcode & 0x0FFF \
125 #define arm_decode_data_trans_reg() \
126 u32 rn = (opcode >> 16) & 0x0F; \
127 u32 rd = (opcode >> 12) & 0x0F; \
128 u32 rm = opcode & 0x0F \
130 #define arm_decode_block_trans() \
131 u32 rn = (opcode >> 16) & 0x0F; \
132 u32 reg_list = opcode & 0xFFFF \
134 #define arm_decode_branch() \
135 s32 offset = ((s32)(opcode & 0xFFFFFF) << 8) >> 6 \
137 #define thumb_decode_shift() \
138 u32 imm = (opcode >> 6) & 0x1F; \
139 u32 rs = (opcode >> 3) & 0x07; \
140 u32 rd = opcode & 0x07 \
142 #define thumb_decode_add_sub() \
143 u32 rn = (opcode >> 6) & 0x07; \
144 u32 rs = (opcode >> 3) & 0x07; \
145 u32 rd = opcode & 0x07 \
147 #define thumb_decode_add_sub_imm() \
148 u32 imm = (opcode >> 6) & 0x07; \
149 u32 rs = (opcode >> 3) & 0x07; \
150 u32 rd = opcode & 0x07 \
152 #define thumb_decode_imm() \
153 u32 imm = opcode & 0xFF \
155 #define thumb_decode_alu_op() \
156 u32 rs = (opcode >> 3) & 0x07; \
157 u32 rd = opcode & 0x07 \
159 #define thumb_decode_hireg_op() \
160 u32 rs = (opcode >> 3) & 0x0F; \
161 u32 rd = ((opcode >> 4) & 0x08) | (opcode & 0x07) \
163 #define thumb_decode_mem_reg() \
164 u32 ro = (opcode >> 6) & 0x07; \
165 u32 rb = (opcode >> 3) & 0x07; \
166 u32 rd = opcode & 0x07 \
168 #define thumb_decode_mem_imm() \
169 u32 imm = (opcode >> 6) & 0x1F; \
170 u32 rb = (opcode >> 3) & 0x07; \
171 u32 rd = opcode & 0x07 \
173 #define thumb_decode_add_sp() \
174 u32 imm = opcode & 0x7F \
176 #define thumb_decode_rlist() \
177 u32 reg_list = opcode & 0xFF \
179 #define thumb_decode_branch_cond() \
180 s32 offset = (s8)(opcode & 0xFF) \
182 #define thumb_decode_swi() \
183 u32 comment = opcode & 0xFF \
185 #define thumb_decode_branch() \
186 u32 offset = opcode & 0x07FF \
191 #include "psp/mips_emit.h"
193 #elif defined(ARM_ARCH)
195 #include "arm/arm_emit.h"
199 #include "x86/x86_emit.h"
204 #define check_pc_region(pc) \
205 new_pc_region = (pc >> 15); \
206 if(new_pc_region != pc_region) \
208 pc_region = new_pc_region; \
209 pc_address_block = memory_map_read[new_pc_region]; \
211 if(pc_address_block == NULL) \
212 pc_address_block = load_gamepak_page(pc_region & 0x3FF); \
215 #define translate_arm_instruction() \
216 check_pc_region(pc); \
217 opcode = address32(pc_address_block, (pc & 0x7FFF)); \
218 condition = block_data[block_data_position].condition; \
220 if((condition != last_condition) || (condition >= 0x20)) \
222 if((last_condition & 0x0F) != 0x0E) \
224 generate_branch_patch_conditional(backpatch_address, translation_ptr); \
227 last_condition = condition; \
231 if(condition != 0x0E) \
233 arm_conditional_block_header(); \
237 switch((opcode >> 20) & 0xFF) \
240 if((opcode & 0x90) == 0x90) \
244 /* STRH rd, [rn], -rm */ \
245 arm_access_memory(store, down, post, u16, half_reg); \
249 /* MUL rd, rm, rs */ \
250 arm_multiply(no, no); \
255 /* AND rd, rn, reg_op */ \
256 arm_data_proc(and, reg, no_flags); \
261 if((opcode & 0x90) == 0x90) \
263 switch((opcode >> 5) & 0x03) \
266 /* MULS rd, rm, rs */ \
267 arm_multiply(no, yes); \
271 /* LDRH rd, [rn], -rm */ \
272 arm_access_memory(load, down, post, u16, half_reg); \
276 /* LDRSB rd, [rn], -rm */ \
277 arm_access_memory(load, down, post, s8, half_reg); \
281 /* LDRSH rd, [rn], -rm */ \
282 arm_access_memory(load, down, post, s16, half_reg); \
288 /* ANDS rd, rn, reg_op */ \
289 arm_data_proc(ands, reg_flags, flags); \
294 if((opcode & 0x90) == 0x90) \
298 /* STRH rd, [rn], -rm */ \
299 arm_access_memory(store, down, post, u16, half_reg); \
303 /* MLA rd, rm, rs, rn */ \
304 arm_multiply(yes, no); \
309 /* EOR rd, rn, reg_op */ \
310 arm_data_proc(eor, reg, no_flags); \
315 if((opcode & 0x90) == 0x90) \
317 switch((opcode >> 5) & 0x03) \
320 /* MLAS rd, rm, rs, rn */ \
321 arm_multiply(yes, yes); \
325 /* LDRH rd, [rn], -rm */ \
326 arm_access_memory(load, down, post, u16, half_reg); \
330 /* LDRSB rd, [rn], -rm */ \
331 arm_access_memory(load, down, post, s8, half_reg); \
335 /* LDRSH rd, [rn], -rm */ \
336 arm_access_memory(load, down, post, s16, half_reg); \
342 /* EORS rd, rn, reg_op */ \
343 arm_data_proc(eors, reg_flags, flags); \
348 if((opcode & 0x90) == 0x90) \
350 /* STRH rd, [rn], -imm */ \
351 arm_access_memory(store, down, post, u16, half_imm); \
355 /* SUB rd, rn, reg_op */ \
356 arm_data_proc(sub, reg, no_flags); \
361 if((opcode & 0x90) == 0x90) \
363 switch((opcode >> 5) & 0x03) \
366 /* LDRH rd, [rn], -imm */ \
367 arm_access_memory(load, down, post, u16, half_imm); \
371 /* LDRSB rd, [rn], -imm */ \
372 arm_access_memory(load, down, post, s8, half_imm); \
376 /* LDRSH rd, [rn], -imm */ \
377 arm_access_memory(load, down, post, s16, half_imm); \
383 /* SUBS rd, rn, reg_op */ \
384 arm_data_proc(subs, reg, flags); \
389 if((opcode & 0x90) == 0x90) \
391 /* STRH rd, [rn], -imm */ \
392 arm_access_memory(store, down, post, u16, half_imm); \
396 /* RSB rd, rn, reg_op */ \
397 arm_data_proc(rsb, reg, no_flags); \
402 if((opcode & 0x90) == 0x90) \
404 switch((opcode >> 5) & 0x03) \
407 /* LDRH rd, [rn], -imm */ \
408 arm_access_memory(load, down, post, u16, half_imm); \
412 /* LDRSB rd, [rn], -imm */ \
413 arm_access_memory(load, down, post, s8, half_imm); \
417 /* LDRSH rd, [rn], -imm */ \
418 arm_access_memory(load, down, post, s16, half_imm); \
424 /* RSBS rd, rn, reg_op */ \
425 arm_data_proc(rsbs, reg, flags); \
430 if((opcode & 0x90) == 0x90) \
434 /* STRH rd, [rn], +rm */ \
435 arm_access_memory(store, up, post, u16, half_reg); \
439 /* UMULL rd, rm, rs */ \
440 arm_multiply_long(u64, no, no); \
445 /* ADD rd, rn, reg_op */ \
446 arm_data_proc(add, reg, no_flags); \
451 if((opcode & 0x90) == 0x90) \
453 switch((opcode >> 5) & 0x03) \
456 /* UMULLS rdlo, rdhi, rm, rs */ \
457 arm_multiply_long(u64, no, yes); \
461 /* LDRH rd, [rn], +rm */ \
462 arm_access_memory(load, up, post, u16, half_reg); \
466 /* LDRSB rd, [rn], +rm */ \
467 arm_access_memory(load, up, post, s8, half_reg); \
471 /* LDRSH rd, [rn], +rm */ \
472 arm_access_memory(load, up, post, s16, half_reg); \
478 /* ADDS rd, rn, reg_op */ \
479 arm_data_proc(adds, reg, flags); \
484 if((opcode & 0x90) == 0x90) \
488 /* STRH rd, [rn], +rm */ \
489 arm_access_memory(store, up, post, u16, half_reg); \
493 /* UMLAL rd, rm, rs */ \
494 arm_multiply_long(u64_add, yes, no); \
499 /* ADC rd, rn, reg_op */ \
500 arm_data_proc(adc, reg, no_flags); \
505 if((opcode & 0x90) == 0x90) \
507 switch((opcode >> 5) & 0x03) \
510 /* UMLALS rdlo, rdhi, rm, rs */ \
511 arm_multiply_long(u64_add, yes, yes); \
515 /* LDRH rd, [rn], +rm */ \
516 arm_access_memory(load, up, post, u16, half_reg); \
520 /* LDRSB rd, [rn], +rm */ \
521 arm_access_memory(load, up, post, s8, half_reg); \
525 /* LDRSH rd, [rn], +rm */ \
526 arm_access_memory(load, up, post, s16, half_reg); \
532 /* ADCS rd, rn, reg_op */ \
533 arm_data_proc(adcs, reg, flags); \
538 if((opcode & 0x90) == 0x90) \
542 /* STRH rd, [rn], +imm */ \
543 arm_access_memory(store, up, post, u16, half_imm); \
547 /* SMULL rd, rm, rs */ \
548 arm_multiply_long(s64, no, no); \
553 /* SBC rd, rn, reg_op */ \
554 arm_data_proc(sbc, reg, no_flags); \
559 if((opcode & 0x90) == 0x90) \
561 switch((opcode >> 5) & 0x03) \
564 /* SMULLS rdlo, rdhi, rm, rs */ \
565 arm_multiply_long(s64, no, yes); \
569 /* LDRH rd, [rn], +imm */ \
570 arm_access_memory(load, up, post, u16, half_imm); \
574 /* LDRSB rd, [rn], +imm */ \
575 arm_access_memory(load, up, post, s8, half_imm); \
579 /* LDRSH rd, [rn], +imm */ \
580 arm_access_memory(load, up, post, s16, half_imm); \
586 /* SBCS rd, rn, reg_op */ \
587 arm_data_proc(sbcs, reg, flags); \
592 if((opcode & 0x90) == 0x90) \
596 /* STRH rd, [rn], +imm */ \
597 arm_access_memory(store, up, post, u16, half_imm); \
601 /* SMLAL rd, rm, rs */ \
602 arm_multiply_long(s64_add, yes, no); \
607 /* RSC rd, rn, reg_op */ \
608 arm_data_proc(rsc, reg, no_flags); \
613 if((opcode & 0x90) == 0x90) \
615 switch((opcode >> 5) & 0x03) \
618 /* SMLALS rdlo, rdhi, rm, rs */ \
619 arm_multiply_long(s64_add, yes, yes); \
623 /* LDRH rd, [rn], +imm */ \
624 arm_access_memory(load, up, post, u16, half_imm); \
628 /* LDRSB rd, [rn], +imm */ \
629 arm_access_memory(load, up, post, s8, half_imm); \
633 /* LDRSH rd, [rn], +imm */ \
634 arm_access_memory(load, up, post, s16, half_imm); \
640 /* RSCS rd, rn, reg_op */ \
641 arm_data_proc(rscs, reg, flags); \
646 if((opcode & 0x90) == 0x90) \
650 /* STRH rd, [rn - rm] */ \
651 arm_access_memory(store, down, pre, u16, half_reg); \
655 /* SWP rd, rm, [rn] */ \
662 arm_psr(reg, read, cpsr); \
667 if((opcode & 0x90) == 0x90) \
669 switch((opcode >> 5) & 0x03) \
672 /* LDRH rd, [rn - rm] */ \
673 arm_access_memory(load, down, pre, u16, half_reg); \
677 /* LDRSB rd, [rn - rm] */ \
678 arm_access_memory(load, down, pre, s8, half_reg); \
682 /* LDRSH rd, [rn - rm] */ \
683 arm_access_memory(load, down, pre, s16, half_reg); \
689 /* TST rd, rn, reg_op */ \
690 arm_data_proc_test(tst, reg_flags); \
695 if((opcode & 0x90) == 0x90) \
697 /* STRH rd, [rn - rm]! */ \
698 arm_access_memory(store, down, pre_wb, u16, half_reg); \
710 arm_psr(reg, store, cpsr); \
716 if((opcode & 0x90) == 0x90) \
718 switch((opcode >> 5) & 0x03) \
721 /* LDRH rd, [rn - rm]! */ \
722 arm_access_memory(load, down, pre_wb, u16, half_reg); \
726 /* LDRSB rd, [rn - rm]! */ \
727 arm_access_memory(load, down, pre_wb, s8, half_reg); \
731 /* LDRSH rd, [rn - rm]! */ \
732 arm_access_memory(load, down, pre_wb, s16, half_reg); \
738 /* TEQ rd, rn, reg_op */ \
739 arm_data_proc_test(teq, reg_flags); \
744 if((opcode & 0x90) == 0x90) \
748 /* STRH rd, [rn - imm] */ \
749 arm_access_memory(store, down, pre, u16, half_imm); \
753 /* SWPB rd, rm, [rn] */ \
760 arm_psr(reg, read, spsr); \
765 if((opcode & 0x90) == 0x90) \
767 switch((opcode >> 5) & 0x03) \
770 /* LDRH rd, [rn - imm] */ \
771 arm_access_memory(load, down, pre, u16, half_imm); \
775 /* LDRSB rd, [rn - imm] */ \
776 arm_access_memory(load, down, pre, s8, half_imm); \
780 /* LDRSH rd, [rn - imm] */ \
781 arm_access_memory(load, down, pre, s16, half_imm); \
787 /* CMP rn, reg_op */ \
788 arm_data_proc_test(cmp, reg); \
793 if((opcode & 0x90) == 0x90) \
795 /* STRH rd, [rn - imm]! */ \
796 arm_access_memory(store, down, pre_wb, u16, half_imm); \
801 arm_psr(reg, store, spsr); \
806 if((opcode & 0x90) == 0x90) \
808 switch((opcode >> 5) & 0x03) \
811 /* LDRH rd, [rn - imm]! */ \
812 arm_access_memory(load, down, pre_wb, u16, half_imm); \
816 /* LDRSB rd, [rn - imm]! */ \
817 arm_access_memory(load, down, pre_wb, s8, half_imm); \
821 /* LDRSH rd, [rn - imm]! */ \
822 arm_access_memory(load, down, pre_wb, s16, half_imm); \
828 /* CMN rd, rn, reg_op */ \
829 arm_data_proc_test(cmn, reg); \
834 if((opcode & 0x90) == 0x90) \
836 /* STRH rd, [rn + rm] */ \
837 arm_access_memory(store, up, pre, u16, half_reg); \
841 /* ORR rd, rn, reg_op */ \
842 arm_data_proc(orr, reg, no_flags); \
847 if((opcode & 0x90) == 0x90) \
849 switch((opcode >> 5) & 0x03) \
852 /* LDRH rd, [rn + rm] */ \
853 arm_access_memory(load, up, pre, u16, half_reg); \
857 /* LDRSB rd, [rn + rm] */ \
858 arm_access_memory(load, up, pre, s8, half_reg); \
862 /* LDRSH rd, [rn + rm] */ \
863 arm_access_memory(load, up, pre, s16, half_reg); \
869 /* ORRS rd, rn, reg_op */ \
870 arm_data_proc(orrs, reg_flags, flags); \
875 if((opcode & 0x90) == 0x90) \
877 /* STRH rd, [rn + rm]! */ \
878 arm_access_memory(store, up, pre_wb, u16, half_reg); \
882 /* MOV rd, reg_op */ \
883 arm_data_proc_unary(mov, reg, no_flags); \
888 if((opcode & 0x90) == 0x90) \
890 switch((opcode >> 5) & 0x03) \
893 /* LDRH rd, [rn + rm]! */ \
894 arm_access_memory(load, up, pre_wb, u16, half_reg); \
898 /* LDRSB rd, [rn + rm]! */ \
899 arm_access_memory(load, up, pre_wb, s8, half_reg); \
903 /* LDRSH rd, [rn + rm]! */ \
904 arm_access_memory(load, up, pre_wb, s16, half_reg); \
910 /* MOVS rd, reg_op */ \
911 arm_data_proc_unary(movs, reg_flags, flags); \
916 if((opcode & 0x90) == 0x90) \
918 /* STRH rd, [rn + imm] */ \
919 arm_access_memory(store, up, pre, u16, half_imm); \
923 /* BIC rd, rn, reg_op */ \
924 arm_data_proc(bic, reg, no_flags); \
929 if((opcode & 0x90) == 0x90) \
931 switch((opcode >> 5) & 0x03) \
934 /* LDRH rd, [rn + imm] */ \
935 arm_access_memory(load, up, pre, u16, half_imm); \
939 /* LDRSB rd, [rn + imm] */ \
940 arm_access_memory(load, up, pre, s8, half_imm); \
944 /* LDRSH rd, [rn + imm] */ \
945 arm_access_memory(load, up, pre, s16, half_imm); \
951 /* BICS rd, rn, reg_op */ \
952 arm_data_proc(bics, reg_flags, flags); \
957 if((opcode & 0x90) == 0x90) \
959 /* STRH rd, [rn + imm]! */ \
960 arm_access_memory(store, up, pre_wb, u16, half_imm); \
964 /* MVN rd, reg_op */ \
965 arm_data_proc_unary(mvn, reg, no_flags); \
970 if((opcode & 0x90) == 0x90) \
972 switch((opcode >> 5) & 0x03) \
975 /* LDRH rd, [rn + imm]! */ \
976 arm_access_memory(load, up, pre_wb, u16, half_imm); \
980 /* LDRSB rd, [rn + imm]! */ \
981 arm_access_memory(load, up, pre_wb, s8, half_imm); \
985 /* LDRSH rd, [rn + imm]! */ \
986 arm_access_memory(load, up, pre_wb, s16, half_imm); \
992 /* MVNS rd, rn, reg_op */ \
993 arm_data_proc_unary(mvns, reg_flags, flags); \
998 /* AND rd, rn, imm */ \
999 arm_data_proc(and, imm, no_flags); \
1003 /* ANDS rd, rn, imm */ \
1004 arm_data_proc(ands, imm_flags, flags); \
1008 /* EOR rd, rn, imm */ \
1009 arm_data_proc(eor, imm, no_flags); \
1013 /* EORS rd, rn, imm */ \
1014 arm_data_proc(eors, imm_flags, flags); \
1018 /* SUB rd, rn, imm */ \
1019 arm_data_proc(sub, imm, no_flags); \
1023 /* SUBS rd, rn, imm */ \
1024 arm_data_proc(subs, imm, flags); \
1028 /* RSB rd, rn, imm */ \
1029 arm_data_proc(rsb, imm, no_flags); \
1033 /* RSBS rd, rn, imm */ \
1034 arm_data_proc(rsbs, imm, flags); \
1038 /* ADD rd, rn, imm */ \
1039 arm_data_proc(add, imm, no_flags); \
1043 /* ADDS rd, rn, imm */ \
1044 arm_data_proc(adds, imm, flags); \
1048 /* ADC rd, rn, imm */ \
1049 arm_data_proc(adc, imm, no_flags); \
1053 /* ADCS rd, rn, imm */ \
1054 arm_data_proc(adcs, imm, flags); \
1058 /* SBC rd, rn, imm */ \
1059 arm_data_proc(sbc, imm, no_flags); \
1063 /* SBCS rd, rn, imm */ \
1064 arm_data_proc(sbcs, imm, flags); \
1068 /* RSC rd, rn, imm */ \
1069 arm_data_proc(rsc, imm, no_flags); \
1073 /* RSCS rd, rn, imm */ \
1074 arm_data_proc(rscs, imm, flags); \
1077 case 0x30 ... 0x31: \
1079 arm_data_proc_test(tst, imm); \
1083 /* MSR cpsr, imm */ \
1084 arm_psr(imm, store, cpsr); \
1089 arm_data_proc_test(teq, imm); \
1092 case 0x34 ... 0x35: \
1094 arm_data_proc_test(cmp, imm); \
1098 /* MSR spsr, imm */ \
1099 arm_psr(imm, store, spsr); \
1104 arm_data_proc_test(cmn, imm); \
1108 /* ORR rd, rn, imm */ \
1109 arm_data_proc(orr, imm, no_flags); \
1113 /* ORRS rd, rn, imm */ \
1114 arm_data_proc(orrs, imm_flags, flags); \
1119 arm_data_proc_unary(mov, imm, no_flags); \
1123 /* MOVS rd, imm */ \
1124 arm_data_proc_unary(movs, imm_flags, flags); \
1128 /* BIC rd, rn, imm */ \
1129 arm_data_proc(bic, imm, no_flags); \
1133 /* BICS rd, rn, imm */ \
1134 arm_data_proc(bics, imm_flags, flags); \
1139 arm_data_proc_unary(mvn, imm, no_flags); \
1143 /* MVNS rd, imm */ \
1144 arm_data_proc_unary(mvns, imm_flags, flags); \
1148 /* STR rd, [rn], -imm */ \
1149 arm_access_memory(store, down, post, u32, imm); \
1153 /* LDR rd, [rn], -imm */ \
1154 arm_access_memory(load, down, post, u32, imm); \
1158 /* STRT rd, [rn], -imm */ \
1159 arm_access_memory(store, down, post, u32, imm); \
1163 /* LDRT rd, [rn], -imm */ \
1164 arm_access_memory(load, down, post, u32, imm); \
1168 /* STRB rd, [rn], -imm */ \
1169 arm_access_memory(store, down, post, u8, imm); \
1173 /* LDRB rd, [rn], -imm */ \
1174 arm_access_memory(load, down, post, u8, imm); \
1178 /* STRBT rd, [rn], -imm */ \
1179 arm_access_memory(store, down, post, u8, imm); \
1183 /* LDRBT rd, [rn], -imm */ \
1184 arm_access_memory(load, down, post, u8, imm); \
1188 /* STR rd, [rn], +imm */ \
1189 arm_access_memory(store, up, post, u32, imm); \
1193 /* LDR rd, [rn], +imm */ \
1194 arm_access_memory(load, up, post, u32, imm); \
1198 /* STRT rd, [rn], +imm */ \
1199 arm_access_memory(store, up, post, u32, imm); \
1203 /* LDRT rd, [rn], +imm */ \
1204 arm_access_memory(load, up, post, u32, imm); \
1208 /* STRB rd, [rn], +imm */ \
1209 arm_access_memory(store, up, post, u8, imm); \
1213 /* LDRB rd, [rn], +imm */ \
1214 arm_access_memory(load, up, post, u8, imm); \
1218 /* STRBT rd, [rn], +imm */ \
1219 arm_access_memory(store, up, post, u8, imm); \
1223 /* LDRBT rd, [rn], +imm */ \
1224 arm_access_memory(load, up, post, u8, imm); \
1228 /* STR rd, [rn - imm] */ \
1229 arm_access_memory(store, down, pre, u32, imm); \
1233 /* LDR rd, [rn - imm] */ \
1234 arm_access_memory(load, down, pre, u32, imm); \
1238 /* STR rd, [rn - imm]! */ \
1239 arm_access_memory(store, down, pre_wb, u32, imm); \
1243 /* LDR rd, [rn - imm]! */ \
1244 arm_access_memory(load, down, pre_wb, u32, imm); \
1248 /* STRB rd, [rn - imm] */ \
1249 arm_access_memory(store, down, pre, u8, imm); \
1253 /* LDRB rd, [rn - imm] */ \
1254 arm_access_memory(load, down, pre, u8, imm); \
1258 /* STRB rd, [rn - imm]! */ \
1259 arm_access_memory(store, down, pre_wb, u8, imm); \
1263 /* LDRB rd, [rn - imm]! */ \
1264 arm_access_memory(load, down, pre_wb, u8, imm); \
1268 /* STR rd, [rn + imm] */ \
1269 arm_access_memory(store, up, pre, u32, imm); \
1273 /* LDR rd, [rn + imm] */ \
1274 arm_access_memory(load, up, pre, u32, imm); \
1278 /* STR rd, [rn + imm]! */ \
1279 arm_access_memory(store, up, pre_wb, u32, imm); \
1283 /* LDR rd, [rn + imm]! */ \
1284 arm_access_memory(load, up, pre_wb, u32, imm); \
1288 /* STRB rd, [rn + imm] */ \
1289 arm_access_memory(store, up, pre, u8, imm); \
1293 /* LDRB rd, [rn + imm] */ \
1294 arm_access_memory(load, up, pre, u8, imm); \
1298 /* STRB rd, [rn + imm]! */ \
1299 arm_access_memory(store, up, pre_wb, u8, imm); \
1303 /* LDRBT rd, [rn + imm]! */ \
1304 arm_access_memory(load, up, pre_wb, u8, imm); \
1308 /* STR rd, [rn], -rm */ \
1309 arm_access_memory(store, down, post, u32, reg); \
1313 /* LDR rd, [rn], -rm */ \
1314 arm_access_memory(load, down, post, u32, reg); \
1318 /* STRT rd, [rn], -rm */ \
1319 arm_access_memory(store, down, post, u32, reg); \
1323 /* LDRT rd, [rn], -rm */ \
1324 arm_access_memory(load, down, post, u32, reg); \
1328 /* STRB rd, [rn], -rm */ \
1329 arm_access_memory(store, down, post, u8, reg); \
1333 /* LDRB rd, [rn], -rm */ \
1334 arm_access_memory(load, down, post, u8, reg); \
1338 /* STRBT rd, [rn], -rm */ \
1339 arm_access_memory(store, down, post, u8, reg); \
1343 /* LDRBT rd, [rn], -rm */ \
1344 arm_access_memory(load, down, post, u8, reg); \
1348 /* STR rd, [rn], +rm */ \
1349 arm_access_memory(store, up, post, u32, reg); \
1353 /* LDR rd, [rn], +rm */ \
1354 arm_access_memory(load, up, post, u32, reg); \
1358 /* STRT rd, [rn], +rm */ \
1359 arm_access_memory(store, up, post, u32, reg); \
1363 /* LDRT rd, [rn], +rm */ \
1364 arm_access_memory(load, up, post, u32, reg); \
1368 /* STRB rd, [rn], +rm */ \
1369 arm_access_memory(store, up, post, u8, reg); \
1373 /* LDRB rd, [rn], +rm */ \
1374 arm_access_memory(load, up, post, u8, reg); \
1378 /* STRBT rd, [rn], +rm */ \
1379 arm_access_memory(store, up, post, u8, reg); \
1383 /* LDRBT rd, [rn], +rm */ \
1384 arm_access_memory(load, up, post, u8, reg); \
1388 /* STR rd, [rn - rm] */ \
1389 arm_access_memory(store, down, pre, u32, reg); \
1393 /* LDR rd, [rn - rm] */ \
1394 arm_access_memory(load, down, pre, u32, reg); \
1398 /* STR rd, [rn - rm]! */ \
1399 arm_access_memory(store, down, pre_wb, u32, reg); \
1403 /* LDR rd, [rn - rm]! */ \
1404 arm_access_memory(load, down, pre_wb, u32, reg); \
1408 /* STRB rd, [rn - rm] */ \
1409 arm_access_memory(store, down, pre, u8, reg); \
1413 /* LDRB rd, [rn - rm] */ \
1414 arm_access_memory(load, down, pre, u8, reg); \
1418 /* STRB rd, [rn - rm]! */ \
1419 arm_access_memory(store, down, pre_wb, u8, reg); \
1423 /* LDRB rd, [rn - rm]! */ \
1424 arm_access_memory(load, down, pre_wb, u8, reg); \
1428 /* STR rd, [rn + rm] */ \
1429 arm_access_memory(store, up, pre, u32, reg); \
1433 /* LDR rd, [rn + rm] */ \
1434 arm_access_memory(load, up, pre, u32, reg); \
1438 /* STR rd, [rn + rm]! */ \
1439 arm_access_memory(store, up, pre_wb, u32, reg); \
1443 /* LDR rd, [rn + rm]! */ \
1444 arm_access_memory(load, up, pre_wb, u32, reg); \
1448 /* STRB rd, [rn + rm] */ \
1449 arm_access_memory(store, up, pre, u8, reg); \
1453 /* LDRB rd, [rn + rm] */ \
1454 arm_access_memory(load, up, pre, u8, reg); \
1458 /* STRB rd, [rn + rm]! */ \
1459 arm_access_memory(store, up, pre_wb, u8, reg); \
1463 /* LDRBT rd, [rn + rm]! */ \
1464 arm_access_memory(load, up, pre_wb, u8, reg); \
1468 /* STMDA rn, rlist */ \
1469 arm_block_memory(store, down_a, no, no); \
1473 /* LDMDA rn, rlist */ \
1474 arm_block_memory(load, down_a, no, no); \
1478 /* STMDA rn!, rlist */ \
1479 arm_block_memory(store, down_a, down, no); \
1483 /* LDMDA rn!, rlist */ \
1484 arm_block_memory(load, down_a, down, no); \
1488 /* STMDA rn, rlist^ */ \
1489 arm_block_memory(store, down_a, no, yes); \
1493 /* LDMDA rn, rlist^ */ \
1494 arm_block_memory(load, down_a, no, yes); \
1498 /* STMDA rn!, rlist^ */ \
1499 arm_block_memory(store, down_a, down, yes); \
1503 /* LDMDA rn!, rlist^ */ \
1504 arm_block_memory(load, down_a, down, yes); \
1508 /* STMIA rn, rlist */ \
1509 arm_block_memory(store, no, no, no); \
1513 /* LDMIA rn, rlist */ \
1514 arm_block_memory(load, no, no, no); \
1518 /* STMIA rn!, rlist */ \
1519 arm_block_memory(store, no, up, no); \
1523 /* LDMIA rn!, rlist */ \
1524 arm_block_memory(load, no, up, no); \
1528 /* STMIA rn, rlist^ */ \
1529 arm_block_memory(store, no, no, yes); \
1533 /* LDMIA rn, rlist^ */ \
1534 arm_block_memory(load, no, no, yes); \
1538 /* STMIA rn!, rlist^ */ \
1539 arm_block_memory(store, no, up, yes); \
1543 /* LDMIA rn!, rlist^ */ \
1544 arm_block_memory(load, no, up, yes); \
1548 /* STMDB rn, rlist */ \
1549 arm_block_memory(store, down_b, no, no); \
1553 /* LDMDB rn, rlist */ \
1554 arm_block_memory(load, down_b, no, no); \
1558 /* STMDB rn!, rlist */ \
1559 arm_block_memory(store, down_b, down, no); \
1563 /* LDMDB rn!, rlist */ \
1564 arm_block_memory(load, down_b, down, no); \
1568 /* STMDB rn, rlist^ */ \
1569 arm_block_memory(store, down_b, no, yes); \
1573 /* LDMDB rn, rlist^ */ \
1574 arm_block_memory(load, down_b, no, yes); \
1578 /* STMDB rn!, rlist^ */ \
1579 arm_block_memory(store, down_b, down, yes); \
1583 /* LDMDB rn!, rlist^ */ \
1584 arm_block_memory(load, down_b, down, yes); \
1588 /* STMIB rn, rlist */ \
1589 arm_block_memory(store, up, no, no); \
1593 /* LDMIB rn, rlist */ \
1594 arm_block_memory(load, up, no, no); \
1598 /* STMIB rn!, rlist */ \
1599 arm_block_memory(store, up, up, no); \
1603 /* LDMIB rn!, rlist */ \
1604 arm_block_memory(load, up, up, no); \
1608 /* STMIB rn, rlist^ */ \
1609 arm_block_memory(store, up, no, yes); \
1613 /* LDMIB rn, rlist^ */ \
1614 arm_block_memory(load, up, no, yes); \
1618 /* STMIB rn!, rlist^ */ \
1619 arm_block_memory(store, up, up, yes); \
1623 /* LDMIB rn!, rlist^ */ \
1624 arm_block_memory(load, up, up, yes); \
1627 case 0xA0 ... 0xAF: \
1634 case 0xB0 ... 0xBF: \
1641 case 0xC0 ... 0xEF: \
1642 /* coprocessor instructions, reserved on GBA */ \
1645 case 0xF0 ... 0xFF: \
1655 #define arm_flag_status() \
1657 #define translate_thumb_instruction() \
1658 flag_status = block_data[block_data_position].flag_data; \
1659 check_pc_region(pc); \
1660 last_opcode = opcode; \
1661 opcode = address16(pc_address_block, (pc & 0x7FFF)); \
1663 switch((opcode >> 8) & 0xFF) \
1665 case 0x00 ... 0x07: \
1666 /* LSL rd, rs, imm */ \
1667 thumb_shift(shift, lsl, imm); \
1670 case 0x08 ... 0x0F: \
1671 /* LSR rd, rs, imm */ \
1672 thumb_shift(shift, lsr, imm); \
1675 case 0x10 ... 0x17: \
1676 /* ASR rd, rs, imm */ \
1677 thumb_shift(shift, asr, imm); \
1680 case 0x18 ... 0x19: \
1681 /* ADD rd, rs, rn */ \
1682 thumb_data_proc(add_sub, adds, reg, rd, rs, rn); \
1685 case 0x1A ... 0x1B: \
1686 /* SUB rd, rs, rn */ \
1687 thumb_data_proc(add_sub, subs, reg, rd, rs, rn); \
1690 case 0x1C ... 0x1D: \
1691 /* ADD rd, rs, imm */ \
1692 thumb_data_proc(add_sub_imm, adds, imm, rd, rs, imm); \
1695 case 0x1E ... 0x1F: \
1696 /* SUB rd, rs, imm */ \
1697 thumb_data_proc(add_sub_imm, subs, imm, rd, rs, imm); \
1702 thumb_data_proc_unary(imm, movs, imm, 0, imm); \
1707 thumb_data_proc_unary(imm, movs, imm, 1, imm); \
1712 thumb_data_proc_unary(imm, movs, imm, 2, imm); \
1717 thumb_data_proc_unary(imm, movs, imm, 3, imm); \
1722 thumb_data_proc_unary(imm, movs, imm, 4, imm); \
1727 thumb_data_proc_unary(imm, movs, imm, 5, imm); \
1732 thumb_data_proc_unary(imm, movs, imm, 6, imm); \
1737 thumb_data_proc_unary(imm, movs, imm, 7, imm); \
1742 thumb_data_proc_test(imm, cmp, imm, 0, imm); \
1747 thumb_data_proc_test(imm, cmp, imm, 1, imm); \
1752 thumb_data_proc_test(imm, cmp, imm, 2, imm); \
1757 thumb_data_proc_test(imm, cmp, imm, 3, imm); \
1762 thumb_data_proc_test(imm, cmp, imm, 4, imm); \
1767 thumb_data_proc_test(imm, cmp, imm, 5, imm); \
1772 thumb_data_proc_test(imm, cmp, imm, 6, imm); \
1777 thumb_data_proc_test(imm, cmp, imm, 7, imm); \
1782 thumb_data_proc(imm, adds, imm, 0, 0, imm); \
1787 thumb_data_proc(imm, adds, imm, 1, 1, imm); \
1792 thumb_data_proc(imm, adds, imm, 2, 2, imm); \
1797 thumb_data_proc(imm, adds, imm, 3, 3, imm); \
1802 thumb_data_proc(imm, adds, imm, 4, 4, imm); \
1807 thumb_data_proc(imm, adds, imm, 5, 5, imm); \
1812 thumb_data_proc(imm, adds, imm, 6, 6, imm); \
1817 thumb_data_proc(imm, adds, imm, 7, 7, imm); \
1822 thumb_data_proc(imm, subs, imm, 0, 0, imm); \
1827 thumb_data_proc(imm, subs, imm, 1, 1, imm); \
1832 thumb_data_proc(imm, subs, imm, 2, 2, imm); \
1837 thumb_data_proc(imm, subs, imm, 3, 3, imm); \
1842 thumb_data_proc(imm, subs, imm, 4, 4, imm); \
1847 thumb_data_proc(imm, subs, imm, 5, 5, imm); \
1852 thumb_data_proc(imm, subs, imm, 6, 6, imm); \
1857 thumb_data_proc(imm, subs, imm, 7, 7, imm); \
1861 switch((opcode >> 6) & 0x03) \
1865 thumb_data_proc(alu_op, ands, reg, rd, rd, rs); \
1870 thumb_data_proc(alu_op, eors, reg, rd, rd, rs); \
1875 thumb_shift(alu_op, lsl, reg); \
1880 thumb_shift(alu_op, lsr, reg); \
1886 switch((opcode >> 6) & 0x03) \
1890 thumb_shift(alu_op, asr, reg); \
1895 thumb_data_proc(alu_op, adcs, reg, rd, rd, rs); \
1900 thumb_data_proc(alu_op, sbcs, reg, rd, rd, rs); \
1905 thumb_shift(alu_op, ror, reg); \
1911 switch((opcode >> 6) & 0x03) \
1915 thumb_data_proc_test(alu_op, tst, reg, rd, rs); \
1920 thumb_data_proc_unary(alu_op, neg, reg, rd, rs); \
1925 thumb_data_proc_test(alu_op, cmp, reg, rd, rs); \
1930 thumb_data_proc_test(alu_op, cmn, reg, rd, rs); \
1936 switch((opcode >> 6) & 0x03) \
1940 thumb_data_proc(alu_op, orrs, reg, rd, rd, rs); \
1945 thumb_data_proc(alu_op, muls, reg, rd, rd, rs); \
1950 thumb_data_proc(alu_op, bics, reg, rd, rd, rs); \
1955 thumb_data_proc_unary(alu_op, mvns, reg, rd, rs); \
1962 thumb_data_proc_hi(add); \
1967 thumb_data_proc_test_hi(cmp); \
1972 thumb_data_proc_mov_hi(); \
1981 /* LDR r0, [pc + imm] */ \
1982 thumb_access_memory(load, imm, 0, 0, 0, pc_relative, \
1983 (pc & ~2) + (imm * 4) + 4, u32); \
1987 /* LDR r1, [pc + imm] */ \
1988 thumb_access_memory(load, imm, 1, 0, 0, pc_relative, \
1989 (pc & ~2) + (imm * 4) + 4, u32); \
1993 /* LDR r2, [pc + imm] */ \
1994 thumb_access_memory(load, imm, 2, 0, 0, pc_relative, \
1995 (pc & ~2) + (imm * 4) + 4, u32); \
1999 /* LDR r3, [pc + imm] */ \
2000 thumb_access_memory(load, imm, 3, 0, 0, pc_relative, \
2001 (pc & ~2) + (imm * 4) + 4, u32); \
2005 /* LDR r4, [pc + imm] */ \
2006 thumb_access_memory(load, imm, 4, 0, 0, pc_relative, \
2007 (pc & ~2) + (imm * 4) + 4, u32); \
2011 /* LDR r5, [pc + imm] */ \
2012 thumb_access_memory(load, imm, 5, 0, 0, pc_relative, \
2013 (pc & ~2) + (imm * 4) + 4, u32); \
2017 /* LDR r6, [pc + imm] */ \
2018 thumb_access_memory(load, imm, 6, 0, 0, pc_relative, \
2019 (pc & ~2) + (imm * 4) + 4, u32); \
2023 /* LDR r7, [pc + imm] */ \
2024 thumb_access_memory(load, imm, 7, 0, 0, pc_relative, \
2025 (pc & ~2) + (imm * 4) + 4, u32); \
2028 case 0x50 ... 0x51: \
2029 /* STR rd, [rb + ro] */ \
2030 thumb_access_memory(store, mem_reg, rd, rb, ro, reg_reg, 0, u32); \
2033 case 0x52 ... 0x53: \
2034 /* STRH rd, [rb + ro] */ \
2035 thumb_access_memory(store, mem_reg, rd, rb, ro, reg_reg, 0, u16); \
2038 case 0x54 ... 0x55: \
2039 /* STRB rd, [rb + ro] */ \
2040 thumb_access_memory(store, mem_reg, rd, rb, ro, reg_reg, 0, u8); \
2043 case 0x56 ... 0x57: \
2044 /* LDSB rd, [rb + ro] */ \
2045 thumb_access_memory(load, mem_reg, rd, rb, ro, reg_reg, 0, s8); \
2048 case 0x58 ... 0x59: \
2049 /* LDR rd, [rb + ro] */ \
2050 thumb_access_memory(load, mem_reg, rd, rb, ro, reg_reg, 0, u32); \
2053 case 0x5A ... 0x5B: \
2054 /* LDRH rd, [rb + ro] */ \
2055 thumb_access_memory(load, mem_reg, rd, rb, ro, reg_reg, 0, u16); \
2058 case 0x5C ... 0x5D: \
2059 /* LDRB rd, [rb + ro] */ \
2060 thumb_access_memory(load, mem_reg, rd, rb, ro, reg_reg, 0, u8); \
2063 case 0x5E ... 0x5F: \
2064 /* LDSH rd, [rb + ro] */ \
2065 thumb_access_memory(load, mem_reg, rd, rb, ro, reg_reg, 0, s16); \
2068 case 0x60 ... 0x67: \
2069 /* STR rd, [rb + imm] */ \
2070 thumb_access_memory(store, mem_imm, rd, rb, 0, reg_imm, (imm * 4), \
2074 case 0x68 ... 0x6F: \
2075 /* LDR rd, [rb + imm] */ \
2076 thumb_access_memory(load, mem_imm, rd, rb, 0, reg_imm, (imm * 4), u32); \
2079 case 0x70 ... 0x77: \
2080 /* STRB rd, [rb + imm] */ \
2081 thumb_access_memory(store, mem_imm, rd, rb, 0, reg_imm, imm, u8); \
2084 case 0x78 ... 0x7F: \
2085 /* LDRB rd, [rb + imm] */ \
2086 thumb_access_memory(load, mem_imm, rd, rb, 0, reg_imm, imm, u8); \
2089 case 0x80 ... 0x87: \
2090 /* STRH rd, [rb + imm] */ \
2091 thumb_access_memory(store, mem_imm, rd, rb, 0, reg_imm, \
2095 case 0x88 ... 0x8F: \
2096 /* LDRH rd, [rb + imm] */ \
2097 thumb_access_memory(load, mem_imm, rd, rb, 0, reg_imm, (imm * 2), u16); \
2101 /* STR r0, [sp + imm] */ \
2102 thumb_access_memory(store, imm, 0, 13, 0, reg_imm_sp, imm, u32); \
2106 /* STR r1, [sp + imm] */ \
2107 thumb_access_memory(store, imm, 1, 13, 0, reg_imm_sp, imm, u32); \
2111 /* STR r2, [sp + imm] */ \
2112 thumb_access_memory(store, imm, 2, 13, 0, reg_imm_sp, imm, u32); \
2116 /* STR r3, [sp + imm] */ \
2117 thumb_access_memory(store, imm, 3, 13, 0, reg_imm_sp, imm, u32); \
2121 /* STR r4, [sp + imm] */ \
2122 thumb_access_memory(store, imm, 4, 13, 0, reg_imm_sp, imm, u32); \
2126 /* STR r5, [sp + imm] */ \
2127 thumb_access_memory(store, imm, 5, 13, 0, reg_imm_sp, imm, u32); \
2131 /* STR r6, [sp + imm] */ \
2132 thumb_access_memory(store, imm, 6, 13, 0, reg_imm_sp, imm, u32); \
2136 /* STR r7, [sp + imm] */ \
2137 thumb_access_memory(store, imm, 7, 13, 0, reg_imm_sp, imm, u32); \
2141 /* LDR r0, [sp + imm] */ \
2142 thumb_access_memory(load, imm, 0, 13, 0, reg_imm_sp, imm, u32); \
2146 /* LDR r1, [sp + imm] */ \
2147 thumb_access_memory(load, imm, 1, 13, 0, reg_imm_sp, imm, u32); \
2151 /* LDR r2, [sp + imm] */ \
2152 thumb_access_memory(load, imm, 2, 13, 0, reg_imm_sp, imm, u32); \
2156 /* LDR r3, [sp + imm] */ \
2157 thumb_access_memory(load, imm, 3, 13, 0, reg_imm_sp, imm, u32); \
2161 /* LDR r4, [sp + imm] */ \
2162 thumb_access_memory(load, imm, 4, 13, 0, reg_imm_sp, imm, u32); \
2166 /* LDR r5, [sp + imm] */ \
2167 thumb_access_memory(load, imm, 5, 13, 0, reg_imm_sp, imm, u32); \
2171 /* LDR r6, [sp + imm] */ \
2172 thumb_access_memory(load, imm, 6, 13, 0, reg_imm_sp, imm, u32); \
2176 /* LDR r7, [sp + imm] */ \
2177 thumb_access_memory(load, imm, 7, 13, 0, reg_imm_sp, imm, u32); \
2181 /* ADD r0, pc, +imm */ \
2186 /* ADD r1, pc, +imm */ \
2191 /* ADD r2, pc, +imm */ \
2196 /* ADD r3, pc, +imm */ \
2201 /* ADD r4, pc, +imm */ \
2206 /* ADD r5, pc, +imm */ \
2211 /* ADD r6, pc, +imm */ \
2216 /* ADD r7, pc, +imm */ \
2221 /* ADD r0, sp, +imm */ \
2226 /* ADD r1, sp, +imm */ \
2231 /* ADD r2, sp, +imm */ \
2236 /* ADD r3, sp, +imm */ \
2241 /* ADD r4, sp, +imm */ \
2246 /* ADD r5, sp, +imm */ \
2251 /* ADD r6, sp, +imm */ \
2256 /* ADD r7, sp, +imm */ \
2260 case 0xB0 ... 0xB3: \
2261 if((opcode >> 7) & 0x01) \
2263 /* ADD sp, -imm */ \
2264 thumb_adjust_sp(down); \
2268 /* ADD sp, +imm */ \
2269 thumb_adjust_sp(up); \
2275 thumb_block_memory(store, down, no, 13); \
2279 /* PUSH rlist, lr */ \
2280 thumb_block_memory(store, push_lr, push_lr, 13); \
2285 thumb_block_memory(load, no, up, 13); \
2289 /* POP rlist, pc */ \
2290 thumb_block_memory(load, no, pop_pc, 13); \
2294 /* STMIA r0!, rlist */ \
2295 thumb_block_memory(store, no, up, 0); \
2299 /* STMIA r1!, rlist */ \
2300 thumb_block_memory(store, no, up, 1); \
2304 /* STMIA r2!, rlist */ \
2305 thumb_block_memory(store, no, up, 2); \
2309 /* STMIA r3!, rlist */ \
2310 thumb_block_memory(store, no, up, 3); \
2314 /* STMIA r4!, rlist */ \
2315 thumb_block_memory(store, no, up, 4); \
2319 /* STMIA r5!, rlist */ \
2320 thumb_block_memory(store, no, up, 5); \
2324 /* STMIA r6!, rlist */ \
2325 thumb_block_memory(store, no, up, 6); \
2329 /* STMIA r7!, rlist */ \
2330 thumb_block_memory(store, no, up, 7); \
2334 /* LDMIA r0!, rlist */ \
2335 thumb_block_memory(load, no, up, 0); \
2339 /* LDMIA r1!, rlist */ \
2340 thumb_block_memory(load, no, up, 1); \
2344 /* LDMIA r2!, rlist */ \
2345 thumb_block_memory(load, no, up, 2); \
2349 /* LDMIA r3!, rlist */ \
2350 thumb_block_memory(load, no, up, 3); \
2354 /* LDMIA r4!, rlist */ \
2355 thumb_block_memory(load, no, up, 4); \
2359 /* LDMIA r5!, rlist */ \
2360 thumb_block_memory(load, no, up, 5); \
2364 /* LDMIA r6!, rlist */ \
2365 thumb_block_memory(load, no, up, 6); \
2369 /* LDMIA r7!, rlist */ \
2370 thumb_block_memory(load, no, up, 7); \
2375 thumb_conditional_branch(eq); \
2380 thumb_conditional_branch(ne); \
2385 thumb_conditional_branch(cs); \
2390 thumb_conditional_branch(cc); \
2395 thumb_conditional_branch(mi); \
2400 thumb_conditional_branch(pl); \
2405 thumb_conditional_branch(vs); \
2410 thumb_conditional_branch(vc); \
2415 thumb_conditional_branch(hi); \
2420 thumb_conditional_branch(ls); \
2425 thumb_conditional_branch(ge); \
2430 thumb_conditional_branch(lt); \
2435 thumb_conditional_branch(gt); \
2440 thumb_conditional_branch(le); \
2450 case 0xE0 ... 0xE7: \
2457 case 0xF0 ... 0xF7: \
2459 /* (low word) BL label */ \
2460 /* This should possibly generate code if not in conjunction with a BLH \
2461 next, but I don't think anyone will do that. */ \
2465 case 0xF8 ... 0xFF: \
2467 /* (high word) BL label */ \
2468 /* This might not be preceeding a BL low word (Golden Sun 2), if so \
2469 it must be handled like an indirect branch. */ \
2470 if((last_opcode >= 0xF000) && (last_opcode < 0xF800)) \
2484 #define thumb_flag_modifies_all() \
2485 flag_status |= 0xFF \
2487 #define thumb_flag_modifies_zn() \
2488 flag_status |= 0xCC \
2490 #define thumb_flag_modifies_znc() \
2491 flag_status |= 0xEE \
2493 #define thumb_flag_modifies_zn_maybe_c() \
2494 flag_status |= 0xCE \
2496 #define thumb_flag_modifies_c() \
2497 flag_status |= 0x22 \
2499 #define thumb_flag_requires_c() \
2500 flag_status |= 0x200 \
2502 #define thumb_flag_requires_all() \
2503 flag_status |= 0xF00 \
2505 #define thumb_flag_status() \
2507 u16 flag_status = 0; \
2508 switch((opcode >> 8) & 0xFF) \
2510 /* left shift by imm */ \
2511 case 0x00 ... 0x07: \
2512 thumb_flag_modifies_zn(); \
2513 if(((opcode >> 6) & 0x1F) != 0) \
2515 thumb_flag_modifies_c(); \
2519 /* right shift by imm */ \
2520 case 0x08 ... 0x17: \
2521 thumb_flag_modifies_znc(); \
2524 /* add, subtract */ \
2525 case 0x18 ... 0x1F: \
2526 thumb_flag_modifies_all(); \
2529 /* mov reg, imm */ \
2530 case 0x20 ... 0x27: \
2531 thumb_flag_modifies_zn(); \
2534 /* cmp reg, imm; add, subtract */ \
2535 case 0x28 ... 0x3F: \
2536 thumb_flag_modifies_all(); \
2540 switch((opcode >> 6) & 0x03) \
2544 thumb_flag_modifies_zn(); \
2549 thumb_flag_modifies_zn(); \
2554 thumb_flag_modifies_zn_maybe_c(); \
2559 thumb_flag_modifies_zn_maybe_c(); \
2565 switch((opcode >> 6) & 0x03) \
2569 thumb_flag_modifies_zn_maybe_c(); \
2574 thumb_flag_modifies_all(); \
2575 thumb_flag_requires_c(); \
2580 thumb_flag_modifies_all(); \
2581 thumb_flag_requires_c(); \
2586 thumb_flag_modifies_zn_maybe_c(); \
2591 /* TST, NEG, CMP, CMN */ \
2593 thumb_flag_modifies_all(); \
2596 /* ORR, MUL, BIC, MVN */ \
2598 thumb_flag_modifies_zn(); \
2603 thumb_flag_modifies_all(); \
2606 /* mov might change PC (fall through if so) */ \
2608 if((opcode & 0xFF87) != 0x4687) \
2611 /* branches (can change PC) */ \
2614 case 0xD0 ... 0xE7: \
2615 case 0xF0 ... 0xFF: \
2616 thumb_flag_requires_all(); \
2619 block_data[block_data_position].flag_data = flag_status; \
2622 u8 *ram_block_ptrs[1024 * 64];
2623 u32 ram_block_tag_top = 0x0101;
2625 u8 *bios_block_ptrs[1024 * 8];
2626 u32 bios_block_tag_top = 0x0101;
2628 // This function will return a pointer to a translated block of code. If it
2629 // doesn't exist it will translate it, if it does it will pass it back.
2631 // type should be "arm", "thumb", or "dual." For arm or thumb the PC should
2632 // be a real PC, for dual the least significant bit will determine if it's
2633 // ARM or Thumb mode.
2635 #define block_lookup_address_pc_arm() \
2638 #define block_lookup_address_pc_thumb() \
2641 #define block_lookup_address_pc_dual() \
2642 u32 thumb = pc & 0x01; \
2647 reg[REG_CPSR] |= 0x20; \
2651 pc = (pc + 2) & ~0x03; \
2652 reg[REG_CPSR] &= ~0x20; \
2655 #define ram_translation_region TRANSLATION_REGION_RAM
2656 #define rom_translation_region TRANSLATION_REGION_ROM
2657 #define bios_translation_region TRANSLATION_REGION_BIOS
2659 #define block_lookup_translate_arm(mem_type, smc_enable) \
2660 translation_result = translate_block_arm(pc, mem_type##_translation_region, \
2663 #define block_lookup_translate_thumb(mem_type, smc_enable) \
2664 translation_result = translate_block_thumb(pc, \
2665 mem_type##_translation_region, smc_enable) \
2667 #define block_lookup_translate_dual(mem_type, smc_enable) \
2670 translation_result = translate_block_thumb(pc, \
2671 mem_type##_translation_region, smc_enable); \
2675 translation_result = translate_block_arm(pc, \
2676 mem_type##_translation_region, smc_enable); \
2679 // 0x0101 is the smallest tag that can be used. 0xFFFF is marked
2680 // in the middle of blocks and used for write guarding, it doesn't
2681 // indicate a valid block either (it's okay to compile a new block
2682 // that overlaps the earlier one, although this should be relatively
2685 #define fill_tag_arm(mem_type) \
2686 location[0] = mem_type##_block_tag_top; \
2687 location[1] = 0xFFFF \
2689 #define fill_tag_thumb(mem_type) \
2690 *location = mem_type##_block_tag_top \
2692 #define fill_tag_dual(mem_type) \
2694 fill_tag_thumb(mem_type); \
2696 fill_tag_arm(mem_type) \
2698 #define block_lookup_translate(instruction_type, mem_type, smc_enable) \
2699 block_tag = *location; \
2700 if((block_tag < 0x0101) || (block_tag == 0xFFFF)) \
2703 s32 translation_result; \
2707 translation_recursion_level++; \
2708 block_address = mem_type##_translation_ptr + block_prologue_size; \
2709 mem_type##_block_ptrs[mem_type##_block_tag_top] = block_address; \
2710 fill_tag_##instruction_type(mem_type); \
2711 mem_type##_block_tag_top++; \
2713 block_lookup_translate_##instruction_type(mem_type, smc_enable); \
2714 translation_recursion_level--; \
2716 /* If the translation failed then pass that failure on if we're in \
2717 a recursive level, or try again if we've hit the bottom. */ \
2718 if(translation_result == -1) \
2720 if(translation_recursion_level) \
2726 if(translation_recursion_level == 0) \
2727 translate_invalidate_dcache(); \
2731 block_address = mem_type##_block_ptrs[block_tag]; \
2734 u32 translation_recursion_level = 0;
2735 u32 translation_flush_count = 0;
2738 #define block_lookup_address_builder(type) \
2739 u8 function_cc *block_lookup_address_##type(u32 pc) \
2743 u8 *block_address; \
2745 /* Starting at the beginning, we allow for one translation cache flush. */ \
2746 if(translation_recursion_level == 0) \
2747 translation_flush_count = 0; \
2748 block_lookup_address_pc_##type(); \
2753 bios_region_read_allow(); \
2754 location = (u16 *)(bios_rom + pc + 0x4000); \
2755 block_lookup_translate(type, bios, 0); \
2756 if(translation_recursion_level == 0) \
2757 bios_region_read_allow(); \
2761 location = (u16 *)(ewram + (pc & 0x7FFF) + ((pc & 0x38000) * 2)); \
2762 block_lookup_translate(type, ram, 1); \
2763 if(translation_recursion_level == 0) \
2764 bios_region_read_protect(); \
2768 location = (u16 *)(iwram + (pc & 0x7FFF)); \
2769 block_lookup_translate(type, ram, 1); \
2770 if(translation_recursion_level == 0) \
2771 bios_region_read_protect(); \
2776 u32 hash_target = ((pc * 2654435761U) >> 16) & \
2777 (ROM_BRANCH_HASH_SIZE - 1); \
2778 u32 *block_ptr = rom_branch_hash[hash_target]; \
2779 u32 **block_ptr_address = rom_branch_hash + hash_target; \
2783 if(block_ptr[0] == pc) \
2785 block_address = (u8 *)(block_ptr + 2) + block_prologue_size; \
2789 block_ptr_address = (u32 **)(block_ptr + 1); \
2790 block_ptr = (u32 *)block_ptr[1]; \
2793 if(block_ptr == NULL) \
2796 s32 translation_result; \
2800 translation_recursion_level++; \
2801 ((u32 *)rom_translation_ptr)[0] = pc; \
2802 ((u32 **)rom_translation_ptr)[1] = NULL; \
2803 *block_ptr_address = (u32 *)rom_translation_ptr; \
2804 rom_translation_ptr += 8; \
2805 block_address = rom_translation_ptr + block_prologue_size; \
2806 block_lookup_translate_##type(rom, 0); \
2807 translation_recursion_level--; \
2809 /* If the translation failed then pass that failure on if we're in \
2810 a recursive level, or try again if we've hit the bottom. */ \
2811 if(translation_result == -1) \
2813 if(translation_recursion_level) \
2819 if(translation_recursion_level == 0) \
2820 translate_invalidate_dcache(); \
2822 if(translation_recursion_level == 0) \
2823 bios_region_read_protect(); \
2828 /* If we're at the bottom, it means we're actually trying to jump to an \
2829 address that we can't handle. Otherwise, it means that code scanned \
2830 has reached an address that can't be handled, which means that we \
2831 have most likely hit an area that doesn't contain code yet (for \
2832 instance, in RAM). If such a thing happens, return -1 and the \
2833 block translater will naively link it (it'll be okay, since it \
2834 should never be hit) */ \
2835 if(translation_recursion_level == 0) \
2838 sprintf(buffer, "bad jump %x (%x) (%x)\n", pc, reg[REG_PC], \
2839 last_instruction); \
2843 block_address = (u8 *)(-1); \
2847 return block_address; \
2850 block_lookup_address_builder(arm);
2851 block_lookup_address_builder(thumb);
2852 block_lookup_address_builder(dual);
2854 // Potential exit point: If the rd field is pc for instructions is 0x0F,
2855 // the instruction is b/bl/bx, or the instruction is ldm with PC in the
2857 // All instructions with upper 3 bits less than 100b have an rd field
2858 // except bx, where the bits must be 0xF there anyway, multiplies,
2859 // which cannot have 0xF in the corresponding fields, and msr, which
2860 // has 0x0F there but doesn't end things (therefore must be special
2861 // checked against). Because MSR and BX overlap both are checked for.
2863 #define arm_exit_point \
2864 (((opcode < 0x8000000) && ((opcode & 0x000F000) == 0x000F000) && \
2865 ((opcode & 0xDB0F000) != 0x120F000)) || \
2866 ((opcode & 0x12FFF10) == 0x12FFF10) || \
2867 ((opcode & 0x8108000) == 0x8108000) || \
2868 ((opcode >= 0xA000000) && (opcode < 0xF000000)) || \
2869 ((opcode > 0xF000000) && (!swi_hle_handle[((opcode >> 16) & 0xFF)]))) \
2871 #define arm_opcode_branch \
2872 ((opcode & 0xE000000) == 0xA000000) \
2874 #define arm_opcode_swi \
2875 ((opcode & 0xF000000) == 0xF000000) \
2877 #define arm_opcode_unconditional_branch \
2878 (condition == 0x0E) \
2880 #define arm_load_opcode() \
2881 opcode = address32(pc_address_block, (block_end_pc & 0x7FFF)); \
2882 condition = opcode >> 28; \
2884 opcode &= 0xFFFFFFF; \
2888 #define arm_branch_target() \
2889 branch_target = (block_end_pc + 4 + (((s32)(opcode & 0xFFFFFF) << 8) >> 6)) \
2891 // Contiguous conditional block flags modification - it will set 0x20 in the
2892 // condition's bits if this instruction modifies flags. Taken from the CPU
2893 // switch so it'd better be right this time.
2895 #define arm_set_condition(_condition) \
2896 block_data[block_data_position].condition = _condition; \
2897 switch((opcode >> 20) & 0xFF) \
2905 if((((opcode >> 5) & 0x03) == 0) || ((opcode & 0x90) != 0x90)) \
2906 block_data[block_data_position].condition |= 0x20; \
2913 case 0x15 ... 0x17: \
2918 if((opcode & 0x90) != 0x90) \
2919 block_data[block_data_position].condition |= 0x20; \
2923 if(((opcode & 0x90) != 0x90) && !(opcode & 0x10)) \
2924 block_data[block_data_position].condition |= 0x20; \
2934 case 0x2F ... 0x37: \
2939 block_data[block_data_position].condition |= 0x20; \
2943 #define arm_link_block() \
2944 translation_target = block_lookup_address_arm(branch_target) \
2946 #define arm_instruction_width 4
2948 #define arm_base_cycles() \
2949 cycle_count += waitstate_cycles_sequential[pc >> 24][2] \
2951 // For now this just sets a variable that says flags should always be
2954 #define arm_dead_flag_eliminate() \
2957 // The following Thumb instructions can exit:
2958 // b, bl, bx, swi, pop {... pc}, and mov pc, ..., the latter being a hireg
2959 // op only. Rather simpler to identify than the ARM set.
2961 #define thumb_exit_point \
2962 (((opcode >= 0xD000) && (opcode < 0xDF00)) || \
2963 (((opcode & 0xFF00) == 0xDF00) && \
2964 (!swi_hle_handle[opcode & 0xFF])) || \
2965 ((opcode >= 0xE000) && (opcode < 0xE800)) || \
2966 ((opcode & 0xFF00) == 0x4700) || \
2967 ((opcode & 0xFF00) == 0xBD00) || \
2968 ((opcode & 0xFF87) == 0x4687) || \
2969 ((opcode >= 0xF800))) \
2971 #define thumb_opcode_branch \
2972 (((opcode >= 0xD000) && (opcode < 0xDF00)) || \
2973 ((opcode >= 0xE000) && (opcode < 0xE800)) || \
2974 (opcode >= 0xF800)) \
2976 #define thumb_opcode_swi \
2977 ((opcode & 0xFF00) == 0xDF00) \
2979 #define thumb_opcode_unconditional_branch \
2980 ((opcode < 0xD000) || (opcode >= 0xDF00)) \
2982 #define thumb_load_opcode() \
2983 last_opcode = opcode; \
2984 opcode = address16(pc_address_block, (block_end_pc & 0x7FFF)); \
2988 #define thumb_branch_target() \
2989 if(opcode < 0xE000) \
2991 branch_target = block_end_pc + 2 + ((s8)(opcode & 0xFF) * 2); \
2995 if(opcode < 0xF800) \
2997 branch_target = block_end_pc + 2 + ((s32)((opcode & 0x7FF) << 21) >> 20); \
3001 if((last_opcode >= 0xF000) && (last_opcode < 0xF800)) \
3004 (block_end_pc + ((s32)((last_opcode & 0x07FF) << 21) >> 9) + \
3005 ((opcode & 0x07FF) * 2)); \
3009 goto no_direct_branch; \
3013 #define thumb_set_condition(_condition) \
3015 #define thumb_link_block() \
3016 if(branch_target != 0x00000008) \
3017 translation_target = block_lookup_address_thumb(branch_target); \
3019 translation_target = block_lookup_address_arm(branch_target) \
3021 #define thumb_instruction_width 2
3023 #define thumb_base_cycles() \
3024 cycle_count += waitstate_cycles_sequential[pc >> 24][1] \
3026 // Here's how this works: each instruction has three different sets of flag
3027 // attributes, each consisiting of a 4bit mask describing how that instruction
3028 // interacts with the 4 main flags (N/Z/C/V).
3029 // The first set, in bits 0:3, is the set of flags the instruction may
3030 // modify. After this pass this is changed to the set of flags the instruction
3031 // should modify - if the bit for the corresponding flag is not set then code
3032 // does not have to be generated to calculate the flag for that instruction.
3034 // The second set, in bits 7:4, is the set of flags that the instruction must
3035 // modify (ie, for shifts by the register values the instruction may not
3036 // always modify the C flag, and thus the C bit won't be set here).
3038 // The third set, in bits 11:8, is the set of flags that the instruction uses
3039 // in its computation, or the set of flags that will be needed after the
3040 // instruction is done. For any instructions that change the PC all of the
3041 // bits should be set because it is (for now) unknown what flags will be
3042 // needed after it arrives at its destination. Instructions that use the
3043 // carry flag as input will have it set as well.
3045 // The algorithm is a simple liveness analysis procedure: It starts at the
3046 // bottom of the instruction stream and sets a "currently needed" mask to
3047 // the flags needed mask of the current instruction. Then it moves down
3048 // an instruction, ANDs that instructions "should generate" mask by the
3049 // "currently needed" mask, then ANDs the "currently needed" mask by
3050 // the 1's complement of the instruction's "must generate" mask, and ORs
3051 // the "currently needed" mask by the instruction's "flags needed" mask.
3053 #define thumb_dead_flag_eliminate() \
3056 needed_mask = block_data[block_data_position].flag_data >> 8; \
3058 block_data_position--; \
3059 while(block_data_position >= 0) \
3061 flag_status = block_data[block_data_position].flag_data; \
3062 block_data[block_data_position].flag_data = \
3063 (flag_status & needed_mask); \
3064 needed_mask &= ~((flag_status >> 4) & 0x0F); \
3065 needed_mask |= flag_status >> 8; \
3066 block_data_position--; \
3070 #define MAX_BLOCK_SIZE 8192
3071 #define MAX_EXITS 256
3073 block_data_type block_data[MAX_BLOCK_SIZE];
3074 block_exit_type block_exits[MAX_EXITS];
3076 #define smc_write_arm_yes() \
3077 if(address32(pc_address_block, (block_end_pc & 0x7FFF) - 0x8000) == 0x0000) \
3079 address32(pc_address_block, (block_end_pc & 0x7FFF) - 0x8000) = \
3083 #define smc_write_thumb_yes() \
3084 if(address16(pc_address_block, (block_end_pc & 0x7FFF) - 0x8000) == 0x0000) \
3086 address16(pc_address_block, (block_end_pc & 0x7FFF) - 0x8000) = 0xFFFF; \
3089 #define smc_write_arm_no() \
3091 #define smc_write_thumb_no() \
3093 #define scan_block(type, smc_write_op) \
3095 __label__ block_end; \
3096 /* Find the end of the block */ \
3099 check_pc_region(block_end_pc); \
3100 smc_write_##type##_##smc_write_op(); \
3101 type##_load_opcode(); \
3102 type##_flag_status(); \
3104 if(type##_exit_point) \
3106 /* Branch/branch with link */ \
3107 if(type##_opcode_branch) \
3109 __label__ no_direct_branch; \
3110 type##_branch_target(); \
3111 block_exits[block_exit_position].branch_target = branch_target; \
3112 block_exit_position++; \
3114 /* Give the branch target macro somewhere to bail if it turns out to \
3115 be an indirect branch (ala malformed Thumb bl) */ \
3116 no_direct_branch:; \
3119 /* SWI branches to the BIOS, this will likely change when \
3120 some HLE BIOS is implemented. */ \
3121 if(type##_opcode_swi) \
3123 block_exits[block_exit_position].branch_target = 0x00000008; \
3124 block_exit_position++; \
3127 type##_set_condition(condition | 0x10); \
3129 /* Only unconditional branches can end the block. */ \
3130 if(type##_opcode_unconditional_branch) \
3132 /* Check to see if any prior block exits branch after here, \
3133 if so don't end the block. Starts from the top and works \
3134 down because the most recent branch is most likely to \
3135 join after the end (if/then form) */ \
3136 for(i = block_exit_position - 2; i >= 0; i--) \
3138 if(block_exits[i].branch_target == block_end_pc) \
3145 if(block_exit_position == MAX_EXITS) \
3150 type##_set_condition(condition); \
3153 for(i = 0; i < translation_gate_targets; i++) \
3155 if(block_end_pc == translation_gate_target_pc[i]) \
3159 block_data[block_data_position].update_cycles = 0; \
3160 block_data_position++; \
3161 if((block_data_position == MAX_BLOCK_SIZE) || \
3162 (block_end_pc == 0x3007FF0) || (block_end_pc == 0x203FFFF0)) \
3171 #define arm_fix_pc() \
3174 #define thumb_fix_pc() \
3177 #define translate_block_builder(type) \
3178 s32 translate_block_##type(u32 pc, translation_region_type \
3179 translation_region, u32 smc_enable) \
3184 u32 last_condition; \
3185 u32 pc_region = (pc >> 15); \
3186 u32 new_pc_region; \
3187 u8 *pc_address_block = memory_map_read[pc_region]; \
3188 u32 block_start_pc = pc; \
3189 u32 block_end_pc = pc; \
3190 u32 block_exit_position = 0; \
3191 s32 block_data_position = 0; \
3192 u32 external_block_exit_position = 0; \
3193 u32 branch_target; \
3194 u32 cycle_count = 0; \
3195 u8 *translation_target; \
3196 u8 *backpatch_address; \
3197 u8 *translation_ptr; \
3198 u8 *translation_cache_limit; \
3201 block_exit_type external_block_exits[MAX_EXITS]; \
3202 generate_block_extra_vars_##type(); \
3205 if(pc_address_block == NULL) \
3206 pc_address_block = load_gamepak_page(pc_region & 0x3FF); \
3208 switch(translation_region) \
3210 case TRANSLATION_REGION_RAM: \
3211 if(pc >= 0x3000000) \
3213 if((pc < iwram_code_min) || (iwram_code_min == 0xFFFFFFFF)) \
3214 iwram_code_min = pc; \
3218 if(pc >= 0x2000000) \
3220 if((pc < ewram_code_min) || (ewram_code_min == 0xFFFFFFFF)) \
3221 ewram_code_min = pc; \
3224 translation_ptr = ram_translation_ptr; \
3225 translation_cache_limit = \
3226 ram_translation_cache + RAM_TRANSLATION_CACHE_SIZE - \
3227 TRANSLATION_CACHE_LIMIT_THRESHOLD; \
3230 case TRANSLATION_REGION_ROM: \
3231 translation_ptr = rom_translation_ptr; \
3232 translation_cache_limit = \
3233 rom_translation_cache + ROM_TRANSLATION_CACHE_SIZE - \
3234 TRANSLATION_CACHE_LIMIT_THRESHOLD; \
3237 case TRANSLATION_REGION_BIOS: \
3238 translation_ptr = bios_translation_ptr; \
3239 translation_cache_limit = bios_translation_cache + \
3240 BIOS_TRANSLATION_CACHE_SIZE; \
3244 generate_block_prologue(); \
3246 /* This is a function because it's used a lot more than it might seem (all \
3247 of the data processing functions can access it), and its expansion was \
3248 massacreing the compiler. */ \
3252 scan_block(type, yes); \
3256 scan_block(type, no); \
3259 for(i = 0; i < block_exit_position; i++) \
3261 branch_target = block_exits[i].branch_target; \
3263 if((branch_target > block_start_pc) && \
3264 (branch_target < block_end_pc)) \
3266 block_data[(branch_target - block_start_pc) / \
3267 type##_instruction_width].update_cycles = 1; \
3271 type##_dead_flag_eliminate(); \
3273 block_exit_position = 0; \
3274 block_data_position = 0; \
3276 last_condition = 0x0E; \
3278 while(pc != block_end_pc) \
3280 block_data[block_data_position].block_offset = translation_ptr; \
3281 type##_base_cycles(); \
3282 /*generate_step_debug();*/ \
3284 translate_##type##_instruction(); \
3285 block_data_position++; \
3287 /* If it went too far the cache needs to be flushed and the process \
3288 restarted. Because we might already be nested several stages in \
3289 a simple recursive call here won't work, it has to pedal out to \
3292 if(translation_ptr > translation_cache_limit) \
3294 translation_flush_count++; \
3296 switch(translation_region) \
3298 case TRANSLATION_REGION_RAM: \
3299 flush_translation_cache_ram(); \
3302 case TRANSLATION_REGION_ROM: \
3303 flush_translation_cache_rom(); \
3306 case TRANSLATION_REGION_BIOS: \
3307 flush_translation_cache_bios(); \
3314 /* If the next instruction is a block entry point update the \
3315 cycle counter and update */ \
3316 if(block_data[block_data_position].update_cycles == 1) \
3318 generate_cycle_update(); \
3321 for(i = 0; i < translation_gate_targets; i++) \
3323 if(pc == translation_gate_target_pc[i]) \
3325 generate_translation_gate(type); \
3330 for(i = 0; i < block_exit_position; i++) \
3332 branch_target = block_exits[i].branch_target; \
3334 if((branch_target >= block_start_pc) && (branch_target < block_end_pc)) \
3336 /* Internal branch, patch to recorded address */ \
3337 translation_target = \
3338 block_data[(branch_target - block_start_pc) / \
3339 type##_instruction_width].block_offset; \
3341 generate_branch_patch_unconditional(block_exits[i].branch_source, \
3342 translation_target); \
3346 /* External branch, save for later */ \
3347 external_block_exits[external_block_exit_position].branch_target = \
3349 external_block_exits[external_block_exit_position].branch_source = \
3350 block_exits[i].branch_source; \
3351 external_block_exit_position++; \
3355 switch(translation_region) \
3357 case TRANSLATION_REGION_RAM: \
3358 if(pc >= 0x3000000) \
3360 if((pc > iwram_code_max) || (iwram_code_max == 0xFFFFFFFF)) \
3361 iwram_code_max = pc; \
3365 if(pc >= 0x2000000) \
3367 if((pc > ewram_code_max) || (ewram_code_max == 0xFFFFFFFF)) \
3368 ewram_code_max = pc; \
3371 ram_translation_ptr = translation_ptr; \
3374 case TRANSLATION_REGION_ROM: \
3375 rom_translation_ptr = translation_ptr; \
3378 case TRANSLATION_REGION_BIOS: \
3379 bios_translation_ptr = translation_ptr; \
3383 for(i = 0; i < external_block_exit_position; i++) \
3385 branch_target = external_block_exits[i].branch_target; \
3386 type##_link_block(); \
3387 if(translation_target == NULL) \
3389 generate_branch_patch_unconditional( \
3390 external_block_exits[i].branch_source, translation_target); \
3396 translate_block_builder(arm);
3397 translate_block_builder(thumb);
3399 void flush_translation_cache_ram()
3402 /* printf("ram flush %d (pc %x), %x to %x, %x to %x\n",
3403 flush_ram_count, reg[REG_PC], iwram_code_min, iwram_code_max,
3404 ewram_code_min, ewram_code_max); */
3407 invalidate_icache_region(ram_translation_cache,
3408 (ram_translation_ptr - ram_translation_cache) + 0x100);
3410 ram_translation_ptr = ram_translation_cache;
3411 last_ram_translation_ptr = ram_translation_cache;
3412 ram_block_tag_top = 0x0101;
3413 if(iwram_code_min != 0xFFFFFFFF)
3415 iwram_code_min &= 0x7FFF;
3416 iwram_code_max &= 0x7FFF;
3417 memset(iwram + iwram_code_min, 0, iwram_code_max - iwram_code_min);
3420 if(ewram_code_min != 0xFFFFFFFF)
3422 u32 ewram_code_min_page;
3423 u32 ewram_code_max_page;
3424 u32 ewram_code_min_offset;
3425 u32 ewram_code_max_offset;
3428 ewram_code_min &= 0x3FFFF;
3429 ewram_code_max &= 0x3FFFF;
3431 ewram_code_min_page = ewram_code_min >> 15;
3432 ewram_code_max_page = ewram_code_max >> 15;
3433 ewram_code_min_offset = ewram_code_min & 0x7FFF;
3434 ewram_code_max_offset = ewram_code_max & 0x7FFF;
3436 if(ewram_code_min_page == ewram_code_max_page)
3438 memset(ewram + (ewram_code_min_page * 0x10000) +
3439 ewram_code_min_offset, 0,
3440 ewram_code_max_offset - ewram_code_min_offset);
3444 for(i = ewram_code_min_page + 1; i < ewram_code_max_page; i++)
3446 memset(ewram + (i * 0x10000), 0, 0x8000);
3449 memset(ewram, 0, ewram_code_max_offset);
3453 iwram_code_min = 0xFFFFFFFF;
3454 iwram_code_max = 0xFFFFFFFF;
3455 ewram_code_min = 0xFFFFFFFF;
3456 ewram_code_max = 0xFFFFFFFF;
3459 void flush_translation_cache_rom()
3462 invalidate_icache_region(rom_translation_cache,
3463 rom_translation_ptr - rom_translation_cache + 0x100);
3466 rom_translation_ptr = rom_translation_cache;
3467 last_rom_translation_ptr = rom_translation_cache;
3468 memset(rom_branch_hash, 0, sizeof(rom_branch_hash));
3471 void flush_translation_cache_bios()
3474 invalidate_icache_region(bios_translation_cache,
3475 bios_translation_ptr - bios_translation_cache + 0x100);
3478 bios_block_tag_top = 0x0101;
3479 bios_translation_ptr = bios_translation_cache;
3480 last_bios_translation_ptr = bios_translation_cache;
3481 memset(bios_rom + 0x4000, 0, 0x4000);
3484 #define cache_dump_prefix ""
3486 void dump_translation_cache()
3488 file_open(ram_cache, cache_dump_prefix "ram_cache.bin", write);
3489 file_write(ram_cache, ram_translation_cache,
3490 ram_translation_ptr - ram_translation_cache);
3491 file_close(ram_cache);
3493 file_open(rom_cache, cache_dump_prefix "rom_cache.bin", write);
3494 file_write(rom_cache, rom_translation_cache,
3495 rom_translation_ptr - rom_translation_cache);
3496 file_close(rom_cache);
3498 file_open(bios_cache, cache_dump_prefix "bios_cache.bin", write);
3499 file_write(bios_cache, bios_translation_cache,
3500 bios_translation_ptr - bios_translation_cache);
3501 file_close(bios_cache);