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