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
26 u8 rom_translation_cache[ROM_TRANSLATION_CACHE_SIZE];
27 u8 *rom_translation_ptr = rom_translation_cache;
29 u8 ram_translation_cache[RAM_TRANSLATION_CACHE_SIZE];
30 u8 *ram_translation_ptr = ram_translation_cache;
31 u32 iwram_code_min = 0xFFFFFFFF;
32 u32 iwram_code_max = 0xFFFFFFFF;
33 u32 ewram_code_min = 0xFFFFFFFF;
34 u32 ewram_code_max = 0xFFFFFFFF;
36 u8 bios_translation_cache[BIOS_TRANSLATION_CACHE_SIZE];
37 u8 *bios_translation_ptr = bios_translation_cache;
39 u32 *rom_branch_hash[ROM_BRANCH_HASH_SIZE];
42 u32 idle_loop_target_pc = 0xFFFFFFFF;
43 u32 force_pc_update_target = 0xFFFFFFFF;
44 u32 translation_gate_target_pc[MAX_TRANSLATION_GATES];
45 u32 translation_gate_targets = 0;
46 u32 iwram_stack_optimize = 1;
47 u32 allow_smc_ram_u8 = 1;
48 u32 allow_smc_ram_u16 = 1;
49 u32 allow_smc_ram_u32 = 1;
65 extern u8 bit_count[256];
67 #define arm_decode_data_proc_reg() \
68 u32 rn = (opcode >> 16) & 0x0F; \
69 u32 rd = (opcode >> 12) & 0x0F; \
70 u32 rm = opcode & 0x0F \
72 #define arm_decode_data_proc_imm() \
73 u32 rn = (opcode >> 16) & 0x0F; \
74 u32 rd = (opcode >> 12) & 0x0F; \
75 u32 imm = opcode & 0xFF; \
76 u32 imm_ror = ((opcode >> 8) & 0x0F) * 2 \
78 #define arm_decode_psr_reg() \
79 u32 psr_field = (opcode >> 16) & 0x0F; \
80 u32 rd = (opcode >> 12) & 0x0F; \
81 u32 rm = opcode & 0x0F \
83 #define arm_decode_psr_imm() \
84 u32 psr_field = (opcode >> 16) & 0x0F; \
85 u32 rd = (opcode >> 12) & 0x0F; \
86 u32 imm = opcode & 0xFF; \
87 u32 imm_ror = ((opcode >> 8) & 0x0F) * 2 \
89 #define arm_decode_branchx() \
90 u32 rn = opcode & 0x0F \
92 #define arm_decode_multiply() \
93 u32 rd = (opcode >> 16) & 0x0F; \
94 u32 rn = (opcode >> 12) & 0x0F; \
95 u32 rs = (opcode >> 8) & 0x0F; \
96 u32 rm = opcode & 0x0F \
98 #define arm_decode_multiply_long() \
99 u32 rdhi = (opcode >> 16) & 0x0F; \
100 u32 rdlo = (opcode >> 12) & 0x0F; \
101 u32 rs = (opcode >> 8) & 0x0F; \
102 u32 rm = opcode & 0x0F \
104 #define arm_decode_swap() \
105 u32 rn = (opcode >> 16) & 0x0F; \
106 u32 rd = (opcode >> 12) & 0x0F; \
107 u32 rm = opcode & 0x0F \
109 #define arm_decode_half_trans_r() \
110 u32 rn = (opcode >> 16) & 0x0F; \
111 u32 rd = (opcode >> 12) & 0x0F; \
112 u32 rm = opcode & 0x0F \
114 #define arm_decode_half_trans_of() \
115 u32 rn = (opcode >> 16) & 0x0F; \
116 u32 rd = (opcode >> 12) & 0x0F; \
117 u32 offset = ((opcode >> 4) & 0xF0) | (opcode & 0x0F) \
119 #define arm_decode_data_trans_imm() \
120 u32 rn = (opcode >> 16) & 0x0F; \
121 u32 rd = (opcode >> 12) & 0x0F; \
122 u32 offset = opcode & 0x0FFF \
124 #define arm_decode_data_trans_reg() \
125 u32 rn = (opcode >> 16) & 0x0F; \
126 u32 rd = (opcode >> 12) & 0x0F; \
127 u32 rm = opcode & 0x0F \
129 #define arm_decode_block_trans() \
130 u32 rn = (opcode >> 16) & 0x0F; \
131 u32 reg_list = opcode & 0xFFFF \
133 #define arm_decode_branch() \
134 s32 offset = ((s32)(opcode & 0xFFFFFF) << 8) >> 6 \
136 #define thumb_decode_shift() \
137 u32 imm = (opcode >> 6) & 0x1F; \
138 u32 rs = (opcode >> 3) & 0x07; \
139 u32 rd = opcode & 0x07 \
141 #define thumb_decode_add_sub() \
142 u32 rn = (opcode >> 6) & 0x07; \
143 u32 rs = (opcode >> 3) & 0x07; \
144 u32 rd = opcode & 0x07 \
146 #define thumb_decode_add_sub_imm() \
147 u32 imm = (opcode >> 6) & 0x07; \
148 u32 rs = (opcode >> 3) & 0x07; \
149 u32 rd = opcode & 0x07 \
151 #define thumb_decode_imm() \
152 u32 imm = opcode & 0xFF \
154 #define thumb_decode_alu_op() \
155 u32 rs = (opcode >> 3) & 0x07; \
156 u32 rd = opcode & 0x07 \
158 #define thumb_decode_hireg_op() \
159 u32 rs = (opcode >> 3) & 0x0F; \
160 u32 rd = ((opcode >> 4) & 0x08) | (opcode & 0x07) \
162 #define thumb_decode_mem_reg() \
163 u32 ro = (opcode >> 6) & 0x07; \
164 u32 rb = (opcode >> 3) & 0x07; \
165 u32 rd = opcode & 0x07 \
167 #define thumb_decode_mem_imm() \
168 u32 imm = (opcode >> 6) & 0x1F; \
169 u32 rb = (opcode >> 3) & 0x07; \
170 u32 rd = opcode & 0x07 \
172 #define thumb_decode_add_sp() \
173 u32 imm = opcode & 0x7F \
175 #define thumb_decode_rlist() \
176 u32 reg_list = opcode & 0xFF \
178 #define thumb_decode_branch_cond() \
179 s32 offset = (s8)(opcode & 0xFF) \
181 #define thumb_decode_swi() \
182 u32 comment = opcode & 0xFF \
184 #define thumb_decode_branch() \
185 u32 offset = opcode & 0x07FF \
190 #include "psp/mips_emit.h"
192 #elif defined(ARM_ARCH)
194 #include "arm/arm_emit.h"
198 #include "x86/x86_emit.h"
203 #define check_pc_region(pc) \
204 new_pc_region = (pc >> 15); \
205 if(new_pc_region != pc_region) \
207 pc_region = new_pc_region; \
208 pc_address_block = memory_map_read[new_pc_region]; \
210 if(pc_address_block == NULL) \
211 pc_address_block = load_gamepak_page(pc_region & 0x3FF); \
214 #define translate_arm_instruction() \
215 check_pc_region(pc); \
216 opcode = address32(pc_address_block, (pc & 0x7FFF)); \
217 condition = block_data[block_data_position].condition; \
219 if((condition != last_condition) || (condition >= 0x20)) \
221 if((last_condition & 0x0F) != 0x0E) \
223 generate_branch_patch_conditional(backpatch_address, translation_ptr); \
226 last_condition = condition; \
230 if(condition != 0x0E) \
232 arm_conditional_block_header(); \
236 switch((opcode >> 20) & 0xFF) \
239 if((opcode & 0x90) == 0x90) \
243 /* STRH rd, [rn], -rm */ \
244 arm_access_memory(store, down, post, u16, half_reg); \
248 /* MUL rd, rm, rs */ \
249 arm_multiply(no, no); \
254 /* AND rd, rn, reg_op */ \
255 arm_data_proc(and, reg, no_flags); \
260 if((opcode & 0x90) == 0x90) \
262 switch((opcode >> 5) & 0x03) \
265 /* MULS rd, rm, rs */ \
266 arm_multiply(no, yes); \
270 /* LDRH rd, [rn], -rm */ \
271 arm_access_memory(load, down, post, u16, half_reg); \
275 /* LDRSB rd, [rn], -rm */ \
276 arm_access_memory(load, down, post, s8, half_reg); \
280 /* LDRSH rd, [rn], -rm */ \
281 arm_access_memory(load, down, post, s16, half_reg); \
287 /* ANDS rd, rn, reg_op */ \
288 arm_data_proc(ands, reg_flags, flags); \
293 if((opcode & 0x90) == 0x90) \
297 /* STRH rd, [rn], -rm */ \
298 arm_access_memory(store, down, post, u16, half_reg); \
302 /* MLA rd, rm, rs, rn */ \
303 arm_multiply(yes, no); \
308 /* EOR rd, rn, reg_op */ \
309 arm_data_proc(eor, reg, no_flags); \
314 if((opcode & 0x90) == 0x90) \
316 switch((opcode >> 5) & 0x03) \
319 /* MLAS rd, rm, rs, rn */ \
320 arm_multiply(yes, yes); \
324 /* LDRH rd, [rn], -rm */ \
325 arm_access_memory(load, down, post, u16, half_reg); \
329 /* LDRSB rd, [rn], -rm */ \
330 arm_access_memory(load, down, post, s8, half_reg); \
334 /* LDRSH rd, [rn], -rm */ \
335 arm_access_memory(load, down, post, s16, half_reg); \
341 /* EORS rd, rn, reg_op */ \
342 arm_data_proc(eors, reg_flags, flags); \
347 if((opcode & 0x90) == 0x90) \
349 /* STRH rd, [rn], -imm */ \
350 arm_access_memory(store, down, post, u16, half_imm); \
354 /* SUB rd, rn, reg_op */ \
355 arm_data_proc(sub, reg, no_flags); \
360 if((opcode & 0x90) == 0x90) \
362 switch((opcode >> 5) & 0x03) \
365 /* LDRH rd, [rn], -imm */ \
366 arm_access_memory(load, down, post, u16, half_imm); \
370 /* LDRSB rd, [rn], -imm */ \
371 arm_access_memory(load, down, post, s8, half_imm); \
375 /* LDRSH rd, [rn], -imm */ \
376 arm_access_memory(load, down, post, s16, half_imm); \
382 /* SUBS rd, rn, reg_op */ \
383 arm_data_proc(subs, reg, flags); \
388 if((opcode & 0x90) == 0x90) \
390 /* STRH rd, [rn], -imm */ \
391 arm_access_memory(store, down, post, u16, half_imm); \
395 /* RSB rd, rn, reg_op */ \
396 arm_data_proc(rsb, reg, no_flags); \
401 if((opcode & 0x90) == 0x90) \
403 switch((opcode >> 5) & 0x03) \
406 /* LDRH rd, [rn], -imm */ \
407 arm_access_memory(load, down, post, u16, half_imm); \
411 /* LDRSB rd, [rn], -imm */ \
412 arm_access_memory(load, down, post, s8, half_imm); \
416 /* LDRSH rd, [rn], -imm */ \
417 arm_access_memory(load, down, post, s16, half_imm); \
423 /* RSBS rd, rn, reg_op */ \
424 arm_data_proc(rsbs, reg, flags); \
429 if((opcode & 0x90) == 0x90) \
433 /* STRH rd, [rn], +rm */ \
434 arm_access_memory(store, up, post, u16, half_reg); \
438 /* UMULL rd, rm, rs */ \
439 arm_multiply_long(u64, no, no); \
444 /* ADD rd, rn, reg_op */ \
445 arm_data_proc(add, reg, no_flags); \
450 if((opcode & 0x90) == 0x90) \
452 switch((opcode >> 5) & 0x03) \
455 /* UMULLS rdlo, rdhi, rm, rs */ \
456 arm_multiply_long(u64, no, yes); \
460 /* LDRH rd, [rn], +rm */ \
461 arm_access_memory(load, up, post, u16, half_reg); \
465 /* LDRSB rd, [rn], +rm */ \
466 arm_access_memory(load, up, post, s8, half_reg); \
470 /* LDRSH rd, [rn], +rm */ \
471 arm_access_memory(load, up, post, s16, half_reg); \
477 /* ADDS rd, rn, reg_op */ \
478 arm_data_proc(adds, reg, flags); \
483 if((opcode & 0x90) == 0x90) \
487 /* STRH rd, [rn], +rm */ \
488 arm_access_memory(store, up, post, u16, half_reg); \
492 /* UMLAL rd, rm, rs */ \
493 arm_multiply_long(u64_add, yes, no); \
498 /* ADC rd, rn, reg_op */ \
499 arm_data_proc(adc, reg, no_flags); \
504 if((opcode & 0x90) == 0x90) \
506 switch((opcode >> 5) & 0x03) \
509 /* UMLALS rdlo, rdhi, rm, rs */ \
510 arm_multiply_long(u64_add, yes, yes); \
514 /* LDRH rd, [rn], +rm */ \
515 arm_access_memory(load, up, post, u16, half_reg); \
519 /* LDRSB rd, [rn], +rm */ \
520 arm_access_memory(load, up, post, s8, half_reg); \
524 /* LDRSH rd, [rn], +rm */ \
525 arm_access_memory(load, up, post, s16, half_reg); \
531 /* ADCS rd, rn, reg_op */ \
532 arm_data_proc(adcs, reg, flags); \
537 if((opcode & 0x90) == 0x90) \
541 /* STRH rd, [rn], +imm */ \
542 arm_access_memory(store, up, post, u16, half_imm); \
546 /* SMULL rd, rm, rs */ \
547 arm_multiply_long(s64, no, no); \
552 /* SBC rd, rn, reg_op */ \
553 arm_data_proc(sbc, reg, no_flags); \
558 if((opcode & 0x90) == 0x90) \
560 switch((opcode >> 5) & 0x03) \
563 /* SMULLS rdlo, rdhi, rm, rs */ \
564 arm_multiply_long(s64, no, yes); \
568 /* LDRH rd, [rn], +imm */ \
569 arm_access_memory(load, up, post, u16, half_imm); \
573 /* LDRSB rd, [rn], +imm */ \
574 arm_access_memory(load, up, post, s8, half_imm); \
578 /* LDRSH rd, [rn], +imm */ \
579 arm_access_memory(load, up, post, s16, half_imm); \
585 /* SBCS rd, rn, reg_op */ \
586 arm_data_proc(sbcs, reg, flags); \
591 if((opcode & 0x90) == 0x90) \
595 /* STRH rd, [rn], +imm */ \
596 arm_access_memory(store, up, post, u16, half_imm); \
600 /* SMLAL rd, rm, rs */ \
601 arm_multiply_long(s64_add, yes, no); \
606 /* RSC rd, rn, reg_op */ \
607 arm_data_proc(rsc, reg, no_flags); \
612 if((opcode & 0x90) == 0x90) \
614 switch((opcode >> 5) & 0x03) \
617 /* SMLALS rdlo, rdhi, rm, rs */ \
618 arm_multiply_long(s64_add, yes, yes); \
622 /* LDRH rd, [rn], +imm */ \
623 arm_access_memory(load, up, post, u16, half_imm); \
627 /* LDRSB rd, [rn], +imm */ \
628 arm_access_memory(load, up, post, s8, half_imm); \
632 /* LDRSH rd, [rn], +imm */ \
633 arm_access_memory(load, up, post, s16, half_imm); \
639 /* RSCS rd, rn, reg_op */ \
640 arm_data_proc(rscs, reg, flags); \
645 if((opcode & 0x90) == 0x90) \
649 /* STRH rd, [rn - rm] */ \
650 arm_access_memory(store, down, pre, u16, half_reg); \
654 /* SWP rd, rm, [rn] */ \
661 arm_psr(reg, read, cpsr); \
666 if((opcode & 0x90) == 0x90) \
668 switch((opcode >> 5) & 0x03) \
671 /* LDRH rd, [rn - rm] */ \
672 arm_access_memory(load, down, pre, u16, half_reg); \
676 /* LDRSB rd, [rn - rm] */ \
677 arm_access_memory(load, down, pre, s8, half_reg); \
681 /* LDRSH rd, [rn - rm] */ \
682 arm_access_memory(load, down, pre, s16, half_reg); \
688 /* TST rd, rn, reg_op */ \
689 arm_data_proc_test(tst, reg_flags); \
694 if((opcode & 0x90) == 0x90) \
696 /* STRH rd, [rn - rm]! */ \
697 arm_access_memory(store, down, pre_wb, u16, half_reg); \
709 arm_psr(reg, store, cpsr); \
715 if((opcode & 0x90) == 0x90) \
717 switch((opcode >> 5) & 0x03) \
720 /* LDRH rd, [rn - rm]! */ \
721 arm_access_memory(load, down, pre_wb, u16, half_reg); \
725 /* LDRSB rd, [rn - rm]! */ \
726 arm_access_memory(load, down, pre_wb, s8, half_reg); \
730 /* LDRSH rd, [rn - rm]! */ \
731 arm_access_memory(load, down, pre_wb, s16, half_reg); \
737 /* TEQ rd, rn, reg_op */ \
738 arm_data_proc_test(teq, reg_flags); \
743 if((opcode & 0x90) == 0x90) \
747 /* STRH rd, [rn - imm] */ \
748 arm_access_memory(store, down, pre, u16, half_imm); \
752 /* SWPB rd, rm, [rn] */ \
759 arm_psr(reg, read, spsr); \
764 if((opcode & 0x90) == 0x90) \
766 switch((opcode >> 5) & 0x03) \
769 /* LDRH rd, [rn - imm] */ \
770 arm_access_memory(load, down, pre, u16, half_imm); \
774 /* LDRSB rd, [rn - imm] */ \
775 arm_access_memory(load, down, pre, s8, half_imm); \
779 /* LDRSH rd, [rn - imm] */ \
780 arm_access_memory(load, down, pre, s16, half_imm); \
786 /* CMP rn, reg_op */ \
787 arm_data_proc_test(cmp, reg); \
792 if((opcode & 0x90) == 0x90) \
794 /* STRH rd, [rn - imm]! */ \
795 arm_access_memory(store, down, pre_wb, u16, half_imm); \
800 arm_psr(reg, store, spsr); \
805 if((opcode & 0x90) == 0x90) \
807 switch((opcode >> 5) & 0x03) \
810 /* LDRH rd, [rn - imm]! */ \
811 arm_access_memory(load, down, pre_wb, u16, half_imm); \
815 /* LDRSB rd, [rn - imm]! */ \
816 arm_access_memory(load, down, pre_wb, s8, half_imm); \
820 /* LDRSH rd, [rn - imm]! */ \
821 arm_access_memory(load, down, pre_wb, s16, half_imm); \
827 /* CMN rd, rn, reg_op */ \
828 arm_data_proc_test(cmn, reg); \
833 if((opcode & 0x90) == 0x90) \
835 /* STRH rd, [rn + rm] */ \
836 arm_access_memory(store, up, pre, u16, half_reg); \
840 /* ORR rd, rn, reg_op */ \
841 arm_data_proc(orr, reg, no_flags); \
846 if((opcode & 0x90) == 0x90) \
848 switch((opcode >> 5) & 0x03) \
851 /* LDRH rd, [rn + rm] */ \
852 arm_access_memory(load, up, pre, u16, half_reg); \
856 /* LDRSB rd, [rn + rm] */ \
857 arm_access_memory(load, up, pre, s8, half_reg); \
861 /* LDRSH rd, [rn + rm] */ \
862 arm_access_memory(load, up, pre, s16, half_reg); \
868 /* ORRS rd, rn, reg_op */ \
869 arm_data_proc(orrs, reg_flags, flags); \
874 if((opcode & 0x90) == 0x90) \
876 /* STRH rd, [rn + rm]! */ \
877 arm_access_memory(store, up, pre_wb, u16, half_reg); \
881 /* MOV rd, reg_op */ \
882 arm_data_proc_unary(mov, reg, no_flags); \
887 if((opcode & 0x90) == 0x90) \
889 switch((opcode >> 5) & 0x03) \
892 /* LDRH rd, [rn + rm]! */ \
893 arm_access_memory(load, up, pre_wb, u16, half_reg); \
897 /* LDRSB rd, [rn + rm]! */ \
898 arm_access_memory(load, up, pre_wb, s8, half_reg); \
902 /* LDRSH rd, [rn + rm]! */ \
903 arm_access_memory(load, up, pre_wb, s16, half_reg); \
909 /* MOVS rd, reg_op */ \
910 arm_data_proc_unary(movs, reg_flags, flags); \
915 if((opcode & 0x90) == 0x90) \
917 /* STRH rd, [rn + imm] */ \
918 arm_access_memory(store, up, pre, u16, half_imm); \
922 /* BIC rd, rn, reg_op */ \
923 arm_data_proc(bic, reg, no_flags); \
928 if((opcode & 0x90) == 0x90) \
930 switch((opcode >> 5) & 0x03) \
933 /* LDRH rd, [rn + imm] */ \
934 arm_access_memory(load, up, pre, u16, half_imm); \
938 /* LDRSB rd, [rn + imm] */ \
939 arm_access_memory(load, up, pre, s8, half_imm); \
943 /* LDRSH rd, [rn + imm] */ \
944 arm_access_memory(load, up, pre, s16, half_imm); \
950 /* BICS rd, rn, reg_op */ \
951 arm_data_proc(bics, reg_flags, flags); \
956 if((opcode & 0x90) == 0x90) \
958 /* STRH rd, [rn + imm]! */ \
959 arm_access_memory(store, up, pre_wb, u16, half_imm); \
963 /* MVN rd, reg_op */ \
964 arm_data_proc_unary(mvn, reg, no_flags); \
969 if((opcode & 0x90) == 0x90) \
971 switch((opcode >> 5) & 0x03) \
974 /* LDRH rd, [rn + imm]! */ \
975 arm_access_memory(load, up, pre_wb, u16, half_imm); \
979 /* LDRSB rd, [rn + imm]! */ \
980 arm_access_memory(load, up, pre_wb, s8, half_imm); \
984 /* LDRSH rd, [rn + imm]! */ \
985 arm_access_memory(load, up, pre_wb, s16, half_imm); \
991 /* MVNS rd, rn, reg_op */ \
992 arm_data_proc_unary(mvns, reg_flags, flags); \
997 /* AND rd, rn, imm */ \
998 arm_data_proc(and, imm, no_flags); \
1002 /* ANDS rd, rn, imm */ \
1003 arm_data_proc(ands, imm_flags, flags); \
1007 /* EOR rd, rn, imm */ \
1008 arm_data_proc(eor, imm, no_flags); \
1012 /* EORS rd, rn, imm */ \
1013 arm_data_proc(eors, imm_flags, flags); \
1017 /* SUB rd, rn, imm */ \
1018 arm_data_proc(sub, imm, no_flags); \
1022 /* SUBS rd, rn, imm */ \
1023 arm_data_proc(subs, imm, flags); \
1027 /* RSB rd, rn, imm */ \
1028 arm_data_proc(rsb, imm, no_flags); \
1032 /* RSBS rd, rn, imm */ \
1033 arm_data_proc(rsbs, imm, flags); \
1037 /* ADD rd, rn, imm */ \
1038 arm_data_proc(add, imm, no_flags); \
1042 /* ADDS rd, rn, imm */ \
1043 arm_data_proc(adds, imm, flags); \
1047 /* ADC rd, rn, imm */ \
1048 arm_data_proc(adc, imm, no_flags); \
1052 /* ADCS rd, rn, imm */ \
1053 arm_data_proc(adcs, imm, flags); \
1057 /* SBC rd, rn, imm */ \
1058 arm_data_proc(sbc, imm, no_flags); \
1062 /* SBCS rd, rn, imm */ \
1063 arm_data_proc(sbcs, imm, flags); \
1067 /* RSC rd, rn, imm */ \
1068 arm_data_proc(rsc, imm, no_flags); \
1072 /* RSCS rd, rn, imm */ \
1073 arm_data_proc(rscs, imm, flags); \
1076 case 0x30 ... 0x31: \
1078 arm_data_proc_test(tst, imm); \
1082 /* MSR cpsr, imm */ \
1083 arm_psr(imm, store, cpsr); \
1088 arm_data_proc_test(teq, imm); \
1091 case 0x34 ... 0x35: \
1093 arm_data_proc_test(cmp, imm); \
1097 /* MSR spsr, imm */ \
1098 arm_psr(imm, store, spsr); \
1103 arm_data_proc_test(cmn, imm); \
1107 /* ORR rd, rn, imm */ \
1108 arm_data_proc(orr, imm, no_flags); \
1112 /* ORRS rd, rn, imm */ \
1113 arm_data_proc(orrs, imm_flags, flags); \
1118 arm_data_proc_unary(mov, imm, no_flags); \
1122 /* MOVS rd, imm */ \
1123 arm_data_proc_unary(movs, imm_flags, flags); \
1127 /* BIC rd, rn, imm */ \
1128 arm_data_proc(bic, imm, no_flags); \
1132 /* BICS rd, rn, imm */ \
1133 arm_data_proc(bics, imm_flags, flags); \
1138 arm_data_proc_unary(mvn, imm, no_flags); \
1142 /* MVNS rd, imm */ \
1143 arm_data_proc_unary(mvns, imm_flags, flags); \
1147 /* STR rd, [rn], -imm */ \
1148 arm_access_memory(store, down, post, u32, imm); \
1152 /* LDR rd, [rn], -imm */ \
1153 arm_access_memory(load, down, post, u32, imm); \
1157 /* STRT rd, [rn], -imm */ \
1158 arm_access_memory(store, down, post, u32, imm); \
1162 /* LDRT rd, [rn], -imm */ \
1163 arm_access_memory(load, down, post, u32, imm); \
1167 /* STRB rd, [rn], -imm */ \
1168 arm_access_memory(store, down, post, u8, imm); \
1172 /* LDRB rd, [rn], -imm */ \
1173 arm_access_memory(load, down, post, u8, imm); \
1177 /* STRBT rd, [rn], -imm */ \
1178 arm_access_memory(store, down, post, u8, imm); \
1182 /* LDRBT rd, [rn], -imm */ \
1183 arm_access_memory(load, down, post, u8, imm); \
1187 /* STR rd, [rn], +imm */ \
1188 arm_access_memory(store, up, post, u32, imm); \
1192 /* LDR rd, [rn], +imm */ \
1193 arm_access_memory(load, up, post, u32, imm); \
1197 /* STRT rd, [rn], +imm */ \
1198 arm_access_memory(store, up, post, u32, imm); \
1202 /* LDRT rd, [rn], +imm */ \
1203 arm_access_memory(load, up, post, u32, imm); \
1207 /* STRB rd, [rn], +imm */ \
1208 arm_access_memory(store, up, post, u8, imm); \
1212 /* LDRB rd, [rn], +imm */ \
1213 arm_access_memory(load, up, post, u8, imm); \
1217 /* STRBT rd, [rn], +imm */ \
1218 arm_access_memory(store, up, post, u8, imm); \
1222 /* LDRBT rd, [rn], +imm */ \
1223 arm_access_memory(load, up, post, u8, imm); \
1227 /* STR rd, [rn - imm] */ \
1228 arm_access_memory(store, down, pre, u32, imm); \
1232 /* LDR rd, [rn - imm] */ \
1233 arm_access_memory(load, down, pre, u32, imm); \
1237 /* STR rd, [rn - imm]! */ \
1238 arm_access_memory(store, down, pre_wb, u32, imm); \
1242 /* LDR rd, [rn - imm]! */ \
1243 arm_access_memory(load, down, pre_wb, u32, imm); \
1247 /* STRB rd, [rn - imm] */ \
1248 arm_access_memory(store, down, pre, u8, imm); \
1252 /* LDRB rd, [rn - imm] */ \
1253 arm_access_memory(load, down, pre, u8, imm); \
1257 /* STRB rd, [rn - imm]! */ \
1258 arm_access_memory(store, down, pre_wb, u8, imm); \
1262 /* LDRB rd, [rn - imm]! */ \
1263 arm_access_memory(load, down, pre_wb, u8, imm); \
1267 /* STR rd, [rn + imm] */ \
1268 arm_access_memory(store, up, pre, u32, imm); \
1272 /* LDR rd, [rn + imm] */ \
1273 arm_access_memory(load, up, pre, u32, imm); \
1277 /* STR rd, [rn + imm]! */ \
1278 arm_access_memory(store, up, pre_wb, u32, imm); \
1282 /* LDR rd, [rn + imm]! */ \
1283 arm_access_memory(load, up, pre_wb, u32, imm); \
1287 /* STRB rd, [rn + imm] */ \
1288 arm_access_memory(store, up, pre, u8, imm); \
1292 /* LDRB rd, [rn + imm] */ \
1293 arm_access_memory(load, up, pre, u8, imm); \
1297 /* STRB rd, [rn + imm]! */ \
1298 arm_access_memory(store, up, pre_wb, u8, imm); \
1302 /* LDRBT rd, [rn + imm]! */ \
1303 arm_access_memory(load, up, pre_wb, u8, imm); \
1307 /* STR rd, [rn], -rm */ \
1308 arm_access_memory(store, down, post, u32, reg); \
1312 /* LDR rd, [rn], -rm */ \
1313 arm_access_memory(load, down, post, u32, reg); \
1317 /* STRT rd, [rn], -rm */ \
1318 arm_access_memory(store, down, post, u32, reg); \
1322 /* LDRT rd, [rn], -rm */ \
1323 arm_access_memory(load, down, post, u32, reg); \
1327 /* STRB rd, [rn], -rm */ \
1328 arm_access_memory(store, down, post, u8, reg); \
1332 /* LDRB rd, [rn], -rm */ \
1333 arm_access_memory(load, down, post, u8, reg); \
1337 /* STRBT rd, [rn], -rm */ \
1338 arm_access_memory(store, down, post, u8, reg); \
1342 /* LDRBT rd, [rn], -rm */ \
1343 arm_access_memory(load, down, post, u8, reg); \
1347 /* STR rd, [rn], +rm */ \
1348 arm_access_memory(store, up, post, u32, reg); \
1352 /* LDR rd, [rn], +rm */ \
1353 arm_access_memory(load, up, post, u32, reg); \
1357 /* STRT rd, [rn], +rm */ \
1358 arm_access_memory(store, up, post, u32, reg); \
1362 /* LDRT rd, [rn], +rm */ \
1363 arm_access_memory(load, up, post, u32, reg); \
1367 /* STRB rd, [rn], +rm */ \
1368 arm_access_memory(store, up, post, u8, reg); \
1372 /* LDRB rd, [rn], +rm */ \
1373 arm_access_memory(load, up, post, u8, reg); \
1377 /* STRBT rd, [rn], +rm */ \
1378 arm_access_memory(store, up, post, u8, reg); \
1382 /* LDRBT rd, [rn], +rm */ \
1383 arm_access_memory(load, up, post, u8, reg); \
1387 /* STR rd, [rn - rm] */ \
1388 arm_access_memory(store, down, pre, u32, reg); \
1392 /* LDR rd, [rn - rm] */ \
1393 arm_access_memory(load, down, pre, u32, reg); \
1397 /* STR rd, [rn - rm]! */ \
1398 arm_access_memory(store, down, pre_wb, u32, reg); \
1402 /* LDR rd, [rn - rm]! */ \
1403 arm_access_memory(load, down, pre_wb, u32, reg); \
1407 /* STRB rd, [rn - rm] */ \
1408 arm_access_memory(store, down, pre, u8, reg); \
1412 /* LDRB rd, [rn - rm] */ \
1413 arm_access_memory(load, down, pre, u8, reg); \
1417 /* STRB rd, [rn - rm]! */ \
1418 arm_access_memory(store, down, pre_wb, u8, reg); \
1422 /* LDRB rd, [rn - rm]! */ \
1423 arm_access_memory(load, down, pre_wb, u8, reg); \
1427 /* STR rd, [rn + rm] */ \
1428 arm_access_memory(store, up, pre, u32, reg); \
1432 /* LDR rd, [rn + rm] */ \
1433 arm_access_memory(load, up, pre, u32, reg); \
1437 /* STR rd, [rn + rm]! */ \
1438 arm_access_memory(store, up, pre_wb, u32, reg); \
1442 /* LDR rd, [rn + rm]! */ \
1443 arm_access_memory(load, up, pre_wb, u32, reg); \
1447 /* STRB rd, [rn + rm] */ \
1448 arm_access_memory(store, up, pre, u8, reg); \
1452 /* LDRB rd, [rn + rm] */ \
1453 arm_access_memory(load, up, pre, u8, reg); \
1457 /* STRB rd, [rn + rm]! */ \
1458 arm_access_memory(store, up, pre_wb, u8, reg); \
1462 /* LDRBT rd, [rn + rm]! */ \
1463 arm_access_memory(load, up, pre_wb, u8, reg); \
1467 /* STMDA rn, rlist */ \
1468 arm_block_memory(store, down_a, no, no); \
1472 /* LDMDA rn, rlist */ \
1473 arm_block_memory(load, down_a, no, no); \
1477 /* STMDA rn!, rlist */ \
1478 arm_block_memory(store, down_a, down, no); \
1482 /* LDMDA rn!, rlist */ \
1483 arm_block_memory(load, down_a, down, no); \
1487 /* STMDA rn, rlist^ */ \
1488 arm_block_memory(store, down_a, no, yes); \
1492 /* LDMDA rn, rlist^ */ \
1493 arm_block_memory(load, down_a, no, yes); \
1497 /* STMDA rn!, rlist^ */ \
1498 arm_block_memory(store, down_a, down, yes); \
1502 /* LDMDA rn!, rlist^ */ \
1503 arm_block_memory(load, down_a, down, yes); \
1507 /* STMIA rn, rlist */ \
1508 arm_block_memory(store, no, no, no); \
1512 /* LDMIA rn, rlist */ \
1513 arm_block_memory(load, no, no, no); \
1517 /* STMIA rn!, rlist */ \
1518 arm_block_memory(store, no, up, no); \
1522 /* LDMIA rn!, rlist */ \
1523 arm_block_memory(load, no, up, no); \
1527 /* STMIA rn, rlist^ */ \
1528 arm_block_memory(store, no, no, yes); \
1532 /* LDMIA rn, rlist^ */ \
1533 arm_block_memory(load, no, no, yes); \
1537 /* STMIA rn!, rlist^ */ \
1538 arm_block_memory(store, no, up, yes); \
1542 /* LDMIA rn!, rlist^ */ \
1543 arm_block_memory(load, no, up, yes); \
1547 /* STMDB rn, rlist */ \
1548 arm_block_memory(store, down_b, no, no); \
1552 /* LDMDB rn, rlist */ \
1553 arm_block_memory(load, down_b, no, no); \
1557 /* STMDB rn!, rlist */ \
1558 arm_block_memory(store, down_b, down, no); \
1562 /* LDMDB rn!, rlist */ \
1563 arm_block_memory(load, down_b, down, no); \
1567 /* STMDB rn, rlist^ */ \
1568 arm_block_memory(store, down_b, no, yes); \
1572 /* LDMDB rn, rlist^ */ \
1573 arm_block_memory(load, down_b, no, yes); \
1577 /* STMDB rn!, rlist^ */ \
1578 arm_block_memory(store, down_b, down, yes); \
1582 /* LDMDB rn!, rlist^ */ \
1583 arm_block_memory(load, down_b, down, yes); \
1587 /* STMIB rn, rlist */ \
1588 arm_block_memory(store, up, no, no); \
1592 /* LDMIB rn, rlist */ \
1593 arm_block_memory(load, up, no, no); \
1597 /* STMIB rn!, rlist */ \
1598 arm_block_memory(store, up, up, no); \
1602 /* LDMIB rn!, rlist */ \
1603 arm_block_memory(load, up, up, no); \
1607 /* STMIB rn, rlist^ */ \
1608 arm_block_memory(store, up, no, yes); \
1612 /* LDMIB rn, rlist^ */ \
1613 arm_block_memory(load, up, no, yes); \
1617 /* STMIB rn!, rlist^ */ \
1618 arm_block_memory(store, up, up, yes); \
1622 /* LDMIB rn!, rlist^ */ \
1623 arm_block_memory(load, up, up, yes); \
1626 case 0xA0 ... 0xAF: \
1633 case 0xB0 ... 0xBF: \
1640 case 0xC0 ... 0xEF: \
1641 /* coprocessor instructions, reserved on GBA */ \
1644 case 0xF0 ... 0xFF: \
1654 #define arm_flag_status() \
1656 #define translate_thumb_instruction() \
1657 flag_status = block_data[block_data_position].flag_data; \
1658 check_pc_region(pc); \
1659 last_opcode = opcode; \
1660 opcode = address16(pc_address_block, (pc & 0x7FFF)); \
1662 switch((opcode >> 8) & 0xFF) \
1664 case 0x00 ... 0x07: \
1665 /* LSL rd, rs, imm */ \
1666 thumb_shift(shift, lsl, imm); \
1669 case 0x08 ... 0x0F: \
1670 /* LSR rd, rs, imm */ \
1671 thumb_shift(shift, lsr, imm); \
1674 case 0x10 ... 0x17: \
1675 /* ASR rd, rs, imm */ \
1676 thumb_shift(shift, asr, imm); \
1679 case 0x18 ... 0x19: \
1680 /* ADD rd, rs, rn */ \
1681 thumb_data_proc(add_sub, adds, reg, rd, rs, rn); \
1684 case 0x1A ... 0x1B: \
1685 /* SUB rd, rs, rn */ \
1686 thumb_data_proc(add_sub, subs, reg, rd, rs, rn); \
1689 case 0x1C ... 0x1D: \
1690 /* ADD rd, rs, imm */ \
1691 thumb_data_proc(add_sub_imm, adds, imm, rd, rs, imm); \
1694 case 0x1E ... 0x1F: \
1695 /* SUB rd, rs, imm */ \
1696 thumb_data_proc(add_sub_imm, subs, imm, rd, rs, imm); \
1701 thumb_data_proc_unary(imm, movs, imm, 0, imm); \
1706 thumb_data_proc_unary(imm, movs, imm, 1, imm); \
1711 thumb_data_proc_unary(imm, movs, imm, 2, imm); \
1716 thumb_data_proc_unary(imm, movs, imm, 3, imm); \
1721 thumb_data_proc_unary(imm, movs, imm, 4, imm); \
1726 thumb_data_proc_unary(imm, movs, imm, 5, imm); \
1731 thumb_data_proc_unary(imm, movs, imm, 6, imm); \
1736 thumb_data_proc_unary(imm, movs, imm, 7, imm); \
1741 thumb_data_proc_test(imm, cmp, imm, 0, imm); \
1746 thumb_data_proc_test(imm, cmp, imm, 1, imm); \
1751 thumb_data_proc_test(imm, cmp, imm, 2, imm); \
1756 thumb_data_proc_test(imm, cmp, imm, 3, imm); \
1761 thumb_data_proc_test(imm, cmp, imm, 4, imm); \
1766 thumb_data_proc_test(imm, cmp, imm, 5, imm); \
1771 thumb_data_proc_test(imm, cmp, imm, 6, imm); \
1776 thumb_data_proc_test(imm, cmp, imm, 7, imm); \
1781 thumb_data_proc(imm, adds, imm, 0, 0, imm); \
1786 thumb_data_proc(imm, adds, imm, 1, 1, imm); \
1791 thumb_data_proc(imm, adds, imm, 2, 2, imm); \
1796 thumb_data_proc(imm, adds, imm, 3, 3, imm); \
1801 thumb_data_proc(imm, adds, imm, 4, 4, imm); \
1806 thumb_data_proc(imm, adds, imm, 5, 5, imm); \
1811 thumb_data_proc(imm, adds, imm, 6, 6, imm); \
1816 thumb_data_proc(imm, adds, imm, 7, 7, imm); \
1821 thumb_data_proc(imm, subs, imm, 0, 0, imm); \
1826 thumb_data_proc(imm, subs, imm, 1, 1, imm); \
1831 thumb_data_proc(imm, subs, imm, 2, 2, imm); \
1836 thumb_data_proc(imm, subs, imm, 3, 3, imm); \
1841 thumb_data_proc(imm, subs, imm, 4, 4, imm); \
1846 thumb_data_proc(imm, subs, imm, 5, 5, imm); \
1851 thumb_data_proc(imm, subs, imm, 6, 6, imm); \
1856 thumb_data_proc(imm, subs, imm, 7, 7, imm); \
1860 switch((opcode >> 6) & 0x03) \
1864 thumb_data_proc(alu_op, ands, reg, rd, rd, rs); \
1869 thumb_data_proc(alu_op, eors, reg, rd, rd, rs); \
1874 thumb_shift(alu_op, lsl, reg); \
1879 thumb_shift(alu_op, lsr, reg); \
1885 switch((opcode >> 6) & 0x03) \
1889 thumb_shift(alu_op, asr, reg); \
1894 thumb_data_proc(alu_op, adcs, reg, rd, rd, rs); \
1899 thumb_data_proc(alu_op, sbcs, reg, rd, rd, rs); \
1904 thumb_shift(alu_op, ror, reg); \
1910 switch((opcode >> 6) & 0x03) \
1914 thumb_data_proc_test(alu_op, tst, reg, rd, rs); \
1919 thumb_data_proc_unary(alu_op, neg, reg, rd, rs); \
1924 thumb_data_proc_test(alu_op, cmp, reg, rd, rs); \
1929 thumb_data_proc_test(alu_op, cmn, reg, rd, rs); \
1935 switch((opcode >> 6) & 0x03) \
1939 thumb_data_proc(alu_op, orrs, reg, rd, rd, rs); \
1944 thumb_data_proc(alu_op, muls, reg, rd, rd, rs); \
1949 thumb_data_proc(alu_op, bics, reg, rd, rd, rs); \
1954 thumb_data_proc_unary(alu_op, mvns, reg, rd, rs); \
1961 thumb_data_proc_hi(add); \
1966 thumb_data_proc_test_hi(cmp); \
1971 thumb_data_proc_mov_hi(); \
1980 /* LDR r0, [pc + imm] */ \
1981 thumb_access_memory(load, imm, 0, 0, 0, pc_relative, \
1982 (pc & ~2) + (imm * 4) + 4, u32); \
1986 /* LDR r1, [pc + imm] */ \
1987 thumb_access_memory(load, imm, 1, 0, 0, pc_relative, \
1988 (pc & ~2) + (imm * 4) + 4, u32); \
1992 /* LDR r2, [pc + imm] */ \
1993 thumb_access_memory(load, imm, 2, 0, 0, pc_relative, \
1994 (pc & ~2) + (imm * 4) + 4, u32); \
1998 /* LDR r3, [pc + imm] */ \
1999 thumb_access_memory(load, imm, 3, 0, 0, pc_relative, \
2000 (pc & ~2) + (imm * 4) + 4, u32); \
2004 /* LDR r4, [pc + imm] */ \
2005 thumb_access_memory(load, imm, 4, 0, 0, pc_relative, \
2006 (pc & ~2) + (imm * 4) + 4, u32); \
2010 /* LDR r5, [pc + imm] */ \
2011 thumb_access_memory(load, imm, 5, 0, 0, pc_relative, \
2012 (pc & ~2) + (imm * 4) + 4, u32); \
2016 /* LDR r6, [pc + imm] */ \
2017 thumb_access_memory(load, imm, 6, 0, 0, pc_relative, \
2018 (pc & ~2) + (imm * 4) + 4, u32); \
2022 /* LDR r7, [pc + imm] */ \
2023 thumb_access_memory(load, imm, 7, 0, 0, pc_relative, \
2024 (pc & ~2) + (imm * 4) + 4, u32); \
2027 case 0x50 ... 0x51: \
2028 /* STR rd, [rb + ro] */ \
2029 thumb_access_memory(store, mem_reg, rd, rb, ro, reg_reg, 0, u32); \
2032 case 0x52 ... 0x53: \
2033 /* STRH rd, [rb + ro] */ \
2034 thumb_access_memory(store, mem_reg, rd, rb, ro, reg_reg, 0, u16); \
2037 case 0x54 ... 0x55: \
2038 /* STRB rd, [rb + ro] */ \
2039 thumb_access_memory(store, mem_reg, rd, rb, ro, reg_reg, 0, u8); \
2042 case 0x56 ... 0x57: \
2043 /* LDSB rd, [rb + ro] */ \
2044 thumb_access_memory(load, mem_reg, rd, rb, ro, reg_reg, 0, s8); \
2047 case 0x58 ... 0x59: \
2048 /* LDR rd, [rb + ro] */ \
2049 thumb_access_memory(load, mem_reg, rd, rb, ro, reg_reg, 0, u32); \
2052 case 0x5A ... 0x5B: \
2053 /* LDRH rd, [rb + ro] */ \
2054 thumb_access_memory(load, mem_reg, rd, rb, ro, reg_reg, 0, u16); \
2057 case 0x5C ... 0x5D: \
2058 /* LDRB rd, [rb + ro] */ \
2059 thumb_access_memory(load, mem_reg, rd, rb, ro, reg_reg, 0, u8); \
2062 case 0x5E ... 0x5F: \
2063 /* LDSH rd, [rb + ro] */ \
2064 thumb_access_memory(load, mem_reg, rd, rb, ro, reg_reg, 0, s16); \
2067 case 0x60 ... 0x67: \
2068 /* STR rd, [rb + imm] */ \
2069 thumb_access_memory(store, mem_imm, rd, rb, 0, reg_imm, (imm * 4), \
2073 case 0x68 ... 0x6F: \
2074 /* LDR rd, [rb + imm] */ \
2075 thumb_access_memory(load, mem_imm, rd, rb, 0, reg_imm, (imm * 4), u32); \
2078 case 0x70 ... 0x77: \
2079 /* STRB rd, [rb + imm] */ \
2080 thumb_access_memory(store, mem_imm, rd, rb, 0, reg_imm, imm, u8); \
2083 case 0x78 ... 0x7F: \
2084 /* LDRB rd, [rb + imm] */ \
2085 thumb_access_memory(load, mem_imm, rd, rb, 0, reg_imm, imm, u8); \
2088 case 0x80 ... 0x87: \
2089 /* STRH rd, [rb + imm] */ \
2090 thumb_access_memory(store, mem_imm, rd, rb, 0, reg_imm, \
2094 case 0x88 ... 0x8F: \
2095 /* LDRH rd, [rb + imm] */ \
2096 thumb_access_memory(load, mem_imm, rd, rb, 0, reg_imm, (imm * 2), u16); \
2100 /* STR r0, [sp + imm] */ \
2101 thumb_access_memory(store, imm, 0, 13, 0, reg_imm_sp, imm, u32); \
2105 /* STR r1, [sp + imm] */ \
2106 thumb_access_memory(store, imm, 1, 13, 0, reg_imm_sp, imm, u32); \
2110 /* STR r2, [sp + imm] */ \
2111 thumb_access_memory(store, imm, 2, 13, 0, reg_imm_sp, imm, u32); \
2115 /* STR r3, [sp + imm] */ \
2116 thumb_access_memory(store, imm, 3, 13, 0, reg_imm_sp, imm, u32); \
2120 /* STR r4, [sp + imm] */ \
2121 thumb_access_memory(store, imm, 4, 13, 0, reg_imm_sp, imm, u32); \
2125 /* STR r5, [sp + imm] */ \
2126 thumb_access_memory(store, imm, 5, 13, 0, reg_imm_sp, imm, u32); \
2130 /* STR r6, [sp + imm] */ \
2131 thumb_access_memory(store, imm, 6, 13, 0, reg_imm_sp, imm, u32); \
2135 /* STR r7, [sp + imm] */ \
2136 thumb_access_memory(store, imm, 7, 13, 0, reg_imm_sp, imm, u32); \
2140 /* LDR r0, [sp + imm] */ \
2141 thumb_access_memory(load, imm, 0, 13, 0, reg_imm_sp, imm, u32); \
2145 /* LDR r1, [sp + imm] */ \
2146 thumb_access_memory(load, imm, 1, 13, 0, reg_imm_sp, imm, u32); \
2150 /* LDR r2, [sp + imm] */ \
2151 thumb_access_memory(load, imm, 2, 13, 0, reg_imm_sp, imm, u32); \
2155 /* LDR r3, [sp + imm] */ \
2156 thumb_access_memory(load, imm, 3, 13, 0, reg_imm_sp, imm, u32); \
2160 /* LDR r4, [sp + imm] */ \
2161 thumb_access_memory(load, imm, 4, 13, 0, reg_imm_sp, imm, u32); \
2165 /* LDR r5, [sp + imm] */ \
2166 thumb_access_memory(load, imm, 5, 13, 0, reg_imm_sp, imm, u32); \
2170 /* LDR r6, [sp + imm] */ \
2171 thumb_access_memory(load, imm, 6, 13, 0, reg_imm_sp, imm, u32); \
2175 /* LDR r7, [sp + imm] */ \
2176 thumb_access_memory(load, imm, 7, 13, 0, reg_imm_sp, imm, u32); \
2180 /* ADD r0, pc, +imm */ \
2185 /* ADD r1, pc, +imm */ \
2190 /* ADD r2, pc, +imm */ \
2195 /* ADD r3, pc, +imm */ \
2200 /* ADD r4, pc, +imm */ \
2205 /* ADD r5, pc, +imm */ \
2210 /* ADD r6, pc, +imm */ \
2215 /* ADD r7, pc, +imm */ \
2220 /* ADD r0, sp, +imm */ \
2225 /* ADD r1, sp, +imm */ \
2230 /* ADD r2, sp, +imm */ \
2235 /* ADD r3, sp, +imm */ \
2240 /* ADD r4, sp, +imm */ \
2245 /* ADD r5, sp, +imm */ \
2250 /* ADD r6, sp, +imm */ \
2255 /* ADD r7, sp, +imm */ \
2259 case 0xB0 ... 0xB3: \
2260 if((opcode >> 7) & 0x01) \
2262 /* ADD sp, -imm */ \
2263 thumb_adjust_sp(down); \
2267 /* ADD sp, +imm */ \
2268 thumb_adjust_sp(up); \
2274 thumb_block_memory(store, down, no, 13); \
2278 /* PUSH rlist, lr */ \
2279 thumb_block_memory(store, push_lr, push_lr, 13); \
2284 thumb_block_memory(load, no, up, 13); \
2288 /* POP rlist, pc */ \
2289 thumb_block_memory(load, no, pop_pc, 13); \
2293 /* STMIA r0!, rlist */ \
2294 thumb_block_memory(store, no, up, 0); \
2298 /* STMIA r1!, rlist */ \
2299 thumb_block_memory(store, no, up, 1); \
2303 /* STMIA r2!, rlist */ \
2304 thumb_block_memory(store, no, up, 2); \
2308 /* STMIA r3!, rlist */ \
2309 thumb_block_memory(store, no, up, 3); \
2313 /* STMIA r4!, rlist */ \
2314 thumb_block_memory(store, no, up, 4); \
2318 /* STMIA r5!, rlist */ \
2319 thumb_block_memory(store, no, up, 5); \
2323 /* STMIA r6!, rlist */ \
2324 thumb_block_memory(store, no, up, 6); \
2328 /* STMIA r7!, rlist */ \
2329 thumb_block_memory(store, no, up, 7); \
2333 /* LDMIA r0!, rlist */ \
2334 thumb_block_memory(load, no, up, 0); \
2338 /* LDMIA r1!, rlist */ \
2339 thumb_block_memory(load, no, up, 1); \
2343 /* LDMIA r2!, rlist */ \
2344 thumb_block_memory(load, no, up, 2); \
2348 /* LDMIA r3!, rlist */ \
2349 thumb_block_memory(load, no, up, 3); \
2353 /* LDMIA r4!, rlist */ \
2354 thumb_block_memory(load, no, up, 4); \
2358 /* LDMIA r5!, rlist */ \
2359 thumb_block_memory(load, no, up, 5); \
2363 /* LDMIA r6!, rlist */ \
2364 thumb_block_memory(load, no, up, 6); \
2368 /* LDMIA r7!, rlist */ \
2369 thumb_block_memory(load, no, up, 7); \
2374 thumb_conditional_branch(eq); \
2379 thumb_conditional_branch(ne); \
2384 thumb_conditional_branch(cs); \
2389 thumb_conditional_branch(cc); \
2394 thumb_conditional_branch(mi); \
2399 thumb_conditional_branch(pl); \
2404 thumb_conditional_branch(vs); \
2409 thumb_conditional_branch(vc); \
2414 thumb_conditional_branch(hi); \
2419 thumb_conditional_branch(ls); \
2424 thumb_conditional_branch(ge); \
2429 thumb_conditional_branch(lt); \
2434 thumb_conditional_branch(gt); \
2439 thumb_conditional_branch(le); \
2449 case 0xE0 ... 0xE7: \
2456 case 0xF0 ... 0xF7: \
2458 /* (low word) BL label */ \
2459 /* This should possibly generate code if not in conjunction with a BLH \
2460 next, but I don't think anyone will do that. */ \
2464 case 0xF8 ... 0xFF: \
2466 /* (high word) BL label */ \
2467 /* This might not be preceeding a BL low word (Golden Sun 2), if so \
2468 it must be handled like an indirect branch. */ \
2469 if((last_opcode >= 0xF000) && (last_opcode < 0xF800)) \
2483 #define thumb_flag_modifies_all() \
2484 flag_status |= 0xFF \
2486 #define thumb_flag_modifies_zn() \
2487 flag_status |= 0xCC \
2489 #define thumb_flag_modifies_znc() \
2490 flag_status |= 0xEE \
2492 #define thumb_flag_modifies_zn_maybe_c() \
2493 flag_status |= 0xCE \
2495 #define thumb_flag_modifies_c() \
2496 flag_status |= 0x22 \
2498 #define thumb_flag_requires_c() \
2499 flag_status |= 0x200 \
2501 #define thumb_flag_requires_all() \
2502 flag_status |= 0xF00 \
2504 #define thumb_flag_status() \
2506 u16 flag_status = 0; \
2507 switch((opcode >> 8) & 0xFF) \
2509 /* left shift by imm */ \
2510 case 0x00 ... 0x07: \
2511 thumb_flag_modifies_zn(); \
2512 if(((opcode >> 6) & 0x1F) != 0) \
2514 thumb_flag_modifies_c(); \
2518 /* right shift by imm */ \
2519 case 0x08 ... 0x17: \
2520 thumb_flag_modifies_znc(); \
2523 /* add, subtract */ \
2524 case 0x18 ... 0x1F: \
2525 thumb_flag_modifies_all(); \
2528 /* mov reg, imm */ \
2529 case 0x20 ... 0x27: \
2530 thumb_flag_modifies_zn(); \
2533 /* cmp reg, imm; add, subtract */ \
2534 case 0x28 ... 0x3F: \
2535 thumb_flag_modifies_all(); \
2539 switch((opcode >> 6) & 0x03) \
2543 thumb_flag_modifies_zn(); \
2548 thumb_flag_modifies_zn(); \
2553 thumb_flag_modifies_zn_maybe_c(); \
2558 thumb_flag_modifies_zn_maybe_c(); \
2564 switch((opcode >> 6) & 0x03) \
2568 thumb_flag_modifies_zn_maybe_c(); \
2573 thumb_flag_modifies_all(); \
2574 thumb_flag_requires_c(); \
2579 thumb_flag_modifies_all(); \
2580 thumb_flag_requires_c(); \
2585 thumb_flag_modifies_zn_maybe_c(); \
2590 /* TST, NEG, CMP, CMN */ \
2592 thumb_flag_modifies_all(); \
2595 /* ORR, MUL, BIC, MVN */ \
2597 thumb_flag_modifies_zn(); \
2602 thumb_flag_modifies_all(); \
2605 /* mov might change PC (fall through if so) */ \
2607 if((opcode & 0xFF87) != 0x4687) \
2610 /* branches (can change PC) */ \
2613 case 0xD0 ... 0xE7: \
2614 case 0xF0 ... 0xFF: \
2615 thumb_flag_requires_all(); \
2618 block_data[block_data_position].flag_data = flag_status; \
2621 u8 *ram_block_ptrs[1024 * 64];
2622 u32 ram_block_tag_top = 0x0101;
2624 u8 *bios_block_ptrs[1024 * 8];
2625 u32 bios_block_tag_top = 0x0101;
2627 // This function will return a pointer to a translated block of code. If it
2628 // doesn't exist it will translate it, if it does it will pass it back.
2630 // type should be "arm", "thumb", or "dual." For arm or thumb the PC should
2631 // be a real PC, for dual the least significant bit will determine if it's
2632 // ARM or Thumb mode.
2634 #define block_lookup_address_pc_arm() \
2637 #define block_lookup_address_pc_thumb() \
2640 #define block_lookup_address_pc_dual() \
2641 u32 thumb = pc & 0x01; \
2646 reg[REG_CPSR] |= 0x20; \
2650 pc = (pc + 2) & ~0x03; \
2651 reg[REG_CPSR] &= ~0x20; \
2654 #define ram_translation_region TRANSLATION_REGION_RAM
2655 #define rom_translation_region TRANSLATION_REGION_ROM
2656 #define bios_translation_region TRANSLATION_REGION_BIOS
2658 #define block_lookup_translate_arm(mem_type, smc_enable) \
2659 translation_result = translate_block_arm(pc, mem_type##_translation_region, \
2662 #define block_lookup_translate_thumb(mem_type, smc_enable) \
2663 translation_result = translate_block_thumb(pc, \
2664 mem_type##_translation_region, smc_enable) \
2666 #define block_lookup_translate_dual(mem_type, smc_enable) \
2669 translation_result = translate_block_thumb(pc, \
2670 mem_type##_translation_region, smc_enable); \
2674 translation_result = translate_block_arm(pc, \
2675 mem_type##_translation_region, smc_enable); \
2678 // 0x0101 is the smallest tag that can be used. 0xFFFF is marked
2679 // in the middle of blocks and used for write guarding, it doesn't
2680 // indicate a valid block either (it's okay to compile a new block
2681 // that overlaps the earlier one, although this should be relatively
2684 #define fill_tag_arm(mem_type) \
2685 location[0] = mem_type##_block_tag_top; \
2686 location[1] = 0xFFFF \
2688 #define fill_tag_thumb(mem_type) \
2689 *location = mem_type##_block_tag_top \
2691 #define fill_tag_dual(mem_type) \
2693 fill_tag_thumb(mem_type); \
2695 fill_tag_arm(mem_type) \
2697 #define block_lookup_translate(instruction_type, mem_type, smc_enable) \
2698 block_tag = *location; \
2699 if((block_tag < 0x0101) || (block_tag == 0xFFFF)) \
2702 s32 translation_result; \
2706 translation_recursion_level++; \
2707 block_address = mem_type##_translation_ptr + block_prologue_size; \
2708 mem_type##_block_ptrs[mem_type##_block_tag_top] = block_address; \
2709 fill_tag_##instruction_type(mem_type); \
2710 mem_type##_block_tag_top++; \
2712 block_lookup_translate_##instruction_type(mem_type, smc_enable); \
2713 translation_recursion_level--; \
2715 /* If the translation failed then pass that failure on if we're in \
2716 a recursive level, or try again if we've hit the bottom. */ \
2717 if(translation_result == -1) \
2719 if(translation_recursion_level) \
2725 if(translation_recursion_level == 0) \
2726 translate_invalidate_dcache(); \
2730 block_address = mem_type##_block_ptrs[block_tag]; \
2733 u32 translation_recursion_level = 0;
2734 u32 translation_flush_count = 0;
2737 #define block_lookup_address_builder(type) \
2738 u8 function_cc *block_lookup_address_##type(u32 pc) \
2742 u8 *block_address; \
2744 /* Starting at the beginning, we allow for one translation cache flush. */ \
2745 if(translation_recursion_level == 0) \
2746 translation_flush_count = 0; \
2747 block_lookup_address_pc_##type(); \
2752 bios_region_read_allow(); \
2753 location = (u16 *)(bios_rom + pc + 0x4000); \
2754 block_lookup_translate(type, bios, 0); \
2755 if(translation_recursion_level == 0) \
2756 bios_region_read_allow(); \
2760 location = (u16 *)(ewram + (pc & 0x7FFF) + ((pc & 0x38000) * 2)); \
2761 block_lookup_translate(type, ram, 1); \
2762 if(translation_recursion_level == 0) \
2763 bios_region_read_protect(); \
2767 location = (u16 *)(iwram + (pc & 0x7FFF)); \
2768 block_lookup_translate(type, ram, 1); \
2769 if(translation_recursion_level == 0) \
2770 bios_region_read_protect(); \
2775 u32 hash_target = ((pc * 2654435761U) >> 16) & \
2776 (ROM_BRANCH_HASH_SIZE - 1); \
2777 u32 *block_ptr = rom_branch_hash[hash_target]; \
2778 u32 **block_ptr_address = rom_branch_hash + hash_target; \
2782 if(block_ptr[0] == pc) \
2784 block_address = (u8 *)(block_ptr + 2) + block_prologue_size; \
2788 block_ptr_address = (u32 **)(block_ptr + 1); \
2789 block_ptr = (u32 *)block_ptr[1]; \
2792 if(block_ptr == NULL) \
2795 s32 translation_result; \
2799 translation_recursion_level++; \
2800 ((u32 *)rom_translation_ptr)[0] = pc; \
2801 ((u32 **)rom_translation_ptr)[1] = NULL; \
2802 *block_ptr_address = (u32 *)rom_translation_ptr; \
2803 rom_translation_ptr += 8; \
2804 block_address = rom_translation_ptr + block_prologue_size; \
2805 block_lookup_translate_##type(rom, 0); \
2806 translation_recursion_level--; \
2808 /* If the translation failed then pass that failure on if we're in \
2809 a recursive level, or try again if we've hit the bottom. */ \
2810 if(translation_result == -1) \
2812 if(translation_recursion_level) \
2818 if(translation_recursion_level == 0) \
2819 translate_invalidate_dcache(); \
2821 if(translation_recursion_level == 0) \
2822 bios_region_read_protect(); \
2827 /* If we're at the bottom, it means we're actually trying to jump to an \
2828 address that we can't handle. Otherwise, it means that code scanned \
2829 has reached an address that can't be handled, which means that we \
2830 have most likely hit an area that doesn't contain code yet (for \
2831 instance, in RAM). If such a thing happens, return -1 and the \
2832 block translater will naively link it (it'll be okay, since it \
2833 should never be hit) */ \
2834 if(translation_recursion_level == 0) \
2837 sprintf(buffer, "bad jump %x (%x) (%x)\n", pc, reg[REG_PC], \
2838 last_instruction); \
2839 printf("%s", buffer); \
2842 block_address = (u8 *)(-1); \
2846 return block_address; \
2849 block_lookup_address_builder(arm);
2850 block_lookup_address_builder(thumb);
2851 block_lookup_address_builder(dual);
2853 // Potential exit point: If the rd field is pc for instructions is 0x0F,
2854 // the instruction is b/bl/bx, or the instruction is ldm with PC in the
2856 // All instructions with upper 3 bits less than 100b have an rd field
2857 // except bx, where the bits must be 0xF there anyway, multiplies,
2858 // which cannot have 0xF in the corresponding fields, and msr, which
2859 // has 0x0F there but doesn't end things (therefore must be special
2860 // checked against). Because MSR and BX overlap both are checked for.
2862 #define arm_exit_point \
2863 (((opcode < 0x8000000) && ((opcode & 0x000F000) == 0x000F000) && \
2864 ((opcode & 0xDB0F000) != 0x120F000)) || \
2865 ((opcode & 0x12FFF10) == 0x12FFF10) || \
2866 ((opcode & 0x8108000) == 0x8108000) || \
2867 ((opcode >= 0xA000000) && (opcode < 0xF000000)) || \
2868 ((opcode > 0xF000000) && (!swi_hle_handle[((opcode >> 16) & 0xFF)]))) \
2870 #define arm_opcode_branch \
2871 ((opcode & 0xE000000) == 0xA000000) \
2873 #define arm_opcode_swi \
2874 ((opcode & 0xF000000) == 0xF000000) \
2876 #define arm_opcode_unconditional_branch \
2877 (condition == 0x0E) \
2879 #define arm_load_opcode() \
2880 opcode = address32(pc_address_block, (block_end_pc & 0x7FFF)); \
2881 condition = opcode >> 28; \
2883 opcode &= 0xFFFFFFF; \
2887 #define arm_branch_target() \
2888 branch_target = (block_end_pc + 4 + (((s32)(opcode & 0xFFFFFF) << 8) >> 6)) \
2890 // Contiguous conditional block flags modification - it will set 0x20 in the
2891 // condition's bits if this instruction modifies flags. Taken from the CPU
2892 // switch so it'd better be right this time.
2894 #define arm_set_condition(_condition) \
2895 block_data[block_data_position].condition = _condition; \
2896 switch((opcode >> 20) & 0xFF) \
2904 if((((opcode >> 5) & 0x03) == 0) || ((opcode & 0x90) != 0x90)) \
2905 block_data[block_data_position].condition |= 0x20; \
2912 case 0x15 ... 0x17: \
2917 if((opcode & 0x90) != 0x90) \
2918 block_data[block_data_position].condition |= 0x20; \
2922 if(((opcode & 0x90) != 0x90) && !(opcode & 0x10)) \
2923 block_data[block_data_position].condition |= 0x20; \
2933 case 0x2F ... 0x37: \
2938 block_data[block_data_position].condition |= 0x20; \
2942 #define arm_link_block() \
2943 translation_target = block_lookup_address_arm(branch_target) \
2945 #define arm_instruction_width 4
2947 #define arm_base_cycles() \
2948 cycle_count += waitstate_cycles_sequential[pc >> 24][2] \
2950 // For now this just sets a variable that says flags should always be
2953 #define arm_dead_flag_eliminate() \
2956 // The following Thumb instructions can exit:
2957 // b, bl, bx, swi, pop {... pc}, and mov pc, ..., the latter being a hireg
2958 // op only. Rather simpler to identify than the ARM set.
2960 #define thumb_exit_point \
2961 (((opcode >= 0xD000) && (opcode < 0xDF00)) || \
2962 (((opcode & 0xFF00) == 0xDF00) && \
2963 (!swi_hle_handle[opcode & 0xFF])) || \
2964 ((opcode >= 0xE000) && (opcode < 0xE800)) || \
2965 ((opcode & 0xFF00) == 0x4700) || \
2966 ((opcode & 0xFF00) == 0xBD00) || \
2967 ((opcode & 0xFF87) == 0x4687) || \
2968 ((opcode >= 0xF800))) \
2970 #define thumb_opcode_branch \
2971 (((opcode >= 0xD000) && (opcode < 0xDF00)) || \
2972 ((opcode >= 0xE000) && (opcode < 0xE800)) || \
2973 (opcode >= 0xF800)) \
2975 #define thumb_opcode_swi \
2976 ((opcode & 0xFF00) == 0xDF00) \
2978 #define thumb_opcode_unconditional_branch \
2979 ((opcode < 0xD000) || (opcode >= 0xDF00)) \
2981 #define thumb_load_opcode() \
2982 last_opcode = opcode; \
2983 opcode = address16(pc_address_block, (block_end_pc & 0x7FFF)); \
2987 #define thumb_branch_target() \
2988 if(opcode < 0xE000) \
2990 branch_target = block_end_pc + 2 + ((s8)(opcode & 0xFF) * 2); \
2994 if(opcode < 0xF800) \
2996 branch_target = block_end_pc + 2 + ((s32)((opcode & 0x7FF) << 21) >> 20); \
3000 if((last_opcode >= 0xF000) && (last_opcode < 0xF800)) \
3003 (block_end_pc + ((s32)((last_opcode & 0x07FF) << 21) >> 9) + \
3004 ((opcode & 0x07FF) * 2)); \
3008 goto no_direct_branch; \
3012 #define thumb_set_condition(_condition) \
3014 #define thumb_link_block() \
3015 if(branch_target != 0x00000008) \
3016 translation_target = block_lookup_address_thumb(branch_target); \
3018 translation_target = block_lookup_address_arm(branch_target) \
3020 #define thumb_instruction_width 2
3022 #define thumb_base_cycles() \
3023 cycle_count += waitstate_cycles_sequential[pc >> 24][1] \
3025 // Here's how this works: each instruction has three different sets of flag
3026 // attributes, each consisiting of a 4bit mask describing how that instruction
3027 // interacts with the 4 main flags (N/Z/C/V).
3028 // The first set, in bits 0:3, is the set of flags the instruction may
3029 // modify. After this pass this is changed to the set of flags the instruction
3030 // should modify - if the bit for the corresponding flag is not set then code
3031 // does not have to be generated to calculate the flag for that instruction.
3033 // The second set, in bits 7:4, is the set of flags that the instruction must
3034 // modify (ie, for shifts by the register values the instruction may not
3035 // always modify the C flag, and thus the C bit won't be set here).
3037 // The third set, in bits 11:8, is the set of flags that the instruction uses
3038 // in its computation, or the set of flags that will be needed after the
3039 // instruction is done. For any instructions that change the PC all of the
3040 // bits should be set because it is (for now) unknown what flags will be
3041 // needed after it arrives at its destination. Instructions that use the
3042 // carry flag as input will have it set as well.
3044 // The algorithm is a simple liveness analysis procedure: It starts at the
3045 // bottom of the instruction stream and sets a "currently needed" mask to
3046 // the flags needed mask of the current instruction. Then it moves down
3047 // an instruction, ANDs that instructions "should generate" mask by the
3048 // "currently needed" mask, then ANDs the "currently needed" mask by
3049 // the 1's complement of the instruction's "must generate" mask, and ORs
3050 // the "currently needed" mask by the instruction's "flags needed" mask.
3052 #define thumb_dead_flag_eliminate() \
3055 needed_mask = block_data[block_data_position].flag_data >> 8; \
3057 block_data_position--; \
3058 while(block_data_position >= 0) \
3060 flag_status = block_data[block_data_position].flag_data; \
3061 block_data[block_data_position].flag_data = \
3062 (flag_status & needed_mask); \
3063 needed_mask &= ~((flag_status >> 4) & 0x0F); \
3064 needed_mask |= flag_status >> 8; \
3065 block_data_position--; \
3069 #define MAX_BLOCK_SIZE 8192
3070 #define MAX_EXITS 256
3072 block_data_type block_data[MAX_BLOCK_SIZE];
3073 block_exit_type block_exits[MAX_EXITS];
3075 #define smc_write_arm_yes() \
3076 if(address32(pc_address_block, (block_end_pc & 0x7FFF) - 0x8000) == 0x0000) \
3078 address32(pc_address_block, (block_end_pc & 0x7FFF) - 0x8000) = \
3082 #define smc_write_thumb_yes() \
3083 if(address16(pc_address_block, (block_end_pc & 0x7FFF) - 0x8000) == 0x0000) \
3085 address16(pc_address_block, (block_end_pc & 0x7FFF) - 0x8000) = 0xFFFF; \
3088 #define smc_write_arm_no() \
3090 #define smc_write_thumb_no() \
3092 #define scan_block(type, smc_write_op) \
3094 __label__ block_end; \
3095 /* Find the end of the block */ \
3098 check_pc_region(block_end_pc); \
3099 smc_write_##type##_##smc_write_op(); \
3100 type##_load_opcode(); \
3101 type##_flag_status(); \
3103 if(type##_exit_point) \
3105 /* Branch/branch with link */ \
3106 if(type##_opcode_branch) \
3108 __label__ no_direct_branch; \
3109 type##_branch_target(); \
3110 block_exits[block_exit_position].branch_target = branch_target; \
3111 block_exit_position++; \
3113 /* Give the branch target macro somewhere to bail if it turns out to \
3114 be an indirect branch (ala malformed Thumb bl) */ \
3115 no_direct_branch:; \
3118 /* SWI branches to the BIOS, this will likely change when \
3119 some HLE BIOS is implemented. */ \
3120 if(type##_opcode_swi) \
3122 block_exits[block_exit_position].branch_target = 0x00000008; \
3123 block_exit_position++; \
3126 type##_set_condition(condition | 0x10); \
3128 /* Only unconditional branches can end the block. */ \
3129 if(type##_opcode_unconditional_branch) \
3131 /* Check to see if any prior block exits branch after here, \
3132 if so don't end the block. Starts from the top and works \
3133 down because the most recent branch is most likely to \
3134 join after the end (if/then form) */ \
3135 for(i = block_exit_position - 2; i >= 0; i--) \
3137 if(block_exits[i].branch_target == block_end_pc) \
3144 if(block_exit_position == MAX_EXITS) \
3149 type##_set_condition(condition); \
3152 for(i = 0; i < translation_gate_targets; i++) \
3154 if(block_end_pc == translation_gate_target_pc[i]) \
3158 block_data[block_data_position].update_cycles = 0; \
3159 block_data_position++; \
3160 if((block_data_position == MAX_BLOCK_SIZE) || \
3161 (block_end_pc == 0x3007FF0) || (block_end_pc == 0x203FFFF0)) \
3170 #define arm_fix_pc() \
3173 #define thumb_fix_pc() \
3176 #define translate_block_builder(type) \
3177 s32 translate_block_##type(u32 pc, translation_region_type \
3178 translation_region, u32 smc_enable) \
3183 u32 last_condition; \
3184 u32 pc_region = (pc >> 15); \
3185 u32 new_pc_region; \
3186 u8 *pc_address_block = memory_map_read[pc_region]; \
3187 u32 block_start_pc = pc; \
3188 u32 block_end_pc = pc; \
3189 u32 block_exit_position = 0; \
3190 s32 block_data_position = 0; \
3191 u32 external_block_exit_position = 0; \
3192 u32 branch_target; \
3193 u32 cycle_count = 0; \
3194 u8 *translation_target; \
3195 u8 *backpatch_address; \
3196 u8 *translation_ptr; \
3197 u8 *translation_cache_limit; \
3200 block_exit_type external_block_exits[MAX_EXITS]; \
3201 generate_block_extra_vars_##type(); \
3204 if(pc_address_block == NULL) \
3205 pc_address_block = load_gamepak_page(pc_region & 0x3FF); \
3207 switch(translation_region) \
3209 case TRANSLATION_REGION_RAM: \
3210 if(pc >= 0x3000000) \
3212 if((pc < iwram_code_min) || (iwram_code_min == 0xFFFFFFFF)) \
3213 iwram_code_min = pc; \
3217 if(pc >= 0x2000000) \
3219 if((pc < ewram_code_min) || (ewram_code_min == 0xFFFFFFFF)) \
3220 ewram_code_min = pc; \
3223 translation_ptr = ram_translation_ptr; \
3224 translation_cache_limit = \
3225 ram_translation_cache + RAM_TRANSLATION_CACHE_SIZE - \
3226 TRANSLATION_CACHE_LIMIT_THRESHOLD; \
3229 case TRANSLATION_REGION_ROM: \
3230 translation_ptr = rom_translation_ptr; \
3231 translation_cache_limit = \
3232 rom_translation_cache + ROM_TRANSLATION_CACHE_SIZE - \
3233 TRANSLATION_CACHE_LIMIT_THRESHOLD; \
3236 case TRANSLATION_REGION_BIOS: \
3237 translation_ptr = bios_translation_ptr; \
3238 translation_cache_limit = bios_translation_cache + \
3239 BIOS_TRANSLATION_CACHE_SIZE; \
3243 generate_block_prologue(); \
3245 /* This is a function because it's used a lot more than it might seem (all \
3246 of the data processing functions can access it), and its expansion was \
3247 massacreing the compiler. */ \
3251 scan_block(type, yes); \
3255 scan_block(type, no); \
3258 for(i = 0; i < block_exit_position; i++) \
3260 branch_target = block_exits[i].branch_target; \
3262 if((branch_target > block_start_pc) && \
3263 (branch_target < block_end_pc)) \
3265 block_data[(branch_target - block_start_pc) / \
3266 type##_instruction_width].update_cycles = 1; \
3270 type##_dead_flag_eliminate(); \
3272 block_exit_position = 0; \
3273 block_data_position = 0; \
3275 last_condition = 0x0E; \
3277 while(pc != block_end_pc) \
3279 block_data[block_data_position].block_offset = translation_ptr; \
3280 type##_base_cycles(); \
3281 /*generate_step_debug();*/ \
3283 translate_##type##_instruction(); \
3284 block_data_position++; \
3286 /* If it went too far the cache needs to be flushed and the process \
3287 restarted. Because we might already be nested several stages in \
3288 a simple recursive call here won't work, it has to pedal out to \
3291 if(translation_ptr > translation_cache_limit) \
3293 translation_flush_count++; \
3295 switch(translation_region) \
3297 case TRANSLATION_REGION_RAM: \
3298 flush_translation_cache_ram(); \
3301 case TRANSLATION_REGION_ROM: \
3302 flush_translation_cache_rom(); \
3305 case TRANSLATION_REGION_BIOS: \
3306 flush_translation_cache_bios(); \
3313 /* If the next instruction is a block entry point update the \
3314 cycle counter and update */ \
3315 if(block_data[block_data_position].update_cycles == 1) \
3317 generate_cycle_update(); \
3320 for(i = 0; i < translation_gate_targets; i++) \
3322 if(pc == translation_gate_target_pc[i]) \
3324 generate_translation_gate(type); \
3329 for(i = 0; i < block_exit_position; i++) \
3331 branch_target = block_exits[i].branch_target; \
3333 if((branch_target >= block_start_pc) && (branch_target < block_end_pc)) \
3335 /* Internal branch, patch to recorded address */ \
3336 translation_target = \
3337 block_data[(branch_target - block_start_pc) / \
3338 type##_instruction_width].block_offset; \
3340 generate_branch_patch_unconditional(block_exits[i].branch_source, \
3341 translation_target); \
3345 /* External branch, save for later */ \
3346 external_block_exits[external_block_exit_position].branch_target = \
3348 external_block_exits[external_block_exit_position].branch_source = \
3349 block_exits[i].branch_source; \
3350 external_block_exit_position++; \
3354 switch(translation_region) \
3356 case TRANSLATION_REGION_RAM: \
3357 if(pc >= 0x3000000) \
3359 if((pc > iwram_code_max) || (iwram_code_max == 0xFFFFFFFF)) \
3360 iwram_code_max = pc; \
3364 if(pc >= 0x2000000) \
3366 if((pc > ewram_code_max) || (ewram_code_max == 0xFFFFFFFF)) \
3367 ewram_code_max = pc; \
3370 ram_translation_ptr = translation_ptr; \
3373 case TRANSLATION_REGION_ROM: \
3374 rom_translation_ptr = translation_ptr; \
3377 case TRANSLATION_REGION_BIOS: \
3378 bios_translation_ptr = translation_ptr; \
3382 for(i = 0; i < external_block_exit_position; i++) \
3384 branch_target = external_block_exits[i].branch_target; \
3385 type##_link_block(); \
3386 if(translation_target == NULL) \
3388 generate_branch_patch_unconditional( \
3389 external_block_exits[i].branch_source, translation_target); \
3395 translate_block_builder(arm);
3396 translate_block_builder(thumb);
3398 void flush_translation_cache_ram()
3401 /* printf("ram flush %d (pc %x), %x to %x, %x to %x\n",
3402 flush_ram_count, reg[REG_PC], iwram_code_min, iwram_code_max,
3403 ewram_code_min, ewram_code_max); */
3406 invalidate_icache_region(ram_translation_cache,
3407 (ram_translation_ptr - ram_translation_cache) + 0x100);
3410 last_ram_translation_ptr = ram_translation_cache;
3412 ram_translation_ptr = ram_translation_cache;
3413 ram_block_tag_top = 0x0101;
3414 if(iwram_code_min != 0xFFFFFFFF)
3416 iwram_code_min &= 0x7FFF;
3417 iwram_code_max &= 0x7FFF;
3418 memset(iwram + iwram_code_min, 0, iwram_code_max - iwram_code_min);
3421 if(ewram_code_min != 0xFFFFFFFF)
3423 u32 ewram_code_min_page;
3424 u32 ewram_code_max_page;
3425 u32 ewram_code_min_offset;
3426 u32 ewram_code_max_offset;
3429 ewram_code_min &= 0x3FFFF;
3430 ewram_code_max &= 0x3FFFF;
3432 ewram_code_min_page = ewram_code_min >> 15;
3433 ewram_code_max_page = ewram_code_max >> 15;
3434 ewram_code_min_offset = ewram_code_min & 0x7FFF;
3435 ewram_code_max_offset = ewram_code_max & 0x7FFF;
3437 if(ewram_code_min_page == ewram_code_max_page)
3439 memset(ewram + (ewram_code_min_page * 0x10000) +
3440 ewram_code_min_offset, 0,
3441 ewram_code_max_offset - ewram_code_min_offset);
3445 for(i = ewram_code_min_page + 1; i < ewram_code_max_page; i++)
3447 memset(ewram + (i * 0x10000), 0, 0x8000);
3450 memset(ewram, 0, ewram_code_max_offset);
3454 iwram_code_min = 0xFFFFFFFF;
3455 iwram_code_max = 0xFFFFFFFF;
3456 ewram_code_min = 0xFFFFFFFF;
3457 ewram_code_max = 0xFFFFFFFF;
3460 void flush_translation_cache_rom()
3463 invalidate_icache_region(rom_translation_cache,
3464 rom_translation_ptr - rom_translation_cache + 0x100);
3467 last_rom_translation_ptr = rom_translation_cache;
3470 rom_translation_ptr = rom_translation_cache;
3471 memset(rom_branch_hash, 0, sizeof(rom_branch_hash));
3474 void flush_translation_cache_bios()
3477 invalidate_icache_region(bios_translation_cache,
3478 bios_translation_ptr - bios_translation_cache + 0x100);
3481 last_bios_translation_ptr = bios_translation_cache;
3484 bios_block_tag_top = 0x0101;
3485 bios_translation_ptr = bios_translation_cache;
3486 memset(bios_rom + 0x4000, 0, 0x4000);
3489 #define cache_dump_prefix ""
3491 void dump_translation_cache()
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);
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);
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);