diff options
author | neonloop | 2021-07-03 19:54:16 +0000 |
---|---|---|
committer | neonloop | 2021-07-03 19:54:16 +0000 |
commit | 2815c248d76932787fb58d5bbaa0f26be7bcb2be (patch) | |
tree | eff2b1e2c458fcd0b5f96902382df944048d36b7 /cpu.c | |
parent | 8dec6231614ba3f47d874d551ab83f4c5acb07cb (diff) | |
parent | 3d874ec5e3d5675ae9513264d857a3c6c9d2417c (diff) | |
download | picogpsp-2815c248d76932787fb58d5bbaa0f26be7bcb2be.tar.gz picogpsp-2815c248d76932787fb58d5bbaa0f26be7bcb2be.tar.bz2 picogpsp-2815c248d76932787fb58d5bbaa0f26be7bcb2be.zip |
Merge remote-tracking branch 'libretro/master' into pico-fe
Diffstat (limited to 'cpu.c')
-rw-r--r-- | cpu.c | 4368 |
1 files changed, 1927 insertions, 2441 deletions
@@ -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() \ @@ -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) \ @@ -729,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]; \ @@ -953,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) \ { \ @@ -972,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 \ { \ @@ -992,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 \ { \ @@ -1024,9 +1016,9 @@ 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); \ + dest = readaddress32(map, _address & 0x7FFF); \ } \ else \ { \ @@ -1131,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) \ @@ -1609,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,13 +1673,17 @@ 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 */ 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) @@ -1712,2542 +1708,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 0x4: + /* MI */ + if(!n_flag) + arm_next_instruction(); + 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 0x5: + /* PL */ + if(n_flag) + arm_next_instruction(); + break; -#ifdef HAVE_UNUSED - case 0xC0 ... 0xEF: - /* coprocessor instructions, reserved on GBA */ - break; -#endif + case 0x6: + /* VS */ + if(!v_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 0x7: + /* VC */ + if(v_flag) + arm_next_instruction(); + break; - /* End of Execute ARM instruction */ - cycles_remaining -= cycles_per_instruction; + case 0x8: + /* HI */ + if((c_flag == 0) | z_flag) + arm_next_instruction(); + break; - if (pc == idle_loop_target_pc && cycles_remaining > 0) cycles_remaining = 0; - } while(cycles_remaining > 0); + case 0x9: + /* LS */ + if(c_flag & (z_flag ^ 1)) + arm_next_instruction(); + break; - collapse_flags(); - cycles_remaining = update_gba(); - if (reg[COMPLETED_FRAME]) - return; - continue; + case 0xA: + /* GE */ + if(n_flag != v_flag) + arm_next_instruction(); + break; - do - { -thumb_loop: + case 0xB: + /* LT */ + if(n_flag == v_flag) + arm_next_instruction(); + break; - collapse_flags(); + 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: + /* 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 = readaddress16(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; |