From 37430f22c5234cb09f2325575806b830f947bf8a Mon Sep 17 00:00:00 2001 From: David Guillen Fandos Date: Fri, 7 May 2021 20:41:54 +0200 Subject: Small optimization (~2-4%) and whitespace cleanup! Cleans up a ton of whitespace in cpu.c (like 100KB!) and improves readability of some massive decode statements. Added an optimization for PC-relative loads (pool load) in ROM (since it's read only and cannot possibily change) that directly emits an immediate load. This is way faster, specially in MIPS/x86, ARM can be even faster if we rewrite the immediate load macros to also use a pool. --- Makefile | 1 + arm/arm_emit.h | 6 +- cpu.c | 4334 ++++++++++++++++++++++++------------------------------- cpu_threaded.c | 392 +---- libretro.c | 1 - psp/mips_emit.h | 7 +- x86/x86_emit.h | 6 +- 7 files changed, 2003 insertions(+), 2744 deletions(-) diff --git a/Makefile b/Makefile index 5d28045..f4c758f 100644 --- a/Makefile +++ b/Makefile @@ -376,6 +376,7 @@ else ifeq ($(platform), mips32) SHARED := -shared -nostdlib -Wl,--version-script=link.T fpic := -fPIC -DPIC CFLAGS += -fomit-frame-pointer -ffast-math -march=mips32 -mtune=mips32r2 -mhard-float + CFLAGS += -fno-caller-saves HAVE_DYNAREC := 1 CPU_ARCH := mips diff --git a/arm/arm_emit.h b/arm/arm_emit.h index 1b6b251..4516404 100644 --- a/arm/arm_emit.h +++ b/arm/arm_emit.h @@ -319,7 +319,7 @@ u32 arm_disect_imm_32bit(u32 imm, u32 *stores, u32 *rotations) #define generate_load_pc(ireg, new_pc) \ - arm_load_imm_32bit(ireg, new_pc) \ + arm_load_imm_32bit(ireg, (new_pc)) \ #define generate_load_imm(ireg, imm, imm_ror) \ ARM_MOV_REG_IMM(0, ireg, imm, imm_ror) \ @@ -1658,6 +1658,10 @@ u32 execute_store_cpsr_body(u32 _cpsr, u32 store_mask, u32 address) /* Operation types: imm, mem_reg, mem_imm */ +#define thumb_load_pc_pool_const(reg_rd, value) \ + generate_load_pc(reg_a0, (value)); \ + generate_store_reg(reg_a0, reg_rd) + #define thumb_access_memory_load(mem_type, _rd) \ cycle_count += 2; \ generate_function_call(execute_load_##mem_type); \ diff --git a/cpu.c b/cpu.c index cd9bba6..d21eb66 100644 --- a/cpu.c +++ b/cpu.c @@ -1714,2546 +1714,2032 @@ arm_loop: if(c_flag) arm_next_instruction(); break; - case 0x4: - /* MI */ - if(!n_flag) - arm_next_instruction(); - break; - - case 0x5: - /* PL */ - if(n_flag) - arm_next_instruction(); - break; - - case 0x6: - /* VS */ - if(!v_flag) - arm_next_instruction(); - break; - - case 0x7: - /* VC */ - if(v_flag) - arm_next_instruction(); - break; - - case 0x8: - /* HI */ - if((c_flag == 0) | z_flag) - arm_next_instruction(); - break; - - case 0x9: - /* LS */ - if(c_flag & (z_flag ^ 1)) - arm_next_instruction(); - break; - - case 0xA: - /* GE */ - if(n_flag != v_flag) - arm_next_instruction(); - break; - - case 0xB: - /* LT */ - if(n_flag == v_flag) - arm_next_instruction(); - break; - - case 0xC: - /* GT */ - if(z_flag | (n_flag != v_flag)) - arm_next_instruction(); - break; - - case 0xD: - /* LE */ - if((z_flag == 0) & (n_flag == v_flag)) - arm_next_instruction(); - break; - - case 0xE: - /* AL */ - break; - - case 0xF: - /* Reserved - treat as "never" */ - arm_next_instruction(); - break; - } - - switch((opcode >> 20) & 0xFF) - { - case 0x00: - if((opcode & 0x90) == 0x90) - { - if(opcode & 0x20) - { - /* STRH rd, [rn], -rm */ - arm_access_memory(store, no_op, half_reg, u16, yes, - reg[rm]); - } - else - { - /* MUL rd, rm, rs */ - arm_multiply(no_op, no); - } - } - else - { - /* AND rd, rn, reg_op */ - arm_data_proc(reg[rn] & reg_sh, reg); - } - break; - - case 0x01: - if((opcode & 0x90) == 0x90) - { - switch((opcode >> 5) & 0x03) - { - case 0: - /* MULS rd, rm, rs */ - arm_multiply(no_op, yes); - break; - - case 1: - /* LDRH rd, [rn], -rm */ - arm_access_memory(load, no_op, half_reg, u16, yes, - reg[rm]); - break; - - case 2: - /* LDRSB rd, [rn], -rm */ - arm_access_memory(load, no_op, half_reg, s8, yes, - reg[rm]); - break; - - case 3: - /* LDRSH rd, [rn], -rm */ - arm_access_memory(load, no_op, half_reg, s16, yes, - reg[rm]); - break; - } - } - else - { - /* ANDS rd, rn, reg_op */ - arm_data_proc_logic_flags(reg[rn] & reg_sh, reg); - } - break; - - case 0x02: - if((opcode & 0x90) == 0x90) - { - if(opcode & 0x20) - { - /* STRH rd, [rn], -rm */ - arm_access_memory(store, no_op, half_reg, u16, yes, - reg[rm]); - } - else - { - /* MLA rd, rm, rs, rn */ - arm_multiply(+ reg[rn], no); - } - } - else - { - /* EOR rd, rn, reg_op */ - arm_data_proc(reg[rn] ^ reg_sh, reg); - } - break; - - case 0x03: - if((opcode & 0x90) == 0x90) - { - switch((opcode >> 5) & 0x03) - { - case 0: - /* MLAS rd, rm, rs, rn */ - arm_multiply(+ reg[rn], yes); - break; - - case 1: - /* LDRH rd, [rn], -rm */ - arm_access_memory(load, no_op, half_reg, u16, yes, - reg[rm]); - break; - - case 2: - /* LDRSB rd, [rn], -rm */ - arm_access_memory(load, no_op, half_reg, s8, yes, - reg[rm]); - break; - - case 3: - /* LDRSH rd, [rn], -rm */ - arm_access_memory(load, no_op, half_reg, s16, yes, - reg[rm]); - break; - } - } - else - { - /* EORS rd, rn, reg_op */ - arm_data_proc_logic_flags(reg[rn] ^ reg_sh, reg); - } - break; - - case 0x04: - if((opcode & 0x90) == 0x90) - { - /* STRH rd, [rn], -imm */ - arm_access_memory(store, no_op, half_imm, u16, yes, - offset); - } - else - { - /* SUB rd, rn, reg_op */ - arm_data_proc(reg[rn] - reg_sh, reg); - } - break; - - case 0x05: - if((opcode & 0x90) == 0x90) - { - switch((opcode >> 5) & 0x03) - { - case 1: - /* LDRH rd, [rn], -imm */ - arm_access_memory(load, no_op, half_imm, u16, yes, - offset); - break; - - case 2: - /* LDRSB rd, [rn], -imm */ - arm_access_memory(load, no_op, half_imm, s8, yes, - offset); - break; - - case 3: - /* LDRSH rd, [rn], -imm */ - arm_access_memory(load, no_op, half_imm, s16, yes, - offset); - break; - } - } - else - { - /* SUBS rd, rn, reg_op */ - arm_data_proc_sub_flags(reg[rn], reg_sh, reg); - } - break; - - case 0x06: - if((opcode & 0x90) == 0x90) - { - /* STRH rd, [rn], -imm */ - arm_access_memory(store, no_op, half_imm, u16, yes, - offset); - } - else - { - /* RSB rd, rn, reg_op */ - arm_data_proc(reg_sh - reg[rn], reg); - } - break; - - case 0x07: - if((opcode & 0x90) == 0x90) - { - switch((opcode >> 5) & 0x03) - { - case 1: - /* LDRH rd, [rn], -imm */ - arm_access_memory(load, no_op, half_imm, u16, yes, - offset); - break; - - case 2: - /* LDRSB rd, [rn], -imm */ - arm_access_memory(load, no_op, half_imm, s8, yes, - offset); - break; - - case 3: - /* LDRSH rd, [rn], -imm */ - arm_access_memory(load, no_op, half_imm, s16, yes, - offset); - break; - } - } - else - { - /* RSBS rd, rn, reg_op */ - arm_data_proc_sub_flags(reg_sh, reg[rn], reg); - } - break; - - case 0x08: - if((opcode & 0x90) == 0x90) - { - if(opcode & 0x20) - { - /* STRH rd, [rn], +rm */ - arm_access_memory(store, no_op, half_reg, u16, yes, + reg[rm]); - } - else - { - /* UMULL rd, rm, rs */ - arm_multiply_long(no_op, no, u); - } - } - else - { - /* ADD rd, rn, reg_op */ - arm_data_proc(reg[rn] + reg_sh, reg); - } - break; - - case 0x09: - if((opcode & 0x90) == 0x90) - { - switch((opcode >> 5) & 0x03) - { - case 0: - /* UMULLS rdlo, rdhi, rm, rs */ - arm_multiply_long(no_op, yes, u); - break; - - case 1: - /* LDRH rd, [rn], +rm */ - arm_access_memory(load, no_op, half_reg, u16, yes, + reg[rm]); - break; - - case 2: - /* LDRSB rd, [rn], +rm */ - arm_access_memory(load, no_op, half_reg, s8, yes, + reg[rm]); - break; - - case 3: - /* LDRSH rd, [rn], +rm */ - arm_access_memory(load, no_op, half_reg, s16, yes, + reg[rm]); - break; - } - } - else - { - /* ADDS rd, rn, reg_op */ - arm_data_proc_add_flags(reg[rn], reg_sh, reg); - } - break; - - case 0x0A: - if((opcode & 0x90) == 0x90) - { - if(opcode & 0x20) - { - /* STRH rd, [rn], +rm */ - arm_access_memory(store, no_op, half_reg, u16, yes, + reg[rm]); - } - else - { - /* UMLAL rd, rm, rs */ - arm_multiply_long(arm_multiply_long_addop(u), no, u); - } - } - else - { - /* ADC rd, rn, reg_op */ - arm_data_proc(reg[rn] + reg_sh + c_flag, reg); - } - break; - - case 0x0B: - if((opcode & 0x90) == 0x90) - { - switch((opcode >> 5) & 0x03) - { - case 0: - /* UMLALS rdlo, rdhi, rm, rs */ - arm_multiply_long(arm_multiply_long_addop(u), yes, u); - break; - - case 1: - /* LDRH rd, [rn], +rm */ - arm_access_memory(load, no_op, half_reg, u16, yes, + reg[rm]); - break; - - case 2: - /* LDRSB rd, [rn], +rm */ - arm_access_memory(load, no_op, half_reg, s8, yes, + reg[rm]); - break; - - case 3: - /* LDRSH rd, [rn], +rm */ - arm_access_memory(load, no_op, half_reg, s16, yes, + reg[rm]); - break; - } - } - else - { - /* ADCS rd, rn, reg_op */ - arm_data_proc_add_flags(reg[rn], reg_sh + c_flag, reg); - } - break; - - case 0x0C: - if((opcode & 0x90) == 0x90) - { - if(opcode & 0x20) - { - /* STRH rd, [rn], +imm */ - arm_access_memory(store, no_op, half_imm, u16, yes, + offset); - } - else - { - /* SMULL rd, rm, rs */ - arm_multiply_long(no_op, no, s); - } - } - else - { - /* SBC rd, rn, reg_op */ - arm_data_proc(reg[rn] - (reg_sh + (c_flag ^ 1)), reg); - } - break; - - case 0x0D: - if((opcode & 0x90) == 0x90) - { - switch((opcode >> 5) & 0x03) - { - case 0: - /* SMULLS rdlo, rdhi, rm, rs */ - arm_multiply_long(no_op, yes, s); - break; - - case 1: - /* LDRH rd, [rn], +imm */ - arm_access_memory(load, no_op, half_imm, u16, yes, + offset); - break; - - case 2: - /* LDRSB rd, [rn], +imm */ - arm_access_memory(load, no_op, half_imm, s8, yes, + offset); - break; - - case 3: - /* LDRSH rd, [rn], +imm */ - arm_access_memory(load, no_op, half_imm, s16, yes, + offset); - break; - } - } - else - { - /* SBCS rd, rn, reg_op */ - arm_data_proc_sub_flags(reg[rn], (reg_sh + (c_flag ^ 1)), reg); - } - break; - - case 0x0E: - if((opcode & 0x90) == 0x90) - { - if(opcode & 0x20) - { - /* STRH rd, [rn], +imm */ - arm_access_memory(store, no_op, half_imm, u16, yes, + offset); - } - else - { - /* SMLAL rd, rm, rs */ - arm_multiply_long(arm_multiply_long_addop(s), no, s); - } - } - else - { - /* RSC rd, rn, reg_op */ - arm_data_proc(reg_sh - reg[rn] + c_flag - 1, reg); - } - break; - - case 0x0F: - if((opcode & 0x90) == 0x90) - { - switch((opcode >> 5) & 0x03) - { - case 0: - /* SMLALS rdlo, rdhi, rm, rs */ - arm_multiply_long(arm_multiply_long_addop(s), yes, s); - break; - - case 1: - /* LDRH rd, [rn], +imm */ - arm_access_memory(load, no_op, half_imm, u16, yes, + offset); - break; - - case 2: - /* LDRSB rd, [rn], +imm */ - arm_access_memory(load, no_op, half_imm, s8, yes, + offset); - break; - - case 3: - /* LDRSH rd, [rn], +imm */ - arm_access_memory(load, no_op, half_imm, s16, yes, + offset); - break; - } - } - else - { - /* RSCS rd, rn, reg_op */ - arm_data_proc_sub_flags((reg_sh + c_flag - 1), reg[rn], reg); - } - break; - - case 0x10: - if((opcode & 0x90) == 0x90) - { - if(opcode & 0x20) - { - /* STRH rd, [rn - rm] */ - arm_access_memory(store, - reg[rm], half_reg, u16, no, no_op); - } - else - { - /* SWP rd, rm, [rn] */ - arm_swap(u32); - } - } - else - { - /* MRS rd, cpsr */ - arm_psr(reg, read, reg[REG_CPSR]); - } - break; - - case 0x11: - if((opcode & 0x90) == 0x90) - { - switch((opcode >> 5) & 0x03) - { - case 1: - /* LDRH rd, [rn - rm] */ - arm_access_memory(load, - reg[rm], half_reg, u16, no, no_op); - break; - - case 2: - /* LDRSB rd, [rn - rm] */ - arm_access_memory(load, - reg[rm], half_reg, s8, no, no_op); - break; - - case 3: - /* LDRSH rd, [rn - rm] */ - arm_access_memory(load, - reg[rm], half_reg, s16, no, no_op); - break; - } - } - else - { - /* TST rd, rn, reg_op */ - arm_data_proc_test_logic(reg[rn] & reg_sh, reg); - } - break; - - case 0x12: - if((opcode & 0x90) == 0x90) - { - /* STRH rd, [rn - rm]! */ - arm_access_memory(store, - reg[rm], half_reg, u16, yes, no_op); - } - else - { - if(opcode & 0x10) - { - /* BX rn */ - arm_decode_branchx(opcode); - u32 src = reg[rn]; - if(src & 0x01) - { - src -= 1; - arm_pc_offset_update_direct(src); - reg[REG_CPSR] |= 0x20; - goto thumb_loop; - } - else - { - arm_pc_offset_update_direct(src); - } - } - 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, - reg[rm], half_reg, u16, yes, no_op); - break; - - case 2: - /* LDRSB rd, [rn - rm]! */ - arm_access_memory(load, - reg[rm], half_reg, s8, yes, no_op); - break; - - case 3: - /* LDRSH rd, [rn - rm]! */ - arm_access_memory(load, - reg[rm], half_reg, s16, yes, no_op); - break; - } - } - else - { - /* TEQ rd, rn, reg_op */ - arm_data_proc_test_logic(reg[rn] ^ reg_sh, reg); - } - break; - - case 0x14: - if((opcode & 0x90) == 0x90) - { - if(opcode & 0x20) - { - /* STRH rd, [rn - imm] */ - arm_access_memory(store, - offset, half_imm, u16, no, no_op); - } - else - { - /* SWPB rd, rm, [rn] */ - arm_swap(u8); - } - } - else - { - /* MRS rd, spsr */ - arm_psr(reg, read, spsr[reg[CPU_MODE]]); - } - break; - - case 0x15: - if((opcode & 0x90) == 0x90) - { - switch((opcode >> 5) & 0x03) - { - case 1: - /* LDRH rd, [rn - imm] */ - arm_access_memory(load, - offset, half_imm, u16, no, no_op); - break; - - case 2: - /* LDRSB rd, [rn - imm] */ - arm_access_memory(load, - offset, half_imm, s8, no, no_op); - break; - - case 3: - /* LDRSH rd, [rn - imm] */ - arm_access_memory(load, - offset, half_imm, s16, no, no_op); - break; - } - } - else - { - /* CMP rn, reg_op */ - arm_data_proc_test_sub(reg[rn], reg_sh, reg); - } - break; - - case 0x16: - if((opcode & 0x90) == 0x90) - { - /* STRH rd, [rn - imm]! */ - arm_access_memory(store, - offset, half_imm, u16, yes, no_op); - } - 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, - offset, half_imm, u16, yes, no_op); - break; - - case 2: - /* LDRSB rd, [rn - imm]! */ - arm_access_memory(load, - offset, half_imm, s8, yes, no_op); - break; - - case 3: - /* LDRSH rd, [rn - imm]! */ - arm_access_memory(load, - offset, half_imm, s16, yes, no_op); - break; - } - } - else - { - /* CMN rd, rn, reg_op */ - arm_data_proc_test_add(reg[rn], reg_sh, reg); - } - break; - - case 0x18: - if((opcode & 0x90) == 0x90) - { - /* STRH rd, [rn + rm] */ - arm_access_memory(store, + reg[rm], half_reg, u16, no, no_op); - } - else - { - /* ORR rd, rn, reg_op */ - arm_data_proc(reg[rn] | reg_sh, reg); - } - break; - - case 0x19: - if((opcode & 0x90) == 0x90) - { - switch((opcode >> 5) & 0x03) - { - case 1: - /* LDRH rd, [rn + rm] */ - arm_access_memory(load, + reg[rm], half_reg, u16, no, no_op); - break; - - case 2: - /* LDRSB rd, [rn + rm] */ - arm_access_memory(load, + reg[rm], half_reg, s8, no, no_op); - break; - - case 3: - /* LDRSH rd, [rn + rm] */ - arm_access_memory(load, + reg[rm], half_reg, s16, no, no_op); - break; - } - } - else - { - /* ORRS rd, rn, reg_op */ - arm_data_proc_logic_flags(reg[rn] | reg_sh, reg); - } - break; - - case 0x1A: - if((opcode & 0x90) == 0x90) - { - /* STRH rd, [rn + rm]! */ - arm_access_memory(store, + reg[rm], half_reg, u16, yes, no_op); - } - else - { - /* MOV rd, reg_op */ - arm_data_proc(reg_sh, reg); - } - break; - - case 0x1B: - if((opcode & 0x90) == 0x90) - { - switch((opcode >> 5) & 0x03) - { - case 1: - /* LDRH rd, [rn + rm]! */ - arm_access_memory(load, + reg[rm], half_reg, u16, yes, no_op); - break; - - case 2: - /* LDRSB rd, [rn + rm]! */ - arm_access_memory(load, + reg[rm], half_reg, s8, yes, no_op); - break; - - case 3: - /* LDRSH rd, [rn + rm]! */ - arm_access_memory(load, + reg[rm], half_reg, s16, yes, no_op); - break; - } - } - else - { - /* MOVS rd, reg_op */ - arm_data_proc_logic_flags(reg_sh, reg); - } - break; - - case 0x1C: - if((opcode & 0x90) == 0x90) - { - /* STRH rd, [rn + imm] */ - arm_access_memory(store, + offset, half_imm, u16, no, no_op); - } - else - { - /* BIC rd, rn, reg_op */ - arm_data_proc(reg[rn] & (~reg_sh), reg); - } - break; - - case 0x1D: - if((opcode & 0x90) == 0x90) - { - switch((opcode >> 5) & 0x03) - { - case 1: - /* LDRH rd, [rn + imm] */ - arm_access_memory(load, + offset, half_imm, u16, no, no_op); - break; - - case 2: - /* LDRSB rd, [rn + imm] */ - arm_access_memory(load, + offset, half_imm, s8, no, no_op); - break; - - case 3: - /* LDRSH rd, [rn + imm] */ - arm_access_memory(load, + offset, half_imm, s16, no, no_op); - break; - } - } - else - { - /* BICS rd, rn, reg_op */ - arm_data_proc_logic_flags(reg[rn] & (~reg_sh), reg); - } - break; - - case 0x1E: - if((opcode & 0x90) == 0x90) - { - /* STRH rd, [rn + imm]! */ - arm_access_memory(store, + offset, half_imm, u16, yes, no_op); - } - else - { - /* MVN rd, reg_op */ - arm_data_proc(~reg_sh, reg); - } - break; - - case 0x1F: - if((opcode & 0x90) == 0x90) - { - switch((opcode >> 5) & 0x03) - { - case 1: - /* LDRH rd, [rn + imm]! */ - arm_access_memory(load, + offset, half_imm, u16, yes, no_op); - break; - - case 2: - /* LDRSB rd, [rn + imm]! */ - arm_access_memory(load, + offset, half_imm, s8, yes, no_op); - break; - - case 3: - /* LDRSH rd, [rn + imm]! */ - arm_access_memory(load, + offset, half_imm, s16, yes, no_op); - break; - } - } - else - { - /* MVNS rd, rn, reg_op */ - arm_data_proc_logic_flags(~reg_sh, reg); - } - break; - - case 0x20: - /* AND rd, rn, imm */ - arm_data_proc(reg[rn] & imm, imm); - break; - - case 0x21: - /* ANDS rd, rn, imm */ - arm_data_proc_logic_flags(reg[rn] & imm, imm); - break; - - case 0x22: - /* EOR rd, rn, imm */ - arm_data_proc(reg[rn] ^ imm, imm); - break; - - case 0x23: - /* EORS rd, rn, imm */ - arm_data_proc_logic_flags(reg[rn] ^ imm, imm); - break; - - case 0x24: - /* SUB rd, rn, imm */ - arm_data_proc(reg[rn] - imm, imm); - break; - - case 0x25: - /* SUBS rd, rn, imm */ - arm_data_proc_sub_flags(reg[rn], imm, imm); - break; - - case 0x26: - /* RSB rd, rn, imm */ - arm_data_proc(imm - reg[rn], imm); - break; - - case 0x27: - /* RSBS rd, rn, imm */ - arm_data_proc_sub_flags(imm, reg[rn], imm); - break; - - case 0x28: - /* ADD rd, rn, imm */ - arm_data_proc(reg[rn] + imm, imm); - break; - - case 0x29: - /* ADDS rd, rn, imm */ - arm_data_proc_add_flags(reg[rn], imm, imm); - break; - - case 0x2A: - /* ADC rd, rn, imm */ - arm_data_proc(reg[rn] + imm + c_flag, imm); - break; - - case 0x2B: - /* ADCS rd, rn, imm */ - arm_data_proc_add_flags(reg[rn] + imm, c_flag, imm); - break; - - case 0x2C: - /* SBC rd, rn, imm */ - arm_data_proc(reg[rn] - imm + c_flag - 1, imm); - break; - - case 0x2D: - /* SBCS rd, rn, imm */ - arm_data_proc_sub_flags(reg[rn], (imm + (c_flag ^ 1)), imm); - break; - - case 0x2E: - /* RSC rd, rn, imm */ - arm_data_proc(imm - reg[rn] + c_flag - 1, imm); - break; - - case 0x2F: - /* RSCS rd, rn, imm */ - arm_data_proc_sub_flags((imm + c_flag - 1), reg[rn], imm); - break; - - case 0x30: - case 0x31: - /* TST rn, imm */ - arm_data_proc_test_logic(reg[rn] & imm, imm); - break; - - case 0x32: - /* MSR cpsr, imm */ - arm_psr(imm, store, cpsr); - break; - - case 0x33: - /* TEQ rn, imm */ - arm_data_proc_test_logic(reg[rn] ^ imm, imm); - break; - - case 0x34: - case 0x35: - /* CMP rn, imm */ - arm_data_proc_test_sub(reg[rn], imm, imm); - break; - - case 0x36: - /* MSR spsr, imm */ - arm_psr(imm, store, spsr); - break; - - case 0x37: - /* CMN rn, imm */ - arm_data_proc_test_add(reg[rn], imm, imm); - break; - - case 0x38: - /* ORR rd, rn, imm */ - arm_data_proc(reg[rn] | imm, imm); - break; - - case 0x39: - /* ORRS rd, rn, imm */ - arm_data_proc_logic_flags(reg[rn] | imm, imm); - break; - - case 0x3A: - /* MOV rd, imm */ - arm_data_proc(imm, imm); - break; - - case 0x3B: - /* MOVS rd, imm */ - arm_data_proc_logic_flags(imm, imm); - break; - - case 0x3C: - /* BIC rd, rn, imm */ - arm_data_proc(reg[rn] & (~imm), imm); - break; - - case 0x3D: - /* BICS rd, rn, imm */ - arm_data_proc_logic_flags(reg[rn] & (~imm), imm); - break; - - case 0x3E: - /* MVN rd, imm */ - arm_data_proc(~imm, imm); - break; - - case 0x3F: - /* MVNS rd, imm */ - arm_data_proc_logic_flags(~imm, imm); - break; - - case 0x40: - /* STR rd, [rn], -imm */ - arm_access_memory(store, no_op, imm, u32, yes, - offset); - break; - - case 0x41: - /* LDR rd, [rn], -imm */ - arm_access_memory(load, no_op, imm, u32, yes, - offset); - break; - - case 0x42: - /* STRT rd, [rn], -imm */ - arm_access_memory(store, no_op, imm, u32, yes, - offset); - break; - - case 0x43: - /* LDRT rd, [rn], -imm */ - arm_access_memory(load, no_op, imm, u32, yes, - offset); - break; - - case 0x44: - /* STRB rd, [rn], -imm */ - arm_access_memory(store, no_op, imm, u8, yes, - offset); - break; - - case 0x45: - /* LDRB rd, [rn], -imm */ - arm_access_memory(load, no_op, imm, u8, yes, - offset); - break; - - case 0x46: - /* STRBT rd, [rn], -imm */ - arm_access_memory(store, no_op, imm, u8, yes, - offset); - break; - - case 0x47: - /* LDRBT rd, [rn], -imm */ - arm_access_memory(load, no_op, imm, u8, yes, - offset); - break; - - case 0x48: - /* STR rd, [rn], +imm */ - arm_access_memory(store, no_op, imm, u32, yes, + offset); - break; - - case 0x49: - /* LDR rd, [rn], +imm */ - arm_access_memory(load, no_op, imm, u32, yes, + offset); - break; - - case 0x4A: - /* STRT rd, [rn], +imm */ - arm_access_memory(store, no_op, imm, u32, yes, + offset); - break; - - case 0x4B: - /* LDRT rd, [rn], +imm */ - arm_access_memory(load, no_op, imm, u32, yes, + offset); - break; - - case 0x4C: - /* STRB rd, [rn], +imm */ - arm_access_memory(store, no_op, imm, u8, yes, + offset); - break; - - case 0x4D: - /* LDRB rd, [rn], +imm */ - arm_access_memory(load, no_op, imm, u8, yes, + offset); - break; - - case 0x4E: - /* STRBT rd, [rn], +imm */ - arm_access_memory(store, no_op, imm, u8, yes, + offset); - break; - - case 0x4F: - /* LDRBT rd, [rn], +imm */ - arm_access_memory(load, no_op, imm, u8, yes, + offset); - break; - - case 0x50: - /* STR rd, [rn - imm] */ - arm_access_memory(store, - offset, imm, u32, no, no_op); - break; - - case 0x51: - /* LDR rd, [rn - imm] */ - arm_access_memory(load, - offset, imm, u32, no, no_op); - break; - - case 0x52: - /* STR rd, [rn - imm]! */ - arm_access_memory(store, - offset, imm, u32, yes, no_op); - break; - - case 0x53: - /* LDR rd, [rn - imm]! */ - arm_access_memory(load, - offset, imm, u32, yes, no_op); - break; - - case 0x54: - /* STRB rd, [rn - imm] */ - arm_access_memory(store, - offset, imm, u8, no, no_op); - break; - - case 0x55: - /* LDRB rd, [rn - imm] */ - arm_access_memory(load, - offset, imm, u8, no, no_op); - break; - - case 0x56: - /* STRB rd, [rn - imm]! */ - arm_access_memory(store, - offset, imm, u8, yes, no_op); - break; - - case 0x57: - /* LDRB rd, [rn - imm]! */ - arm_access_memory(load, - offset, imm, u8, yes, no_op); - break; - - case 0x58: - /* STR rd, [rn + imm] */ - arm_access_memory(store, + offset, imm, u32, no, no_op); - break; - - case 0x59: - /* LDR rd, [rn + imm] */ - arm_access_memory(load, + offset, imm, u32, no, no_op); - break; - - case 0x5A: - /* STR rd, [rn + imm]! */ - arm_access_memory(store, + offset, imm, u32, yes, no_op); - break; - - case 0x5B: - /* LDR rd, [rn + imm]! */ - arm_access_memory(load, + offset, imm, u32, yes, no_op); - break; - - case 0x5C: - /* STRB rd, [rn + imm] */ - arm_access_memory(store, + offset, imm, u8, no, no_op); - break; - - case 0x5D: - /* LDRB rd, [rn + imm] */ - arm_access_memory(load, + offset, imm, u8, no, no_op); - break; - - case 0x5E: - /* STRB rd, [rn + imm]! */ - arm_access_memory(store, + offset, imm, u8, yes, no_op); - break; - - case 0x5F: - /* LDRBT rd, [rn + imm]! */ - arm_access_memory(load, + offset, imm, u8, yes, no_op); - break; - - case 0x60: - /* STR rd, [rn], -reg_op */ - arm_access_memory(store, no_op, reg, u32, yes, - reg_offset); - break; - - case 0x61: - /* LDR rd, [rn], -reg_op */ - arm_access_memory(load, no_op, reg, u32, yes, - reg_offset); - break; - - case 0x62: - /* STRT rd, [rn], -reg_op */ - arm_access_memory(store, no_op, reg, u32, yes, - reg_offset); - break; - - case 0x63: - /* LDRT rd, [rn], -reg_op */ - arm_access_memory(load, no_op, reg, u32, yes, - reg_offset); - break; - - case 0x64: - /* STRB rd, [rn], -reg_op */ - arm_access_memory(store, no_op, reg, u8, yes, - reg_offset); - break; - - case 0x65: - /* LDRB rd, [rn], -reg_op */ - arm_access_memory(load, no_op, reg, u8, yes, - reg_offset); - break; - - case 0x66: - /* STRBT rd, [rn], -reg_op */ - arm_access_memory(store, no_op, reg, u8, yes, - reg_offset); - break; - - case 0x67: - /* LDRBT rd, [rn], -reg_op */ - arm_access_memory(load, no_op, reg, u8, yes, - reg_offset); - break; - - case 0x68: - /* STR rd, [rn], +reg_op */ - arm_access_memory(store, no_op, reg, u32, yes, + reg_offset); - break; - - case 0x69: - /* LDR rd, [rn], +reg_op */ - arm_access_memory(load, no_op, reg, u32, yes, + reg_offset); - break; - - case 0x6A: - /* STRT rd, [rn], +reg_op */ - arm_access_memory(store, no_op, reg, u32, yes, + reg_offset); - break; - - case 0x6B: - /* LDRT rd, [rn], +reg_op */ - arm_access_memory(load, no_op, reg, u32, yes, + reg_offset); - break; - - case 0x6C: - /* STRB rd, [rn], +reg_op */ - arm_access_memory(store, no_op, reg, u8, yes, + reg_offset); - break; - - case 0x6D: - /* LDRB rd, [rn], +reg_op */ - arm_access_memory(load, no_op, reg, u8, yes, + reg_offset); - break; - - case 0x6E: - /* STRBT rd, [rn], +reg_op */ - arm_access_memory(store, no_op, reg, u8, yes, + reg_offset); - break; - - case 0x6F: - /* LDRBT rd, [rn], +reg_op */ - arm_access_memory(load, no_op, reg, u8, yes, + reg_offset); - break; - - case 0x70: - /* STR rd, [rn - reg_op] */ - arm_access_memory(store, - reg_offset, reg, u32, no, no_op); - break; - - case 0x71: - /* LDR rd, [rn - reg_op] */ - arm_access_memory(load, - reg_offset, reg, u32, no, no_op); - break; - - case 0x72: - /* STR rd, [rn - reg_op]! */ - arm_access_memory(store, - reg_offset, reg, u32, yes, no_op); - break; - - case 0x73: - /* LDR rd, [rn - reg_op]! */ - arm_access_memory(load, - reg_offset, reg, u32, yes, no_op); - break; - - case 0x74: - /* STRB rd, [rn - reg_op] */ - arm_access_memory(store, - reg_offset, reg, u8, no, no_op); - break; - - case 0x75: - /* LDRB rd, [rn - reg_op] */ - arm_access_memory(load, - reg_offset, reg, u8, no, no_op); - break; - - case 0x76: - /* STRB rd, [rn - reg_op]! */ - arm_access_memory(store, - reg_offset, reg, u8, yes, no_op); - break; - - case 0x77: - /* LDRB rd, [rn - reg_op]! */ - arm_access_memory(load, - reg_offset, reg, u8, yes, no_op); - break; - - case 0x78: - /* STR rd, [rn + reg_op] */ - arm_access_memory(store, + reg_offset, reg, u32, no, no_op); - break; - - case 0x79: - /* LDR rd, [rn + reg_op] */ - arm_access_memory(load, + reg_offset, reg, u32, no, no_op); - break; - - case 0x7A: - /* STR rd, [rn + reg_op]! */ - arm_access_memory(store, + reg_offset, reg, u32, yes, no_op); - break; - - case 0x7B: - /* LDR rd, [rn + reg_op]! */ - arm_access_memory(load, + reg_offset, reg, u32, yes, no_op); - break; - - case 0x7C: - /* STRB rd, [rn + reg_op] */ - arm_access_memory(store, + reg_offset, reg, u8, no, no_op); - break; - - case 0x7D: - /* LDRB rd, [rn + reg_op] */ - arm_access_memory(load, + reg_offset, reg, u8, no, no_op); - break; - - case 0x7E: - /* STRB rd, [rn + reg_op]! */ - arm_access_memory(store, + reg_offset, reg, u8, yes, no_op); - break; - - case 0x7F: - /* LDRBT rd, [rn + reg_op]! */ - arm_access_memory(load, + reg_offset, reg, u8, yes, no_op); - 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: - case 0xA1: - case 0xA2: - case 0xA3: - case 0xA4: - case 0xA5: - case 0xA6: - case 0xA7: - case 0xA8: - case 0xA9: - case 0xAA: - case 0xAB: - case 0xAC: - case 0xAD: - case 0xAE: - case 0xAF: - { - /* B offset */ - arm_decode_branch(); - arm_pc_offset_update(offset + 8); - break; - } - - case 0xB0: - case 0xB1: - case 0xB2: - case 0xB3: - case 0xB4: - case 0xB5: - case 0xB6: - case 0xB7: - case 0xB8: - case 0xB9: - case 0xBA: - case 0xBB: - case 0xBC: - case 0xBD: - case 0xBE: - case 0xBF: - { - /* BL offset */ - arm_decode_branch(); - reg[REG_LR] = pc + 4; - arm_pc_offset_update(offset + 8); - break; - } + case 0x4: + /* MI */ + if(!n_flag) + arm_next_instruction(); + break; -#ifdef HAVE_UNUSED - case 0xC0 ... 0xEF: - /* coprocessor instructions, reserved on GBA */ - break; -#endif + case 0x5: + /* PL */ + if(n_flag) + arm_next_instruction(); + break; - case 0xF0: - case 0xF1: - case 0xF2: - case 0xF3: - case 0xF4: - case 0xF5: - case 0xF6: - case 0xF7: - case 0xF8: - case 0xF9: - case 0xFA: - case 0xFB: - case 0xFC: - case 0xFD: - case 0xFE: - case 0xFF: - { - /* SWI comment */ - u32 swi_comment = opcode & 0x00FFFFFF; - - switch(swi_comment >> 16) - { - /* Jump to BIOS SWI handler */ - default: - reg_mode[MODE_SUPERVISOR][6] = pc + 4; - collapse_flags(); - spsr[MODE_SUPERVISOR] = reg[REG_CPSR]; - reg[REG_PC] = 0x00000008; - arm_update_pc(); - reg[REG_CPSR] = (reg[REG_CPSR] & ~0x1F) | 0x13; - set_cpu_mode(MODE_SUPERVISOR); - break; - } - break; - } - } - -skip_instruction: + case 0x6: + /* VS */ + if(!v_flag) + arm_next_instruction(); + break; - /* End of Execute ARM instruction */ - cycles_remaining -= cycles_per_instruction; + case 0x7: + /* VC */ + if(v_flag) + arm_next_instruction(); + break; - if (pc == idle_loop_target_pc && cycles_remaining > 0) cycles_remaining = 0; - } while(cycles_remaining > 0); + case 0x8: + /* HI */ + if((c_flag == 0) | z_flag) + arm_next_instruction(); + break; - collapse_flags(); - cycles_remaining = update_gba(); - if (reg[COMPLETED_FRAME]) - return; - continue; + case 0x9: + /* LS */ + if(c_flag & (z_flag ^ 1)) + arm_next_instruction(); + break; - do - { -thumb_loop: + case 0xA: + /* GE */ + if(n_flag != v_flag) + arm_next_instruction(); + break; - collapse_flags(); + case 0xB: + /* LT */ + if(n_flag == v_flag) + arm_next_instruction(); + break; - /* Process cheats if we are about to execute the cheat hook */ - if (pc == cheat_master_hook) - process_cheats(); + case 0xC: + /* GT */ + if(z_flag | (n_flag != v_flag)) + arm_next_instruction(); + break; - old_pc = pc; + case 0xD: + /* LE */ + if((z_flag == 0) & (n_flag == v_flag)) + arm_next_instruction(); + break; - /* Execute THUMB instruction */ + case 0xE: + /* AL */ + break; - using_instruction(thumb); - check_pc_region(); - pc &= ~0x01; - opcode = address16(pc_address_block, (pc & 0x7FFF)); + case 0xF: + /* Reserved - treat as "never" */ + arm_next_instruction(); + break; + } - switch((opcode >> 8) & 0xFF) - { + switch((opcode >> 20) & 0xFF) + { case 0x00: + if((opcode & 0x90) == 0x90) + { + if(opcode & 0x20) + { + /* STRH rd, [rn], -rm */ + arm_access_memory(store, no_op, half_reg, u16, yes, - reg[rm]); + } + else + { + /* MUL rd, rm, rs */ + arm_multiply(no_op, no); + } + } + else + { + /* AND rd, rn, reg_op */ + arm_data_proc(reg[rn] & reg_sh, reg); + } + break; + case 0x01: + if((opcode & 0x90) == 0x90) + { + switch((opcode >> 5) & 0x03) + { + case 0: + /* MULS rd, rm, rs */ + arm_multiply(no_op, yes); + break; + + case 1: + /* LDRH rd, [rn], -rm */ + arm_access_memory(load, no_op, half_reg, u16, yes, - reg[rm]); + break; + + case 2: + /* LDRSB rd, [rn], -rm */ + arm_access_memory(load, no_op, half_reg, s8, yes, - reg[rm]); + break; + + case 3: + /* LDRSH rd, [rn], -rm */ + arm_access_memory(load, no_op, half_reg, s16, yes, - reg[rm]); + break; + } + } + else + { + /* ANDS rd, rn, reg_op */ + arm_data_proc_logic_flags(reg[rn] & reg_sh, reg); + } + break; + case 0x02: + if((opcode & 0x90) == 0x90) + { + if(opcode & 0x20) + { + /* STRH rd, [rn], -rm */ + arm_access_memory(store, no_op, half_reg, u16, yes, - reg[rm]); + } + else + { + /* MLA rd, rm, rs, rn */ + arm_multiply(+ reg[rn], no); + } + } + else + { + /* EOR rd, rn, reg_op */ + arm_data_proc(reg[rn] ^ reg_sh, reg); + } + break; + case 0x03: + if((opcode & 0x90) == 0x90) + { + switch((opcode >> 5) & 0x03) + { + case 0: + /* MLAS rd, rm, rs, rn */ + arm_multiply(+ reg[rn], yes); + break; + + case 1: + /* LDRH rd, [rn], -rm */ + arm_access_memory(load, no_op, half_reg, u16, yes, - reg[rm]); + break; + + case 2: + /* LDRSB rd, [rn], -rm */ + arm_access_memory(load, no_op, half_reg, s8, yes, - reg[rm]); + break; + + case 3: + /* LDRSH rd, [rn], -rm */ + arm_access_memory(load, no_op, half_reg, s16, yes, - reg[rm]); + break; + } + } + else + { + /* EORS rd, rn, reg_op */ + arm_data_proc_logic_flags(reg[rn] ^ reg_sh, reg); + } + break; + case 0x04: + if((opcode & 0x90) == 0x90) + { + /* STRH rd, [rn], -imm */ + arm_access_memory(store, no_op, half_imm, u16, yes, - offset); + } + else + { + /* SUB rd, rn, reg_op */ + arm_data_proc(reg[rn] - reg_sh, reg); + } + break; + case 0x05: + if((opcode & 0x90) == 0x90) + { + switch((opcode >> 5) & 0x03) + { + case 1: + /* LDRH rd, [rn], -imm */ + arm_access_memory(load, no_op, half_imm, u16, yes, - offset); + break; + + case 2: + /* LDRSB rd, [rn], -imm */ + arm_access_memory(load, no_op, half_imm, s8, yes, - offset); + break; + + case 3: + /* LDRSH rd, [rn], -imm */ + arm_access_memory(load, no_op, half_imm, s16, yes, - offset); + break; + } + } + else + { + /* SUBS rd, rn, reg_op */ + arm_data_proc_sub_flags(reg[rn], reg_sh, reg); + } + break; + case 0x06: - case 0x07: - /* LSL rd, rs, offset */ - thumb_shift(shift, lsl, imm); - break; + if((opcode & 0x90) == 0x90) + { + /* STRH rd, [rn], -imm */ + arm_access_memory(store, no_op, half_imm, u16, yes, - offset); + } + else + { + /* RSB rd, rn, reg_op */ + arm_data_proc(reg_sh - reg[rn], reg); + } + break; + + case 0x07: + if((opcode & 0x90) == 0x90) + { + switch((opcode >> 5) & 0x03) + { + case 1: + /* LDRH rd, [rn], -imm */ + arm_access_memory(load, no_op, half_imm, u16, yes, - offset); + break; + + case 2: + /* LDRSB rd, [rn], -imm */ + arm_access_memory(load, no_op, half_imm, s8, yes, - offset); + break; + + case 3: + /* LDRSH rd, [rn], -imm */ + arm_access_memory(load, no_op, half_imm, s16, yes, - offset); + break; + } + } + else + { + /* RSBS rd, rn, reg_op */ + arm_data_proc_sub_flags(reg_sh, reg[rn], reg); + } + break; case 0x08: + if((opcode & 0x90) == 0x90) + { + if(opcode & 0x20) + { + /* STRH rd, [rn], +rm */ + arm_access_memory(store, no_op, half_reg, u16, yes, + reg[rm]); + } + else + { + /* UMULL rd, rm, rs */ + arm_multiply_long(no_op, no, u); + } + } + else + { + /* ADD rd, rn, reg_op */ + arm_data_proc(reg[rn] + reg_sh, reg); + } + break; + case 0x09: + if((opcode & 0x90) == 0x90) + { + switch((opcode >> 5) & 0x03) + { + case 0: + /* UMULLS rdlo, rdhi, rm, rs */ + arm_multiply_long(no_op, yes, u); + break; + + case 1: + /* LDRH rd, [rn], +rm */ + arm_access_memory(load, no_op, half_reg, u16, yes, + reg[rm]); + break; + + case 2: + /* LDRSB rd, [rn], +rm */ + arm_access_memory(load, no_op, half_reg, s8, yes, + reg[rm]); + break; + + case 3: + /* LDRSH rd, [rn], +rm */ + arm_access_memory(load, no_op, half_reg, s16, yes, + reg[rm]); + break; + } + } + else + { + /* ADDS rd, rn, reg_op */ + arm_data_proc_add_flags(reg[rn], reg_sh, reg); + } + break; + case 0x0A: + if((opcode & 0x90) == 0x90) + { + if(opcode & 0x20) + { + /* STRH rd, [rn], +rm */ + arm_access_memory(store, no_op, half_reg, u16, yes, + reg[rm]); + } + else + { + /* UMLAL rd, rm, rs */ + arm_multiply_long(arm_multiply_long_addop(u), no, u); + } + } + else + { + /* ADC rd, rn, reg_op */ + arm_data_proc(reg[rn] + reg_sh + c_flag, reg); + } + break; + case 0x0B: + if((opcode & 0x90) == 0x90) + { + switch((opcode >> 5) & 0x03) + { + case 0: + /* UMLALS rdlo, rdhi, rm, rs */ + arm_multiply_long(arm_multiply_long_addop(u), yes, u); + break; + + case 1: + /* LDRH rd, [rn], +rm */ + arm_access_memory(load, no_op, half_reg, u16, yes, + reg[rm]); + break; + + case 2: + /* LDRSB rd, [rn], +rm */ + arm_access_memory(load, no_op, half_reg, s8, yes, + reg[rm]); + break; + + case 3: + /* LDRSH rd, [rn], +rm */ + arm_access_memory(load, no_op, half_reg, s16, yes, + reg[rm]); + break; + } + } + else + { + /* ADCS rd, rn, reg_op */ + arm_data_proc_add_flags(reg[rn], reg_sh + c_flag, reg); + } + break; + case 0x0C: + if((opcode & 0x90) == 0x90) + { + if(opcode & 0x20) + { + /* STRH rd, [rn], +imm */ + arm_access_memory(store, no_op, half_imm, u16, yes, + offset); + } + else + { + /* SMULL rd, rm, rs */ + arm_multiply_long(no_op, no, s); + } + } + else + { + /* SBC rd, rn, reg_op */ + arm_data_proc(reg[rn] - (reg_sh + (c_flag ^ 1)), reg); + } + break; + case 0x0D: + if((opcode & 0x90) == 0x90) + { + switch((opcode >> 5) & 0x03) + { + case 0: + /* SMULLS rdlo, rdhi, rm, rs */ + arm_multiply_long(no_op, yes, s); + break; + + case 1: + /* LDRH rd, [rn], +imm */ + arm_access_memory(load, no_op, half_imm, u16, yes, + offset); + break; + + case 2: + /* LDRSB rd, [rn], +imm */ + arm_access_memory(load, no_op, half_imm, s8, yes, + offset); + break; + + case 3: + /* LDRSH rd, [rn], +imm */ + arm_access_memory(load, no_op, half_imm, s16, yes, + offset); + break; + } + } + else + { + /* SBCS rd, rn, reg_op */ + arm_data_proc_sub_flags(reg[rn], (reg_sh + (c_flag ^ 1)), reg); + } + break; + case 0x0E: - case 0x0F: - /* LSR rd, rs, offset */ - thumb_shift(shift, lsr, imm); - break; + if((opcode & 0x90) == 0x90) + { + if(opcode & 0x20) + { + /* STRH rd, [rn], +imm */ + arm_access_memory(store, no_op, half_imm, u16, yes, + offset); + } + else + { + /* SMLAL rd, rm, rs */ + arm_multiply_long(arm_multiply_long_addop(s), no, s); + } + } + else + { + /* RSC rd, rn, reg_op */ + arm_data_proc(reg_sh - reg[rn] + c_flag - 1, reg); + } + break; + + case 0x0F: + if((opcode & 0x90) == 0x90) + { + switch((opcode >> 5) & 0x03) + { + case 0: + /* SMLALS rdlo, rdhi, rm, rs */ + arm_multiply_long(arm_multiply_long_addop(s), yes, s); + break; + + case 1: + /* LDRH rd, [rn], +imm */ + arm_access_memory(load, no_op, half_imm, u16, yes, + offset); + break; + + case 2: + /* LDRSB rd, [rn], +imm */ + arm_access_memory(load, no_op, half_imm, s8, yes, + offset); + break; + + case 3: + /* LDRSH rd, [rn], +imm */ + arm_access_memory(load, no_op, half_imm, s16, yes, + offset); + break; + } + } + else + { + /* RSCS rd, rn, reg_op */ + arm_data_proc_sub_flags((reg_sh + c_flag - 1), reg[rn], reg); + } + break; case 0x10: + if((opcode & 0x90) == 0x90) + { + if(opcode & 0x20) + { + /* STRH rd, [rn - rm] */ + arm_access_memory(store, - reg[rm], half_reg, u16, no, no_op); + } + else + { + /* SWP rd, rm, [rn] */ + arm_swap(u32); + } + } + else + { + /* MRS rd, cpsr */ + arm_psr(reg, read, reg[REG_CPSR]); + } + break; + case 0x11: + if((opcode & 0x90) == 0x90) + { + switch((opcode >> 5) & 0x03) + { + case 1: + /* LDRH rd, [rn - rm] */ + arm_access_memory(load, - reg[rm], half_reg, u16, no, no_op); + break; + + case 2: + /* LDRSB rd, [rn - rm] */ + arm_access_memory(load, - reg[rm], half_reg, s8, no, no_op); + break; + + case 3: + /* LDRSH rd, [rn - rm] */ + arm_access_memory(load, - reg[rm], half_reg, s16, no, no_op); + break; + } + } + else + { + /* TST rd, rn, reg_op */ + arm_data_proc_test_logic(reg[rn] & reg_sh, reg); + } + break; + case 0x12: + if((opcode & 0x90) == 0x90) + { + /* STRH rd, [rn - rm]! */ + arm_access_memory(store, - reg[rm], half_reg, u16, yes, no_op); + } + else + { + if(opcode & 0x10) + { + /* BX rn */ + arm_decode_branchx(opcode); + u32 src = reg[rn]; + if(src & 0x01) + { + src -= 1; + arm_pc_offset_update_direct(src); + reg[REG_CPSR] |= 0x20; + goto thumb_loop; + } + else + { + arm_pc_offset_update_direct(src); + } + } + 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, - reg[rm], half_reg, u16, yes, no_op); + break; + + case 2: + /* LDRSB rd, [rn - rm]! */ + arm_access_memory(load, - reg[rm], half_reg, s8, yes, no_op); + break; + + case 3: + /* LDRSH rd, [rn - rm]! */ + arm_access_memory(load, - reg[rm], half_reg, s16, yes, no_op); + break; + } + } + else + { + /* TEQ rd, rn, reg_op */ + arm_data_proc_test_logic(reg[rn] ^ reg_sh, reg); + } + break; + case 0x14: + if((opcode & 0x90) == 0x90) + { + if(opcode & 0x20) + { + /* STRH rd, [rn - imm] */ + arm_access_memory(store, - offset, half_imm, u16, no, no_op); + } + else + { + /* SWPB rd, rm, [rn] */ + arm_swap(u8); + } + } + else + { + /* MRS rd, spsr */ + arm_psr(reg, read, spsr[reg[CPU_MODE]]); + } + break; + case 0x15: + if((opcode & 0x90) == 0x90) + { + switch((opcode >> 5) & 0x03) + { + case 1: + /* LDRH rd, [rn - imm] */ + arm_access_memory(load, - offset, half_imm, u16, no, no_op); + break; + + case 2: + /* LDRSB rd, [rn - imm] */ + arm_access_memory(load, - offset, half_imm, s8, no, no_op); + break; + + case 3: + /* LDRSH rd, [rn - imm] */ + arm_access_memory(load, - offset, half_imm, s16, no, no_op); + break; + } + } + else + { + /* CMP rn, reg_op */ + arm_data_proc_test_sub(reg[rn], reg_sh, reg); + } + break; + case 0x16: - case 0x17: - /* ASR rd, rs, offset */ - thumb_shift(shift, asr, imm); - break; + if((opcode & 0x90) == 0x90) + { + /* STRH rd, [rn - imm]! */ + arm_access_memory(store, - offset, half_imm, u16, yes, no_op); + } + 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, - offset, half_imm, u16, yes, no_op); + break; + + case 2: + /* LDRSB rd, [rn - imm]! */ + arm_access_memory(load, - offset, half_imm, s8, yes, no_op); + break; + + case 3: + /* LDRSH rd, [rn - imm]! */ + arm_access_memory(load, - offset, half_imm, s16, yes, no_op); + break; + } + } + else + { + /* CMN rd, rn, reg_op */ + arm_data_proc_test_add(reg[rn], reg_sh, reg); + } + break; case 0x18: - case 0x19: - /* ADD rd, rs, rn */ - thumb_add(add_sub, rd, reg[rs], reg[rn]); - break; + if((opcode & 0x90) == 0x90) + { + /* STRH rd, [rn + rm] */ + arm_access_memory(store, + reg[rm], half_reg, u16, no, no_op); + } + else + { + /* ORR rd, rn, reg_op */ + arm_data_proc(reg[rn] | reg_sh, reg); + } + break; + + case 0x19: + if((opcode & 0x90) == 0x90) + { + switch((opcode >> 5) & 0x03) + { + case 1: + /* LDRH rd, [rn + rm] */ + arm_access_memory(load, + reg[rm], half_reg, u16, no, no_op); + break; + + case 2: + /* LDRSB rd, [rn + rm] */ + arm_access_memory(load, + reg[rm], half_reg, s8, no, no_op); + break; + + case 3: + /* LDRSH rd, [rn + rm] */ + arm_access_memory(load, + reg[rm], half_reg, s16, no, no_op); + break; + } + } + else + { + /* ORRS rd, rn, reg_op */ + arm_data_proc_logic_flags(reg[rn] | reg_sh, reg); + } + break; case 0x1A: - case 0x1B: - /* SUB rd, rs, rn */ - thumb_sub(add_sub, rd, reg[rs], reg[rn]); - break; + if((opcode & 0x90) == 0x90) + { + /* STRH rd, [rn + rm]! */ + arm_access_memory(store, + reg[rm], half_reg, u16, yes, no_op); + } + else + { + /* MOV rd, reg_op */ + arm_data_proc(reg_sh, reg); + } + break; + + case 0x1B: + if((opcode & 0x90) == 0x90) + { + switch((opcode >> 5) & 0x03) + { + case 1: + /* LDRH rd, [rn + rm]! */ + arm_access_memory(load, + reg[rm], half_reg, u16, yes, no_op); + break; + + case 2: + /* LDRSB rd, [rn + rm]! */ + arm_access_memory(load, + reg[rm], half_reg, s8, yes, no_op); + break; + + case 3: + /* LDRSH rd, [rn + rm]! */ + arm_access_memory(load, + reg[rm], half_reg, s16, yes, no_op); + break; + } + } + else + { + /* MOVS rd, reg_op */ + arm_data_proc_logic_flags(reg_sh, reg); + } + break; case 0x1C: - case 0x1D: - /* ADD rd, rs, imm */ - thumb_add(add_sub_imm, rd, reg[rs], imm); - break; + if((opcode & 0x90) == 0x90) + { + /* STRH rd, [rn + imm] */ + arm_access_memory(store, + offset, half_imm, u16, no, no_op); + } + else + { + /* BIC rd, rn, reg_op */ + arm_data_proc(reg[rn] & (~reg_sh), reg); + } + break; + + case 0x1D: + if((opcode & 0x90) == 0x90) + { + switch((opcode >> 5) & 0x03) + { + case 1: + /* LDRH rd, [rn + imm] */ + arm_access_memory(load, + offset, half_imm, u16, no, no_op); + break; + + case 2: + /* LDRSB rd, [rn + imm] */ + arm_access_memory(load, + offset, half_imm, s8, no, no_op); + break; + + case 3: + /* LDRSH rd, [rn + imm] */ + arm_access_memory(load, + offset, half_imm, s16, no, no_op); + break; + } + } + else + { + /* BICS rd, rn, reg_op */ + arm_data_proc_logic_flags(reg[rn] & (~reg_sh), reg); + } + break; case 0x1E: - case 0x1F: - /* SUB rd, rs, imm */ - thumb_sub(add_sub_imm, rd, reg[rs], imm); - break; - - case 0x20: - /* MOV r0, imm */ - thumb_logic(imm, 0, imm); - break; - - case 0x21: - /* MOV r1, imm */ - thumb_logic(imm, 1, imm); - break; - - case 0x22: - /* MOV r2, imm */ - thumb_logic(imm, 2, imm); - break; - - case 0x23: - /* MOV r3, imm */ - thumb_logic(imm, 3, imm); - break; - - case 0x24: - /* MOV r4, imm */ - thumb_logic(imm, 4, imm); - break; - - case 0x25: - /* MOV r5, imm */ - thumb_logic(imm, 5, imm); - break; - - case 0x26: - /* MOV r6, imm */ - thumb_logic(imm, 6, imm); - break; - - case 0x27: - /* MOV r7, imm */ - thumb_logic(imm, 7, imm); - break; - - case 0x28: - /* CMP r0, imm */ - thumb_test_sub(imm, reg[0], imm); - break; - - case 0x29: - /* CMP r1, imm */ - thumb_test_sub(imm, reg[1], imm); - break; - - case 0x2A: - /* CMP r2, imm */ - thumb_test_sub(imm, reg[2], imm); - break; - - case 0x2B: - /* CMP r3, imm */ - thumb_test_sub(imm, reg[3], imm); - break; - - case 0x2C: - /* CMP r4, imm */ - thumb_test_sub(imm, reg[4], imm); - break; - - case 0x2D: - /* CMP r5, imm */ - thumb_test_sub(imm, reg[5], imm); - break; - - case 0x2E: - /* CMP r6, imm */ - thumb_test_sub(imm, reg[6], imm); - break; - - case 0x2F: - /* CMP r7, imm */ - thumb_test_sub(imm, reg[7], imm); - break; - - case 0x30: - /* ADD r0, imm */ - thumb_add(imm, 0, reg[0], imm); - break; - - case 0x31: - /* ADD r1, imm */ - thumb_add(imm, 1, reg[1], imm); - break; - - case 0x32: - /* ADD r2, imm */ - thumb_add(imm, 2, reg[2], imm); - break; - - case 0x33: - /* ADD r3, imm */ - thumb_add(imm, 3, reg[3], imm); - break; - - case 0x34: - /* ADD r4, imm */ - thumb_add(imm, 4, reg[4], imm); - break; - - case 0x35: - /* ADD r5, imm */ - thumb_add(imm, 5, reg[5], imm); - break; - - case 0x36: - /* ADD r6, imm */ - thumb_add(imm, 6, reg[6], imm); - break; - - case 0x37: - /* ADD r7, imm */ - thumb_add(imm, 7, reg[7], imm); - break; - - case 0x38: - /* SUB r0, imm */ - thumb_sub(imm, 0, reg[0], imm); - break; - - case 0x39: - /* SUB r1, imm */ - thumb_sub(imm, 1, reg[1], imm); - break; - - case 0x3A: - /* SUB r2, imm */ - thumb_sub(imm, 2, reg[2], imm); - break; - - case 0x3B: - /* SUB r3, imm */ - thumb_sub(imm, 3, reg[3], imm); - break; - - case 0x3C: - /* SUB r4, imm */ - thumb_sub(imm, 4, reg[4], imm); - break; - - case 0x3D: - /* SUB r5, imm */ - thumb_sub(imm, 5, reg[5], imm); - break; - - case 0x3E: - /* SUB r6, imm */ - thumb_sub(imm, 6, reg[6], imm); - break; - - case 0x3F: - /* SUB r7, imm */ - thumb_sub(imm, 7, reg[7], imm); - break; - - case 0x40: - switch((opcode >> 6) & 0x03) - { - case 0x00: - /* AND rd, rs */ - thumb_logic(alu_op, rd, reg[rd] & reg[rs]); - break; - - case 0x01: - /* EOR rd, rs */ - thumb_logic(alu_op, rd, reg[rd] ^ reg[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_add(alu_op, rd, reg[rd] + reg[rs], c_flag); - break; - - case 0x02: - /* SBC rd, rs */ - thumb_sub(alu_op, rd, reg[rd] - reg[rs], (c_flag ^ 1)); - 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_test_logic(alu_op, reg[rd] & reg[rs]); - break; - - case 0x01: - /* NEG rd, rs */ - thumb_sub(alu_op, rd, 0, reg[rs]); - break; - - case 0x02: - /* CMP rd, rs */ - thumb_test_sub(alu_op, reg[rd], reg[rs]); - break; - - case 0x03: - /* CMN rd, rs */ - thumb_test_add(alu_op, reg[rd], reg[rs]); - break; - } - break; - - case 0x43: - switch((opcode >> 6) & 0x03) - { - case 0x00: - /* ORR rd, rs */ - thumb_logic(alu_op, rd, reg[rd] | reg[rs]); - break; - - case 0x01: - /* MUL rd, rs */ - thumb_logic(alu_op, rd, reg[rd] * reg[rs]); - break; - - case 0x02: - /* BIC rd, rs */ - thumb_logic(alu_op, rd, reg[rd] & (~reg[rs])); - break; - - case 0x03: - /* MVN rd, rs */ - thumb_logic(alu_op, rd, ~reg[rs]); - break; - } - break; - - case 0x44: - /* ADD rd, rs */ - thumb_hireg_op(reg[rd] + reg[rs]); - break; - - case 0x45: - /* CMP rd, rs */ - { - thumb_pc_offset(4); - thumb_decode_hireg_op(); - u32 _sa = reg[rd]; - u32 _sb = reg[rs]; - u32 dest = _sa - _sb; - thumb_pc_offset(-2); - calculate_flags_sub(dest, _sa, _sb); - } - break; - - case 0x46: - /* MOV rd, rs */ - thumb_hireg_op(reg[rs]); - break; - - case 0x47: - /* BX rs */ - { - thumb_decode_hireg_op(); - u32 src; - thumb_pc_offset(4); - src = reg[rs]; - if(src & 0x01) - { - src -= 1; - thumb_pc_offset_update_direct(src); - } - else - { - /* Switch to ARM mode */ - thumb_pc_offset_update_direct(src); - reg[REG_CPSR] &= ~0x20; - collapse_flags(); - goto arm_loop; - } - } - break; - - case 0x48: - /* LDR r0, [pc + imm] */ - thumb_access_memory(load, imm, (pc & ~2) + (imm * 4) + 4, reg[0], u32); - break; - - case 0x49: - /* LDR r1, [pc + imm] */ - thumb_access_memory(load, imm, (pc & ~2) + (imm * 4) + 4, reg[1], u32); - break; - - case 0x4A: - /* LDR r2, [pc + imm] */ - thumb_access_memory(load, imm, (pc & ~2) + (imm * 4) + 4, reg[2], u32); - break; - - case 0x4B: - /* LDR r3, [pc + imm] */ - thumb_access_memory(load, imm, (pc & ~2) + (imm * 4) + 4, reg[3], u32); - break; - - case 0x4C: - /* LDR r4, [pc + imm] */ - thumb_access_memory(load, imm, (pc & ~2) + (imm * 4) + 4, reg[4], u32); - break; - - case 0x4D: - /* LDR r5, [pc + imm] */ - thumb_access_memory(load, imm, (pc & ~2) + (imm * 4) + 4, reg[5], u32); - break; - - case 0x4E: - /* LDR r6, [pc + imm] */ - thumb_access_memory(load, imm, (pc & ~2) + (imm * 4) + 4, reg[6], u32); - break; - - case 0x4F: - /* LDR r7, [pc + imm] */ - thumb_access_memory(load, imm, (pc & ~2) + (imm * 4) + 4, reg[7], u32); - break; + if((opcode & 0x90) == 0x90) + { + /* STRH rd, [rn + imm]! */ + arm_access_memory(store, + offset, half_imm, u16, yes, no_op); + } + else + { + /* MVN rd, reg_op */ + arm_data_proc(~reg_sh, reg); + } + break; + + case 0x1F: + if((opcode & 0x90) == 0x90) + { + switch((opcode >> 5) & 0x03) + { + case 1: + /* LDRH rd, [rn + imm]! */ + arm_access_memory(load, + offset, half_imm, u16, yes, no_op); + break; + + case 2: + /* LDRSB rd, [rn + imm]! */ + arm_access_memory(load, + offset, half_imm, s8, yes, no_op); + break; + + case 3: + /* LDRSH rd, [rn + imm]! */ + arm_access_memory(load, + offset, half_imm, s16, yes, no_op); + break; + } + } + else + { + /* MVNS rd, rn, reg_op */ + arm_data_proc_logic_flags(~reg_sh, reg); + } + break; + + case 0x20: + /* AND rd, rn, imm */ + arm_data_proc(reg[rn] & imm, imm); + break; + + case 0x21: + /* ANDS rd, rn, imm */ + arm_data_proc_logic_flags(reg[rn] & imm, imm); + break; + + case 0x22: + /* EOR rd, rn, imm */ + arm_data_proc(reg[rn] ^ imm, imm); + break; + + case 0x23: + /* EORS rd, rn, imm */ + arm_data_proc_logic_flags(reg[rn] ^ imm, imm); + break; + + case 0x24: + /* SUB rd, rn, imm */ + arm_data_proc(reg[rn] - imm, imm); + break; + + case 0x25: + /* SUBS rd, rn, imm */ + arm_data_proc_sub_flags(reg[rn], imm, imm); + break; + + case 0x26: + /* RSB rd, rn, imm */ + arm_data_proc(imm - reg[rn], imm); + break; + + case 0x27: + /* RSBS rd, rn, imm */ + arm_data_proc_sub_flags(imm, reg[rn], imm); + break; + + case 0x28: + /* ADD rd, rn, imm */ + arm_data_proc(reg[rn] + imm, imm); + break; + + case 0x29: + /* ADDS rd, rn, imm */ + arm_data_proc_add_flags(reg[rn], imm, imm); + break; + + case 0x2A: + /* ADC rd, rn, imm */ + arm_data_proc(reg[rn] + imm + c_flag, imm); + break; + + case 0x2B: + /* ADCS rd, rn, imm */ + arm_data_proc_add_flags(reg[rn] + imm, c_flag, imm); + break; + + case 0x2C: + /* SBC rd, rn, imm */ + arm_data_proc(reg[rn] - imm + c_flag - 1, imm); + break; + + case 0x2D: + /* SBCS rd, rn, imm */ + arm_data_proc_sub_flags(reg[rn], (imm + (c_flag ^ 1)), imm); + break; + + case 0x2E: + /* RSC rd, rn, imm */ + arm_data_proc(imm - reg[rn] + c_flag - 1, imm); + break; + + case 0x2F: + /* RSCS rd, rn, imm */ + arm_data_proc_sub_flags((imm + c_flag - 1), reg[rn], imm); + break; + + case 0x30: + case 0x31: + /* TST rn, imm */ + arm_data_proc_test_logic(reg[rn] & imm, imm); + break; + + case 0x32: + /* MSR cpsr, imm */ + arm_psr(imm, store, cpsr); + break; + + case 0x33: + /* TEQ rn, imm */ + arm_data_proc_test_logic(reg[rn] ^ imm, imm); + break; + + case 0x34: + case 0x35: + /* CMP rn, imm */ + arm_data_proc_test_sub(reg[rn], imm, imm); + break; + + case 0x36: + /* MSR spsr, imm */ + arm_psr(imm, store, spsr); + break; + + case 0x37: + /* CMN rn, imm */ + arm_data_proc_test_add(reg[rn], imm, imm); + break; + + case 0x38: + /* ORR rd, rn, imm */ + arm_data_proc(reg[rn] | imm, imm); + break; + + case 0x39: + /* ORRS rd, rn, imm */ + arm_data_proc_logic_flags(reg[rn] | imm, imm); + break; + + case 0x3A: + /* MOV rd, imm */ + arm_data_proc(imm, imm); + break; + + case 0x3B: + /* MOVS rd, imm */ + arm_data_proc_logic_flags(imm, imm); + break; + + case 0x3C: + /* BIC rd, rn, imm */ + arm_data_proc(reg[rn] & (~imm), imm); + break; + + case 0x3D: + /* BICS rd, rn, imm */ + arm_data_proc_logic_flags(reg[rn] & (~imm), imm); + break; + + case 0x3E: + /* MVN rd, imm */ + arm_data_proc(~imm, imm); + break; + + case 0x3F: + /* MVNS rd, imm */ + arm_data_proc_logic_flags(~imm, imm); + break; + + case 0x40: + /* STR rd, [rn], -imm */ + arm_access_memory(store, no_op, imm, u32, yes, - offset); + break; + + case 0x41: + /* LDR rd, [rn], -imm */ + arm_access_memory(load, no_op, imm, u32, yes, - offset); + break; + + case 0x42: + /* STRT rd, [rn], -imm */ + arm_access_memory(store, no_op, imm, u32, yes, - offset); + break; + + case 0x43: + /* LDRT rd, [rn], -imm */ + arm_access_memory(load, no_op, imm, u32, yes, - offset); + break; + + case 0x44: + /* STRB rd, [rn], -imm */ + arm_access_memory(store, no_op, imm, u8, yes, - offset); + break; + + case 0x45: + /* LDRB rd, [rn], -imm */ + arm_access_memory(load, no_op, imm, u8, yes, - offset); + break; + + case 0x46: + /* STRBT rd, [rn], -imm */ + arm_access_memory(store, no_op, imm, u8, yes, - offset); + break; + + case 0x47: + /* LDRBT rd, [rn], -imm */ + arm_access_memory(load, no_op, imm, u8, yes, - offset); + break; + + case 0x48: + /* STR rd, [rn], +imm */ + arm_access_memory(store, no_op, imm, u32, yes, + offset); + break; + + case 0x49: + /* LDR rd, [rn], +imm */ + arm_access_memory(load, no_op, imm, u32, yes, + offset); + break; + + case 0x4A: + /* STRT rd, [rn], +imm */ + arm_access_memory(store, no_op, imm, u32, yes, + offset); + break; + + case 0x4B: + /* LDRT rd, [rn], +imm */ + arm_access_memory(load, no_op, imm, u32, yes, + offset); + break; + + case 0x4C: + /* STRB rd, [rn], +imm */ + arm_access_memory(store, no_op, imm, u8, yes, + offset); + break; + + case 0x4D: + /* LDRB rd, [rn], +imm */ + arm_access_memory(load, no_op, imm, u8, yes, + offset); + break; + + case 0x4E: + /* STRBT rd, [rn], +imm */ + arm_access_memory(store, no_op, imm, u8, yes, + offset); + break; + + case 0x4F: + /* LDRBT rd, [rn], +imm */ + arm_access_memory(load, no_op, imm, u8, yes, + offset); + break; case 0x50: - case 0x51: - /* STR rd, [rb + ro] */ - thumb_access_memory(store, mem_reg, reg[rb] + reg[ro], reg[rd], u32); - break; + /* STR rd, [rn - imm] */ + arm_access_memory(store, - offset, imm, u32, no, no_op); + break; + + case 0x51: + /* LDR rd, [rn - imm] */ + arm_access_memory(load, - offset, imm, u32, no, no_op); + break; case 0x52: - case 0x53: - /* STRH rd, [rb + ro] */ - thumb_access_memory(store, mem_reg, reg[rb] + reg[ro], reg[rd], u16); - break; + /* STR rd, [rn - imm]! */ + arm_access_memory(store, - offset, imm, u32, yes, no_op); + break; + + case 0x53: + /* LDR rd, [rn - imm]! */ + arm_access_memory(load, - offset, imm, u32, yes, no_op); + break; case 0x54: + /* STRB rd, [rn - imm] */ + arm_access_memory(store, - offset, imm, u8, no, no_op); + break; + case 0x55: - /* STRB rd, [rb + ro] */ - thumb_access_memory(store, mem_reg, reg[rb] + reg[ro], reg[rd], u8); - break; + /* LDRB rd, [rn - imm] */ + arm_access_memory(load, - offset, imm, u8, no, no_op); + break; case 0x56: + /* STRB rd, [rn - imm]! */ + arm_access_memory(store, - offset, imm, u8, yes, no_op); + break; + case 0x57: - /* LDSB rd, [rb + ro] */ - thumb_access_memory(load, mem_reg, reg[rb] + reg[ro], reg[rd], s8); - break; + /* LDRB rd, [rn - imm]! */ + arm_access_memory(load, - offset, imm, u8, yes, no_op); + break; case 0x58: + /* STR rd, [rn + imm] */ + arm_access_memory(store, + offset, imm, u32, no, no_op); + break; + case 0x59: - /* LDR rd, [rb + ro] */ - thumb_access_memory(load, mem_reg, reg[rb] + reg[ro], reg[rd], u32); - break; + /* LDR rd, [rn + imm] */ + arm_access_memory(load, + offset, imm, u32, no, no_op); + break; case 0x5A: + /* STR rd, [rn + imm]! */ + arm_access_memory(store, + offset, imm, u32, yes, no_op); + break; + case 0x5B: - /* LDRH rd, [rb + ro] */ - thumb_access_memory(load, mem_reg, reg[rb] + reg[ro], reg[rd], u16); - break; + /* LDR rd, [rn + imm]! */ + arm_access_memory(load, + offset, imm, u32, yes, no_op); + break; case 0x5C: + /* STRB rd, [rn + imm] */ + arm_access_memory(store, + offset, imm, u8, no, no_op); + break; + case 0x5D: - /* LDRB rd, [rb + ro] */ - thumb_access_memory(load, mem_reg, reg[rb] + reg[ro], reg[rd], u8); - break; + /* LDRB rd, [rn + imm] */ + arm_access_memory(load, + offset, imm, u8, no, no_op); + break; case 0x5E: + /* STRB rd, [rn + imm]! */ + arm_access_memory(store, + offset, imm, u8, yes, no_op); + break; + case 0x5F: - /* LDSH rd, [rb + ro] */ - thumb_access_memory(load, mem_reg, reg[rb] + reg[ro], reg[rd], s16); - break; + /* LDRBT rd, [rn + imm]! */ + arm_access_memory(load, + offset, imm, u8, yes, no_op); + break; case 0x60: + /* STR rd, [rn], -reg_op */ + arm_access_memory(store, no_op, reg, u32, yes, - reg_offset); + break; + case 0x61: + /* LDR rd, [rn], -reg_op */ + arm_access_memory(load, no_op, reg, u32, yes, - reg_offset); + break; + case 0x62: + /* STRT rd, [rn], -reg_op */ + arm_access_memory(store, no_op, reg, u32, yes, - reg_offset); + break; + case 0x63: + /* LDRT rd, [rn], -reg_op */ + arm_access_memory(load, no_op, reg, u32, yes, - reg_offset); + break; + case 0x64: + /* STRB rd, [rn], -reg_op */ + arm_access_memory(store, no_op, reg, u8, yes, - reg_offset); + break; + case 0x65: + /* LDRB rd, [rn], -reg_op */ + arm_access_memory(load, no_op, reg, u8, yes, - reg_offset); + break; + case 0x66: - case 0x67: - /* STR rd, [rb + imm] */ - thumb_access_memory(store, mem_imm, reg[rb] + (imm * 4), reg[rd], u32); - break; + /* STRBT rd, [rn], -reg_op */ + arm_access_memory(store, no_op, reg, u8, yes, - reg_offset); + break; + + case 0x67: + /* LDRBT rd, [rn], -reg_op */ + arm_access_memory(load, no_op, reg, u8, yes, - reg_offset); + break; case 0x68: + /* STR rd, [rn], +reg_op */ + arm_access_memory(store, no_op, reg, u32, yes, + reg_offset); + break; + case 0x69: + /* LDR rd, [rn], +reg_op */ + arm_access_memory(load, no_op, reg, u32, yes, + reg_offset); + break; + case 0x6A: + /* STRT rd, [rn], +reg_op */ + arm_access_memory(store, no_op, reg, u32, yes, + reg_offset); + break; + case 0x6B: + /* LDRT rd, [rn], +reg_op */ + arm_access_memory(load, no_op, reg, u32, yes, + reg_offset); + break; + case 0x6C: - case 0x6D: + /* STRB rd, [rn], +reg_op */ + arm_access_memory(store, no_op, reg, u8, yes, + reg_offset); + break; + + case 0x6D: + /* LDRB rd, [rn], +reg_op */ + arm_access_memory(load, no_op, reg, u8, yes, + reg_offset); + break; + case 0x6E: - case 0x6F: - /* LDR rd, [rb + imm] */ - thumb_access_memory(load, mem_imm, reg[rb] + (imm * 4), reg[rd], u32); - break; + /* STRBT rd, [rn], +reg_op */ + arm_access_memory(store, no_op, reg, u8, yes, + reg_offset); + break; + + case 0x6F: + /* LDRBT rd, [rn], +reg_op */ + arm_access_memory(load, no_op, reg, u8, yes, + reg_offset); + break; case 0x70: + /* STR rd, [rn - reg_op] */ + arm_access_memory(store, - reg_offset, reg, u32, no, no_op); + break; + case 0x71: + /* LDR rd, [rn - reg_op] */ + arm_access_memory(load, - reg_offset, reg, u32, no, no_op); + break; + case 0x72: + /* STR rd, [rn - reg_op]! */ + arm_access_memory(store, - reg_offset, reg, u32, yes, no_op); + break; + case 0x73: + /* LDR rd, [rn - reg_op]! */ + arm_access_memory(load, - reg_offset, reg, u32, yes, no_op); + break; + case 0x74: + /* STRB rd, [rn - reg_op] */ + arm_access_memory(store, - reg_offset, reg, u8, no, no_op); + break; + case 0x75: + /* LDRB rd, [rn - reg_op] */ + arm_access_memory(load, - reg_offset, reg, u8, no, no_op); + break; + case 0x76: - case 0x77: - /* STRB rd, [rb + imm] */ - thumb_access_memory(store, mem_imm, reg[rb] + imm, reg[rd], u8); - break; + /* STRB rd, [rn - reg_op]! */ + arm_access_memory(store, - reg_offset, reg, u8, yes, no_op); + break; + + case 0x77: + /* LDRB rd, [rn - reg_op]! */ + arm_access_memory(load, - reg_offset, reg, u8, yes, no_op); + break; case 0x78: + /* STR rd, [rn + reg_op] */ + arm_access_memory(store, + reg_offset, reg, u32, no, no_op); + break; + case 0x79: + /* LDR rd, [rn + reg_op] */ + arm_access_memory(load, + reg_offset, reg, u32, no, no_op); + break; + case 0x7A: + /* STR rd, [rn + reg_op]! */ + arm_access_memory(store, + reg_offset, reg, u32, yes, no_op); + break; + case 0x7B: + /* LDR rd, [rn + reg_op]! */ + arm_access_memory(load, + reg_offset, reg, u32, yes, no_op); + break; + case 0x7C: + /* STRB rd, [rn + reg_op] */ + arm_access_memory(store, + reg_offset, reg, u8, no, no_op); + break; + case 0x7D: + /* LDRB rd, [rn + reg_op] */ + arm_access_memory(load, + reg_offset, reg, u8, no, no_op); + break; + case 0x7E: - case 0x7F: - /* LDRB rd, [rb + imm] */ - thumb_access_memory(load, mem_imm, reg[rb] + imm, reg[rd], u8); - break; + /* STRB rd, [rn + reg_op]! */ + arm_access_memory(store, + reg_offset, reg, u8, yes, no_op); + break; + + case 0x7F: + /* LDRBT rd, [rn + reg_op]! */ + arm_access_memory(load, + reg_offset, reg, u8, yes, no_op); + 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: - case 0x87: - /* STRH rd, [rb + imm] */ - thumb_access_memory(store, mem_imm, reg[rb] + (imm * 2), reg[rd], u16); - break; + /* 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: - case 0x8F: - /* LDRH rd, [rb + imm] */ - thumb_access_memory(load, mem_imm, reg[rb] + (imm * 2), reg[rd], u16); - break; - - case 0x90: - /* STR r0, [sp + imm] */ - thumb_access_memory(store, imm, reg[REG_SP] + (imm * 4), reg[0], u32); - break; - - case 0x91: - /* STR r1, [sp + imm] */ - thumb_access_memory(store, imm, reg[REG_SP] + (imm * 4), reg[1], u32); - break; - - case 0x92: - /* STR r2, [sp + imm] */ - thumb_access_memory(store, imm, reg[REG_SP] + (imm * 4), reg[2], u32); - break; - - case 0x93: - /* STR r3, [sp + imm] */ - thumb_access_memory(store, imm, reg[REG_SP] + (imm * 4), reg[3], u32); - break; - - case 0x94: - /* STR r4, [sp + imm] */ - thumb_access_memory(store, imm, reg[REG_SP] + (imm * 4), reg[4], u32); - break; - - case 0x95: - /* STR r5, [sp + imm] */ - thumb_access_memory(store, imm, reg[REG_SP] + (imm * 4), reg[5], u32); - break; - - case 0x96: - /* STR r6, [sp + imm] */ - thumb_access_memory(store, imm, reg[REG_SP] + (imm * 4), reg[6], u32); - break; - - case 0x97: - /* STR r7, [sp + imm] */ - thumb_access_memory(store, imm, reg[REG_SP] + (imm * 4), reg[7], u32); - break; - - case 0x98: - /* LDR r0, [sp + imm] */ - thumb_access_memory(load, imm, reg[REG_SP] + (imm * 4), reg[0], u32); - break; - - case 0x99: - /* LDR r1, [sp + imm] */ - thumb_access_memory(load, imm, reg[REG_SP] + (imm * 4), reg[1], u32); - break; - - case 0x9A: - /* LDR r2, [sp + imm] */ - thumb_access_memory(load, imm, reg[REG_SP] + (imm * 4), reg[2], u32); - break; - - case 0x9B: - /* LDR r3, [sp + imm] */ - thumb_access_memory(load, imm, reg[REG_SP] + (imm * 4), reg[3], u32); - break; - - case 0x9C: - /* LDR r4, [sp + imm] */ - thumb_access_memory(load, imm, reg[REG_SP] + (imm * 4), reg[4], u32); - break; - - case 0x9D: - /* LDR r5, [sp + imm] */ - thumb_access_memory(load, imm, reg[REG_SP] + (imm * 4), reg[5], u32); - break; - - case 0x9E: - /* LDR r6, [sp + imm] */ - thumb_access_memory(load, imm, reg[REG_SP] + (imm * 4), reg[6], u32); - break; - - case 0x9F: - /* LDR r7, [sp + imm] */ - thumb_access_memory(load, imm, reg[REG_SP] + (imm * 4), reg[7], u32); - break; - - case 0xA0: - /* ADD r0, pc, +imm */ - thumb_add_noflags(imm, 0, (pc & ~2) + 4, (imm * 4)); - break; - - case 0xA1: - /* ADD r1, pc, +imm */ - thumb_add_noflags(imm, 1, (pc & ~2) + 4, (imm * 4)); - break; - - case 0xA2: - /* ADD r2, pc, +imm */ - thumb_add_noflags(imm, 2, (pc & ~2) + 4, (imm * 4)); - break; - - case 0xA3: - /* ADD r3, pc, +imm */ - thumb_add_noflags(imm, 3, (pc & ~2) + 4, (imm * 4)); - break; - - case 0xA4: - /* ADD r4, pc, +imm */ - thumb_add_noflags(imm, 4, (pc & ~2) + 4, (imm * 4)); - break; - - case 0xA5: - /* ADD r5, pc, +imm */ - thumb_add_noflags(imm, 5, (pc & ~2) + 4, (imm * 4)); - break; - - case 0xA6: - /* ADD r6, pc, +imm */ - thumb_add_noflags(imm, 6, (pc & ~2) + 4, (imm * 4)); - break; - - case 0xA7: - /* ADD r7, pc, +imm */ - thumb_add_noflags(imm, 7, (pc & ~2) + 4, (imm * 4)); - break; - - case 0xA8: - /* ADD r0, sp, +imm */ - thumb_add_noflags(imm, 0, reg[REG_SP], (imm * 4)); - break; - - case 0xA9: - /* ADD r1, sp, +imm */ - thumb_add_noflags(imm, 1, reg[REG_SP], (imm * 4)); - break; - - case 0xAA: - /* ADD r2, sp, +imm */ - thumb_add_noflags(imm, 2, reg[REG_SP], (imm * 4)); - break; - - case 0xAB: - /* ADD r3, sp, +imm */ - thumb_add_noflags(imm, 3, reg[REG_SP], (imm * 4)); - break; - - case 0xAC: - /* ADD r4, sp, +imm */ - thumb_add_noflags(imm, 4, reg[REG_SP], (imm * 4)); - break; - - case 0xAD: - /* ADD r5, sp, +imm */ - thumb_add_noflags(imm, 5, reg[REG_SP], (imm * 4)); - break; - - case 0xAE: - /* ADD r6, sp, +imm */ - thumb_add_noflags(imm, 6, reg[REG_SP], (imm * 4)); - break; - - case 0xAF: - /* ADD r7, sp, +imm */ - thumb_add_noflags(imm, 7, reg[REG_SP], (imm * 4)); - break; + /* 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_decode_branch(); + arm_pc_offset_update(offset + 8); + break; + } + + case 0xB0 ... 0xBF: + { + /* BL offset */ + arm_decode_branch(); + reg[REG_LR] = pc + 4; + arm_pc_offset_update(offset + 8); + break; + } + +#ifdef HAVE_UNUSED + case 0xC0 ... 0xEF: + /* coprocessor instructions, reserved on GBA */ + break; +#endif + + case 0xF0 ... 0xFF: + { + /* SWI comment */ + u32 swi_comment = opcode & 0x00FFFFFF; + + switch(swi_comment >> 16) + { + /* Jump to BIOS SWI handler */ + default: + reg_mode[MODE_SUPERVISOR][6] = pc + 4; + collapse_flags(); + spsr[MODE_SUPERVISOR] = reg[REG_CPSR]; + reg[REG_PC] = 0x00000008; + arm_update_pc(); + reg[REG_CPSR] = (reg[REG_CPSR] & ~0x1F) | 0x13; + set_cpu_mode(MODE_SUPERVISOR); + break; + } + break; + } + } + +skip_instruction: + + /* End of Execute ARM instruction */ + cycles_remaining -= cycles_per_instruction; + + if (pc == idle_loop_target_pc && cycles_remaining > 0) cycles_remaining = 0; + } while(cycles_remaining > 0); + + collapse_flags(); + cycles_remaining = update_gba(); + if (reg[COMPLETED_FRAME]) + return; + continue; + + do + { +thumb_loop: + + collapse_flags(); + + /* Process cheats if we are about to execute the cheat hook */ + if (pc == cheat_master_hook) + process_cheats(); + + old_pc = pc; + + /* Execute THUMB instruction */ + + using_instruction(thumb); + check_pc_region(); + pc &= ~0x01; + opcode = address16(pc_address_block, (pc & 0x7FFF)); + + switch((opcode >> 8) & 0xFF) + { + case 0x00 ... 0x07: + /* LSL rd, rs, offset */ + thumb_shift(shift, lsl, imm); + break; + + case 0x08 ... 0x0F: + /* LSR rd, rs, offset */ + thumb_shift(shift, lsr, imm); + break; + + case 0x10 ... 0x17: + /* ASR rd, rs, offset */ + thumb_shift(shift, asr, imm); + break; + + case 0x18: + case 0x19: + /* ADD rd, rs, rn */ + thumb_add(add_sub, rd, reg[rs], reg[rn]); + break; + + case 0x1A: + case 0x1B: + /* SUB rd, rs, rn */ + thumb_sub(add_sub, rd, reg[rs], reg[rn]); + break; + + case 0x1C: + case 0x1D: + /* ADD rd, rs, imm */ + thumb_add(add_sub_imm, rd, reg[rs], imm); + break; + + case 0x1E: + case 0x1F: + /* SUB rd, rs, imm */ + thumb_sub(add_sub_imm, rd, reg[rs], imm); + break; + + case 0x20 ... 0x27: + /* MOV r0..7, imm */ + thumb_logic(imm, ((opcode >> 8) & 7), imm); + break; + + case 0x28 ... 0x2F: + /* CMP r0..7, imm */ + thumb_test_sub(imm, reg[(opcode >> 8) & 7], imm); + break; + + case 0x30 ... 0x37: + /* ADD r0..7, imm */ + thumb_add(imm, ((opcode >> 8) & 7), reg[(opcode >> 8) & 7], imm); + break; + + case 0x38 ... 0x3F: + /* SUB r0..7, imm */ + thumb_sub(imm, ((opcode >> 8) & 7), reg[(opcode >> 8) & 7], imm); + break; + + case 0x40: + switch((opcode >> 6) & 0x03) + { + case 0x00: + /* AND rd, rs */ + thumb_logic(alu_op, rd, reg[rd] & reg[rs]); + break; + + case 0x01: + /* EOR rd, rs */ + thumb_logic(alu_op, rd, reg[rd] ^ reg[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_add(alu_op, rd, reg[rd] + reg[rs], c_flag); + break; + + case 0x02: + /* SBC rd, rs */ + thumb_sub(alu_op, rd, reg[rd] - reg[rs], (c_flag ^ 1)); + 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_test_logic(alu_op, reg[rd] & reg[rs]); + break; + + case 0x01: + /* NEG rd, rs */ + thumb_sub(alu_op, rd, 0, reg[rs]); + break; + + case 0x02: + /* CMP rd, rs */ + thumb_test_sub(alu_op, reg[rd], reg[rs]); + break; + + case 0x03: + /* CMN rd, rs */ + thumb_test_add(alu_op, reg[rd], reg[rs]); + break; + } + break; + + case 0x43: + switch((opcode >> 6) & 0x03) + { + case 0x00: + /* ORR rd, rs */ + thumb_logic(alu_op, rd, reg[rd] | reg[rs]); + break; + + case 0x01: + /* MUL rd, rs */ + thumb_logic(alu_op, rd, reg[rd] * reg[rs]); + break; + + case 0x02: + /* BIC rd, rs */ + thumb_logic(alu_op, rd, reg[rd] & (~reg[rs])); + break; + + case 0x03: + /* MVN rd, rs */ + thumb_logic(alu_op, rd, ~reg[rs]); + break; + } + break; + + case 0x44: + /* ADD rd, rs */ + thumb_hireg_op(reg[rd] + reg[rs]); + break; + + case 0x45: + /* CMP rd, rs */ + { + thumb_pc_offset(4); + thumb_decode_hireg_op(); + u32 _sa = reg[rd]; + u32 _sb = reg[rs]; + u32 dest = _sa - _sb; + thumb_pc_offset(-2); + calculate_flags_sub(dest, _sa, _sb); + } + break; + + case 0x46: + /* MOV rd, rs */ + thumb_hireg_op(reg[rs]); + break; + + case 0x47: + /* BX rs */ + { + thumb_decode_hireg_op(); + u32 src; + thumb_pc_offset(4); + src = reg[rs]; + if(src & 0x01) + { + src -= 1; + thumb_pc_offset_update_direct(src); + } + else + { + /* Switch to ARM mode */ + thumb_pc_offset_update_direct(src); + reg[REG_CPSR] &= ~0x20; + collapse_flags(); + goto arm_loop; + } + } + break; + + case 0x48 ... 0x4F: + /* LDR r0..7, [pc + imm] */ + thumb_access_memory(load, imm, (pc & ~2) + (imm * 4) + 4, reg[(opcode >> 8) & 7], u32); + break; + + case 0x50: + case 0x51: + /* STR rd, [rb + ro] */ + thumb_access_memory(store, mem_reg, reg[rb] + reg[ro], reg[rd], u32); + break; + + case 0x52: + case 0x53: + /* STRH rd, [rb + ro] */ + thumb_access_memory(store, mem_reg, reg[rb] + reg[ro], reg[rd], u16); + break; + + case 0x54: + case 0x55: + /* STRB rd, [rb + ro] */ + thumb_access_memory(store, mem_reg, reg[rb] + reg[ro], reg[rd], u8); + break; + + case 0x56: + case 0x57: + /* LDSB rd, [rb + ro] */ + thumb_access_memory(load, mem_reg, reg[rb] + reg[ro], reg[rd], s8); + break; + + case 0x58: + case 0x59: + /* LDR rd, [rb + ro] */ + thumb_access_memory(load, mem_reg, reg[rb] + reg[ro], reg[rd], u32); + break; + + case 0x5A: + case 0x5B: + /* LDRH rd, [rb + ro] */ + thumb_access_memory(load, mem_reg, reg[rb] + reg[ro], reg[rd], u16); + break; + + case 0x5C: + case 0x5D: + /* LDRB rd, [rb + ro] */ + thumb_access_memory(load, mem_reg, reg[rb] + reg[ro], reg[rd], u8); + break; + + case 0x5E: + case 0x5F: + /* LDSH rd, [rb + ro] */ + thumb_access_memory(load, mem_reg, reg[rb] + reg[ro], reg[rd], s16); + break; + + case 0x60 ... 0x67: + /* STR rd, [rb + imm] */ + thumb_access_memory(store, mem_imm, reg[rb] + (imm * 4), reg[rd], u32); + break; + + case 0x68 ... 0x6F: + /* LDR rd, [rb + imm] */ + thumb_access_memory(load, mem_imm, reg[rb] + (imm * 4), reg[rd], u32); + break; + + case 0x70 ... 0x77: + /* STRB rd, [rb + imm] */ + thumb_access_memory(store, mem_imm, reg[rb] + imm, reg[rd], u8); + break; + + case 0x78 ... 0x7F: + /* LDRB rd, [rb + imm] */ + thumb_access_memory(load, mem_imm, reg[rb] + imm, reg[rd], u8); + break; + + case 0x80 ... 0x87: + /* STRH rd, [rb + imm] */ + thumb_access_memory(store, mem_imm, reg[rb] + (imm * 2), reg[rd], u16); + break; + + case 0x88 ... 0x8F: + /* LDRH rd, [rb + imm] */ + thumb_access_memory(load, mem_imm, reg[rb] + (imm * 2), reg[rd], u16); + break; + + case 0x90 ... 0x97: + /* STR r0..7, [sp + imm] */ + thumb_access_memory(store, imm, reg[REG_SP] + (imm * 4), reg[(opcode >> 8) & 7], u32); + break; + + case 0x98 ... 0x9F: + /* LDR r0..7, [sp + imm] */ + thumb_access_memory(load, imm, reg[REG_SP] + (imm * 4), reg[(opcode >> 8) & 7], u32); + break; + + case 0xA0 ... 0xA7: + /* ADD r0..7, pc, +imm */ + thumb_add_noflags(imm, ((opcode >> 8) & 7), (pc & ~2) + 4, (imm * 4)); + break; + + case 0xA8 ... 0xAF: + /* ADD r0..7, sp, +imm */ + thumb_add_noflags(imm, ((opcode >> 8) & 7), reg[REG_SP], (imm * 4)); + break; case 0xB0: case 0xB1: case 0xB2: - case 0xB3: - if((opcode >> 7) & 0x01) - { - /* ADD sp, -imm */ - thumb_add_noflags(add_sp, 13, reg[REG_SP], -(imm * 4)); - } - else - { - /* ADD sp, +imm */ - thumb_add_noflags(add_sp, 13, reg[REG_SP], (imm * 4)); - } - break; - - case 0xB4: - /* PUSH rlist */ - thumb_block_memory(store, down, no_op, 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_op, up, 13); - break; - - case 0xBD: - /* POP rlist, pc */ - thumb_block_memory(load, no_op, pop_pc, 13); - break; - - case 0xC0: - /* STMIA r0!, rlist */ - thumb_block_memory(store, no_op, up, 0); - break; - - case 0xC1: - /* STMIA r1!, rlist */ - thumb_block_memory(store, no_op, up, 1); - break; - - case 0xC2: - /* STMIA r2!, rlist */ - thumb_block_memory(store, no_op, up, 2); - break; - - case 0xC3: - /* STMIA r3!, rlist */ - thumb_block_memory(store, no_op, up, 3); - break; - - case 0xC4: - /* STMIA r4!, rlist */ - thumb_block_memory(store, no_op, up, 4); - break; - - case 0xC5: - /* STMIA r5!, rlist */ - thumb_block_memory(store, no_op, up, 5); - break; - - case 0xC6: - /* STMIA r6!, rlist */ - thumb_block_memory(store, no_op, up, 6); - break; - - case 0xC7: - /* STMIA r7!, rlist */ - thumb_block_memory(store, no_op, up, 7); - break; - - case 0xC8: - /* LDMIA r0!, rlist */ - thumb_block_memory(load, no_op, up, 0); - break; - - case 0xC9: - /* LDMIA r1!, rlist */ - thumb_block_memory(load, no_op, up, 1); - break; - - case 0xCA: - /* LDMIA r2!, rlist */ - thumb_block_memory(load, no_op, up, 2); - break; - - case 0xCB: - /* LDMIA r3!, rlist */ - thumb_block_memory(load, no_op, up, 3); - break; - - case 0xCC: - /* LDMIA r4!, rlist */ - thumb_block_memory(load, no_op, up, 4); - break; - - case 0xCD: - /* LDMIA r5!, rlist */ - thumb_block_memory(load, no_op, up, 5); - break; - - case 0xCE: - /* LDMIA r6!, rlist */ - thumb_block_memory(load, no_op, up, 6); - break; - - case 0xCF: - /* LDMIA r7!, rlist */ - thumb_block_memory(load, no_op, up, 7); - break; - - case 0xD0: - /* BEQ label */ - thumb_conditional_branch(z_flag == 1); - break; - - case 0xD1: - /* BNE label */ - thumb_conditional_branch(z_flag == 0); - break; - - case 0xD2: - /* BCS label */ - thumb_conditional_branch(c_flag == 1); - break; - - case 0xD3: - /* BCC label */ - thumb_conditional_branch(c_flag == 0); - break; - - case 0xD4: - /* BMI label */ - thumb_conditional_branch(n_flag == 1); - break; - - case 0xD5: - /* BPL label */ - thumb_conditional_branch(n_flag == 0); - break; - - case 0xD6: - /* BVS label */ - thumb_conditional_branch(v_flag == 1); - break; - - case 0xD7: - /* BVC label */ - thumb_conditional_branch(v_flag == 0); - break; - - case 0xD8: - /* BHI label */ - thumb_conditional_branch(c_flag & (z_flag ^ 1)); - break; - - case 0xD9: - /* BLS label */ - thumb_conditional_branch((c_flag == 0) | z_flag); - break; - - case 0xDA: - /* BGE label */ - thumb_conditional_branch(n_flag == v_flag); - break; - - case 0xDB: - /* BLT label */ - thumb_conditional_branch(n_flag != v_flag); - break; - - case 0xDC: - /* BGT label */ - thumb_conditional_branch((z_flag == 0) & (n_flag == v_flag)); - break; - - case 0xDD: - /* BLE label */ - thumb_conditional_branch(z_flag | (n_flag != v_flag)); - break; - - case 0xDF: - { - /* SWI comment */ - u32 swi_comment = opcode & 0xFF; - - switch(swi_comment) - { - default: - reg_mode[MODE_SUPERVISOR][6] = pc + 2; - spsr[MODE_SUPERVISOR] = reg[REG_CPSR]; - reg[REG_PC] = 0x00000008; - thumb_update_pc(); - reg[REG_CPSR] = (reg[REG_CPSR] & ~0x3F) | 0x13; - set_cpu_mode(MODE_SUPERVISOR); - collapse_flags(); - goto arm_loop; - } - break; - } - - case 0xE0: - case 0xE1: - case 0xE2: - case 0xE3: - case 0xE4: - case 0xE5: - case 0xE6: - case 0xE7: - { - /* B label */ - thumb_decode_branch(); - thumb_pc_offset_update(((s32)(offset << 21) >> 20) + 4); - break; - } - - case 0xF0: - case 0xF1: - case 0xF2: - case 0xF3: - case 0xF4: - case 0xF5: - case 0xF6: - case 0xF7: - { - /* (low word) BL label */ - thumb_decode_branch(); - reg[REG_LR] = pc + 4 + ((s32)(offset << 21) >> 9); - thumb_pc_offset(2); - break; - } - - case 0xF8: - case 0xF9: - case 0xFA: - case 0xFB: - case 0xFC: - case 0xFD: - case 0xFE: - case 0xFF: - { - /* (high word) BL label */ - thumb_decode_branch(); - u32 lr = (pc + 2) | 0x01; - pc = reg[REG_LR] + (offset * 2); - reg[REG_LR] = lr; - reg[REG_PC] = pc; - break; - } - } + case 0xB3: + if((opcode >> 7) & 0x01) + { + /* ADD sp, -imm */ + thumb_add_noflags(add_sp, 13, reg[REG_SP], -(imm * 4)); + } + else + { + /* ADD sp, +imm */ + thumb_add_noflags(add_sp, 13, reg[REG_SP], (imm * 4)); + } + break; + + case 0xB4: + /* PUSH rlist */ + thumb_block_memory(store, down, no_op, 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_op, up, 13); + break; + + case 0xBD: + /* POP rlist, pc */ + thumb_block_memory(load, no_op, pop_pc, 13); + break; + + case 0xC0 ... 0xC7: + /* STMIA r0..7!, rlist */ + thumb_block_memory(store, no_op, up, ((opcode >> 8) & 7)); + break; + + case 0xC8 ... 0xCF: + /* LDMIA r0..7!, rlist */ + thumb_block_memory(load, no_op, up, ((opcode >> 8) & 7)); + break; + + case 0xD0: + /* BEQ label */ + thumb_conditional_branch(z_flag == 1); + break; + + case 0xD1: + /* BNE label */ + thumb_conditional_branch(z_flag == 0); + break; + + case 0xD2: + /* BCS label */ + thumb_conditional_branch(c_flag == 1); + break; + + case 0xD3: + /* BCC label */ + thumb_conditional_branch(c_flag == 0); + break; + + case 0xD4: + /* BMI label */ + thumb_conditional_branch(n_flag == 1); + break; + + case 0xD5: + /* BPL label */ + thumb_conditional_branch(n_flag == 0); + break; + + case 0xD6: + /* BVS label */ + thumb_conditional_branch(v_flag == 1); + break; + + case 0xD7: + /* BVC label */ + thumb_conditional_branch(v_flag == 0); + break; + + case 0xD8: + /* BHI label */ + thumb_conditional_branch(c_flag & (z_flag ^ 1)); + break; + + case 0xD9: + /* BLS label */ + thumb_conditional_branch((c_flag == 0) | z_flag); + break; + + case 0xDA: + /* BGE label */ + thumb_conditional_branch(n_flag == v_flag); + break; + + case 0xDB: + /* BLT label */ + thumb_conditional_branch(n_flag != v_flag); + break; + + case 0xDC: + /* BGT label */ + thumb_conditional_branch((z_flag == 0) & (n_flag == v_flag)); + break; + + case 0xDD: + /* BLE label */ + thumb_conditional_branch(z_flag | (n_flag != v_flag)); + break; + + case 0xDF: + { + /* SWI comment */ + u32 swi_comment = opcode & 0xFF; + + switch(swi_comment) + { + default: + reg_mode[MODE_SUPERVISOR][6] = pc + 2; + spsr[MODE_SUPERVISOR] = reg[REG_CPSR]; + reg[REG_PC] = 0x00000008; + thumb_update_pc(); + reg[REG_CPSR] = (reg[REG_CPSR] & ~0x3F) | 0x13; + set_cpu_mode(MODE_SUPERVISOR); + collapse_flags(); + goto arm_loop; + } + break; + } + + case 0xE0 ... 0xE7: + { + /* B label */ + thumb_decode_branch(); + thumb_pc_offset_update(((s32)(offset << 21) >> 20) + 4); + break; + } + + case 0xF0 ... 0xF7: + { + /* (low word) BL label */ + thumb_decode_branch(); + reg[REG_LR] = pc + 4 + ((s32)(offset << 21) >> 9); + thumb_pc_offset(2); + break; + } + + case 0xF8 ... 0xFF: + { + /* (high word) BL label */ + thumb_decode_branch(); + u32 lr = (pc + 2) | 0x01; + pc = reg[REG_LR] + (offset * 2); + reg[REG_LR] = lr; + reg[REG_PC] = pc; + break; + } + } /* End of Execute THUMB instruction */ cycles_remaining -= cycles_per_instruction; diff --git a/cpu_threaded.c b/cpu_threaded.c index 6874ae0..3cef5b1 100644 --- a/cpu_threaded.c +++ b/cpu_threaded.c @@ -1705,8 +1705,9 @@ void translate_icache_sync() { last_opcode = opcode; \ opcode = address16(pc_address_block, (pc & 0x7FFF)); \ emit_trace_thumb_instruction(pc); \ + u8 hiop = opcode >> 8; \ \ - switch((opcode >> 8) & 0xFF) \ + switch(hiop) \ { \ case 0x00 ... 0x07: \ /* LSL rd, rs, imm */ \ @@ -1743,165 +1744,45 @@ void translate_icache_sync() { 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; \ + /* MOV r0..7, imm */ \ + case 0x20: thumb_data_proc_unary(imm, movs, imm, 0, imm); break; \ + case 0x21: thumb_data_proc_unary(imm, movs, imm, 1, imm); break; \ + case 0x22: thumb_data_proc_unary(imm, movs, imm, 2, imm); break; \ + case 0x23: thumb_data_proc_unary(imm, movs, imm, 3, imm); break; \ + case 0x24: thumb_data_proc_unary(imm, movs, imm, 4, imm); break; \ + case 0x25: thumb_data_proc_unary(imm, movs, imm, 5, imm); break; \ + case 0x26: thumb_data_proc_unary(imm, movs, imm, 6, imm); break; \ + case 0x27: thumb_data_proc_unary(imm, movs, imm, 7, imm); break; \ + \ + /* CMP r0, imm */ \ + case 0x28: thumb_data_proc_test(imm, cmp, imm, 0, imm); break; \ + case 0x29: thumb_data_proc_test(imm, cmp, imm, 1, imm); break; \ + case 0x2A: thumb_data_proc_test(imm, cmp, imm, 2, imm); break; \ + case 0x2B: thumb_data_proc_test(imm, cmp, imm, 3, imm); break; \ + case 0x2C: thumb_data_proc_test(imm, cmp, imm, 4, imm); break; \ + case 0x2D: thumb_data_proc_test(imm, cmp, imm, 5, imm); break; \ + case 0x2E: thumb_data_proc_test(imm, cmp, imm, 6, imm); break; \ + case 0x2F: thumb_data_proc_test(imm, cmp, imm, 7, imm); break; \ + \ + /* ADD r0..7, imm */ \ + case 0x30: thumb_data_proc(imm, adds, imm, 0, 0, imm); break; \ + case 0x31: thumb_data_proc(imm, adds, imm, 1, 1, imm); break; \ + case 0x32: thumb_data_proc(imm, adds, imm, 2, 2, imm); break; \ + case 0x33: thumb_data_proc(imm, adds, imm, 3, 3, imm); break; \ + case 0x34: thumb_data_proc(imm, adds, imm, 4, 4, imm); break; \ + case 0x35: thumb_data_proc(imm, adds, imm, 5, 5, imm); break; \ + case 0x36: thumb_data_proc(imm, adds, imm, 6, 6, imm); break; \ + case 0x37: thumb_data_proc(imm, adds, imm, 7, 7, imm); break; \ + \ + /* SUB r0..7, imm */ \ + case 0x38: thumb_data_proc(imm, subs, imm, 0, 0, imm); break; \ + case 0x39: thumb_data_proc(imm, subs, imm, 1, 1, imm); break; \ + case 0x3A: thumb_data_proc(imm, subs, imm, 2, 2, imm); break; \ + case 0x3B: thumb_data_proc(imm, subs, imm, 3, 3, imm); break; \ + case 0x3C: thumb_data_proc(imm, subs, imm, 4, 4, imm); break; \ + case 0x3D: thumb_data_proc(imm, subs, imm, 5, 5, imm); break; \ + case 0x3E: thumb_data_proc(imm, subs, imm, 6, 6, imm); break; \ + case 0x3F: thumb_data_proc(imm, subs, imm, 7, 7, imm); break; \ \ case 0x40: \ switch((opcode >> 6) & 0x03) \ @@ -2023,52 +1904,21 @@ void translate_icache_sync() { 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); \ + case 0x48 ... 0x4F: \ + /* LDR r0..7, [pc + imm] */ \ + { \ + thumb_decode_imm(); \ + u32 rdreg = (hiop & 7); \ + u32 aoff = (pc & ~2) + (imm*4) + 4; \ + /* ROM + same page -> optimize as const load */ \ + if (translation_region == TRANSLATION_REGION_ROM && \ + (((aoff + 4) >> 15) == (pc >> 15))) { \ + u32 value = address32(pc_address_block, (aoff & 0x7FFF)); \ + thumb_load_pc_pool_const(rdreg, value); \ + } else { \ + thumb_access_memory(load, imm, rdreg, 0, 0, pc_relative, aoff, u32);\ + } \ + } \ break; \ \ case 0x50 ... 0x51: \ @@ -2143,165 +1993,77 @@ void translate_icache_sync() { thumb_access_memory(load, mem_imm, rd, rb, 0, reg_imm, (imm * 2), u16); \ break; \ \ + /* STR r0..7, [sp + imm] */ \ 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; \ \ + /* LDR r0..7, [sp + imm] */ \ 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; \ + /* ADD r0..7, pc, +imm */ \ + case 0xA0: thumb_load_pc(0); break; \ + case 0xA1: thumb_load_pc(1); break; \ + case 0xA2: thumb_load_pc(2); break; \ + case 0xA3: thumb_load_pc(3); break; \ + case 0xA4: thumb_load_pc(4); break; \ + case 0xA5: thumb_load_pc(5); break; \ + case 0xA6: thumb_load_pc(6); break; \ + case 0xA7: thumb_load_pc(7); break; \ + \ + /* ADD r0..7, sp, +imm */ \ + case 0xA8: thumb_load_sp(0); break; \ + case 0xA9: thumb_load_sp(1); break; \ + case 0xAA: thumb_load_sp(2); break; \ + case 0xAB: thumb_load_sp(3); break; \ + case 0xAC: thumb_load_sp(4); break; \ + case 0xAD: thumb_load_sp(5); break; \ + case 0xAE: thumb_load_sp(6); break; \ + case 0xAF: thumb_load_sp(7); break; \ \ case 0xB0 ... 0xB3: \ if((opcode >> 7) & 0x01) \ diff --git a/libretro.c b/libretro.c index d8e9efc..4126eca 100644 --- a/libretro.c +++ b/libretro.c @@ -872,7 +872,6 @@ bool retro_load_game(const struct retro_game_info* info) strcpy(filename_bios, main_path); bool bios_loaded = false; - printf("USE %d\n", (int)selected_bios); if (selected_bios == auto_detect || selected_bios == official_bios) { bios_loaded = true; diff --git a/psp/mips_emit.h b/psp/mips_emit.h index aa00d86..3f70f13 100644 --- a/psp/mips_emit.h +++ b/psp/mips_emit.h @@ -535,14 +535,14 @@ u32 arm_to_mips_reg[] = #define generate_load_pc(ireg, new_pc) \ { \ - s32 pc_delta = new_pc - stored_pc; \ + s32 pc_delta = (new_pc) - (stored_pc); \ if((pc_delta >= -32768) && (pc_delta <= 32767)) \ { \ mips_emit_addiu(ireg, reg_pc, pc_delta); \ } \ else \ { \ - generate_load_imm(ireg, new_pc); \ + generate_load_imm(ireg, (new_pc)); \ } \ } \ @@ -1697,6 +1697,9 @@ u32 execute_store_cpsr_body(u32 _cpsr, u32 store_mask, u32 address) arm_psr_##transfer_type(op_type, psr_reg); \ } \ +#define thumb_load_pc_pool_const(rd, value) \ + generate_load_imm(arm_to_mips_reg[rd], (value)); \ + #define arm_access_memory_load(mem_type) \ cycle_count += 2; \ mips_emit_jal(mips_absolute_offset(execute_load_##mem_type)); \ diff --git a/x86/x86_emit.h b/x86/x86_emit.h index 45b663b..69c1f8e 100644 --- a/x86/x86_emit.h +++ b/x86/x86_emit.h @@ -325,7 +325,7 @@ typedef enum x86_emit_mov_reg_mem(reg_##ireg, reg_base, reg_index * 4); \ #define generate_load_pc(ireg, new_pc) \ - x86_emit_mov_reg_imm(reg_##ireg, new_pc) \ + x86_emit_mov_reg_imm(reg_##ireg, (new_pc)) \ #define generate_load_imm(ireg, imm) \ x86_emit_mov_reg_imm(reg_##ireg, imm) \ @@ -1894,6 +1894,10 @@ u32 function_cc execute_ror_imm_op(u32 value, u32 shift) // Operation types: imm, mem_reg, mem_imm +#define thumb_load_pc_pool_const(reg_rd, value) \ + generate_load_pc(a0, (value)); \ + generate_store_reg(a0, reg_rd) + #define thumb_access_memory_load(mem_type, reg_rd) \ cycle_count += 2; \ generate_function_call(execute_load_##mem_type); \ -- cgit v1.2.3