summaryrefslogtreecommitdiff
path: root/cpu_threaded.c
diff options
context:
space:
mode:
authornotaz2009-05-21 18:48:31 +0300
committernotaz2009-05-21 18:48:31 +0300
commit2823a4c8196a02da86ee180cf55586d4e8c91a2f (patch)
tree7e9b3f35b55af9917b3a05dd32de14be9a8c3f3c /cpu_threaded.c
downloadpicogpsp-2823a4c8196a02da86ee180cf55586d4e8c91a2f.tar.gz
picogpsp-2823a4c8196a02da86ee180cf55586d4e8c91a2f.tar.bz2
picogpsp-2823a4c8196a02da86ee180cf55586d4e8c91a2f.zip
original source from gpsp09-2xb_src.tar.bz2
Diffstat (limited to 'cpu_threaded.c')
-rw-r--r--cpu_threaded.c3508
1 files changed, 3508 insertions, 0 deletions
diff --git a/cpu_threaded.c b/cpu_threaded.c
new file mode 100644
index 0000000..a753c17
--- /dev/null
+++ b/cpu_threaded.c
@@ -0,0 +1,3508 @@
+/* gameplaySP
+ *
+ * Copyright (C) 2006 Exophase <exophase@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+// Not-so-important todo:
+// - stm reglist writeback when base is in the list needs adjustment
+// - block memory needs psr swapping and user mode reg swapping
+
+#include <stdio.h>
+#include "common.h"
+
+u8 rom_translation_cache[ROM_TRANSLATION_CACHE_SIZE];
+u8 *rom_translation_ptr = rom_translation_cache;
+
+u8 ram_translation_cache[RAM_TRANSLATION_CACHE_SIZE];
+u8 *ram_translation_ptr = ram_translation_cache;
+u32 iwram_code_min = 0xFFFFFFFF;
+u32 iwram_code_max = 0xFFFFFFFF;
+u32 ewram_code_min = 0xFFFFFFFF;
+u32 ewram_code_max = 0xFFFFFFFF;
+
+u8 bios_translation_cache[BIOS_TRANSLATION_CACHE_SIZE];
+u8 *bios_translation_ptr = bios_translation_cache;
+
+u32 *rom_branch_hash[ROM_BRANCH_HASH_SIZE];
+
+// Default
+u32 idle_loop_target_pc = 0xFFFFFFFF;
+u32 force_pc_update_target = 0xFFFFFFFF;
+u32 translation_gate_target_pc[MAX_TRANSLATION_GATES];
+u32 translation_gate_targets = 0;
+u32 iwram_stack_optimize = 1;
+u32 allow_smc_ram_u8 = 1;
+u32 allow_smc_ram_u16 = 1;
+u32 allow_smc_ram_u32 = 1;
+
+typedef struct
+{
+ u8 *block_offset;
+ u16 flag_data;
+ u8 condition;
+ u8 update_cycles;
+} block_data_type;
+
+typedef struct
+{
+ u32 branch_target;
+ u8 *branch_source;
+} block_exit_type;
+
+extern u8 bit_count[256];
+
+#define arm_decode_data_proc_reg() \
+ u32 rn = (opcode >> 16) & 0x0F; \
+ u32 rd = (opcode >> 12) & 0x0F; \
+ u32 rm = opcode & 0x0F \
+
+#define arm_decode_data_proc_imm() \
+ u32 rn = (opcode >> 16) & 0x0F; \
+ u32 rd = (opcode >> 12) & 0x0F; \
+ u32 imm = opcode & 0xFF; \
+ u32 imm_ror = ((opcode >> 8) & 0x0F) * 2 \
+
+#define arm_decode_psr_reg() \
+ u32 psr_field = (opcode >> 16) & 0x0F; \
+ u32 rd = (opcode >> 12) & 0x0F; \
+ u32 rm = opcode & 0x0F \
+
+#define arm_decode_psr_imm() \
+ u32 psr_field = (opcode >> 16) & 0x0F; \
+ u32 rd = (opcode >> 12) & 0x0F; \
+ u32 imm = opcode & 0xFF; \
+ u32 imm_ror = ((opcode >> 8) & 0x0F) * 2 \
+
+#define arm_decode_branchx() \
+ u32 rn = opcode & 0x0F \
+
+#define arm_decode_multiply() \
+ u32 rd = (opcode >> 16) & 0x0F; \
+ u32 rn = (opcode >> 12) & 0x0F; \
+ u32 rs = (opcode >> 8) & 0x0F; \
+ u32 rm = opcode & 0x0F \
+
+#define arm_decode_multiply_long() \
+ u32 rdhi = (opcode >> 16) & 0x0F; \
+ u32 rdlo = (opcode >> 12) & 0x0F; \
+ u32 rs = (opcode >> 8) & 0x0F; \
+ u32 rm = opcode & 0x0F \
+
+#define arm_decode_swap() \
+ u32 rn = (opcode >> 16) & 0x0F; \
+ u32 rd = (opcode >> 12) & 0x0F; \
+ u32 rm = opcode & 0x0F \
+
+#define arm_decode_half_trans_r() \
+ u32 rn = (opcode >> 16) & 0x0F; \
+ u32 rd = (opcode >> 12) & 0x0F; \
+ u32 rm = opcode & 0x0F \
+
+#define arm_decode_half_trans_of() \
+ u32 rn = (opcode >> 16) & 0x0F; \
+ u32 rd = (opcode >> 12) & 0x0F; \
+ u32 offset = ((opcode >> 4) & 0xF0) | (opcode & 0x0F) \
+
+#define arm_decode_data_trans_imm() \
+ u32 rn = (opcode >> 16) & 0x0F; \
+ u32 rd = (opcode >> 12) & 0x0F; \
+ u32 offset = opcode & 0x0FFF \
+
+#define arm_decode_data_trans_reg() \
+ u32 rn = (opcode >> 16) & 0x0F; \
+ u32 rd = (opcode >> 12) & 0x0F; \
+ u32 rm = opcode & 0x0F \
+
+#define arm_decode_block_trans() \
+ u32 rn = (opcode >> 16) & 0x0F; \
+ u32 reg_list = opcode & 0xFFFF \
+
+#define arm_decode_branch() \
+ s32 offset = ((s32)(opcode & 0xFFFFFF) << 8) >> 6 \
+
+#define thumb_decode_shift() \
+ u32 imm = (opcode >> 6) & 0x1F; \
+ u32 rs = (opcode >> 3) & 0x07; \
+ u32 rd = opcode & 0x07 \
+
+#define thumb_decode_add_sub() \
+ u32 rn = (opcode >> 6) & 0x07; \
+ u32 rs = (opcode >> 3) & 0x07; \
+ u32 rd = opcode & 0x07 \
+
+#define thumb_decode_add_sub_imm() \
+ u32 imm = (opcode >> 6) & 0x07; \
+ u32 rs = (opcode >> 3) & 0x07; \
+ u32 rd = opcode & 0x07 \
+
+#define thumb_decode_imm() \
+ u32 imm = opcode & 0xFF \
+
+#define thumb_decode_alu_op() \
+ u32 rs = (opcode >> 3) & 0x07; \
+ u32 rd = opcode & 0x07 \
+
+#define thumb_decode_hireg_op() \
+ u32 rs = (opcode >> 3) & 0x0F; \
+ u32 rd = ((opcode >> 4) & 0x08) | (opcode & 0x07) \
+
+#define thumb_decode_mem_reg() \
+ u32 ro = (opcode >> 6) & 0x07; \
+ u32 rb = (opcode >> 3) & 0x07; \
+ u32 rd = opcode & 0x07 \
+
+#define thumb_decode_mem_imm() \
+ u32 imm = (opcode >> 6) & 0x1F; \
+ u32 rb = (opcode >> 3) & 0x07; \
+ u32 rd = opcode & 0x07 \
+
+#define thumb_decode_add_sp() \
+ u32 imm = opcode & 0x7F \
+
+#define thumb_decode_rlist() \
+ u32 reg_list = opcode & 0xFF \
+
+#define thumb_decode_branch_cond() \
+ s32 offset = (s8)(opcode & 0xFF) \
+
+#define thumb_decode_swi() \
+ u32 comment = opcode & 0xFF \
+
+#define thumb_decode_branch() \
+ u32 offset = opcode & 0x07FF \
+
+
+#ifdef PSP_BUILD
+
+#include "psp/mips_emit.h"
+
+#elif defined(GP2X_BUILD)
+
+#include "gp2x/arm_emit.h"
+
+#elif defined(GIZ_BUILD)
+
+#include "giz/arm_emit.h"
+
+#else
+
+#include "x86/x86_emit.h"
+
+#endif
+
+
+#define check_pc_region(pc) \
+ new_pc_region = (pc >> 15); \
+ if(new_pc_region != pc_region) \
+ { \
+ pc_region = new_pc_region; \
+ pc_address_block = memory_map_read[new_pc_region]; \
+ \
+ if(pc_address_block == NULL) \
+ pc_address_block = load_gamepak_page(pc_region & 0x3FF); \
+ } \
+
+#define translate_arm_instruction() \
+ check_pc_region(pc); \
+ opcode = address32(pc_address_block, (pc & 0x7FFF)); \
+ condition = block_data[block_data_position].condition; \
+ \
+ if((condition != last_condition) || (condition >= 0x20)) \
+ { \
+ if((last_condition & 0x0F) != 0x0E) \
+ { \
+ generate_branch_patch_conditional(backpatch_address, translation_ptr); \
+ } \
+ \
+ last_condition = condition; \
+ \
+ condition &= 0x0F; \
+ \
+ if(condition != 0x0E) \
+ { \
+ arm_conditional_block_header(); \
+ } \
+ } \
+ \
+ switch((opcode >> 20) & 0xFF) \
+ { \
+ case 0x00: \
+ if((opcode & 0x90) == 0x90) \
+ { \
+ if(opcode & 0x20) \
+ { \
+ /* STRH rd, [rn], -rm */ \
+ arm_access_memory(store, down, post, u16, half_reg); \
+ } \
+ else \
+ { \
+ /* MUL rd, rm, rs */ \
+ arm_multiply(no, no); \
+ } \
+ } \
+ else \
+ { \
+ /* AND rd, rn, reg_op */ \
+ arm_data_proc(and, reg, no_flags); \
+ } \
+ break; \
+ \
+ case 0x01: \
+ if((opcode & 0x90) == 0x90) \
+ { \
+ switch((opcode >> 5) & 0x03) \
+ { \
+ case 0: \
+ /* MULS rd, rm, rs */ \
+ arm_multiply(no, yes); \
+ break; \
+ \
+ case 1: \
+ /* LDRH rd, [rn], -rm */ \
+ arm_access_memory(load, down, post, u16, half_reg); \
+ break; \
+ \
+ case 2: \
+ /* LDRSB rd, [rn], -rm */ \
+ arm_access_memory(load, down, post, s8, half_reg); \
+ break; \
+ \
+ case 3: \
+ /* LDRSH rd, [rn], -rm */ \
+ arm_access_memory(load, down, post, s16, half_reg); \
+ break; \
+ } \
+ } \
+ else \
+ { \
+ /* ANDS rd, rn, reg_op */ \
+ arm_data_proc(ands, reg_flags, flags); \
+ } \
+ break; \
+ \
+ case 0x02: \
+ if((opcode & 0x90) == 0x90) \
+ { \
+ if(opcode & 0x20) \
+ { \
+ /* STRH rd, [rn], -rm */ \
+ arm_access_memory(store, down, post, u16, half_reg); \
+ } \
+ else \
+ { \
+ /* MLA rd, rm, rs, rn */ \
+ arm_multiply(yes, no); \
+ } \
+ } \
+ else \
+ { \
+ /* EOR rd, rn, reg_op */ \
+ arm_data_proc(eor, reg, no_flags); \
+ } \
+ break; \
+ \
+ case 0x03: \
+ if((opcode & 0x90) == 0x90) \
+ { \
+ switch((opcode >> 5) & 0x03) \
+ { \
+ case 0: \
+ /* MLAS rd, rm, rs, rn */ \
+ arm_multiply(yes, yes); \
+ break; \
+ \
+ case 1: \
+ /* LDRH rd, [rn], -rm */ \
+ arm_access_memory(load, down, post, u16, half_reg); \
+ break; \
+ \
+ case 2: \
+ /* LDRSB rd, [rn], -rm */ \
+ arm_access_memory(load, down, post, s8, half_reg); \
+ break; \
+ \
+ case 3: \
+ /* LDRSH rd, [rn], -rm */ \
+ arm_access_memory(load, down, post, s16, half_reg); \
+ break; \
+ } \
+ } \
+ else \
+ { \
+ /* EORS rd, rn, reg_op */ \
+ arm_data_proc(eors, reg_flags, flags); \
+ } \
+ break; \
+ \
+ case 0x04: \
+ if((opcode & 0x90) == 0x90) \
+ { \
+ /* STRH rd, [rn], -imm */ \
+ arm_access_memory(store, down, post, u16, half_imm); \
+ } \
+ else \
+ { \
+ /* SUB rd, rn, reg_op */ \
+ arm_data_proc(sub, reg, no_flags); \
+ } \
+ break; \
+ \
+ case 0x05: \
+ if((opcode & 0x90) == 0x90) \
+ { \
+ switch((opcode >> 5) & 0x03) \
+ { \
+ case 1: \
+ /* LDRH rd, [rn], -imm */ \
+ arm_access_memory(load, down, post, u16, half_imm); \
+ break; \
+ \
+ case 2: \
+ /* LDRSB rd, [rn], -imm */ \
+ arm_access_memory(load, down, post, s8, half_imm); \
+ break; \
+ \
+ case 3: \
+ /* LDRSH rd, [rn], -imm */ \
+ arm_access_memory(load, down, post, s16, half_imm); \
+ break; \
+ } \
+ } \
+ else \
+ { \
+ /* SUBS rd, rn, reg_op */ \
+ arm_data_proc(subs, reg, flags); \
+ } \
+ break; \
+ \
+ case 0x06: \
+ if((opcode & 0x90) == 0x90) \
+ { \
+ /* STRH rd, [rn], -imm */ \
+ arm_access_memory(store, down, post, u16, half_imm); \
+ } \
+ else \
+ { \
+ /* RSB rd, rn, reg_op */ \
+ arm_data_proc(rsb, reg, no_flags); \
+ } \
+ break; \
+ \
+ case 0x07: \
+ if((opcode & 0x90) == 0x90) \
+ { \
+ switch((opcode >> 5) & 0x03) \
+ { \
+ case 1: \
+ /* LDRH rd, [rn], -imm */ \
+ arm_access_memory(load, down, post, u16, half_imm); \
+ break; \
+ \
+ case 2: \
+ /* LDRSB rd, [rn], -imm */ \
+ arm_access_memory(load, down, post, s8, half_imm); \
+ break; \
+ \
+ case 3: \
+ /* LDRSH rd, [rn], -imm */ \
+ arm_access_memory(load, down, post, s16, half_imm); \
+ break; \
+ } \
+ } \
+ else \
+ { \
+ /* RSBS rd, rn, reg_op */ \
+ arm_data_proc(rsbs, reg, flags); \
+ } \
+ break; \
+ \
+ case 0x08: \
+ if((opcode & 0x90) == 0x90) \
+ { \
+ if(opcode & 0x20) \
+ { \
+ /* STRH rd, [rn], +rm */ \
+ arm_access_memory(store, up, post, u16, half_reg); \
+ } \
+ else \
+ { \
+ /* UMULL rd, rm, rs */ \
+ arm_multiply_long(u64, no, no); \
+ } \
+ } \
+ else \
+ { \
+ /* ADD rd, rn, reg_op */ \
+ arm_data_proc(add, reg, no_flags); \
+ } \
+ break; \
+ \
+ case 0x09: \
+ if((opcode & 0x90) == 0x90) \
+ { \
+ switch((opcode >> 5) & 0x03) \
+ { \
+ case 0: \
+ /* UMULLS rdlo, rdhi, rm, rs */ \
+ arm_multiply_long(u64, no, yes); \
+ break; \
+ \
+ case 1: \
+ /* LDRH rd, [rn], +rm */ \
+ arm_access_memory(load, up, post, u16, half_reg); \
+ break; \
+ \
+ case 2: \
+ /* LDRSB rd, [rn], +rm */ \
+ arm_access_memory(load, up, post, s8, half_reg); \
+ break; \
+ \
+ case 3: \
+ /* LDRSH rd, [rn], +rm */ \
+ arm_access_memory(load, up, post, s16, half_reg); \
+ break; \
+ } \
+ } \
+ else \
+ { \
+ /* ADDS rd, rn, reg_op */ \
+ arm_data_proc(adds, reg, flags); \
+ } \
+ break; \
+ \
+ case 0x0A: \
+ if((opcode & 0x90) == 0x90) \
+ { \
+ if(opcode & 0x20) \
+ { \
+ /* STRH rd, [rn], +rm */ \
+ arm_access_memory(store, up, post, u16, half_reg); \
+ } \
+ else \
+ { \
+ /* UMLAL rd, rm, rs */ \
+ arm_multiply_long(u64_add, yes, no); \
+ } \
+ } \
+ else \
+ { \
+ /* ADC rd, rn, reg_op */ \
+ arm_data_proc(adc, reg, no_flags); \
+ } \
+ break; \
+ \
+ case 0x0B: \
+ if((opcode & 0x90) == 0x90) \
+ { \
+ switch((opcode >> 5) & 0x03) \
+ { \
+ case 0: \
+ /* UMLALS rdlo, rdhi, rm, rs */ \
+ arm_multiply_long(u64_add, yes, yes); \
+ break; \
+ \
+ case 1: \
+ /* LDRH rd, [rn], +rm */ \
+ arm_access_memory(load, up, post, u16, half_reg); \
+ break; \
+ \
+ case 2: \
+ /* LDRSB rd, [rn], +rm */ \
+ arm_access_memory(load, up, post, s8, half_reg); \
+ break; \
+ \
+ case 3: \
+ /* LDRSH rd, [rn], +rm */ \
+ arm_access_memory(load, up, post, s16, half_reg); \
+ break; \
+ } \
+ } \
+ else \
+ { \
+ /* ADCS rd, rn, reg_op */ \
+ arm_data_proc(adcs, reg, flags); \
+ } \
+ break; \
+ \
+ case 0x0C: \
+ if((opcode & 0x90) == 0x90) \
+ { \
+ if(opcode & 0x20) \
+ { \
+ /* STRH rd, [rn], +imm */ \
+ arm_access_memory(store, up, post, u16, half_imm); \
+ } \
+ else \
+ { \
+ /* SMULL rd, rm, rs */ \
+ arm_multiply_long(s64, no, no); \
+ } \
+ } \
+ else \
+ { \
+ /* SBC rd, rn, reg_op */ \
+ arm_data_proc(sbc, reg, no_flags); \
+ } \
+ break; \
+ \
+ case 0x0D: \
+ if((opcode & 0x90) == 0x90) \
+ { \
+ switch((opcode >> 5) & 0x03) \
+ { \
+ case 0: \
+ /* SMULLS rdlo, rdhi, rm, rs */ \
+ arm_multiply_long(s64, no, yes); \
+ break; \
+ \
+ case 1: \
+ /* LDRH rd, [rn], +imm */ \
+ arm_access_memory(load, up, post, u16, half_imm); \
+ break; \
+ \
+ case 2: \
+ /* LDRSB rd, [rn], +imm */ \
+ arm_access_memory(load, up, post, s8, half_imm); \
+ break; \
+ \
+ case 3: \
+ /* LDRSH rd, [rn], +imm */ \
+ arm_access_memory(load, up, post, s16, half_imm); \
+ break; \
+ } \
+ } \
+ else \
+ { \
+ /* SBCS rd, rn, reg_op */ \
+ arm_data_proc(sbcs, reg, flags); \
+ } \
+ break; \
+ \
+ case 0x0E: \
+ if((opcode & 0x90) == 0x90) \
+ { \
+ if(opcode & 0x20) \
+ { \
+ /* STRH rd, [rn], +imm */ \
+ arm_access_memory(store, up, post, u16, half_imm); \
+ } \
+ else \
+ { \
+ /* SMLAL rd, rm, rs */ \
+ arm_multiply_long(s64_add, yes, no); \
+ } \
+ } \
+ else \
+ { \
+ /* RSC rd, rn, reg_op */ \
+ arm_data_proc(rsc, reg, no_flags); \
+ } \
+ break; \
+ \
+ case 0x0F: \
+ if((opcode & 0x90) == 0x90) \
+ { \
+ switch((opcode >> 5) & 0x03) \
+ { \
+ case 0: \
+ /* SMLALS rdlo, rdhi, rm, rs */ \
+ arm_multiply_long(s64_add, yes, yes); \
+ break; \
+ \
+ case 1: \
+ /* LDRH rd, [rn], +imm */ \
+ arm_access_memory(load, up, post, u16, half_imm); \
+ break; \
+ \
+ case 2: \
+ /* LDRSB rd, [rn], +imm */ \
+ arm_access_memory(load, up, post, s8, half_imm); \
+ break; \
+ \
+ case 3: \
+ /* LDRSH rd, [rn], +imm */ \
+ arm_access_memory(load, up, post, s16, half_imm); \
+ break; \
+ } \
+ } \
+ else \
+ { \
+ /* RSCS rd, rn, reg_op */ \
+ arm_data_proc(rscs, reg, flags); \
+ } \
+ break; \
+ \
+ case 0x10: \
+ if((opcode & 0x90) == 0x90) \
+ { \
+ if(opcode & 0x20) \
+ { \
+ /* STRH rd, [rn - rm] */ \
+ arm_access_memory(store, down, pre, u16, half_reg); \
+ } \
+ else \
+ { \
+ /* SWP rd, rm, [rn] */ \
+ arm_swap(u32); \
+ } \
+ } \
+ else \
+ { \
+ /* MRS rd, cpsr */ \
+ arm_psr(reg, read, cpsr); \
+ } \
+ break; \
+ \
+ case 0x11: \
+ if((opcode & 0x90) == 0x90) \
+ { \
+ switch((opcode >> 5) & 0x03) \
+ { \
+ case 1: \
+ /* LDRH rd, [rn - rm] */ \
+ arm_access_memory(load, down, pre, u16, half_reg); \
+ break; \
+ \
+ case 2: \
+ /* LDRSB rd, [rn - rm] */ \
+ arm_access_memory(load, down, pre, s8, half_reg); \
+ break; \
+ \
+ case 3: \
+ /* LDRSH rd, [rn - rm] */ \
+ arm_access_memory(load, down, pre, s16, half_reg); \
+ break; \
+ } \
+ } \
+ else \
+ { \
+ /* TST rd, rn, reg_op */ \
+ arm_data_proc_test(tst, reg_flags); \
+ } \
+ break; \
+ \
+ case 0x12: \
+ if((opcode & 0x90) == 0x90) \
+ { \
+ /* STRH rd, [rn - rm]! */ \
+ arm_access_memory(store, down, pre_wb, u16, half_reg); \
+ } \
+ else \
+ { \
+ if(opcode & 0x10) \
+ { \
+ /* BX rn */ \
+ arm_bx(); \
+ } \
+ else \
+ { \
+ /* MSR cpsr, rm */ \
+ arm_psr(reg, store, cpsr); \
+ } \
+ } \
+ break; \
+ \
+ case 0x13: \
+ if((opcode & 0x90) == 0x90) \
+ { \
+ switch((opcode >> 5) & 0x03) \
+ { \
+ case 1: \
+ /* LDRH rd, [rn - rm]! */ \
+ arm_access_memory(load, down, pre_wb, u16, half_reg); \
+ break; \
+ \
+ case 2: \
+ /* LDRSB rd, [rn - rm]! */ \
+ arm_access_memory(load, down, pre_wb, s8, half_reg); \
+ break; \
+ \
+ case 3: \
+ /* LDRSH rd, [rn - rm]! */ \
+ arm_access_memory(load, down, pre_wb, s16, half_reg); \
+ break; \
+ } \
+ } \
+ else \
+ { \
+ /* TEQ rd, rn, reg_op */ \
+ arm_data_proc_test(teq, reg_flags); \
+ } \
+ break; \
+ \
+ case 0x14: \
+ if((opcode & 0x90) == 0x90) \
+ { \
+ if(opcode & 0x20) \
+ { \
+ /* STRH rd, [rn - imm] */ \
+ arm_access_memory(store, down, pre, u16, half_imm); \
+ } \
+ else \
+ { \
+ /* SWPB rd, rm, [rn] */ \
+ arm_swap(u8); \
+ } \
+ } \
+ else \
+ { \
+ /* MRS rd, spsr */ \
+ arm_psr(reg, read, spsr); \
+ } \
+ break; \
+ \
+ case 0x15: \
+ if((opcode & 0x90) == 0x90) \
+ { \
+ switch((opcode >> 5) & 0x03) \
+ { \
+ case 1: \
+ /* LDRH rd, [rn - imm] */ \
+ arm_access_memory(load, down, pre, u16, half_imm); \
+ break; \
+ \
+ case 2: \
+ /* LDRSB rd, [rn - imm] */ \
+ arm_access_memory(load, down, pre, s8, half_imm); \
+ break; \
+ \
+ case 3: \
+ /* LDRSH rd, [rn - imm] */ \
+ arm_access_memory(load, down, pre, s16, half_imm); \
+ break; \
+ } \
+ } \
+ else \
+ { \
+ /* CMP rn, reg_op */ \
+ arm_data_proc_test(cmp, reg); \
+ } \
+ break; \
+ \
+ case 0x16: \
+ if((opcode & 0x90) == 0x90) \
+ { \
+ /* STRH rd, [rn - imm]! */ \
+ arm_access_memory(store, down, pre_wb, u16, half_imm); \
+ } \
+ else \
+ { \
+ /* MSR spsr, rm */ \
+ arm_psr(reg, store, spsr); \
+ } \
+ break; \
+ \
+ case 0x17: \
+ if((opcode & 0x90) == 0x90) \
+ { \
+ switch((opcode >> 5) & 0x03) \
+ { \
+ case 1: \
+ /* LDRH rd, [rn - imm]! */ \
+ arm_access_memory(load, down, pre_wb, u16, half_imm); \
+ break; \
+ \
+ case 2: \
+ /* LDRSB rd, [rn - imm]! */ \
+ arm_access_memory(load, down, pre_wb, s8, half_imm); \
+ break; \
+ \
+ case 3: \
+ /* LDRSH rd, [rn - imm]! */ \
+ arm_access_memory(load, down, pre_wb, s16, half_imm); \
+ break; \
+ } \
+ } \
+ else \
+ { \
+ /* CMN rd, rn, reg_op */ \
+ arm_data_proc_test(cmn, reg); \
+ } \
+ break; \
+ \
+ case 0x18: \
+ if((opcode & 0x90) == 0x90) \
+ { \
+ /* STRH rd, [rn + rm] */ \
+ arm_access_memory(store, up, pre, u16, half_reg); \
+ } \
+ else \
+ { \
+ /* ORR rd, rn, reg_op */ \
+ arm_data_proc(orr, reg, no_flags); \
+ } \
+ break; \
+ \
+ case 0x19: \
+ if((opcode & 0x90) == 0x90) \
+ { \
+ switch((opcode >> 5) & 0x03) \
+ { \
+ case 1: \
+ /* LDRH rd, [rn + rm] */ \
+ arm_access_memory(load, up, pre, u16, half_reg); \
+ break; \
+ \
+ case 2: \
+ /* LDRSB rd, [rn + rm] */ \
+ arm_access_memory(load, up, pre, s8, half_reg); \
+ break; \
+ \
+ case 3: \
+ /* LDRSH rd, [rn + rm] */ \
+ arm_access_memory(load, up, pre, s16, half_reg); \
+ break; \
+ } \
+ } \
+ else \
+ { \
+ /* ORRS rd, rn, reg_op */ \
+ arm_data_proc(orrs, reg_flags, flags); \
+ } \
+ break; \
+ \
+ case 0x1A: \
+ if((opcode & 0x90) == 0x90) \
+ { \
+ /* STRH rd, [rn + rm]! */ \
+ arm_access_memory(store, up, pre_wb, u16, half_reg); \
+ } \
+ else \
+ { \
+ /* MOV rd, reg_op */ \
+ arm_data_proc_unary(mov, reg, no_flags); \
+ } \
+ break; \
+ \
+ case 0x1B: \
+ if((opcode & 0x90) == 0x90) \
+ { \
+ switch((opcode >> 5) & 0x03) \
+ { \
+ case 1: \
+ /* LDRH rd, [rn + rm]! */ \
+ arm_access_memory(load, up, pre_wb, u16, half_reg); \
+ break; \
+ \
+ case 2: \
+ /* LDRSB rd, [rn + rm]! */ \
+ arm_access_memory(load, up, pre_wb, s8, half_reg); \
+ break; \
+ \
+ case 3: \
+ /* LDRSH rd, [rn + rm]! */ \
+ arm_access_memory(load, up, pre_wb, s16, half_reg); \
+ break; \
+ } \
+ } \
+ else \
+ { \
+ /* MOVS rd, reg_op */ \
+ arm_data_proc_unary(movs, reg_flags, flags); \
+ } \
+ break; \
+ \
+ case 0x1C: \
+ if((opcode & 0x90) == 0x90) \
+ { \
+ /* STRH rd, [rn + imm] */ \
+ arm_access_memory(store, up, pre, u16, half_imm); \
+ } \
+ else \
+ { \
+ /* BIC rd, rn, reg_op */ \
+ arm_data_proc(bic, reg, no_flags); \
+ } \
+ break; \
+ \
+ case 0x1D: \
+ if((opcode & 0x90) == 0x90) \
+ { \
+ switch((opcode >> 5) & 0x03) \
+ { \
+ case 1: \
+ /* LDRH rd, [rn + imm] */ \
+ arm_access_memory(load, up, pre, u16, half_imm); \
+ break; \
+ \
+ case 2: \
+ /* LDRSB rd, [rn + imm] */ \
+ arm_access_memory(load, up, pre, s8, half_imm); \
+ break; \
+ \
+ case 3: \
+ /* LDRSH rd, [rn + imm] */ \
+ arm_access_memory(load, up, pre, s16, half_imm); \
+ break; \
+ } \
+ } \
+ else \
+ { \
+ /* BICS rd, rn, reg_op */ \
+ arm_data_proc(bics, reg_flags, flags); \
+ } \
+ break; \
+ \
+ case 0x1E: \
+ if((opcode & 0x90) == 0x90) \
+ { \
+ /* STRH rd, [rn + imm]! */ \
+ arm_access_memory(store, up, pre_wb, u16, half_imm); \
+ } \
+ else \
+ { \
+ /* MVN rd, reg_op */ \
+ arm_data_proc_unary(mvn, reg, no_flags); \
+ } \
+ break; \
+ \
+ case 0x1F: \
+ if((opcode & 0x90) == 0x90) \
+ { \
+ switch((opcode >> 5) & 0x03) \
+ { \
+ case 1: \
+ /* LDRH rd, [rn + imm]! */ \
+ arm_access_memory(load, up, pre_wb, u16, half_imm); \
+ break; \
+ \
+ case 2: \
+ /* LDRSB rd, [rn + imm]! */ \
+ arm_access_memory(load, up, pre_wb, s8, half_imm); \
+ break; \
+ \
+ case 3: \
+ /* LDRSH rd, [rn + imm]! */ \
+ arm_access_memory(load, up, pre_wb, s16, half_imm); \
+ break; \
+ } \
+ } \
+ else \
+ { \
+ /* MVNS rd, rn, reg_op */ \
+ arm_data_proc_unary(mvns, reg_flags, flags); \
+ } \
+ break; \
+ \
+ case 0x20: \
+ /* AND rd, rn, imm */ \
+ arm_data_proc(and, imm, no_flags); \
+ break; \
+ \
+ case 0x21: \
+ /* ANDS rd, rn, imm */ \
+ arm_data_proc(ands, imm_flags, flags); \
+ break; \
+ \
+ case 0x22: \
+ /* EOR rd, rn, imm */ \
+ arm_data_proc(eor, imm, no_flags); \
+ break; \
+ \
+ case 0x23: \
+ /* EORS rd, rn, imm */ \
+ arm_data_proc(eors, imm_flags, flags); \
+ break; \
+ \
+ case 0x24: \
+ /* SUB rd, rn, imm */ \
+ arm_data_proc(sub, imm, no_flags); \
+ break; \
+ \
+ case 0x25: \
+ /* SUBS rd, rn, imm */ \
+ arm_data_proc(subs, imm, flags); \
+ break; \
+ \
+ case 0x26: \
+ /* RSB rd, rn, imm */ \
+ arm_data_proc(rsb, imm, no_flags); \
+ break; \
+ \
+ case 0x27: \
+ /* RSBS rd, rn, imm */ \
+ arm_data_proc(rsbs, imm, flags); \
+ break; \
+ \
+ case 0x28: \
+ /* ADD rd, rn, imm */ \
+ arm_data_proc(add, imm, no_flags); \
+ break; \
+ \
+ case 0x29: \
+ /* ADDS rd, rn, imm */ \
+ arm_data_proc(adds, imm, flags); \
+ break; \
+ \
+ case 0x2A: \
+ /* ADC rd, rn, imm */ \
+ arm_data_proc(adc, imm, no_flags); \
+ break; \
+ \
+ case 0x2B: \
+ /* ADCS rd, rn, imm */ \
+ arm_data_proc(adcs, imm, flags); \
+ break; \
+ \
+ case 0x2C: \
+ /* SBC rd, rn, imm */ \
+ arm_data_proc(sbc, imm, no_flags); \
+ break; \
+ \
+ case 0x2D: \
+ /* SBCS rd, rn, imm */ \
+ arm_data_proc(sbcs, imm, flags); \
+ break; \
+ \
+ case 0x2E: \
+ /* RSC rd, rn, imm */ \
+ arm_data_proc(rsc, imm, no_flags); \
+ break; \
+ \
+ case 0x2F: \
+ /* RSCS rd, rn, imm */ \
+ arm_data_proc(rscs, imm, flags); \
+ break; \
+ \
+ case 0x30 ... 0x31: \
+ /* TST rn, imm */ \
+ arm_data_proc_test(tst, imm); \
+ break; \
+ \
+ case 0x32: \
+ /* MSR cpsr, imm */ \
+ arm_psr(imm, store, cpsr); \
+ break; \
+ \
+ case 0x33: \
+ /* TEQ rn, imm */ \
+ arm_data_proc_test(teq, imm); \
+ break; \
+ \
+ case 0x34 ... 0x35: \
+ /* CMP rn, imm */ \
+ arm_data_proc_test(cmp, imm); \
+ break; \
+ \
+ case 0x36: \
+ /* MSR spsr, imm */ \
+ arm_psr(imm, store, spsr); \
+ break; \
+ \
+ case 0x37: \
+ /* CMN rn, imm */ \
+ arm_data_proc_test(cmn, imm); \
+ break; \
+ \
+ case 0x38: \
+ /* ORR rd, rn, imm */ \
+ arm_data_proc(orr, imm, no_flags); \
+ break; \
+ \
+ case 0x39: \
+ /* ORRS rd, rn, imm */ \
+ arm_data_proc(orrs, imm_flags, flags); \
+ break; \
+ \
+ case 0x3A: \
+ /* MOV rd, imm */ \
+ arm_data_proc_unary(mov, imm, no_flags); \
+ break; \
+ \
+ case 0x3B: \
+ /* MOVS rd, imm */ \
+ arm_data_proc_unary(movs, imm_flags, flags); \
+ break; \
+ \
+ case 0x3C: \
+ /* BIC rd, rn, imm */ \
+ arm_data_proc(bic, imm, no_flags); \
+ break; \
+ \
+ case 0x3D: \
+ /* BICS rd, rn, imm */ \
+ arm_data_proc(bics, imm_flags, flags); \
+ break; \
+ \
+ case 0x3E: \
+ /* MVN rd, imm */ \
+ arm_data_proc_unary(mvn, imm, no_flags); \
+ break; \
+ \
+ case 0x3F: \
+ /* MVNS rd, imm */ \
+ arm_data_proc_unary(mvns, imm_flags, flags); \
+ break; \
+ \
+ case 0x40: \
+ /* STR rd, [rn], -imm */ \
+ arm_access_memory(store, down, post, u32, imm); \
+ break; \
+ \
+ case 0x41: \
+ /* LDR rd, [rn], -imm */ \
+ arm_access_memory(load, down, post, u32, imm); \
+ break; \
+ \
+ case 0x42: \
+ /* STRT rd, [rn], -imm */ \
+ arm_access_memory(store, down, post, u32, imm); \
+ break; \
+ \
+ case 0x43: \
+ /* LDRT rd, [rn], -imm */ \
+ arm_access_memory(load, down, post, u32, imm); \
+ break; \
+ \
+ case 0x44: \
+ /* STRB rd, [rn], -imm */ \
+ arm_access_memory(store, down, post, u8, imm); \
+ break; \
+ \
+ case 0x45: \
+ /* LDRB rd, [rn], -imm */ \
+ arm_access_memory(load, down, post, u8, imm); \
+ break; \
+ \
+ case 0x46: \
+ /* STRBT rd, [rn], -imm */ \
+ arm_access_memory(store, down, post, u8, imm); \
+ break; \
+ \
+ case 0x47: \
+ /* LDRBT rd, [rn], -imm */ \
+ arm_access_memory(load, down, post, u8, imm); \
+ break; \
+ \
+ case 0x48: \
+ /* STR rd, [rn], +imm */ \
+ arm_access_memory(store, up, post, u32, imm); \
+ break; \
+ \
+ case 0x49: \
+ /* LDR rd, [rn], +imm */ \
+ arm_access_memory(load, up, post, u32, imm); \
+ break; \
+ \
+ case 0x4A: \
+ /* STRT rd, [rn], +imm */ \
+ arm_access_memory(store, up, post, u32, imm); \
+ break; \
+ \
+ case 0x4B: \
+ /* LDRT rd, [rn], +imm */ \
+ arm_access_memory(load, up, post, u32, imm); \
+ break; \
+ \
+ case 0x4C: \
+ /* STRB rd, [rn], +imm */ \
+ arm_access_memory(store, up, post, u8, imm); \
+ break; \
+ \
+ case 0x4D: \
+ /* LDRB rd, [rn], +imm */ \
+ arm_access_memory(load, up, post, u8, imm); \
+ break; \
+ \
+ case 0x4E: \
+ /* STRBT rd, [rn], +imm */ \
+ arm_access_memory(store, up, post, u8, imm); \
+ break; \
+ \
+ case 0x4F: \
+ /* LDRBT rd, [rn], +imm */ \
+ arm_access_memory(load, up, post, u8, imm); \
+ break; \
+ \
+ case 0x50: \
+ /* STR rd, [rn - imm] */ \
+ arm_access_memory(store, down, pre, u32, imm); \
+ break; \
+ \
+ case 0x51: \
+ /* LDR rd, [rn - imm] */ \
+ arm_access_memory(load, down, pre, u32, imm); \
+ break; \
+ \
+ case 0x52: \
+ /* STR rd, [rn - imm]! */ \
+ arm_access_memory(store, down, pre_wb, u32, imm); \
+ break; \
+ \
+ case 0x53: \
+ /* LDR rd, [rn - imm]! */ \
+ arm_access_memory(load, down, pre_wb, u32, imm); \
+ break; \
+ \
+ case 0x54: \
+ /* STRB rd, [rn - imm] */ \
+ arm_access_memory(store, down, pre, u8, imm); \
+ break; \
+ \
+ case 0x55: \
+ /* LDRB rd, [rn - imm] */ \
+ arm_access_memory(load, down, pre, u8, imm); \
+ break; \
+ \
+ case 0x56: \
+ /* STRB rd, [rn - imm]! */ \
+ arm_access_memory(store, down, pre_wb, u8, imm); \
+ break; \
+ \
+ case 0x57: \
+ /* LDRB rd, [rn - imm]! */ \
+ arm_access_memory(load, down, pre_wb, u8, imm); \
+ break; \
+ \
+ case 0x58: \
+ /* STR rd, [rn + imm] */ \
+ arm_access_memory(store, up, pre, u32, imm); \
+ break; \
+ \
+ case 0x59: \
+ /* LDR rd, [rn + imm] */ \
+ arm_access_memory(load, up, pre, u32, imm); \
+ break; \
+ \
+ case 0x5A: \
+ /* STR rd, [rn + imm]! */ \
+ arm_access_memory(store, up, pre_wb, u32, imm); \
+ break; \
+ \
+ case 0x5B: \
+ /* LDR rd, [rn + imm]! */ \
+ arm_access_memory(load, up, pre_wb, u32, imm); \
+ break; \
+ \
+ case 0x5C: \
+ /* STRB rd, [rn + imm] */ \
+ arm_access_memory(store, up, pre, u8, imm); \
+ break; \
+ \
+ case 0x5D: \
+ /* LDRB rd, [rn + imm] */ \
+ arm_access_memory(load, up, pre, u8, imm); \
+ break; \
+ \
+ case 0x5E: \
+ /* STRB rd, [rn + imm]! */ \
+ arm_access_memory(store, up, pre_wb, u8, imm); \
+ break; \
+ \
+ case 0x5F: \
+ /* LDRBT rd, [rn + imm]! */ \
+ arm_access_memory(load, up, pre_wb, u8, imm); \
+ break; \
+ \
+ case 0x60: \
+ /* STR rd, [rn], -rm */ \
+ arm_access_memory(store, down, post, u32, reg); \
+ break; \
+ \
+ case 0x61: \
+ /* LDR rd, [rn], -rm */ \
+ arm_access_memory(load, down, post, u32, reg); \
+ break; \
+ \
+ case 0x62: \
+ /* STRT rd, [rn], -rm */ \
+ arm_access_memory(store, down, post, u32, reg); \
+ break; \
+ \
+ case 0x63: \
+ /* LDRT rd, [rn], -rm */ \
+ arm_access_memory(load, down, post, u32, reg); \
+ break; \
+ \
+ case 0x64: \
+ /* STRB rd, [rn], -rm */ \
+ arm_access_memory(store, down, post, u8, reg); \
+ break; \
+ \
+ case 0x65: \
+ /* LDRB rd, [rn], -rm */ \
+ arm_access_memory(load, down, post, u8, reg); \
+ break; \
+ \
+ case 0x66: \
+ /* STRBT rd, [rn], -rm */ \
+ arm_access_memory(store, down, post, u8, reg); \
+ break; \
+ \
+ case 0x67: \
+ /* LDRBT rd, [rn], -rm */ \
+ arm_access_memory(load, down, post, u8, reg); \
+ break; \
+ \
+ case 0x68: \
+ /* STR rd, [rn], +rm */ \
+ arm_access_memory(store, up, post, u32, reg); \
+ break; \
+ \
+ case 0x69: \
+ /* LDR rd, [rn], +rm */ \
+ arm_access_memory(load, up, post, u32, reg); \
+ break; \
+ \
+ case 0x6A: \
+ /* STRT rd, [rn], +rm */ \
+ arm_access_memory(store, up, post, u32, reg); \
+ break; \
+ \
+ case 0x6B: \
+ /* LDRT rd, [rn], +rm */ \
+ arm_access_memory(load, up, post, u32, reg); \
+ break; \
+ \
+ case 0x6C: \
+ /* STRB rd, [rn], +rm */ \
+ arm_access_memory(store, up, post, u8, reg); \
+ break; \
+ \
+ case 0x6D: \
+ /* LDRB rd, [rn], +rm */ \
+ arm_access_memory(load, up, post, u8, reg); \
+ break; \
+ \
+ case 0x6E: \
+ /* STRBT rd, [rn], +rm */ \
+ arm_access_memory(store, up, post, u8, reg); \
+ break; \
+ \
+ case 0x6F: \
+ /* LDRBT rd, [rn], +rm */ \
+ arm_access_memory(load, up, post, u8, reg); \
+ break; \
+ \
+ case 0x70: \
+ /* STR rd, [rn - rm] */ \
+ arm_access_memory(store, down, pre, u32, reg); \
+ break; \
+ \
+ case 0x71: \
+ /* LDR rd, [rn - rm] */ \
+ arm_access_memory(load, down, pre, u32, reg); \
+ break; \
+ \
+ case 0x72: \
+ /* STR rd, [rn - rm]! */ \
+ arm_access_memory(store, down, pre_wb, u32, reg); \
+ break; \
+ \
+ case 0x73: \
+ /* LDR rd, [rn - rm]! */ \
+ arm_access_memory(load, down, pre_wb, u32, reg); \
+ break; \
+ \
+ case 0x74: \
+ /* STRB rd, [rn - rm] */ \
+ arm_access_memory(store, down, pre, u8, reg); \
+ break; \
+ \
+ case 0x75: \
+ /* LDRB rd, [rn - rm] */ \
+ arm_access_memory(load, down, pre, u8, reg); \
+ break; \
+ \
+ case 0x76: \
+ /* STRB rd, [rn - rm]! */ \
+ arm_access_memory(store, down, pre_wb, u8, reg); \
+ break; \
+ \
+ case 0x77: \
+ /* LDRB rd, [rn - rm]! */ \
+ arm_access_memory(load, down, pre_wb, u8, reg); \
+ break; \
+ \
+ case 0x78: \
+ /* STR rd, [rn + rm] */ \
+ arm_access_memory(store, up, pre, u32, reg); \
+ break; \
+ \
+ case 0x79: \
+ /* LDR rd, [rn + rm] */ \
+ arm_access_memory(load, up, pre, u32, reg); \
+ break; \
+ \
+ case 0x7A: \
+ /* STR rd, [rn + rm]! */ \
+ arm_access_memory(store, up, pre_wb, u32, reg); \
+ break; \
+ \
+ case 0x7B: \
+ /* LDR rd, [rn + rm]! */ \
+ arm_access_memory(load, up, pre_wb, u32, reg); \
+ break; \
+ \
+ case 0x7C: \
+ /* STRB rd, [rn + rm] */ \
+ arm_access_memory(store, up, pre, u8, reg); \
+ break; \
+ \
+ case 0x7D: \
+ /* LDRB rd, [rn + rm] */ \
+ arm_access_memory(load, up, pre, u8, reg); \
+ break; \
+ \
+ case 0x7E: \
+ /* STRB rd, [rn + rm]! */ \
+ arm_access_memory(store, up, pre_wb, u8, reg); \
+ break; \
+ \
+ case 0x7F: \
+ /* LDRBT rd, [rn + rm]! */ \
+ arm_access_memory(load, up, pre_wb, u8, reg); \
+ break; \
+ \
+ case 0x80: \
+ /* STMDA rn, rlist */ \
+ arm_block_memory(store, down_a, no, no); \
+ break; \
+ \
+ case 0x81: \
+ /* LDMDA rn, rlist */ \
+ arm_block_memory(load, down_a, no, no); \
+ break; \
+ \
+ case 0x82: \
+ /* STMDA rn!, rlist */ \
+ arm_block_memory(store, down_a, down, no); \
+ break; \
+ \
+ case 0x83: \
+ /* LDMDA rn!, rlist */ \
+ arm_block_memory(load, down_a, down, no); \
+ break; \
+ \
+ case 0x84: \
+ /* STMDA rn, rlist^ */ \
+ arm_block_memory(store, down_a, no, yes); \
+ break; \
+ \
+ case 0x85: \
+ /* LDMDA rn, rlist^ */ \
+ arm_block_memory(load, down_a, no, yes); \
+ break; \
+ \
+ case 0x86: \
+ /* STMDA rn!, rlist^ */ \
+ arm_block_memory(store, down_a, down, yes); \
+ break; \
+ \
+ case 0x87: \
+ /* LDMDA rn!, rlist^ */ \
+ arm_block_memory(load, down_a, down, yes); \
+ break; \
+ \
+ case 0x88: \
+ /* STMIA rn, rlist */ \
+ arm_block_memory(store, no, no, no); \
+ break; \
+ \
+ case 0x89: \
+ /* LDMIA rn, rlist */ \
+ arm_block_memory(load, no, no, no); \
+ break; \
+ \
+ case 0x8A: \
+ /* STMIA rn!, rlist */ \
+ arm_block_memory(store, no, up, no); \
+ break; \
+ \
+ case 0x8B: \
+ /* LDMIA rn!, rlist */ \
+ arm_block_memory(load, no, up, no); \
+ break; \
+ \
+ case 0x8C: \
+ /* STMIA rn, rlist^ */ \
+ arm_block_memory(store, no, no, yes); \
+ break; \
+ \
+ case 0x8D: \
+ /* LDMIA rn, rlist^ */ \
+ arm_block_memory(load, no, no, yes); \
+ break; \
+ \
+ case 0x8E: \
+ /* STMIA rn!, rlist^ */ \
+ arm_block_memory(store, no, up, yes); \
+ break; \
+ \
+ case 0x8F: \
+ /* LDMIA rn!, rlist^ */ \
+ arm_block_memory(load, no, up, yes); \
+ break; \
+ \
+ case 0x90: \
+ /* STMDB rn, rlist */ \
+ arm_block_memory(store, down_b, no, no); \
+ break; \
+ \
+ case 0x91: \
+ /* LDMDB rn, rlist */ \
+ arm_block_memory(load, down_b, no, no); \
+ break; \
+ \
+ case 0x92: \
+ /* STMDB rn!, rlist */ \
+ arm_block_memory(store, down_b, down, no); \
+ break; \
+ \
+ case 0x93: \
+ /* LDMDB rn!, rlist */ \
+ arm_block_memory(load, down_b, down, no); \
+ break; \
+ \
+ case 0x94: \
+ /* STMDB rn, rlist^ */ \
+ arm_block_memory(store, down_b, no, yes); \
+ break; \
+ \
+ case 0x95: \
+ /* LDMDB rn, rlist^ */ \
+ arm_block_memory(load, down_b, no, yes); \
+ break; \
+ \
+ case 0x96: \
+ /* STMDB rn!, rlist^ */ \
+ arm_block_memory(store, down_b, down, yes); \
+ break; \
+ \
+ case 0x97: \
+ /* LDMDB rn!, rlist^ */ \
+ arm_block_memory(load, down_b, down, yes); \
+ break; \
+ \
+ case 0x98: \
+ /* STMIB rn, rlist */ \
+ arm_block_memory(store, up, no, no); \
+ break; \
+ \
+ case 0x99: \
+ /* LDMIB rn, rlist */ \
+ arm_block_memory(load, up, no, no); \
+ break; \
+ \
+ case 0x9A: \
+ /* STMIB rn!, rlist */ \
+ arm_block_memory(store, up, up, no); \
+ break; \
+ \
+ case 0x9B: \
+ /* LDMIB rn!, rlist */ \
+ arm_block_memory(load, up, up, no); \
+ break; \
+ \
+ case 0x9C: \
+ /* STMIB rn, rlist^ */ \
+ arm_block_memory(store, up, no, yes); \
+ break; \
+ \
+ case 0x9D: \
+ /* LDMIB rn, rlist^ */ \
+ arm_block_memory(load, up, no, yes); \
+ break; \
+ \
+ case 0x9E: \
+ /* STMIB rn!, rlist^ */ \
+ arm_block_memory(store, up, up, yes); \
+ break; \
+ \
+ case 0x9F: \
+ /* LDMIB rn!, rlist^ */ \
+ arm_block_memory(load, up, up, yes); \
+ break; \
+ \
+ case 0xA0 ... 0xAF: \
+ { \
+ /* B offset */ \
+ arm_b(); \
+ break; \
+ } \
+ \
+ case 0xB0 ... 0xBF: \
+ { \
+ /* BL offset */ \
+ arm_bl(); \
+ break; \
+ } \
+ \
+ case 0xC0 ... 0xEF: \
+ /* coprocessor instructions, reserved on GBA */ \
+ break; \
+ \
+ case 0xF0 ... 0xFF: \
+ { \
+ /* SWI comment */ \
+ arm_swi(); \
+ break; \
+ } \
+ } \
+ \
+ pc += 4 \
+
+#define arm_flag_status() \
+
+#define translate_thumb_instruction() \
+ flag_status = block_data[block_data_position].flag_data; \
+ check_pc_region(pc); \
+ last_opcode = opcode; \
+ opcode = address16(pc_address_block, (pc & 0x7FFF)); \
+ \
+ switch((opcode >> 8) & 0xFF) \
+ { \
+ case 0x00 ... 0x07: \
+ /* LSL rd, rs, imm */ \
+ thumb_shift(shift, lsl, imm); \
+ break; \
+ \
+ case 0x08 ... 0x0F: \
+ /* LSR rd, rs, imm */ \
+ thumb_shift(shift, lsr, imm); \
+ break; \
+ \
+ case 0x10 ... 0x17: \
+ /* ASR rd, rs, imm */ \
+ thumb_shift(shift, asr, imm); \
+ break; \
+ \
+ case 0x18 ... 0x19: \
+ /* ADD rd, rs, rn */ \
+ thumb_data_proc(add_sub, adds, reg, rd, rs, rn); \
+ break; \
+ \
+ case 0x1A ... 0x1B: \
+ /* SUB rd, rs, rn */ \
+ thumb_data_proc(add_sub, subs, reg, rd, rs, rn); \
+ break; \
+ \
+ case 0x1C ... 0x1D: \
+ /* ADD rd, rs, imm */ \
+ thumb_data_proc(add_sub_imm, adds, imm, rd, rs, imm); \
+ break; \
+ \
+ case 0x1E ... 0x1F: \
+ /* SUB rd, rs, imm */ \
+ thumb_data_proc(add_sub_imm, subs, imm, rd, rs, imm); \
+ break; \
+ \
+ case 0x20: \
+ /* MOV r0, imm */ \
+ thumb_data_proc_unary(imm, movs, imm, 0, imm); \
+ break; \
+ \
+ case 0x21: \
+ /* MOV r1, imm */ \
+ thumb_data_proc_unary(imm, movs, imm, 1, imm); \
+ break; \
+ \
+ case 0x22: \
+ /* MOV r2, imm */ \
+ thumb_data_proc_unary(imm, movs, imm, 2, imm); \
+ break; \
+ \
+ case 0x23: \
+ /* MOV r3, imm */ \
+ thumb_data_proc_unary(imm, movs, imm, 3, imm); \
+ break; \
+ \
+ case 0x24: \
+ /* MOV r4, imm */ \
+ thumb_data_proc_unary(imm, movs, imm, 4, imm); \
+ break; \
+ \
+ case 0x25: \
+ /* MOV r5, imm */ \
+ thumb_data_proc_unary(imm, movs, imm, 5, imm); \
+ break; \
+ \
+ case 0x26: \
+ /* MOV r6, imm */ \
+ thumb_data_proc_unary(imm, movs, imm, 6, imm); \
+ break; \
+ \
+ case 0x27: \
+ /* MOV r7, imm */ \
+ thumb_data_proc_unary(imm, movs, imm, 7, imm); \
+ break; \
+ \
+ case 0x28: \
+ /* CMP r0, imm */ \
+ thumb_data_proc_test(imm, cmp, imm, 0, imm); \
+ break; \
+ \
+ case 0x29: \
+ /* CMP r1, imm */ \
+ thumb_data_proc_test(imm, cmp, imm, 1, imm); \
+ break; \
+ \
+ case 0x2A: \
+ /* CMP r2, imm */ \
+ thumb_data_proc_test(imm, cmp, imm, 2, imm); \
+ break; \
+ \
+ case 0x2B: \
+ /* CMP r3, imm */ \
+ thumb_data_proc_test(imm, cmp, imm, 3, imm); \
+ break; \
+ \
+ case 0x2C: \
+ /* CMP r4, imm */ \
+ thumb_data_proc_test(imm, cmp, imm, 4, imm); \
+ break; \
+ \
+ case 0x2D: \
+ /* CMP r5, imm */ \
+ thumb_data_proc_test(imm, cmp, imm, 5, imm); \
+ break; \
+ \
+ case 0x2E: \
+ /* CMP r6, imm */ \
+ thumb_data_proc_test(imm, cmp, imm, 6, imm); \
+ break; \
+ \
+ case 0x2F: \
+ /* CMP r7, imm */ \
+ thumb_data_proc_test(imm, cmp, imm, 7, imm); \
+ break; \
+ \
+ case 0x30: \
+ /* ADD r0, imm */ \
+ thumb_data_proc(imm, adds, imm, 0, 0, imm); \
+ break; \
+ \
+ case 0x31: \
+ /* ADD r1, imm */ \
+ thumb_data_proc(imm, adds, imm, 1, 1, imm); \
+ break; \
+ \
+ case 0x32: \
+ /* ADD r2, imm */ \
+ thumb_data_proc(imm, adds, imm, 2, 2, imm); \
+ break; \
+ \
+ case 0x33: \
+ /* ADD r3, imm */ \
+ thumb_data_proc(imm, adds, imm, 3, 3, imm); \
+ break; \
+ \
+ case 0x34: \
+ /* ADD r4, imm */ \
+ thumb_data_proc(imm, adds, imm, 4, 4, imm); \
+ break; \
+ \
+ case 0x35: \
+ /* ADD r5, imm */ \
+ thumb_data_proc(imm, adds, imm, 5, 5, imm); \
+ break; \
+ \
+ case 0x36: \
+ /* ADD r6, imm */ \
+ thumb_data_proc(imm, adds, imm, 6, 6, imm); \
+ break; \
+ \
+ case 0x37: \
+ /* ADD r7, imm */ \
+ thumb_data_proc(imm, adds, imm, 7, 7, imm); \
+ break; \
+ \
+ case 0x38: \
+ /* SUB r0, imm */ \
+ thumb_data_proc(imm, subs, imm, 0, 0, imm); \
+ break; \
+ \
+ case 0x39: \
+ /* SUB r1, imm */ \
+ thumb_data_proc(imm, subs, imm, 1, 1, imm); \
+ break; \
+ \
+ case 0x3A: \
+ /* SUB r2, imm */ \
+ thumb_data_proc(imm, subs, imm, 2, 2, imm); \
+ break; \
+ \
+ case 0x3B: \
+ /* SUB r3, imm */ \
+ thumb_data_proc(imm, subs, imm, 3, 3, imm); \
+ break; \
+ \
+ case 0x3C: \
+ /* SUB r4, imm */ \
+ thumb_data_proc(imm, subs, imm, 4, 4, imm); \
+ break; \
+ \
+ case 0x3D: \
+ /* SUB r5, imm */ \
+ thumb_data_proc(imm, subs, imm, 5, 5, imm); \
+ break; \
+ \
+ case 0x3E: \
+ /* SUB r6, imm */ \
+ thumb_data_proc(imm, subs, imm, 6, 6, imm); \
+ break; \
+ \
+ case 0x3F: \
+ /* SUB r7, imm */ \
+ thumb_data_proc(imm, subs, imm, 7, 7, imm); \
+ break; \
+ \
+ case 0x40: \
+ switch((opcode >> 6) & 0x03) \
+ { \
+ case 0x00: \
+ /* AND rd, rs */ \
+ thumb_data_proc(alu_op, ands, reg, rd, rd, rs); \
+ break; \
+ \
+ case 0x01: \
+ /* EOR rd, rs */ \
+ thumb_data_proc(alu_op, eors, reg, rd, rd, rs); \
+ break; \
+ \
+ case 0x02: \
+ /* LSL rd, rs */ \
+ thumb_shift(alu_op, lsl, reg); \
+ break; \
+ \
+ case 0x03: \
+ /* LSR rd, rs */ \
+ thumb_shift(alu_op, lsr, reg); \
+ break; \
+ } \
+ break; \
+ \
+ case 0x41: \
+ switch((opcode >> 6) & 0x03) \
+ { \
+ case 0x00: \
+ /* ASR rd, rs */ \
+ thumb_shift(alu_op, asr, reg); \
+ break; \
+ \
+ case 0x01: \
+ /* ADC rd, rs */ \
+ thumb_data_proc(alu_op, adcs, reg, rd, rd, rs); \
+ break; \
+ \
+ case 0x02: \
+ /* SBC rd, rs */ \
+ thumb_data_proc(alu_op, sbcs, reg, rd, rd, rs); \
+ break; \
+ \
+ case 0x03: \
+ /* ROR rd, rs */ \
+ thumb_shift(alu_op, ror, reg); \
+ break; \
+ } \
+ break; \
+ \
+ case 0x42: \
+ switch((opcode >> 6) & 0x03) \
+ { \
+ case 0x00: \
+ /* TST rd, rs */ \
+ thumb_data_proc_test(alu_op, tst, reg, rd, rs); \
+ break; \
+ \
+ case 0x01: \
+ /* NEG rd, rs */ \
+ thumb_data_proc_unary(alu_op, neg, reg, rd, rs); \
+ break; \
+ \
+ case 0x02: \
+ /* CMP rd, rs */ \
+ thumb_data_proc_test(alu_op, cmp, reg, rd, rs); \
+ break; \
+ \
+ case 0x03: \
+ /* CMN rd, rs */ \
+ thumb_data_proc_test(alu_op, cmn, reg, rd, rs); \
+ break; \
+ } \
+ break; \
+ \
+ case 0x43: \
+ switch((opcode >> 6) & 0x03) \
+ { \
+ case 0x00: \
+ /* ORR rd, rs */ \
+ thumb_data_proc(alu_op, orrs, reg, rd, rd, rs); \
+ break; \
+ \
+ case 0x01: \
+ /* MUL rd, rs */ \
+ thumb_data_proc(alu_op, muls, reg, rd, rd, rs); \
+ break; \
+ \
+ case 0x02: \
+ /* BIC rd, rs */ \
+ thumb_data_proc(alu_op, bics, reg, rd, rd, rs); \
+ break; \
+ \
+ case 0x03: \
+ /* MVN rd, rs */ \
+ thumb_data_proc_unary(alu_op, mvns, reg, rd, rs); \
+ break; \
+ } \
+ break; \
+ \
+ case 0x44: \
+ /* ADD rd, rs */ \
+ thumb_data_proc_hi(add); \
+ break; \
+ \
+ case 0x45: \
+ /* CMP rd, rs */ \
+ thumb_data_proc_test_hi(cmp); \
+ break; \
+ \
+ case 0x46: \
+ /* MOV rd, rs */ \
+ thumb_data_proc_mov_hi(); \
+ break; \
+ \
+ case 0x47: \
+ /* BX rs */ \
+ thumb_bx(); \
+ break; \
+ \
+ case 0x48: \
+ /* LDR r0, [pc + imm] */ \
+ thumb_access_memory(load, imm, 0, 0, 0, pc_relative, \
+ (pc & ~2) + (imm * 4) + 4, u32); \
+ break; \
+ \
+ case 0x49: \
+ /* LDR r1, [pc + imm] */ \
+ thumb_access_memory(load, imm, 1, 0, 0, pc_relative, \
+ (pc & ~2) + (imm * 4) + 4, u32); \
+ break; \
+ \
+ case 0x4A: \
+ /* LDR r2, [pc + imm] */ \
+ thumb_access_memory(load, imm, 2, 0, 0, pc_relative, \
+ (pc & ~2) + (imm * 4) + 4, u32); \
+ break; \
+ \
+ case 0x4B: \
+ /* LDR r3, [pc + imm] */ \
+ thumb_access_memory(load, imm, 3, 0, 0, pc_relative, \
+ (pc & ~2) + (imm * 4) + 4, u32); \
+ break; \
+ \
+ case 0x4C: \
+ /* LDR r4, [pc + imm] */ \
+ thumb_access_memory(load, imm, 4, 0, 0, pc_relative, \
+ (pc & ~2) + (imm * 4) + 4, u32); \
+ break; \
+ \
+ case 0x4D: \
+ /* LDR r5, [pc + imm] */ \
+ thumb_access_memory(load, imm, 5, 0, 0, pc_relative, \
+ (pc & ~2) + (imm * 4) + 4, u32); \
+ break; \
+ \
+ case 0x4E: \
+ /* LDR r6, [pc + imm] */ \
+ thumb_access_memory(load, imm, 6, 0, 0, pc_relative, \
+ (pc & ~2) + (imm * 4) + 4, u32); \
+ break; \
+ \
+ case 0x4F: \
+ /* LDR r7, [pc + imm] */ \
+ thumb_access_memory(load, imm, 7, 0, 0, pc_relative, \
+ (pc & ~2) + (imm * 4) + 4, u32); \
+ break; \
+ \
+ case 0x50 ... 0x51: \
+ /* STR rd, [rb + ro] */ \
+ thumb_access_memory(store, mem_reg, rd, rb, ro, reg_reg, 0, u32); \
+ break; \
+ \
+ case 0x52 ... 0x53: \
+ /* STRH rd, [rb + ro] */ \
+ thumb_access_memory(store, mem_reg, rd, rb, ro, reg_reg, 0, u16); \
+ break; \
+ \
+ case 0x54 ... 0x55: \
+ /* STRB rd, [rb + ro] */ \
+ thumb_access_memory(store, mem_reg, rd, rb, ro, reg_reg, 0, u8); \
+ break; \
+ \
+ case 0x56 ... 0x57: \
+ /* LDSB rd, [rb + ro] */ \
+ thumb_access_memory(load, mem_reg, rd, rb, ro, reg_reg, 0, s8); \
+ break; \
+ \
+ case 0x58 ... 0x59: \
+ /* LDR rd, [rb + ro] */ \
+ thumb_access_memory(load, mem_reg, rd, rb, ro, reg_reg, 0, u32); \
+ break; \
+ \
+ case 0x5A ... 0x5B: \
+ /* LDRH rd, [rb + ro] */ \
+ thumb_access_memory(load, mem_reg, rd, rb, ro, reg_reg, 0, u16); \
+ break; \
+ \
+ case 0x5C ... 0x5D: \
+ /* LDRB rd, [rb + ro] */ \
+ thumb_access_memory(load, mem_reg, rd, rb, ro, reg_reg, 0, u8); \
+ break; \
+ \
+ case 0x5E ... 0x5F: \
+ /* LDSH rd, [rb + ro] */ \
+ thumb_access_memory(load, mem_reg, rd, rb, ro, reg_reg, 0, s16); \
+ break; \
+ \
+ case 0x60 ... 0x67: \
+ /* STR rd, [rb + imm] */ \
+ thumb_access_memory(store, mem_imm, rd, rb, 0, reg_imm, (imm * 4), \
+ u32); \
+ break; \
+ \
+ case 0x68 ... 0x6F: \
+ /* LDR rd, [rb + imm] */ \
+ thumb_access_memory(load, mem_imm, rd, rb, 0, reg_imm, (imm * 4), u32); \
+ break; \
+ \
+ case 0x70 ... 0x77: \
+ /* STRB rd, [rb + imm] */ \
+ thumb_access_memory(store, mem_imm, rd, rb, 0, reg_imm, imm, u8); \
+ break; \
+ \
+ case 0x78 ... 0x7F: \
+ /* LDRB rd, [rb + imm] */ \
+ thumb_access_memory(load, mem_imm, rd, rb, 0, reg_imm, imm, u8); \
+ break; \
+ \
+ case 0x80 ... 0x87: \
+ /* STRH rd, [rb + imm] */ \
+ thumb_access_memory(store, mem_imm, rd, rb, 0, reg_imm, \
+ (imm * 2), u16); \
+ break; \
+ \
+ case 0x88 ... 0x8F: \
+ /* LDRH rd, [rb + imm] */ \
+ thumb_access_memory(load, mem_imm, rd, rb, 0, reg_imm, (imm * 2), u16); \
+ break; \
+ \
+ case 0x90: \
+ /* STR r0, [sp + imm] */ \
+ thumb_access_memory(store, imm, 0, 13, 0, reg_imm_sp, imm, u32); \
+ break; \
+ \
+ case 0x91: \
+ /* STR r1, [sp + imm] */ \
+ thumb_access_memory(store, imm, 1, 13, 0, reg_imm_sp, imm, u32); \
+ break; \
+ \
+ case 0x92: \
+ /* STR r2, [sp + imm] */ \
+ thumb_access_memory(store, imm, 2, 13, 0, reg_imm_sp, imm, u32); \
+ break; \
+ \
+ case 0x93: \
+ /* STR r3, [sp + imm] */ \
+ thumb_access_memory(store, imm, 3, 13, 0, reg_imm_sp, imm, u32); \
+ break; \
+ \
+ case 0x94: \
+ /* STR r4, [sp + imm] */ \
+ thumb_access_memory(store, imm, 4, 13, 0, reg_imm_sp, imm, u32); \
+ break; \
+ \
+ case 0x95: \
+ /* STR r5, [sp + imm] */ \
+ thumb_access_memory(store, imm, 5, 13, 0, reg_imm_sp, imm, u32); \
+ break; \
+ \
+ case 0x96: \
+ /* STR r6, [sp + imm] */ \
+ thumb_access_memory(store, imm, 6, 13, 0, reg_imm_sp, imm, u32); \
+ break; \
+ \
+ case 0x97: \
+ /* STR r7, [sp + imm] */ \
+ thumb_access_memory(store, imm, 7, 13, 0, reg_imm_sp, imm, u32); \
+ break; \
+ \
+ case 0x98: \
+ /* LDR r0, [sp + imm] */ \
+ thumb_access_memory(load, imm, 0, 13, 0, reg_imm_sp, imm, u32); \
+ break; \
+ \
+ case 0x99: \
+ /* LDR r1, [sp + imm] */ \
+ thumb_access_memory(load, imm, 1, 13, 0, reg_imm_sp, imm, u32); \
+ break; \
+ \
+ case 0x9A: \
+ /* LDR r2, [sp + imm] */ \
+ thumb_access_memory(load, imm, 2, 13, 0, reg_imm_sp, imm, u32); \
+ break; \
+ \
+ case 0x9B: \
+ /* LDR r3, [sp + imm] */ \
+ thumb_access_memory(load, imm, 3, 13, 0, reg_imm_sp, imm, u32); \
+ break; \
+ \
+ case 0x9C: \
+ /* LDR r4, [sp + imm] */ \
+ thumb_access_memory(load, imm, 4, 13, 0, reg_imm_sp, imm, u32); \
+ break; \
+ \
+ case 0x9D: \
+ /* LDR r5, [sp + imm] */ \
+ thumb_access_memory(load, imm, 5, 13, 0, reg_imm_sp, imm, u32); \
+ break; \
+ \
+ case 0x9E: \
+ /* LDR r6, [sp + imm] */ \
+ thumb_access_memory(load, imm, 6, 13, 0, reg_imm_sp, imm, u32); \
+ break; \
+ \
+ case 0x9F: \
+ /* LDR r7, [sp + imm] */ \
+ thumb_access_memory(load, imm, 7, 13, 0, reg_imm_sp, imm, u32); \
+ break; \
+ \
+ case 0xA0: \
+ /* ADD r0, pc, +imm */ \
+ thumb_load_pc(0); \
+ break; \
+ \
+ case 0xA1: \
+ /* ADD r1, pc, +imm */ \
+ thumb_load_pc(1); \
+ break; \
+ \
+ case 0xA2: \
+ /* ADD r2, pc, +imm */ \
+ thumb_load_pc(2); \
+ break; \
+ \
+ case 0xA3: \
+ /* ADD r3, pc, +imm */ \
+ thumb_load_pc(3); \
+ break; \
+ \
+ case 0xA4: \
+ /* ADD r4, pc, +imm */ \
+ thumb_load_pc(4); \
+ break; \
+ \
+ case 0xA5: \
+ /* ADD r5, pc, +imm */ \
+ thumb_load_pc(5); \
+ break; \
+ \
+ case 0xA6: \
+ /* ADD r6, pc, +imm */ \
+ thumb_load_pc(6); \
+ break; \
+ \
+ case 0xA7: \
+ /* ADD r7, pc, +imm */ \
+ thumb_load_pc(7); \
+ break; \
+ \
+ case 0xA8: \
+ /* ADD r0, sp, +imm */ \
+ thumb_load_sp(0); \
+ break; \
+ \
+ case 0xA9: \
+ /* ADD r1, sp, +imm */ \
+ thumb_load_sp(1); \
+ break; \
+ \
+ case 0xAA: \
+ /* ADD r2, sp, +imm */ \
+ thumb_load_sp(2); \
+ break; \
+ \
+ case 0xAB: \
+ /* ADD r3, sp, +imm */ \
+ thumb_load_sp(3); \
+ break; \
+ \
+ case 0xAC: \
+ /* ADD r4, sp, +imm */ \
+ thumb_load_sp(4); \
+ break; \
+ \
+ case 0xAD: \
+ /* ADD r5, sp, +imm */ \
+ thumb_load_sp(5); \
+ break; \
+ \
+ case 0xAE: \
+ /* ADD r6, sp, +imm */ \
+ thumb_load_sp(6); \
+ break; \
+ \
+ case 0xAF: \
+ /* ADD r7, sp, +imm */ \
+ thumb_load_sp(7); \
+ break; \
+ \
+ case 0xB0 ... 0xB3: \
+ if((opcode >> 7) & 0x01) \
+ { \
+ /* ADD sp, -imm */ \
+ thumb_adjust_sp(down); \
+ } \
+ else \
+ { \
+ /* ADD sp, +imm */ \
+ thumb_adjust_sp(up); \
+ } \
+ break; \
+ \
+ case 0xB4: \
+ /* PUSH rlist */ \
+ thumb_block_memory(store, down, no, 13); \
+ break; \
+ \
+ case 0xB5: \
+ /* PUSH rlist, lr */ \
+ thumb_block_memory(store, push_lr, push_lr, 13); \
+ break; \
+ \
+ case 0xBC: \
+ /* POP rlist */ \
+ thumb_block_memory(load, no, up, 13); \
+ break; \
+ \
+ case 0xBD: \
+ /* POP rlist, pc */ \
+ thumb_block_memory(load, no, pop_pc, 13); \
+ break; \
+ \
+ case 0xC0: \
+ /* STMIA r0!, rlist */ \
+ thumb_block_memory(store, no, up, 0); \
+ break; \
+ \
+ case 0xC1: \
+ /* STMIA r1!, rlist */ \
+ thumb_block_memory(store, no, up, 1); \
+ break; \
+ \
+ case 0xC2: \
+ /* STMIA r2!, rlist */ \
+ thumb_block_memory(store, no, up, 2); \
+ break; \
+ \
+ case 0xC3: \
+ /* STMIA r3!, rlist */ \
+ thumb_block_memory(store, no, up, 3); \
+ break; \
+ \
+ case 0xC4: \
+ /* STMIA r4!, rlist */ \
+ thumb_block_memory(store, no, up, 4); \
+ break; \
+ \
+ case 0xC5: \
+ /* STMIA r5!, rlist */ \
+ thumb_block_memory(store, no, up, 5); \
+ break; \
+ \
+ case 0xC6: \
+ /* STMIA r6!, rlist */ \
+ thumb_block_memory(store, no, up, 6); \
+ break; \
+ \
+ case 0xC7: \
+ /* STMIA r7!, rlist */ \
+ thumb_block_memory(store, no, up, 7); \
+ break; \
+ \
+ case 0xC8: \
+ /* LDMIA r0!, rlist */ \
+ thumb_block_memory(load, no, up, 0); \
+ break; \
+ \
+ case 0xC9: \
+ /* LDMIA r1!, rlist */ \
+ thumb_block_memory(load, no, up, 1); \
+ break; \
+ \
+ case 0xCA: \
+ /* LDMIA r2!, rlist */ \
+ thumb_block_memory(load, no, up, 2); \
+ break; \
+ \
+ case 0xCB: \
+ /* LDMIA r3!, rlist */ \
+ thumb_block_memory(load, no, up, 3); \
+ break; \
+ \
+ case 0xCC: \
+ /* LDMIA r4!, rlist */ \
+ thumb_block_memory(load, no, up, 4); \
+ break; \
+ \
+ case 0xCD: \
+ /* LDMIA r5!, rlist */ \
+ thumb_block_memory(load, no, up, 5); \
+ break; \
+ \
+ case 0xCE: \
+ /* LDMIA r6!, rlist */ \
+ thumb_block_memory(load, no, up, 6); \
+ break; \
+ \
+ case 0xCF: \
+ /* LDMIA r7!, rlist */ \
+ thumb_block_memory(load, no, up, 7); \
+ break; \
+ \
+ case 0xD0: \
+ /* BEQ label */ \
+ thumb_conditional_branch(eq); \
+ break; \
+ \
+ case 0xD1: \
+ /* BNE label */ \
+ thumb_conditional_branch(ne); \
+ break; \
+ \
+ case 0xD2: \
+ /* BCS label */ \
+ thumb_conditional_branch(cs); \
+ break; \
+ \
+ case 0xD3: \
+ /* BCC label */ \
+ thumb_conditional_branch(cc); \
+ break; \
+ \
+ case 0xD4: \
+ /* BMI label */ \
+ thumb_conditional_branch(mi); \
+ break; \
+ \
+ case 0xD5: \
+ /* BPL label */ \
+ thumb_conditional_branch(pl); \
+ break; \
+ \
+ case 0xD6: \
+ /* BVS label */ \
+ thumb_conditional_branch(vs); \
+ break; \
+ \
+ case 0xD7: \
+ /* BVC label */ \
+ thumb_conditional_branch(vc); \
+ break; \
+ \
+ case 0xD8: \
+ /* BHI label */ \
+ thumb_conditional_branch(hi); \
+ break; \
+ \
+ case 0xD9: \
+ /* BLS label */ \
+ thumb_conditional_branch(ls); \
+ break; \
+ \
+ case 0xDA: \
+ /* BGE label */ \
+ thumb_conditional_branch(ge); \
+ break; \
+ \
+ case 0xDB: \
+ /* BLT label */ \
+ thumb_conditional_branch(lt); \
+ break; \
+ \
+ case 0xDC: \
+ /* BGT label */ \
+ thumb_conditional_branch(gt); \
+ break; \
+ \
+ case 0xDD: \
+ /* BLE label */ \
+ thumb_conditional_branch(le); \
+ break; \
+ \
+ case 0xDF: \
+ { \
+ /* SWI comment */ \
+ thumb_swi(); \
+ break; \
+ } \
+ \
+ case 0xE0 ... 0xE7: \
+ { \
+ /* B label */ \
+ thumb_b(); \
+ break; \
+ } \
+ \
+ case 0xF0 ... 0xF7: \
+ { \
+ /* (low word) BL label */ \
+ /* This should possibly generate code if not in conjunction with a BLH \
+ next, but I don't think anyone will do that. */ \
+ break; \
+ } \
+ \
+ case 0xF8 ... 0xFF: \
+ { \
+ /* (high word) BL label */ \
+ /* This might not be preceeding a BL low word (Golden Sun 2), if so \
+ it must be handled like an indirect branch. */ \
+ if((last_opcode >= 0xF000) && (last_opcode < 0xF800)) \
+ { \
+ thumb_bl(); \
+ } \
+ else \
+ { \
+ thumb_blh(); \
+ } \
+ break; \
+ } \
+ } \
+ \
+ pc += 2 \
+
+#define thumb_flag_modifies_all() \
+ flag_status |= 0xFF \
+
+#define thumb_flag_modifies_zn() \
+ flag_status |= 0xCC \
+
+#define thumb_flag_modifies_znc() \
+ flag_status |= 0xEE \
+
+#define thumb_flag_modifies_zn_maybe_c() \
+ flag_status |= 0xCE \
+
+#define thumb_flag_modifies_c() \
+ flag_status |= 0x22 \
+
+#define thumb_flag_requires_c() \
+ flag_status |= 0x200 \
+
+#define thumb_flag_requires_all() \
+ flag_status |= 0xF00 \
+
+#define thumb_flag_status() \
+{ \
+ u16 flag_status = 0; \
+ switch((opcode >> 8) & 0xFF) \
+ { \
+ /* left shift by imm */ \
+ case 0x00 ... 0x07: \
+ thumb_flag_modifies_zn(); \
+ if(((opcode >> 6) & 0x1F) != 0) \
+ { \
+ thumb_flag_modifies_c(); \
+ } \
+ break; \
+ \
+ /* right shift by imm */ \
+ case 0x08 ... 0x17: \
+ thumb_flag_modifies_znc(); \
+ break; \
+ \
+ /* add, subtract */ \
+ case 0x18 ... 0x1F: \
+ thumb_flag_modifies_all(); \
+ break; \
+ \
+ /* mov reg, imm */ \
+ case 0x20 ... 0x27: \
+ thumb_flag_modifies_zn(); \
+ break; \
+ \
+ /* cmp reg, imm; add, subtract */ \
+ case 0x28 ... 0x3F: \
+ thumb_flag_modifies_all(); \
+ break; \
+ \
+ case 0x40: \
+ switch((opcode >> 6) & 0x03) \
+ { \
+ case 0x00: \
+ /* AND rd, rs */ \
+ thumb_flag_modifies_zn(); \
+ break; \
+ \
+ case 0x01: \
+ /* EOR rd, rs */ \
+ thumb_flag_modifies_zn(); \
+ break; \
+ \
+ case 0x02: \
+ /* LSL rd, rs */ \
+ thumb_flag_modifies_zn_maybe_c(); \
+ break; \
+ \
+ case 0x03: \
+ /* LSR rd, rs */ \
+ thumb_flag_modifies_zn_maybe_c(); \
+ break; \
+ } \
+ break; \
+ \
+ case 0x41: \
+ switch((opcode >> 6) & 0x03) \
+ { \
+ case 0x00: \
+ /* ASR rd, rs */ \
+ thumb_flag_modifies_zn_maybe_c(); \
+ break; \
+ \
+ case 0x01: \
+ /* ADC rd, rs */ \
+ thumb_flag_modifies_all(); \
+ thumb_flag_requires_c(); \
+ break; \
+ \
+ case 0x02: \
+ /* SBC rd, rs */ \
+ thumb_flag_modifies_all(); \
+ thumb_flag_requires_c(); \
+ break; \
+ \
+ case 0x03: \
+ /* ROR rd, rs */ \
+ thumb_flag_modifies_zn_maybe_c(); \
+ break; \
+ } \
+ break; \
+ \
+ /* TST, NEG, CMP, CMN */ \
+ case 0x42: \
+ thumb_flag_modifies_all(); \
+ break; \
+ \
+ /* ORR, MUL, BIC, MVN */ \
+ case 0x43: \
+ thumb_flag_modifies_zn(); \
+ break; \
+ \
+ case 0x45: \
+ /* CMP rd, rs */ \
+ thumb_flag_modifies_all(); \
+ break; \
+ \
+ /* mov might change PC (fall through if so) */ \
+ case 0x46: \
+ if((opcode & 0xFF87) != 0x4687) \
+ break; \
+ \
+ /* branches (can change PC) */ \
+ case 0x47: \
+ case 0xBD: \
+ case 0xD0 ... 0xE7: \
+ case 0xF0 ... 0xFF: \
+ thumb_flag_requires_all(); \
+ break; \
+ } \
+ block_data[block_data_position].flag_data = flag_status; \
+} \
+
+u8 *ram_block_ptrs[1024 * 64];
+u32 ram_block_tag_top = 0x0101;
+
+u8 *bios_block_ptrs[1024 * 8];
+u32 bios_block_tag_top = 0x0101;
+
+// This function will return a pointer to a translated block of code. If it
+// doesn't exist it will translate it, if it does it will pass it back.
+
+// type should be "arm", "thumb", or "dual." For arm or thumb the PC should
+// be a real PC, for dual the least significant bit will determine if it's
+// ARM or Thumb mode.
+
+#define block_lookup_address_pc_arm() \
+ pc &= ~0x03
+
+#define block_lookup_address_pc_thumb() \
+ pc &= ~0x01 \
+
+#define block_lookup_address_pc_dual() \
+ u32 thumb = pc & 0x01; \
+ \
+ if(thumb) \
+ { \
+ pc--; \
+ reg[REG_CPSR] |= 0x20; \
+ } \
+ else \
+ { \
+ pc = (pc + 2) & ~0x03; \
+ reg[REG_CPSR] &= ~0x20; \
+ } \
+
+#define ram_translation_region TRANSLATION_REGION_RAM
+#define rom_translation_region TRANSLATION_REGION_ROM
+#define bios_translation_region TRANSLATION_REGION_BIOS
+
+#define block_lookup_translate_arm(mem_type, smc_enable) \
+ translation_result = translate_block_arm(pc, mem_type##_translation_region, \
+ smc_enable) \
+
+#define block_lookup_translate_thumb(mem_type, smc_enable) \
+ translation_result = translate_block_thumb(pc, \
+ mem_type##_translation_region, smc_enable) \
+
+#define block_lookup_translate_dual(mem_type, smc_enable) \
+ if(thumb) \
+ { \
+ translation_result = translate_block_thumb(pc, \
+ mem_type##_translation_region, smc_enable); \
+ } \
+ else \
+ { \
+ translation_result = translate_block_arm(pc, \
+ mem_type##_translation_region, smc_enable); \
+ } \
+
+// 0x0101 is the smallest tag that can be used. 0xFFFF is marked
+// in the middle of blocks and used for write guarding, it doesn't
+// indicate a valid block either (it's okay to compile a new block
+// that overlaps the earlier one, although this should be relatively
+// uncommon)
+
+#define fill_tag_arm(mem_type) \
+ location[0] = mem_type##_block_tag_top; \
+ location[1] = 0xFFFF \
+
+#define fill_tag_thumb(mem_type) \
+ *location = mem_type##_block_tag_top \
+
+#define fill_tag_dual(mem_type) \
+ if(thumb) \
+ fill_tag_thumb(mem_type); \
+ else \
+ fill_tag_arm(mem_type) \
+
+#define block_lookup_translate(instruction_type, mem_type, smc_enable) \
+ block_tag = *location; \
+ if((block_tag < 0x0101) || (block_tag == 0xFFFF)) \
+ { \
+ __label__ redo; \
+ s32 translation_result; \
+ \
+ redo: \
+ \
+ translation_recursion_level++; \
+ block_address = mem_type##_translation_ptr + block_prologue_size; \
+ mem_type##_block_ptrs[mem_type##_block_tag_top] = block_address; \
+ fill_tag_##instruction_type(mem_type); \
+ mem_type##_block_tag_top++; \
+ \
+ block_lookup_translate_##instruction_type(mem_type, smc_enable); \
+ translation_recursion_level--; \
+ \
+ /* If the translation failed then pass that failure on if we're in \
+ a recursive level, or try again if we've hit the bottom. */ \
+ if(translation_result == -1) \
+ { \
+ if(translation_recursion_level) \
+ return NULL; \
+ \
+ goto redo; \
+ } \
+ \
+ if(translation_recursion_level == 0) \
+ translate_invalidate_dcache(); \
+ } \
+ else \
+ { \
+ block_address = mem_type##_block_ptrs[block_tag]; \
+ } \
+
+u32 translation_recursion_level = 0;
+u32 translation_flush_count = 0;
+
+
+#define block_lookup_address_builder(type) \
+u8 function_cc *block_lookup_address_##type(u32 pc) \
+{ \
+ u16 *location; \
+ u32 block_tag; \
+ u8 *block_address; \
+ \
+ /* Starting at the beginning, we allow for one translation cache flush. */ \
+ if(translation_recursion_level == 0) \
+ translation_flush_count = 0; \
+ block_lookup_address_pc_##type(); \
+ \
+ switch(pc >> 24) \
+ { \
+ case 0x0: \
+ bios_region_read_allow(); \
+ location = (u16 *)(bios_rom + pc + 0x4000); \
+ block_lookup_translate(type, bios, 0); \
+ if(translation_recursion_level == 0) \
+ bios_region_read_allow(); \
+ break; \
+ \
+ case 0x2: \
+ location = (u16 *)(ewram + (pc & 0x7FFF) + ((pc & 0x38000) * 2)); \
+ block_lookup_translate(type, ram, 1); \
+ if(translation_recursion_level == 0) \
+ bios_region_read_protect(); \
+ break; \
+ \
+ case 0x3: \
+ location = (u16 *)(iwram + (pc & 0x7FFF)); \
+ block_lookup_translate(type, ram, 1); \
+ if(translation_recursion_level == 0) \
+ bios_region_read_protect(); \
+ break; \
+ \
+ case 0x8 ... 0xD: \
+ { \
+ u32 hash_target = ((pc * 2654435761U) >> 16) & \
+ (ROM_BRANCH_HASH_SIZE - 1); \
+ u32 *block_ptr = rom_branch_hash[hash_target]; \
+ u32 **block_ptr_address = rom_branch_hash + hash_target; \
+ \
+ while(block_ptr) \
+ { \
+ if(block_ptr[0] == pc) \
+ { \
+ block_address = (u8 *)(block_ptr + 2) + block_prologue_size; \
+ break; \
+ } \
+ \
+ block_ptr_address = (u32 **)(block_ptr + 1); \
+ block_ptr = (u32 *)block_ptr[1]; \
+ } \
+ \
+ if(block_ptr == NULL) \
+ { \
+ __label__ redo; \
+ s32 translation_result; \
+ \
+ redo: \
+ \
+ translation_recursion_level++; \
+ ((u32 *)rom_translation_ptr)[0] = pc; \
+ ((u32 **)rom_translation_ptr)[1] = NULL; \
+ *block_ptr_address = (u32 *)rom_translation_ptr; \
+ rom_translation_ptr += 8; \
+ block_address = rom_translation_ptr + block_prologue_size; \
+ block_lookup_translate_##type(rom, 0); \
+ translation_recursion_level--; \
+ \
+ /* If the translation failed then pass that failure on if we're in \
+ a recursive level, or try again if we've hit the bottom. */ \
+ if(translation_result == -1) \
+ { \
+ if(translation_recursion_level) \
+ return NULL; \
+ \
+ goto redo; \
+ } \
+ \
+ if(translation_recursion_level == 0) \
+ translate_invalidate_dcache(); \
+ } \
+ if(translation_recursion_level == 0) \
+ bios_region_read_protect(); \
+ break; \
+ } \
+ \
+ default: \
+ /* If we're at the bottom, it means we're actually trying to jump to an \
+ address that we can't handle. Otherwise, it means that code scanned \
+ has reached an address that can't be handled, which means that we \
+ have most likely hit an area that doesn't contain code yet (for \
+ instance, in RAM). If such a thing happens, return -1 and the \
+ block translater will naively link it (it'll be okay, since it \
+ should never be hit) */ \
+ if(translation_recursion_level == 0) \
+ { \
+ char buffer[256]; \
+ sprintf(buffer, "bad jump %x (%x) (%x)\n", pc, reg[REG_PC], \
+ last_instruction); \
+ printf(buffer); \
+ quit(); \
+ } \
+ block_address = (u8 *)(-1); \
+ break; \
+ } \
+ \
+ return block_address; \
+} \
+
+block_lookup_address_builder(arm);
+block_lookup_address_builder(thumb);
+block_lookup_address_builder(dual);
+
+// Potential exit point: If the rd field is pc for instructions is 0x0F,
+// the instruction is b/bl/bx, or the instruction is ldm with PC in the
+// register list.
+// All instructions with upper 3 bits less than 100b have an rd field
+// except bx, where the bits must be 0xF there anyway, multiplies,
+// which cannot have 0xF in the corresponding fields, and msr, which
+// has 0x0F there but doesn't end things (therefore must be special
+// checked against). Because MSR and BX overlap both are checked for.
+
+#define arm_exit_point \
+ (((opcode < 0x8000000) && ((opcode & 0x000F000) == 0x000F000) && \
+ ((opcode & 0xDB0F000) != 0x120F000)) || \
+ ((opcode & 0x12FFF10) == 0x12FFF10) || \
+ ((opcode & 0x8108000) == 0x8108000) || \
+ ((opcode >= 0xA000000) && (opcode < 0xF000000)) || \
+ ((opcode > 0xF000000) && (!swi_hle_handle[((opcode >> 16) & 0xFF)]))) \
+
+#define arm_opcode_branch \
+ ((opcode & 0xE000000) == 0xA000000) \
+
+#define arm_opcode_swi \
+ ((opcode & 0xF000000) == 0xF000000) \
+
+#define arm_opcode_unconditional_branch \
+ (condition == 0x0E) \
+
+#define arm_load_opcode() \
+ opcode = address32(pc_address_block, (block_end_pc & 0x7FFF)); \
+ condition = opcode >> 28; \
+ \
+ opcode &= 0xFFFFFFF; \
+ \
+ block_end_pc += 4 \
+
+#define arm_branch_target() \
+ branch_target = (block_end_pc + 4 + (((s32)(opcode & 0xFFFFFF) << 8) >> 6)) \
+
+// Contiguous conditional block flags modification - it will set 0x20 in the
+// condition's bits if this instruction modifies flags. Taken from the CPU
+// switch so it'd better be right this time.
+
+#define arm_set_condition(_condition) \
+ block_data[block_data_position].condition = _condition; \
+ switch((opcode >> 20) & 0xFF) \
+ { \
+ case 0x01: \
+ case 0x03: \
+ case 0x09: \
+ case 0x0B: \
+ case 0x0D: \
+ case 0x0F: \
+ if((((opcode >> 5) & 0x03) == 0) || ((opcode & 0x90) != 0x90)) \
+ block_data[block_data_position].condition |= 0x20; \
+ break; \
+ \
+ case 0x05: \
+ case 0x07: \
+ case 0x11: \
+ case 0x13: \
+ case 0x15 ... 0x17: \
+ case 0x19: \
+ case 0x1B: \
+ case 0x1D: \
+ case 0x1F: \
+ if((opcode & 0x90) != 0x90) \
+ block_data[block_data_position].condition |= 0x20; \
+ break; \
+ \
+ case 0x12: \
+ if(((opcode & 0x90) != 0x90) && !(opcode & 0x10)) \
+ block_data[block_data_position].condition |= 0x20; \
+ break; \
+ \
+ case 0x21: \
+ case 0x23: \
+ case 0x25: \
+ case 0x27: \
+ case 0x29: \
+ case 0x2B: \
+ case 0x2D: \
+ case 0x2F ... 0x37: \
+ case 0x39: \
+ case 0x3B: \
+ case 0x3D: \
+ case 0x3F: \
+ block_data[block_data_position].condition |= 0x20; \
+ break; \
+ } \
+
+#define arm_link_block() \
+ translation_target = block_lookup_address_arm(branch_target) \
+
+#define arm_instruction_width 4
+
+#define arm_base_cycles() \
+ cycle_count += waitstate_cycles_sequential[pc >> 24][2] \
+
+// For now this just sets a variable that says flags should always be
+// computed.
+
+#define arm_dead_flag_eliminate() \
+ flag_status = 0xF \
+
+// The following Thumb instructions can exit:
+// b, bl, bx, swi, pop {... pc}, and mov pc, ..., the latter being a hireg
+// op only. Rather simpler to identify than the ARM set.
+
+#define thumb_exit_point \
+ (((opcode >= 0xD000) && (opcode < 0xDF00)) || \
+ (((opcode & 0xFF00) == 0xDF00) && \
+ (!swi_hle_handle[opcode & 0xFF])) || \
+ ((opcode >= 0xE000) && (opcode < 0xE800)) || \
+ ((opcode & 0xFF00) == 0x4700) || \
+ ((opcode & 0xFF00) == 0xBD00) || \
+ ((opcode & 0xFF87) == 0x4687) || \
+ ((opcode >= 0xF800))) \
+
+#define thumb_opcode_branch \
+ (((opcode >= 0xD000) && (opcode < 0xDF00)) || \
+ ((opcode >= 0xE000) && (opcode < 0xE800)) || \
+ (opcode >= 0xF800)) \
+
+#define thumb_opcode_swi \
+ ((opcode & 0xFF00) == 0xDF00) \
+
+#define thumb_opcode_unconditional_branch \
+ ((opcode < 0xD000) || (opcode >= 0xDF00)) \
+
+#define thumb_load_opcode() \
+ last_opcode = opcode; \
+ opcode = address16(pc_address_block, (block_end_pc & 0x7FFF)); \
+ \
+ block_end_pc += 2 \
+
+#define thumb_branch_target() \
+ if(opcode < 0xE000) \
+ { \
+ branch_target = block_end_pc + 2 + ((s8)(opcode & 0xFF) * 2); \
+ } \
+ else \
+ \
+ if(opcode < 0xF800) \
+ { \
+ branch_target = block_end_pc + 2 + ((s32)((opcode & 0x7FF) << 21) >> 20); \
+ } \
+ else \
+ { \
+ if((last_opcode >= 0xF000) && (last_opcode < 0xF800)) \
+ { \
+ branch_target = \
+ (block_end_pc + ((s32)((last_opcode & 0x07FF) << 21) >> 9) + \
+ ((opcode & 0x07FF) * 2)); \
+ } \
+ else \
+ { \
+ goto no_direct_branch; \
+ } \
+ } \
+
+#define thumb_set_condition(_condition) \
+
+#define thumb_link_block() \
+ if(branch_target != 0x00000008) \
+ translation_target = block_lookup_address_thumb(branch_target); \
+ else \
+ translation_target = block_lookup_address_arm(branch_target) \
+
+#define thumb_instruction_width 2
+
+#define thumb_base_cycles() \
+ cycle_count += waitstate_cycles_sequential[pc >> 24][1] \
+
+// Here's how this works: each instruction has three different sets of flag
+// attributes, each consisiting of a 4bit mask describing how that instruction
+// interacts with the 4 main flags (N/Z/C/V).
+// The first set, in bits 0:3, is the set of flags the instruction may
+// modify. After this pass this is changed to the set of flags the instruction
+// should modify - if the bit for the corresponding flag is not set then code
+// does not have to be generated to calculate the flag for that instruction.
+
+// The second set, in bits 7:4, is the set of flags that the instruction must
+// modify (ie, for shifts by the register values the instruction may not
+// always modify the C flag, and thus the C bit won't be set here).
+
+// The third set, in bits 11:8, is the set of flags that the instruction uses
+// in its computation, or the set of flags that will be needed after the
+// instruction is done. For any instructions that change the PC all of the
+// bits should be set because it is (for now) unknown what flags will be
+// needed after it arrives at its destination. Instructions that use the
+// carry flag as input will have it set as well.
+
+// The algorithm is a simple liveness analysis procedure: It starts at the
+// bottom of the instruction stream and sets a "currently needed" mask to
+// the flags needed mask of the current instruction. Then it moves down
+// an instruction, ANDs that instructions "should generate" mask by the
+// "currently needed" mask, then ANDs the "currently needed" mask by
+// the 1's complement of the instruction's "must generate" mask, and ORs
+// the "currently needed" mask by the instruction's "flags needed" mask.
+
+#define thumb_dead_flag_eliminate() \
+{ \
+ u32 needed_mask; \
+ needed_mask = block_data[block_data_position].flag_data >> 8; \
+ \
+ block_data_position--; \
+ while(block_data_position >= 0) \
+ { \
+ flag_status = block_data[block_data_position].flag_data; \
+ block_data[block_data_position].flag_data = \
+ (flag_status & needed_mask); \
+ needed_mask &= ~((flag_status >> 4) & 0x0F); \
+ needed_mask |= flag_status >> 8; \
+ block_data_position--; \
+ } \
+} \
+
+#define MAX_BLOCK_SIZE 8192
+#define MAX_EXITS 256
+
+block_data_type block_data[MAX_BLOCK_SIZE];
+block_exit_type block_exits[MAX_EXITS];
+
+#define smc_write_arm_yes() \
+ if(address32(pc_address_block, (block_end_pc & 0x7FFF) - 0x8000) == 0x0000) \
+ { \
+ address32(pc_address_block, (block_end_pc & 0x7FFF) - 0x8000) = \
+ 0xFFFFFFFF; \
+ } \
+
+#define smc_write_thumb_yes() \
+ if(address16(pc_address_block, (block_end_pc & 0x7FFF) - 0x8000) == 0x0000) \
+ { \
+ address16(pc_address_block, (block_end_pc & 0x7FFF) - 0x8000) = 0xFFFF; \
+ } \
+
+#define smc_write_arm_no() \
+
+#define smc_write_thumb_no() \
+
+#define scan_block(type, smc_write_op) \
+{ \
+ __label__ block_end; \
+ /* Find the end of the block */ \
+ do \
+ { \
+ check_pc_region(block_end_pc); \
+ smc_write_##type##_##smc_write_op(); \
+ type##_load_opcode(); \
+ type##_flag_status(); \
+ \
+ if(type##_exit_point) \
+ { \
+ /* Branch/branch with link */ \
+ if(type##_opcode_branch) \
+ { \
+ __label__ no_direct_branch; \
+ type##_branch_target(); \
+ block_exits[block_exit_position].branch_target = branch_target; \
+ block_exit_position++; \
+ \
+ /* Give the branch target macro somewhere to bail if it turns out to \
+ be an indirect branch (ala malformed Thumb bl) */ \
+ no_direct_branch:; \
+ } \
+ \
+ /* SWI branches to the BIOS, this will likely change when \
+ some HLE BIOS is implemented. */ \
+ if(type##_opcode_swi) \
+ { \
+ block_exits[block_exit_position].branch_target = 0x00000008; \
+ block_exit_position++; \
+ } \
+ \
+ type##_set_condition(condition | 0x10); \
+ \
+ /* Only unconditional branches can end the block. */ \
+ if(type##_opcode_unconditional_branch) \
+ { \
+ /* Check to see if any prior block exits branch after here, \
+ if so don't end the block. Starts from the top and works \
+ down because the most recent branch is most likely to \
+ join after the end (if/then form) */ \
+ for(i = block_exit_position - 2; i >= 0; i--) \
+ { \
+ if(block_exits[i].branch_target == block_end_pc) \
+ break; \
+ } \
+ \
+ if(i < 0) \
+ break; \
+ } \
+ if(block_exit_position == MAX_EXITS) \
+ break; \
+ } \
+ else \
+ { \
+ type##_set_condition(condition); \
+ } \
+ \
+ for(i = 0; i < translation_gate_targets; i++) \
+ { \
+ if(block_end_pc == translation_gate_target_pc[i]) \
+ goto block_end; \
+ } \
+ \
+ block_data[block_data_position].update_cycles = 0; \
+ block_data_position++; \
+ if((block_data_position == MAX_BLOCK_SIZE) || \
+ (block_end_pc == 0x3007FF0) || (block_end_pc == 0x203FFFF0)) \
+ { \
+ break; \
+ } \
+ } while(1); \
+ \
+ block_end:; \
+} \
+
+#define arm_fix_pc() \
+ pc &= ~0x03 \
+
+#define thumb_fix_pc() \
+ pc &= ~0x01 \
+
+#define translate_block_builder(type) \
+s32 translate_block_##type(u32 pc, translation_region_type \
+ translation_region, u32 smc_enable) \
+{ \
+ u32 opcode; \
+ u32 last_opcode; \
+ u32 condition; \
+ u32 last_condition; \
+ u32 pc_region = (pc >> 15); \
+ u32 new_pc_region; \
+ u8 *pc_address_block = memory_map_read[pc_region]; \
+ u32 block_start_pc = pc; \
+ u32 block_end_pc = pc; \
+ u32 block_exit_position = 0; \
+ s32 block_data_position = 0; \
+ u32 external_block_exit_position = 0; \
+ u32 branch_target; \
+ u32 cycle_count = 0; \
+ u8 *translation_target; \
+ u8 *backpatch_address; \
+ u8 *translation_ptr; \
+ u8 *translation_cache_limit; \
+ s32 i; \
+ u32 flag_status; \
+ block_exit_type external_block_exits[MAX_EXITS]; \
+ generate_block_extra_vars_##type(); \
+ type##_fix_pc(); \
+ \
+ if(pc_address_block == NULL) \
+ pc_address_block = load_gamepak_page(pc_region & 0x3FF); \
+ \
+ switch(translation_region) \
+ { \
+ case TRANSLATION_REGION_RAM: \
+ if(pc >= 0x3000000) \
+ { \
+ if((pc < iwram_code_min) || (iwram_code_min == 0xFFFFFFFF)) \
+ iwram_code_min = pc; \
+ } \
+ else \
+ \
+ if(pc >= 0x2000000) \
+ { \
+ if((pc < ewram_code_min) || (ewram_code_min == 0xFFFFFFFF)) \
+ ewram_code_min = pc; \
+ } \
+ \
+ translation_ptr = ram_translation_ptr; \
+ translation_cache_limit = \
+ ram_translation_cache + RAM_TRANSLATION_CACHE_SIZE - \
+ TRANSLATION_CACHE_LIMIT_THRESHOLD; \
+ break; \
+ \
+ case TRANSLATION_REGION_ROM: \
+ translation_ptr = rom_translation_ptr; \
+ translation_cache_limit = \
+ rom_translation_cache + ROM_TRANSLATION_CACHE_SIZE - \
+ TRANSLATION_CACHE_LIMIT_THRESHOLD; \
+ break; \
+ \
+ case TRANSLATION_REGION_BIOS: \
+ translation_ptr = bios_translation_ptr; \
+ translation_cache_limit = bios_translation_cache + \
+ BIOS_TRANSLATION_CACHE_SIZE; \
+ break; \
+ } \
+ \
+ generate_block_prologue(); \
+ \
+ /* This is a function because it's used a lot more than it might seem (all \
+ of the data processing functions can access it), and its expansion was \
+ massacreing the compiler. */ \
+ \
+ if(smc_enable) \
+ { \
+ scan_block(type, yes); \
+ } \
+ else \
+ { \
+ scan_block(type, no); \
+ } \
+ \
+ for(i = 0; i < block_exit_position; i++) \
+ { \
+ branch_target = block_exits[i].branch_target; \
+ \
+ if((branch_target > block_start_pc) && \
+ (branch_target < block_end_pc)) \
+ { \
+ block_data[(branch_target - block_start_pc) / \
+ type##_instruction_width].update_cycles = 1; \
+ } \
+ } \
+ \
+ type##_dead_flag_eliminate(); \
+ \
+ block_exit_position = 0; \
+ block_data_position = 0; \
+ \
+ last_condition = 0x0E; \
+ \
+ while(pc != block_end_pc) \
+ { \
+ block_data[block_data_position].block_offset = translation_ptr; \
+ type##_base_cycles(); \
+ /*generate_step_debug();*/ \
+ \
+ translate_##type##_instruction(); \
+ block_data_position++; \
+ \
+ /* If it went too far the cache needs to be flushed and the process \
+ restarted. Because we might already be nested several stages in \
+ a simple recursive call here won't work, it has to pedal out to \
+ the beginning. */ \
+ \
+ if(translation_ptr > translation_cache_limit) \
+ { \
+ translation_flush_count++; \
+ \
+ switch(translation_region) \
+ { \
+ case TRANSLATION_REGION_RAM: \
+ flush_translation_cache_ram(); \
+ break; \
+ \
+ case TRANSLATION_REGION_ROM: \
+ flush_translation_cache_rom(); \
+ break; \
+ \
+ case TRANSLATION_REGION_BIOS: \
+ flush_translation_cache_bios(); \
+ break; \
+ } \
+ \
+ return -1; \
+ } \
+ \
+ /* If the next instruction is a block entry point update the \
+ cycle counter and update */ \
+ if(block_data[block_data_position].update_cycles == 1) \
+ { \
+ generate_cycle_update(); \
+ } \
+ } \
+ for(i = 0; i < translation_gate_targets; i++) \
+ { \
+ if(pc == translation_gate_target_pc[i]) \
+ { \
+ generate_translation_gate(type); \
+ break; \
+ } \
+ } \
+ \
+ for(i = 0; i < block_exit_position; i++) \
+ { \
+ branch_target = block_exits[i].branch_target; \
+ \
+ if((branch_target >= block_start_pc) && (branch_target < block_end_pc)) \
+ { \
+ /* Internal branch, patch to recorded address */ \
+ translation_target = \
+ block_data[(branch_target - block_start_pc) / \
+ type##_instruction_width].block_offset; \
+ \
+ generate_branch_patch_unconditional(block_exits[i].branch_source, \
+ translation_target); \
+ } \
+ else \
+ { \
+ /* External branch, save for later */ \
+ external_block_exits[external_block_exit_position].branch_target = \
+ branch_target; \
+ external_block_exits[external_block_exit_position].branch_source = \
+ block_exits[i].branch_source; \
+ external_block_exit_position++; \
+ } \
+ } \
+ \
+ switch(translation_region) \
+ { \
+ case TRANSLATION_REGION_RAM: \
+ if(pc >= 0x3000000) \
+ { \
+ if((pc > iwram_code_max) || (iwram_code_max == 0xFFFFFFFF)) \
+ iwram_code_max = pc; \
+ } \
+ else \
+ \
+ if(pc >= 0x2000000) \
+ { \
+ if((pc > ewram_code_max) || (ewram_code_max == 0xFFFFFFFF)) \
+ ewram_code_max = pc; \
+ } \
+ \
+ ram_translation_ptr = translation_ptr; \
+ break; \
+ \
+ case TRANSLATION_REGION_ROM: \
+ rom_translation_ptr = translation_ptr; \
+ break; \
+ \
+ case TRANSLATION_REGION_BIOS: \
+ bios_translation_ptr = translation_ptr; \
+ break; \
+ } \
+ \
+ for(i = 0; i < external_block_exit_position; i++) \
+ { \
+ branch_target = external_block_exits[i].branch_target; \
+ type##_link_block(); \
+ if(translation_target == NULL) \
+ return -1; \
+ generate_branch_patch_unconditional( \
+ external_block_exits[i].branch_source, translation_target); \
+ } \
+ \
+ return 0; \
+} \
+
+translate_block_builder(arm);
+translate_block_builder(thumb);
+
+void flush_translation_cache_ram()
+{
+ flush_ram_count++;
+/* printf("ram flush %d (pc %x), %x to %x, %x to %x\n",
+ flush_ram_count, reg[REG_PC], iwram_code_min, iwram_code_max,
+ ewram_code_min, ewram_code_max); */
+
+#ifndef PC_BUILD
+ invalidate_icache_region(ram_translation_cache,
+ (ram_translation_ptr - ram_translation_cache) + 0x100);
+#endif
+ ram_translation_ptr = ram_translation_cache;
+ ram_block_tag_top = 0x0101;
+ if(iwram_code_min != 0xFFFFFFFF)
+ {
+ iwram_code_min &= 0x7FFF;
+ iwram_code_max &= 0x7FFF;
+ memset(iwram + iwram_code_min, 0, iwram_code_max - iwram_code_min);
+ }
+
+ if(ewram_code_min != 0xFFFFFFFF)
+ {
+ u32 ewram_code_min_page;
+ u32 ewram_code_max_page;
+ u32 ewram_code_min_offset;
+ u32 ewram_code_max_offset;
+ u32 i;
+
+ ewram_code_min &= 0x3FFFF;
+ ewram_code_max &= 0x3FFFF;
+
+ ewram_code_min_page = ewram_code_min >> 15;
+ ewram_code_max_page = ewram_code_max >> 15;
+ ewram_code_min_offset = ewram_code_min & 0x7FFF;
+ ewram_code_max_offset = ewram_code_max & 0x7FFF;
+
+ if(ewram_code_min_page == ewram_code_max_page)
+ {
+ memset(ewram + (ewram_code_min_page * 0x10000) +
+ ewram_code_min_offset, 0,
+ ewram_code_max_offset - ewram_code_min_offset);
+ }
+ else
+ {
+ for(i = ewram_code_min_page + 1; i < ewram_code_max_page; i++)
+ {
+ memset(ewram + (i * 0x10000), 0, 0x8000);
+ }
+
+ memset(ewram, 0, ewram_code_max_offset);
+ }
+ }
+
+ iwram_code_min = 0xFFFFFFFF;
+ iwram_code_max = 0xFFFFFFFF;
+ ewram_code_min = 0xFFFFFFFF;
+ ewram_code_max = 0xFFFFFFFF;
+}
+
+void flush_translation_cache_rom()
+{
+#ifndef PC_BUILD
+ invalidate_icache_region(rom_translation_cache,
+ rom_translation_ptr - rom_translation_cache + 0x100);
+#endif
+
+ rom_translation_ptr = rom_translation_cache;
+ memset(rom_branch_hash, 0, sizeof(rom_branch_hash));
+}
+
+void flush_translation_cache_bios()
+{
+#ifndef PC_BUILD
+ invalidate_icache_region(bios_translation_cache,
+ bios_translation_ptr - bios_translation_cache + 0x100);
+#endif
+
+ bios_block_tag_top = 0x0101;
+ bios_translation_ptr = bios_translation_cache;
+ memset(bios_rom + 0x4000, 0, 0x4000);
+}
+
+#ifdef GP2X_BUILD
+ #define cache_dump_prefix "/mnt/nand/"
+#else
+ #define cache_dump_prefix ""
+#endif
+
+void dump_translation_cache()
+{
+ file_open(ram_cache, cache_dump_prefix "ram_cache.bin", write);
+ file_write(ram_cache, ram_translation_cache,
+ ram_translation_ptr - ram_translation_cache);
+ file_close(ram_cache);
+
+ file_open(rom_cache, cache_dump_prefix "rom_cache.bin", write);
+ file_write(rom_cache, rom_translation_cache,
+ rom_translation_ptr - rom_translation_cache);
+ file_close(rom_cache);
+
+ file_open(bios_cache, cache_dump_prefix "bios_cache.bin", write);
+ file_write(bios_cache, bios_translation_cache,
+ bios_translation_ptr - bios_translation_cache);
+ file_close(bios_cache);
+}
+