From 4fd456e1583a4c8686c8de87c2aeb1eb78125be1 Mon Sep 17 00:00:00 2001 From: David Guillen Fandos Date: Wed, 5 May 2021 02:20:00 +0200 Subject: Adding Code Breaker cheat support This works on both interpreter and dynarec. Tested in MIPS, ARM and x86, still needs some more testing, some edge cases can be buggy. --- cpu.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'cpu.c') diff --git a/cpu.c b/cpu.c index badb9c2..5df8bb8 100644 --- a/cpu.c +++ b/cpu.c @@ -1679,6 +1679,10 @@ arm_loop: collapse_flags(); cycles_per_instruction = global_cycles_per_instruction; + /* Process cheats if we are about to execute the cheat hook */ + if (pc == cheat_master_hook) + process_cheats(); + old_pc = pc; /* Execute ARM instruction */ @@ -3294,6 +3298,10 @@ 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 */ -- cgit v1.2.3 From 7877a8888b4e607c3df77c5d5f47e2c880cb9a24 Mon Sep 17 00:00:00 2001 From: David Guillen Fandos Date: Wed, 5 May 2021 21:31:24 +0200 Subject: Fix aligned32 reads in interpreter mode An address check was missing to read aligned 32 (stm/ldm) data from high mem areas (0xX0000000). This fixes SM4 EU that for some reason has some weird memory access (perhaps a bug?) --- cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'cpu.c') diff --git a/cpu.c b/cpu.c index 5df8bb8..cd9bba6 100644 --- a/cpu.c +++ b/cpu.c @@ -1024,7 +1024,7 @@ const u32 psr_masks[16] = memory_region_access_read_u32[_address >> 24]++; \ memory_reads_u32++; \ } \ - if(map) \ + if(_address < 0x10000000 && map) \ { \ dest = address32(map, _address & 0x7FFF); \ } \ -- cgit v1.2.3 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. --- cpu.c | 4334 +++++++++++++++++++++++++++++------------------------------------ 1 file changed, 1910 insertions(+), 2424 deletions(-) (limited to 'cpu.c') 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; -- cgit v1.2.3 From 7a642069e3268b822fe355d9480a501b60dc4728 Mon Sep 17 00:00:00 2001 From: David Guillen Fandos Date: Wed, 9 Jun 2021 20:21:00 +0200 Subject: Cleanup unused stuff --- cpu.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'cpu.c') diff --git a/cpu.c b/cpu.c index d21eb66..6003849 100644 --- a/cpu.c +++ b/cpu.c @@ -684,14 +684,6 @@ void print_register_usage(void) reg[REG_CPSR] = (n_flag << 31) | (z_flag << 30) | (c_flag << 29) | \ (v_flag << 28) | (reg[REG_CPSR] & 0xFF) \ -#define memory_region(r_dest, l_dest, address) \ - r_dest = memory_regions[address >> 24]; \ - l_dest = memory_limits[address >> 24] \ - - -#define pc_region() \ - memory_region(pc_region, pc_limit, pc) \ - #define check_pc_region() \ new_pc_region = (pc >> 15); \ if(new_pc_region != pc_region) \ -- cgit v1.2.3 From 8dbf5f6c17e3d217877119620e5bbfeba05abd7a Mon Sep 17 00:00:00 2001 From: David Guillen Fandos Date: Sun, 27 Jun 2021 01:16:28 +0200 Subject: Enable big-endian devices: gc/wii This patch adds big-endian compatibility in gpsp (in general but only for the interpreter). There's no performance hit for little-endian platforms (should be a no-op) and only add a small overhead in memory accesses for big-endian platforms. Most memory accesses are wrapped with a byteswap instruction and I/O reg accesses are also rewired for proper access (using macros). Video rendering has been fixed to also do byteswaps but there's a couple of games and rendering modes that still seem broken (but they amount to less than 20 games in my tests with 1K ROMs). This also adds build rules and CI for NGC/WII/WIIU (untested) --- cpu.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'cpu.c') diff --git a/cpu.c b/cpu.c index 6003849..873a5e3 100644 --- a/cpu.c +++ b/cpu.c @@ -721,8 +721,8 @@ u32 high_frequency_branch_targets = 0; // probably not worth optimizing for. #define check_for_interrupts() \ - if((io_registers[REG_IE] & io_registers[REG_IF]) && \ - io_registers[REG_IME] && ((reg[REG_CPSR] & 0x80) == 0)) \ + if((read_ioreg(REG_IE) & read_ioreg(REG_IF)) && \ + read_ioreg(REG_IME) && ((reg[REG_CPSR] & 0x80) == 0)) \ { \ reg_mode[MODE_IRQ][6] = reg[REG_PC] + 4; \ spsr[MODE_IRQ] = reg[REG_CPSR]; \ @@ -945,10 +945,10 @@ const u32 psr_masks[16] = #define aligned_address_mask16 0xF0000001 #define aligned_address_mask32 0xF0000003 -#define fast_read_memory(size, type, address, dest) \ +#define fast_read_memory(size, type, addr, dest) \ { \ u8 *map; \ - u32 _address = address; \ + u32 _address = addr; \ \ if(_address < 0x10000000) \ { \ @@ -964,7 +964,7 @@ const u32 psr_masks[16] = if(((_address & aligned_address_mask##size) == 0) && \ (map = memory_map_read[_address >> 15])) \ { \ - dest = *((type *)((u8 *)map + (_address & 0x7FFF))); \ + dest = (type)readaddress##size(map, (_address & 0x7FFF)); \ } \ else \ { \ @@ -984,7 +984,7 @@ const u32 psr_masks[16] = if(((_address & aligned_address_mask16) == 0) && \ (map = memory_map_read[_address >> 15])) \ { \ - dest = *((s16 *)((u8 *)map + (_address & 0x7FFF))); \ + dest = (s16)readaddress16(map, (_address & 0x7FFF)); \ } \ else \ { \ @@ -1018,7 +1018,7 @@ const u32 psr_masks[16] = } \ if(_address < 0x10000000 && map) \ { \ - dest = address32(map, _address & 0x7FFF); \ + dest = readaddress32(map, _address & 0x7FFF); \ } \ else \ { \ @@ -1123,10 +1123,10 @@ const u32 psr_masks[16] = #define arm_block_writeback_no(access_type) \ #define load_block_memory(address, dest) \ - dest = address32(address_region, (address + offset) & 0x7FFF) \ + dest = readaddress32(address_region, (address + offset) & 0x7FFF) \ #define store_block_memory(address, dest) \ - address32(address_region, (address + offset) & 0x7FFF) = dest \ + address32(address_region, (address + offset) & 0x7FFF) = eswap32(dest) \ #define arm_block_memory_offset_down_a() \ (base - (word_bit_count(reg_list) * 4) + 4) \ @@ -1601,9 +1601,9 @@ void raise_interrupt(irq_type irq_raised) { // The specific IRQ must be enabled in IE, master IRQ enable must be on, // and it must be on in the flags. - io_registers[REG_IF] |= irq_raised; + write_ioreg(REG_IF, read_ioreg(REG_IF) | irq_raised); - if((io_registers[REG_IE] & irq_raised) && io_registers[REG_IME] && + if((read_ioreg(REG_IE) & irq_raised) && read_ioreg(REG_IME) && ((reg[REG_CPSR] & 0x80) == 0)) { bios_read_protect = 0xe55ec002; @@ -1681,7 +1681,7 @@ arm_loop: using_instruction(arm); check_pc_region(); pc &= ~0x03; - opcode = address32(pc_address_block, (pc & 0x7FFF)); + opcode = readaddress32(pc_address_block, (pc & 0x7FFF)); condition = opcode >> 28; switch(condition) @@ -3256,7 +3256,7 @@ thumb_loop: using_instruction(thumb); check_pc_region(); pc &= ~0x01; - opcode = address16(pc_address_block, (pc & 0x7FFF)); + opcode = readaddress16(pc_address_block, (pc & 0x7FFF)); switch((opcode >> 8) & 0xFF) { -- cgit v1.2.3 From 836e51b694f33d864cf4962d1dd3718bb56803c6 Mon Sep 17 00:00:00 2001 From: David Guillen Fandos Date: Wed, 30 Jun 2021 00:29:21 +0200 Subject: Fix some UB behaviour --- cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'cpu.c') diff --git a/cpu.c b/cpu.c index 873a5e3..60ff3bc 100644 --- a/cpu.c +++ b/cpu.c @@ -266,7 +266,7 @@ void print_register_usage(void) using_register_list(arm, reg_list, 16) \ #define arm_decode_branch() \ - s32 offset = ((s32)(opcode & 0xFFFFFF) << 8) >> 6 \ + s32 offset = ((s32)((u32)(opcode << 8))) >> 6 \ #define thumb_decode_shift() \ -- cgit v1.2.3