All pastes #771733 Raw Edit

Someone

public text v1 · immutable
·published 2007-11-13 05:15 UTC
rendered paste body
/* 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
 */

#ifndef ARM_EMIT_H
#define ARM_EMIT_H

#include "arm_codegen.h"

void set_cpu_mode(cpu_mode_type new_mode);
u32 arm_update_gba(u32 pc);

// Although these are defined as a function, don't call them as
// such (jump to it instead)
void arm_indirect_branch_arm(u32 address);
void arm_indirect_branch_thumb(u32 address);
void arm_indirect_branch_dual(u32 address);

void execute_store_cpsr(u32 new_cpsr, u32 store_mask, u32 address);
void execute_store_spsr(u32 new_spsr, u32 store_mask);
u32 execute_store_cpsr_body(u32 _cpsr, u32 store_mask, u32 address);
void step_debug_x86(u32 pc);

#if 0
inline void write32file(u32 val)
{
	FILE* files = fopen("/mnt/sd/code_cache.bin", "ab"); 
	fwrite(&val, 4, 1, files);
	//sync(); 
	fclose(files); 
}
#endif

#define write32(val) *(u32*)translation_ptr = (u32)(val); translation_ptr += 4;			\


#if 0

/*inline*/ void LoadImmediate(u32 imm, u32 reg)							\
{												\
												\
	u8 hit = 0;										\
	if( (imm) == 0 )									\
	{ 											\
		ARM_MOV_REG_IMM(0, reg, ((imm) & 0xFF), 0);					\
	}											\
	else 											\
	{											\
		if( ((imm) & 0xFF) ) 								\
		{										\
			ARM_MOV_REG_IMM(0, reg, ((imm) & 0xFF), 0);				\
			hit = 1;								\
		} 										\
		if( ((imm) & 0xFF00) ) 								\
		{ 										\
			if( hit == 1 )								\
			{ 									\
				ARM_ORR_REG_IMM(0, reg, reg, (((imm) & 0xFF00) >> 8), 24);	\
 			}									\
			else									\
			{									\
				ARM_MOV_REG_IMM(0, reg, (((imm) & 0xFF00) >> 8), 24);		\
				hit = 1; 							\
			}									\
		}										\
		if( ((imm) & 0xFF0000) ) 							\
		{ 										\
			if( hit == 1 )								\
			{ 									\
				ARM_ORR_REG_IMM(0, reg, reg, (((imm) & 0xFF0000) >> 16), 16);	\
			}									\
			else									\
			{									\
				ARM_MOV_REG_IMM(0, reg, (((imm) & 0xFF0000) >> 16), 16);	\
				hit = 1; 							\
			}									\
		}										\
		if( ((imm) & 0xFF000000) ) 							\
		{										\
			if( hit == 1 )								\
			{									\
				ARM_ORR_REG_IMM(0, reg, reg, (((imm) & 0xFF000000) >> 24), 8);	\
			}									\
			else									\
			{									\
				ARM_MOV_REG_IMM(0, reg, (((imm) & 0xFF000000) >> 24), 8);	\
			}									\
		}										\
	}											\
}												\

#else

#define arm_imm_lsl_to_rot(value)                                             \
  (32 - value)                                                                \


u32 arm_disect_imm_32bit(u32 imm, u32 *stores, u32 *rotations)
{
  u32 store_count = 0;
  u32 left_shift = 0;
  u32 i;

  // Otherwise it'll return 0 things to store because it'll never
  // find anything.
  if(imm == 0)
  {
    rotations[0] = 0;
    stores[0] = 0;
    return 1;
  }

  // Find chunks of non-zero data at 2 bit alignments.
  while(1)
  {
    for(; left_shift < 32; left_shift += 2)
    {
      if((imm >> left_shift) & 0x03)
        break;
    }

    if(left_shift == 32)
    {
      // We've hit the end of the useful data.
      return store_count;
    }

    // Hit the end, it might wrap back around to the beginning.
    if(left_shift >= 24)
    {
      // Make a mask for the residual bits. IE, if we have
      // 5 bits of data at the end we can wrap around to 3
      // bits of data in the beginning. Thus the first
      // thing, after being shifted left, has to be less
      // than 111b, 0x7, or (1 << 3) - 1.
      u32 top_bits = 32 - left_shift;
      u32 residual_bits = 8 - top_bits;
      u32 residual_mask = (1 << residual_bits) - 1;

      if((store_count > 1) && (left_shift > 24) &&
       ((stores[0] << ((32 - rotations[0]) & 0x1F)) < residual_mask))
      {
        // Then we can throw out the last bit and tack it on
        // to the first bit.
        u32 initial_bits = rotations[0];
        stores[0] =
         (stores[0] << ((top_bits + (32 - rotations[0])) & 0x1F)) |
         ((imm >> left_shift) & 0xFF);
        rotations[0] = top_bits;

        return store_count;
      }
      else
      {
        // There's nothing to wrap over to in the beginning
        stores[store_count] = (imm >> left_shift) & 0xFF;
        rotations[store_count] = (32 - left_shift) & 0x1F;
        return store_count + 1;
      }
      break;
    }

    stores[store_count] = (imm >> left_shift) & 0xFF;
    rotations[store_count] = (32 - left_shift) & 0x1F;

    store_count++;
    left_shift += 8;
  }
}

void LoadImmediate(u32 imm, u32 ireg)                                         
{                                                                             
  u32 stores[4];                                                             
  u32 rotations[4];                                                           
  u32 store_count = arm_disect_imm_32bit(imm, stores, rotations);             
  u32 i;                                                                      
                                                                              
  ARM_MOV_REG_IMM(0, ireg, stores[0], rotations[0]);                          
                                                                              
  for(i = 1; i < store_count; i++)                                            
  {                                                                           
    ARM_ORR_REG_IMM(0, ireg, ireg, stores[i], rotations[i]);                  
  }                                                                           
}                                                                             

#endif

#define arm_relative_offset(source, offset, next)	    		                        \
  ((((s32)offset - ((s32)source + next)) >> 2) & 0xFFFFFF)					\

#define arm_unequal_operands(op_a, op_b)							\
  (op_a != op_b)										\

#define arm_emit_mov_reg_mem(dest, base, offset)						\
  ARM_LDR_IMM(0, dest, base, offset);								\

#define arm_emit_mov_mem_reg(source, base, offset)						\
  ARM_STR_IMM(0, source, base, offset);							        \

#define arm_emit_mov_reg_reg(dest, source)                                    			\
  if(arm_unequal_operands(dest, source))                                      			\
  {                                                                           			\
    ARM_MOV_REG_REG(0, dest, source);				                         	\
  }                                                                           			\

#define arm_emit_mov_reg_imm(dest, imm)                                		 		\
  LoadImmediate(imm, dest);									\

#define arm_emit_shl_reg_imm(dest, imm)												\
  if( (imm) != 0 ) { ARM_MOV_REG_IMMSHIFT(0, dest, dest, ARMSHIFT_LSL, (imm)); }		\

#define arm_emit_shr_reg_imm(dest, imm)                                       			\
  if( (imm) != 0 ) { ARM_MOV_REG_IMMSHIFT(0, dest, dest, ARMSHIFT_LSR, (imm)); }		\

#define arm_emit_sar_reg_imm(dest, imm)                                       			\
  if( (imm) != 0 ) { ARM_MOV_REG_IMMSHIFT(0, dest, dest, ARMSHIFT_ASR, (imm)); }		\

#define arm_emit_ror_reg_imm(dest, imm)                                      			\
  if( (imm) != 0 ) { ARM_MOV_REG_IMMSHIFT(0, dest, dest, ARMSHIFT_ROR, (imm)); }		\

#define arm_emit_add_reg_reg(dest, source)                                    			\
  ARM_ADD_REG_REG(0, dest, dest, source);							\

#define arm_emit_sub_reg_reg(dest, source)                                    			\
  ARM_SUB_REG_REG(0, dest, dest, source);							\

#define arm_emit_or_reg_reg(dest, source)                                     			\
  ARM_ORR_REG_REG(0, dest, dest, source);							\

#define arm_emit_xor_reg_reg(dest, source)                                    			\
  ARM_EOR_REG_REG(0, dest, dest, source);							\

#define arm_emit_add_reg_imm(dest, imm)          						\
  arm_emit_add_reg_load_imm(dest, imm);								\


#define arm_emit_add_reg_load_imm(dest, imm)                            			\
  LoadImmediate(imm, reg_imm_temp);								\
  ARM_ADD_REG_REG(0, dest, dest, reg_imm_temp);							\

#define arm_emit_add_reg_reg_imm(dest, src, imm)                                 		\
   arm_emit_add_reg_reg_load_imm(dest, src, imm);						\

#define arm_emit_add_reg_reg_load_imm(dest, src, imm)                            		\
		LoadImmediate(imm, reg_imm_temp);						\
		ARM_ADD_REG_REG(0, dest, src, reg_imm_temp);					\

#define arm_emit_sub_reg_imm(dest, imm)                             	        		\
   arm_emit_sub_reg_load_imm(dest, imm);							\

#define arm_emit_sub_reg_load_imm(dest, imm)                             	        	\
  LoadImmediate(imm, reg_imm_temp);								\
  ARM_SUB_REG_REG(0, dest, dest, reg_imm_temp);							\

#define arm_emit_and_reg_imm(dest, imm)                                 			\
	LoadImmediate(imm, reg_imm_temp);							\
	ARM_AND_REG_REG(0, dest, dest, reg_imm_temp);						\

#define arm_emit_xor_reg_imm(dest, imm)                                 			\
	LoadImmediate(imm, reg_imm_temp);							\
	ARM_EOR_REG_REG(0, dest, dest, reg_imm_temp);						\

#define arm_emit_test_reg_imm(dest, imm)                                      			\
	LoadImmediate(imm, reg_imm_temp);							\
	ARM_TST_REG_REG(0, dest, reg_imm_temp);							\

#define arm_emit_cmp_reg_reg(dest, source)                                    			\
  ARM_CMP_REG_REG(0, dest, source);								\

#define arm_emit_test_reg_reg(dest, source)                                   			\
  ARM_TST_REG_REG(0, dest, source);								\

#define arm_emit_cmp_reg_imm(dest, imm)								\
	LoadImmediate(imm, reg_imm_temp);							\
	ARM_CMP_REG_REG(0, dest, reg_imm_temp);							\

#define arm_emit_j_filler(condition_code, writeback_location)       				\
	(writeback_location) = translation_ptr;							\
	translation_ptr += 16;									\
	ARM_BX_COND(0, condition_code, reg_imm_temp);						\

#define arm_emit_jmp_filler(writeback_location)                     				\
	(writeback_location) = translation_ptr;							\
	translation_ptr += 16;									\
	ARM_BX(0, reg_imm_temp);								\

#define reg_base		ARMREG_R4
#define reg_a0			ARMREG_R0
#define reg_a1			ARMREG_R1
#define reg_a2			ARMREG_R2
#define reg_rv			ARMREG_R0
#define reg_s0			ARMREG_R5
#define reg_imm_temp    ARMREG_R6
#define reg_cycles	ARMREG_R8

#define generate_load_reg(ireg, reg_index)                                    			\
  arm_emit_mov_reg_mem(reg_##ireg, reg_base, reg_index * 4);                  			\

#define generate_load_pc(ireg, new_pc)                                        			\
  arm_emit_mov_reg_imm(reg_##ireg, new_pc)                                   			\

#define generate_load_imm(ireg, imm)                                         			\
  arm_emit_mov_reg_imm(reg_##ireg, imm)								\

#define generate_store_reg(ireg, reg_index)                                   			\
  arm_emit_mov_mem_reg(reg_##ireg, reg_base, reg_index * 4);                  			\

#define generate_shift_left(ireg, imm)                                        			\
  arm_emit_shl_reg_imm(reg_##ireg, imm)                                       			\

#define generate_shift_right(ireg, imm)                                       			\
  arm_emit_shr_reg_imm(reg_##ireg, imm)                                       			\

#define generate_shift_right_arithmetic(ireg, imm)                            			\
  arm_emit_sar_reg_imm(reg_##ireg, imm)                                       			\

#define generate_rotate_right(ireg, imm)                                      			\
  arm_emit_ror_reg_imm(reg_##ireg, imm)                                       			\

#define generate_add(ireg_dest, ireg_src)                                     			\
  arm_emit_add_reg_reg(reg_##ireg_dest, reg_##ireg_src)                       			\

#define generate_sub(ireg_dest, ireg_src)                                     			\
  arm_emit_sub_reg_reg(reg_##ireg_dest, reg_##ireg_src)                       			\

#define generate_or(ireg_dest, ireg_src)                                      			\
  arm_emit_or_reg_reg(reg_##ireg_dest, reg_##ireg_src)                        			\

#define generate_xor(ireg_dest, ireg_src)                                     			\
  arm_emit_xor_reg_reg(reg_##ireg_dest, reg_##ireg_src)                       			\

#define generate_add_imm(ireg, imm)                                           			\
  arm_emit_add_reg_imm(reg_##ireg, imm)                                       			\

#define generate_add_load_imm(ireg, imm)                                           		\
  arm_emit_add_reg_load_imm(reg_##ireg, imm)                                       		\

#define generate_sub_imm(ireg, imm)                                           			\
  arm_emit_sub_reg_imm(reg_##ireg, imm)                                       			\

#define generate_sub_load_imm(ireg, imm)                                           		\
  arm_emit_sub_reg_load_imm(reg_##ireg, imm)                                       		\

#define generate_xor_imm(ireg, imm)                                           			\
  arm_emit_xor_reg_imm(reg_##ireg, imm)                                       			\

#define generate_add_reg_reg_imm(ireg_dest, ireg_src, imm)                    			\
  arm_emit_add_reg_reg_imm(reg_##ireg_dest, reg_##ireg_src, imm);              			\

#define generate_and_imm(ireg, imm)                                           			\
  arm_emit_and_reg_imm(reg_##ireg, imm)                                      			\

#define generate_mov(ireg_dest, ireg_src)                                     			\
  arm_emit_mov_reg_reg(reg_##ireg_dest, reg_##ireg_src)                       			\

#define generate_function_call(function_location)						\
	ARM_BL_COND(0, ARMCOND_AL, arm_relative_offset(translation_ptr, function_location, 8));	\

#define generate_function_call_nocycle(function_location)					\
	ARM_BL_COND(0, ARMCOND_AL, arm_relative_offset(translation_ptr, function_location, 8));	\

#define generate_exit_block()	                                                		\
	ARM_BX(0, ARMREG_LR);									\

#define generate_branch_filler_not_zero(ireg_dest, ireg_src, writeback_location)		\
  arm_emit_cmp_reg_imm(reg_##ireg_dest, 0);							\
  arm_emit_j_filler(ARMCOND_NE, writeback_location)                 				\

#define generate_branch_filler_zero(ireg_dest, ireg_src, writeback_location) 			\
  arm_emit_cmp_reg_imm(reg_##ireg_dest, 0);							\
  arm_emit_j_filler(ARMCOND_EQ, writeback_location)                				\

#define generate_branch_filler_not_equal_cmp(ireg_dest, ireg_src, writeback_location)		\
  arm_emit_cmp_reg_reg(reg_##ireg_dest, reg_##ireg_src);					\
  arm_emit_j_filler(ARMCOND_NE, writeback_location)						\

#define generate_branch_filler_equal_cmp(ireg_dest, ireg_src, writeback_location) 		\
  arm_emit_cmp_reg_reg(reg_##ireg_dest, reg_##ireg_src);					\
  arm_emit_j_filler(ARMCOND_EQ, writeback_location)						\


#define generate_update_pc(new_pc)                                            			\
  arm_emit_mov_reg_imm(reg_a0, new_pc)                                           		\

#define generate_update_pc_reg()                                              			\
  generate_update_pc(pc);                                                    			\
  generate_store_reg(a0, REG_PC);                                             			\

#define generate_cycle_update()									\
	LoadImmediate(cycle_count, reg_imm_temp);						\
	arm_emit_sub_reg_reg(reg_cycles, reg_imm_temp);						\
  	cycle_count = 0										\

#define generate_branch_patch_conditional(dest, offset)						\
	*((u32*)((u32)(dest)+0)) = ARM_DEF_DPI_IMM_COND(((((u32)offset) & 0xFF)), ((0) >> 1),	\
(reg_imm_temp), (0), 0, (ARMOP_MOV), ARMCOND_AL);						\
	*((u32*)((u32)(dest)+4)) = ARM_DEF_DPI_IMM_COND((((((u32)offset) & 0xFF00) >> 8)),((24)	\
 >> 1), (reg_imm_temp), (reg_imm_temp), 0, (ARMOP_ORR), ARMCOND_AL);				\
	*((u32*)((u32)(dest)+8)) = ARM_DEF_DPI_IMM_COND((((((u32)offset) & 0xFF0000) >> 16)),	\
 ((16) >> 1), (reg_imm_temp), (reg_imm_temp), 0, (ARMOP_ORR), ARMCOND_AL);			\
	*((u32*)((u32)(dest)+12)) =ARM_DEF_DPI_IMM_COND((((((u32)offset) & 0xFF000000) >> 24)),	\
 ((8) >> 1), (reg_imm_temp), (reg_imm_temp), 0, (ARMOP_ORR), ARMCOND_AL);			\

#define generate_branch_patch_unconditional(dest, offset)					\
	*((u32*)((u32)(dest)+0)) = ARM_DEF_DPI_IMM_COND(((((u32)offset) & 0xFF)), ((0) >> 1),	\
 (reg_imm_temp), (0), 0, (ARMOP_MOV), ARMCOND_AL);						\
	*((u32*)((u32)(dest)+4)) = ARM_DEF_DPI_IMM_COND((((((u32)offset) & 0xFF00) >> 8)),((24)	\
 >> 1), (reg_imm_temp), (reg_imm_temp), 0, (ARMOP_ORR), ARMCOND_AL);				\
	*((u32*)((u32)(dest)+8)) = ARM_DEF_DPI_IMM_COND((((((u32)offset) & 0xFF0000) >> 16)),	\
 ((16) >> 1), (reg_imm_temp), (reg_imm_temp), 0, (ARMOP_ORR), ARMCOND_AL);			\
	*((u32*)((u32)(dest)+12)) =ARM_DEF_DPI_IMM_COND((((((u32)offset) & 0xFF000000) >> 24)),	\
 ((8) >> 1), (reg_imm_temp), (reg_imm_temp), 0, (ARMOP_ORR), ARMCOND_AL);			\

#define generate_branch_no_cycle_update(writeback_location, new_pc)           			\
  if(pc == idle_loop_target_pc)                                               			\
  {                                                                           			\
    arm_emit_mov_reg_imm(reg_a0, new_pc);                                        		\
	ARM_BL_COND(0, ARMCOND_AL, arm_relative_offset(translation_ptr, arm_update_gba, 8));	\
    arm_emit_jmp_filler(writeback_location);                                  			\
  }                                                                           			\
  else                                               	                      			\
  {                                                     	                		\
    arm_emit_mov_reg_imm(reg_a0, new_pc);	                                		\
	ARM_TST_REG_REG(0, reg_cycles, reg_cycles);						\
	ARM_BL_COND(0, ARMCOND_MI, arm_relative_offset(translation_ptr, arm_update_gba, 8));	\
    arm_emit_jmp_filler(writeback_location);                                  			\
  }                                                                           			\

#define generate_branch_cycle_update(writeback_location, new_pc)          			\
  generate_cycle_update();                                                    			\
  generate_branch_no_cycle_update(writeback_location, new_pc)                 			\

#define generate_conditional_branch(ireg_a, ireg_b, type, writeback_location)			\
  generate_branch_filler_##type(ireg_a, ireg_b, writeback_location)				\

// a0 holds the destination

#define generate_indirect_branch_cycle_update(type)                			        \
  generate_cycle_update();                                                    			\
	ARM_BL_COND(0, ARMCOND_AL, arm_relative_offset(translation_ptr,				\
 arm_indirect_branch_##type, 8));								\

#define generate_indirect_branch_no_cycle_update(type)                        			\
	ARM_BL_COND(0, ARMCOND_AL, arm_relative_offset(translation_ptr,				\
 arm_indirect_branch_##type, 8));								\


#define generate_block_prologue()								\

#define generate_block_extra_vars_arm()                                       			\
  void generate_indirect_branch_arm()                                         			\
  {                                                                           			\
    if(condition == 0x0E)                                                     			\
    {                                                                         			\
      generate_indirect_branch_cycle_update(arm);                             			\
    }                                                                         			\
    else                                                                      			\
    {                                                                         			\
      generate_indirect_branch_no_cycle_update(arm);                          			\
    }                                                                         			\
  }                                                                           			\
                                                                              			\
  void generate_indirect_branch_dual()                                        			\
  {                                                                           			\
    if(condition == 0x0E)                                                     			\
    {                                                                         			\
      generate_indirect_branch_cycle_update(dual);                            			\
    }                                                                         			\
    else                                                                      			\
    {                                                                         			\
      generate_indirect_branch_no_cycle_update(dual);                         			\
    }                                                                         			\
  }                                                                           			\

#define generate_block_extra_vars_thumb()                                     			\


#define translate_invalidate_dcache()                                           		\
{												\
  CLEAR_INSN_CACHE(rom_translation_cache,							\
   (ROM_TRANSLATION_CACHE_SIZE));								\
  CLEAR_INSN_CACHE(ram_translation_cache,							\
   (RAM_TRANSLATION_CACHE_SIZE));								\
  CLEAR_INSN_CACHE(bios_translation_cache,							\
   (BIOS_TRANSLATION_CACHE_SIZE));								\
}												\

#define block_prologue_size			0						\

#define calculate_z_flag(dest)                                                			\
  reg[REG_Z_FLAG] = (dest == 0)                                               			\

#define calculate_n_flag(dest)                                                			\
  reg[REG_N_FLAG] = ((signed)dest < 0)                                        			\

#define calculate_c_flag_sub(dest, src_a, src_b)                              			\
  reg[REG_C_FLAG] = ((unsigned)src_b <= (unsigned)src_a)                      			\

#define calculate_v_flag_sub(dest, src_a, src_b)                              			\
  reg[REG_V_FLAG] = ((signed)src_b > (signed)src_a) != ((signed)dest < 0)     			\

#define calculate_c_flag_add(dest, src_a, src_b)                              			\
  reg[REG_C_FLAG] = ((unsigned)dest < (unsigned)src_a)                        			\

#define calculate_v_flag_add(dest, src_a, src_b)                              			\
  reg[REG_V_FLAG] = ((signed)dest < (signed)src_a) != ((signed)src_b < 0)     			\


#define get_shift_imm()                                                       			\
  u32 shift = (opcode >> 7) & 0x1F                                            			\

#define generate_shift_reg(ireg, name, flags_op)                              			\
  generate_load_reg_pc(ireg, rm, 12);                                         			\
  generate_load_reg(a1, ((opcode >> 8) & 0x0F));                              			\
  generate_function_call(execute_##name##_##flags_op##_reg);                  			\
  generate_mov(ireg, rv)                                                      			\

u32 function_cc execute_lsl_no_flags_reg(u32 value, u32 shift)
{
  if(shift != 0)
  {
    if(shift > 31)
      value = 0;
    else
      value <<= shift;
  }
  return value;
}

u32 function_cc execute_lsr_no_flags_reg(u32 value, u32 shift)
{
  if(shift != 0)
  {
    if(shift > 31)
      value = 0;
    else
      value >>= shift;
  }
  return value;
}

u32 function_cc execute_asr_no_flags_reg(u32 value, u32 shift)
{
  if(shift != 0)
  {
    if(shift > 31)
      value = (s32)value >> 31;
    else
      value = (s32)value >> shift;
  }
  return value;
}

u32 function_cc execute_ror_no_flags_reg(u32 value, u32 shift)
{
  if(shift != 0)
  {
    ror(value, value, shift);
  }

  return value;
}


u32 function_cc execute_lsl_flags_reg(u32 value, u32 shift)
{
  if(shift != 0)
  {
    if(shift > 31)
    {
      reg[REG_C_FLAG] = value & 0x01;

      if(shift != 32)
        reg[REG_C_FLAG] = 0;

      value = 0;
    }
    else
    {
      reg[REG_C_FLAG] = (value >> (32 - shift)) & 0x01;
      value <<= shift;
    }
  }
  return value;
}

u32 function_cc execute_lsr_flags_reg(u32 value, u32 shift)
{
  if(shift != 0)
  {
    if(shift > 31)
    {
      reg[REG_C_FLAG] = value >> 31;

      if(shift != 32)
        reg[REG_C_FLAG] = 0;

      value = 0;
    }
    else
    {
      reg[REG_C_FLAG] = (value >> (shift - 1)) & 0x01;
      value >>= shift;
    }
  }
  return value;
}

u32 function_cc execute_asr_flags_reg(u32 value, u32 shift)
{
  if(shift != 0)
  {
    if(shift > 31)
    {
      value = (s32)value >> 31;
      reg[REG_C_FLAG] = value & 0x01;
    }
    else
    {
      reg[REG_C_FLAG] = (value >> (shift - 1)) & 0x01;
      value = (s32)value >> shift;
    }
  }
  return value;
}

u32 function_cc execute_ror_flags_reg(u32 value, u32 shift)
{
  if(shift != 0)
  {
    reg[REG_C_FLAG] = (value >> (shift - 1)) & 0x01;
    ror(value, value, shift);
  }

  return value;
}

u32 function_cc execute_rrx_flags(u32 value)
{
  u32 c_flag = reg[REG_C_FLAG];
  reg[REG_C_FLAG] = value & 0x01;
  return (value >> 1) | (c_flag << 31);
}

u32 function_cc execute_rrx(u32 value)
{
  return (value >> 1) | (reg[REG_C_FLAG] << 31);
}

#define generate_shift_imm_lsl_no_flags(ireg)                                 			\
  generate_load_reg_pc(ireg, rm, 8);                                          			\
  if(shift != 0)                                                              			\
  {                                                                           			\
    generate_shift_left(ireg, shift);                                         			\
  }                                                                           			\

#define generate_shift_imm_lsr_no_flags(ireg)                                 			\
  if(shift != 0)                                                              			\
  {                                                                           			\
    generate_load_reg_pc(ireg, rm, 8);                                        			\
    generate_shift_right(ireg, shift);                                       			\
  }                                                                           			\
  else                                                                        			\
  {                                                                           			\
    generate_load_imm(ireg, 0);                                               			\
  }                                                                           			\

#define generate_shift_imm_asr_no_flags(ireg)                                 			\
  generate_load_reg_pc(ireg, rm, 8);                                          			\
  if(shift != 0)                                                              			\
  {                                                                           			\
    generate_shift_right_arithmetic(ireg, shift);                             			\
  }                                                                           			\
  else                                                                        			\
  {                                                                           			\
    generate_shift_right_arithmetic(ireg, 31);                                			\
  }                                                                           			\

#define generate_shift_imm_ror_no_flags(ireg)                                 			\
  if(shift != 0)                                                             			\
  {                                                                           			\
    generate_load_reg_pc(ireg, rm, 8);                                        			\
    generate_rotate_right(ireg, shift);                                       			\
  }                                                                           			\
  else                                                                        			\
  {                                                                           			\
    generate_load_reg_pc(a0, rm, 8);                                          			\
    generate_function_call(execute_rrx);                                      			\
    generate_mov(ireg, rv);                                                   			\
  }                                                                           			\

#define generate_shift_imm_lsl_flags(ireg)                                    			\
  generate_load_reg_pc(ireg, rm, 8);                                          			\
  if(shift != 0)                                                              			\
  {                                                                           			\
    generate_mov(a1, ireg);                                                   			\
    generate_shift_right(a1, (32 - shift));                                   			\
    generate_and_imm(a1, 1);                                                  			\
    generate_store_reg(a1, REG_C_FLAG);                                       			\
    generate_shift_left(ireg, shift);                                         			\
  }                                                                           			\

#define generate_shift_imm_lsr_flags(ireg)                                    			\
  if(shift != 0)                                                              			\
  {                                                                           			\
    generate_load_reg_pc(ireg, rm, 8);                                        			\
    generate_mov(a1, ireg);                                                   			\
    generate_shift_right(a1, shift - 1);                                      			\
    generate_and_imm(a1, 1);                                                  			\
    generate_store_reg(a1, REG_C_FLAG);                                       			\
    generate_shift_right(ireg, shift);                                        			\
  }                                                                           			\
  else                                                                        			\
  {                                                                          			\
    generate_load_reg_pc(a1, rm, 8);                                          			\
    generate_shift_right(a1, 31);                                             			\
    generate_store_reg(a1, REG_C_FLAG);                                       			\
    generate_load_imm(ireg, 0);                                              			\
  }                                                                          			\

#define generate_shift_imm_asr_flags(ireg)                                    			\
  if(shift != 0)                                                              			\
  {                                                                           			\
    generate_load_reg_pc(ireg, rm, 8);                                        			\
    generate_mov(a1, ireg);                                                   			\
    generate_shift_right_arithmetic(a1, shift - 1);                           			\
    generate_and_imm(a1, 1);                                                  			\
    generate_store_reg(a1, REG_C_FLAG);                                       			\
    generate_shift_right_arithmetic(ireg, shift);                             			\
  }                                                                           			\
  else                                                                        			\
  {                                                                           			\
    generate_load_reg_pc(a0, rm, 8);                                          			\
    generate_shift_right_arithmetic(ireg, 31);                                			\
    generate_mov(a1, ireg);                                                   			\
    generate_and_imm(a1, 1);                                                  			\
    generate_store_reg(a1, REG_C_FLAG);                                       			\
  }                                                                           			\

#define generate_shift_imm_ror_flags(ireg)                                    			\
  generate_load_reg_pc(ireg, rm, 8);                                          			\
  if(shift != 0)                                                              			\
  {                                                                           			\
    generate_mov(a1, ireg);                                                   			\
    generate_shift_right_arithmetic(a1, shift - 1);                           			\
    generate_and_imm(a1, 1);                                                  			\
    generate_store_reg(a1, REG_C_FLAG);                                       			\
    generate_rotate_right(ireg, shift);                                       			\
  }                                                                           			\
  else                                                                        			\
  {                                                                           			\
    generate_function_call(execute_rrx_flags);                                			\
    generate_mov(ireg, rv);                                                   			\
  }                                                                           			\

#define generate_shift_imm(ireg, name, flags_op)                              			\
  get_shift_imm();                                                            			\
  generate_shift_imm_##name##_##flags_op(ireg)                                			\

#define generate_load_rm_sh(flags_op)                                         			\
  switch((opcode >> 4) & 0x07)                                                			\
  {                                                                           			\
    /* LSL imm */                                                             			\
    case 0x0:                                                                 			\
    {                                                                         			\
      generate_shift_imm(a0, lsl, flags_op);                                  			\
      break;                                                                  			\
    }                                                                         			\
                                                                              			\
    /* LSL reg */                                                             			\
    case 0x1:                                                                 			\
    {                                                                         			\
      generate_shift_reg(a0, lsl, flags_op);                                  			\
      break;                                                                  			\
    }                                                                         			\
                                                                              			\
    /* LSR imm */                                                             			\
    case 0x2:                                                                 			\
    {                                                                         			\
      generate_shift_imm(a0, lsr, flags_op);                                  			\
      break;                                                                  			\
    }                                                                         			\
                                                                              			\
    /* LSR reg */                                                             			\
    case 0x3:                                                                 			\
    {                                                                         			\
      generate_shift_reg(a0, lsr, flags_op);                                  			\
      break;                                                                  			\
    }                                                                         			\
                                                                              			\
    /* ASR imm */                                                             			\
    case 0x4:                                                                 			\
    {                                                                         			\
      generate_shift_imm(a0, asr, flags_op);                                  			\
      break;                                                                  			\
    }                                                                         			\
                                                                              			\
    /* ASR reg */                                                             			\
    case 0x5:                                                                 			\
    {                                                                         			\
      generate_shift_reg(a0, asr, flags_op);                                  			\
      break;                                                                  			\
    }                                                                         			\
                                                                              			\
    /* ROR imm */                                                             			\
    case 0x6:                                                                 			\
    {                                                                         			\
      generate_shift_imm(a0, ror, flags_op);                                  			\
      break;                                                                  			\
    }                                                                         			\
                                                                              			\
    /* ROR reg */                                                             			\
    case 0x7:                                                                 			\
    {                                                                         			\
      generate_shift_reg(a0, ror, flags_op);                                  			\
      break;                                                                  			\
    }                                                                        			\
  }                                                                           			\

#define generate_load_offset_sh()                                             			\
  switch((opcode >> 5) & 0x03)                                                			\
  {                                                                           			\
    /* LSL imm */                                                             			\
    case 0x0:                                                                 			\
    {                                                                         			\
      generate_shift_imm(a1, lsl, no_flags);                                  			\
      break;                                                                  			\
    }                                                                         			\
                                                                              			\
    /* LSR imm */                                                             			\
    case 0x1:                                                                 			\
    {                                                                         			\
      generate_shift_imm(a1, lsr, no_flags);                                  			\
      break;                                                                  			\
    }                                                                         			\
                                                                              			\
    /* ASR imm */                                                             			\
    case 0x2:                                                                 			\
    {                                                                         			\
      generate_shift_imm(a1, asr, no_flags);                                  			\
      break;                                                                  			\
    }                                                                         			\
                                                                              			\
    /* ROR imm */                                                             			\
    case 0x3:                                                                 			\
    {                                                                         			\
      generate_shift_imm(a1, ror, no_flags);                                  			\
      break;                                                                  			\
    }                                                                         			\
  }                                                                           			\

#define calculate_flags_add(dest, src_a, src_b)                               			\
  calculate_z_flag(dest);                                                     			\
  calculate_n_flag(dest);                                                     			\
  calculate_c_flag_add(dest, src_a, src_b);                                  			\
  calculate_v_flag_add(dest, src_a, src_b)                                    			\

#define calculate_flags_sub(dest, src_a, src_b)                               			\
  calculate_z_flag(dest);                                                     			\
  calculate_n_flag(dest);                                                     			\
  calculate_c_flag_sub(dest, src_a, src_b);                                   			\
  calculate_v_flag_sub(dest, src_a, src_b)                                    			\

#define calculate_flags_logic(dest)                                           			\
  calculate_z_flag(dest);                                                     			\
  calculate_n_flag(dest)                                                      			\

#define extract_flags()                                                       			\
  reg[REG_N_FLAG] = (reg[REG_CPSR] >> 31);                                    			\
  reg[REG_Z_FLAG] = (reg[REG_CPSR] >> 30) & 0x01;                             			\
  reg[REG_C_FLAG] = (reg[REG_CPSR] >> 29) & 0x01;                             			\
  reg[REG_V_FLAG] = (reg[REG_CPSR] >> 28) & 0x01;                             			\

#define collapse_flags()                                                      			\
  reg[REG_CPSR] = (reg[REG_N_FLAG] << 31) | (reg[REG_Z_FLAG] << 30) |         			\
   (reg[REG_C_FLAG] << 29) | (reg[REG_V_FLAG] << 28) |                        			\
   reg[REG_CPSR] & 0xFF                                                       			\

// It should be okay to still generate result flags, spsr will overwrite them.
// This is pretty infrequent (returning from interrupt handlers, et al) so
// probably not worth optimizing for.

#define check_for_interrupts()                                                			\
  if((io_registers[REG_IE] & io_registers[REG_IF]) &&                         			\
   io_registers[REG_IME] && ((reg[REG_CPSR] & 0x80) == 0))                    			\
  {                                                                           			\
    reg_mode[MODE_IRQ][6] = reg[REG_PC] + 4;                                  			\
    spsr[MODE_IRQ] = reg[REG_CPSR];                                           			\
    reg[REG_CPSR] = 0xD2;                                                     			\
    address = 0x00000018;                                                     			\
    set_cpu_mode(MODE_IRQ);                                                   			\
  }                                                                           			\

#define generate_load_reg_pc(ireg, reg_index, pc_offset)                      			\
  if(reg_index == 15)                                                         			\
  {                                                                           			\
    generate_load_pc(ireg, pc + pc_offset);                                   			\
  }                                                                           			\
  else                                                                        			\
  {                                                                           			\
    generate_load_reg(ireg, reg_index);                                       			\
  }                                                                           			\

#define generate_store_reg_pc_no_flags(ireg, reg_index)                       			\
  generate_store_reg(ireg, reg_index);                                        			\
  if(reg_index == 15)                                                         			\
  {                                                                           			\
    generate_mov(a0, ireg);                                                   			\
    generate_indirect_branch_arm();                                           			\
  }                                                                           			\

u32 function_cc execute_spsr_restore(u32 address)
{
  if(reg[CPU_MODE] != MODE_USER)
  {
    reg[REG_CPSR] = spsr[reg[CPU_MODE]];
    extract_flags();
    set_cpu_mode(cpu_modes[reg[REG_CPSR] & 0x1F]);
    check_for_interrupts();

    if(reg[REG_CPSR] & 0x20)
      address |= 0x01;
  }

  return address;
}

#define generate_store_reg_pc_flags(ireg, reg_index)                          			\
  generate_store_reg(ireg, reg_index);                                        			\
  if(reg_index == 15)                                                         			\
  {                                                                           			\
    generate_mov(a0, ireg);                                                   			\
    generate_function_call(execute_spsr_restore);                             			\
    generate_mov(a0, rv);                                                     			\
    generate_indirect_branch_dual();                                          			\
  }                                                                           			\

typedef enum
{
  CONDITION_EQUAL_CMP,
  CONDITION_NOT_EQUAL_CMP,
  CONDITION_EQUAL,
  CONDITION_NOT_EQUAL
} condition_check_type;


#define generate_condition_eq(ireg_a, ireg_b)                                 			\
  generate_load_reg(ireg_a, REG_Z_FLAG);                                      			\
  generate_conditional_branch(ireg_a, ireg_b, zero, backpatch_address); 			\

#define generate_condition_ne(ireg_a, ireg_b)                                 			\
  generate_load_reg(ireg_a, REG_Z_FLAG);                                      			\
  generate_conditional_branch(ireg_a, ireg_b, not_zero, backpatch_address); 			\

#define generate_condition_cs(ireg_a, ireg_b)                                 			\
  generate_load_reg(ireg_a, REG_C_FLAG);                                      			\
  generate_conditional_branch(ireg_a, ireg_b, zero, backpatch_address); 			\

#define generate_condition_cc(ireg_a, ireg_b)                                 			\
  generate_load_reg(ireg_a, REG_C_FLAG);                                      			\
  generate_conditional_branch(ireg_a, ireg_b, not_zero, backpatch_address); 			\

#define generate_condition_mi(ireg_a, ireg_b)                                 			\
  generate_load_reg(ireg_a, REG_N_FLAG);                                      			\
  generate_conditional_branch(ireg_a, ireg_b, zero, backpatch_address); 			\

#define generate_condition_pl(ireg_a, ireg_b)                                 			\
  generate_load_reg(ireg_a, REG_N_FLAG);                                     			\
  generate_conditional_branch(ireg_a, ireg_b, not_zero, backpatch_address);			\

#define generate_condition_vs(ireg_a, ireg_b)                                 			\
  generate_load_reg(ireg_a, REG_V_FLAG);                                      			\
  generate_conditional_branch(ireg_a, ireg_b, zero, backpatch_address); 			\

#define generate_condition_vc(ireg_a, ireg_b)                                 			\
  generate_load_reg(ireg_a, REG_V_FLAG);                                      			\
  generate_conditional_branch(ireg_a, ireg_b, not_zero, backpatch_address); 			\

#define generate_condition_hi(ireg_a, ireg_b)                                 			\
  generate_load_reg(ireg_a, REG_C_FLAG);                                      			\
  generate_xor_imm(ireg_a, 1);                                                			\
  generate_load_reg(ireg_b, REG_Z_FLAG);                                      			\
  generate_or(ireg_a, ireg_b);                                                			\
  generate_conditional_branch(ireg_a, ireg_b, not_zero, backpatch_address); 			\

#define generate_condition_ls(ireg_a, ireg_b)                                 			\
  generate_load_reg(ireg_a, REG_C_FLAG);                                      			\
  generate_xor_imm(ireg_a, 1);                                                			\
  generate_load_reg(ireg_b, REG_Z_FLAG);                                      			\
  generate_or(ireg_a, ireg_b);                                                			\
  generate_conditional_branch(ireg_a, ireg_b, zero, backpatch_address); 			\

#define generate_condition_ge(ireg_a, ireg_b)                                 			\
  generate_load_reg(ireg_a, REG_N_FLAG);                                      			\
  generate_load_reg(ireg_b, REG_V_FLAG);                                      			\
  generate_conditional_branch(ireg_a, ireg_b, not_equal_cmp, backpatch_address); 		\

#define generate_condition_lt(ireg_a, ireg_b)                                 			\
  generate_load_reg(ireg_a, REG_N_FLAG);                                      			\
  generate_load_reg(ireg_b, REG_V_FLAG);                                      			\
  generate_conditional_branch(ireg_a, ireg_b, equal_cmp, backpatch_address); 			\

#define generate_condition_gt(ireg_a, ireg_b)                                 			\
  generate_load_reg(ireg_a, REG_N_FLAG);                                      			\
  generate_load_reg(ireg_b, REG_V_FLAG);                                      			\
  generate_xor(ireg_b, ireg_a);                                               			\
  generate_load_reg(a0, REG_Z_FLAG);                                          			\
  generate_or(ireg_a, ireg_b);                                                			\
  generate_conditional_branch(ireg_a, ireg_b, not_zero, backpatch_address); 			\

#define generate_condition_le(ireg_a, ireg_b)                                 			\
  generate_load_reg(ireg_a, REG_N_FLAG);                                      			\
  generate_load_reg(ireg_b, REG_V_FLAG);                                      			\
  generate_xor(ireg_b, ireg_a);                                               			\
  generate_load_reg(a0, REG_Z_FLAG);                                          			\
  generate_or(ireg_a, ireg_b);                                                			\
  generate_conditional_branch(ireg_a, ireg_b, zero, backpatch_address); 			\


#define generate_condition(ireg_a, ireg_b)                                    			\
  switch(condition)                                                           			\
  {                                                                           			\
    case 0x0:                                                                 			\
      generate_condition_eq(ireg_a, ireg_b);                                  			\
      break;                                                                  			\
                                                                              			\
    case 0x1:                                                                 			\
      generate_condition_ne(ireg_a, ireg_b);                                  			\
      break;                                                                  			\
                                                                              			\
    case 0x2:                                                                 			\
      generate_condition_cs(ireg_a, ireg_b);                                  			\
      break;                                                                  			\
                                                                              			\
    case 0x3:                                                                 			\
      generate_condition_cc(ireg_a, ireg_b);                                  			\
      break;                                                                  			\
                                                                              			\
    case 0x4:                                                                 			\
      generate_condition_mi(ireg_a, ireg_b);                                  			\
      break;                                                                  			\
                                                                              			\
    case 0x5:                                                                 			\
      generate_condition_pl(ireg_a, ireg_b);                                  			\
      break;                                                                  			\
                                                                              			\
    case 0x6:                                                                 			\
      generate_condition_vs(ireg_a, ireg_b);                                  			\
      break;                                                                  			\
                                                                              			\
    case 0x7:                                                                 			\
      generate_condition_vc(ireg_a, ireg_b);                                  			\
      break;                                                                  			\
                                                                              			\
    case 0x8:                                                                 			\
      generate_condition_hi(ireg_a, ireg_b);                                  			\
      break;                                                                  			\
                                                                              			\
    case 0x9:                                                                 			\
      generate_condition_ls(ireg_a, ireg_b);                                  			\
      break;                                                                  			\
                                                                              			\
    case 0xA:                                                                 			\
      generate_condition_ge(ireg_a, ireg_b);                                  			\
      break;                                                                  			\
                                                                              			\
    case 0xB:                                                                 			\
      generate_condition_lt(ireg_a, ireg_b);                                  			\
      break;                                                                  			\
                                                                              			\
    case 0xC:                                                                 			\
      generate_condition_gt(ireg_a, ireg_b);                                  			\
      break;                                                                  			\
                                                                              			\
    case 0xD:                                                                 			\
      generate_condition_le(ireg_a, ireg_b);                                  			\
      break;                                                                  			\
                                                                              			\
    case 0xE:                                                                 			\
      /* AL       */                                                          			\
      break;                                                                  			\
                                                                              			\
    case 0xF:                                                                 			\
      /* Reserved */                                                          			\
      break;                                                                  			\
  }                                                                           			\
  generate_cycle_update()                                                     			\


#define generate_conditional_branch_type(ireg_a, ireg_b)                      			\


#define generate_branch()                                                     			\
{                                                                             			\
  if(condition == 0x0E)                                                       			\
  {                                                                           			\
    generate_branch_cycle_update(                                             			\
     block_exits[block_exit_position].branch_source,                          			\
     block_exits[block_exit_position].branch_target);                         			\
  }                                                                           			\
  else                                                                        			\
  {                                                                           			\
    generate_branch_no_cycle_update(                                          			\
     block_exits[block_exit_position].branch_source,                          			\
     block_exits[block_exit_position].branch_target);                         			\
  }                                                                           			\
  block_exit_position++;                                                      			\
}                                                                             			\

#define rm_op_reg rm
#define rm_op_imm imm

#define arm_generate_load_reg_pc_no_rn(reg1, reg2, offset)					\

#define arm_generate_load_reg_pc_rn(reg1, reg2, offset)						\
	generate_load_reg_pc(reg1, reg2, offset);						\


#define arm_data_proc_reg_reg_flags(name,rn_type)                                 		\
  arm_decode_data_proc_reg();                                                 			\
  if(flag_status & 0x02)                                                      			\
  {                                                                           			\
    generate_load_rm_sh(flags);                                                			\
  }                                                                           			\
  else                                                                        			\
  {                                                                           			\
    generate_load_rm_sh(no_flags);                                            			\
  }                                                                           			\
	arm_generate_load_reg_pc_##rn_type(a1, rn, 8);                				\
	generate_function_call(execute_##name);							\


#define arm_data_proc_reg_shift_imm_rn(name,type)						\
	get_shift_imm();									\
	generate_load_reg_pc(a0, rm, 8);							\
	arm_generate_load_reg_pc_rn(a1, rn, 8);               					\
	ARM_##name##_REG_IMMSHIFT(0, reg_a0, reg_a1, reg_a0, ARMSHIFT_##type, shift);		\

#define arm_data_proc_reg_shift_imm_no_rn(name,type)						\
	get_shift_imm();									\
	generate_load_reg_pc(a0, rm, 8);							\
	ARM_##name##_REG_IMMSHIFT(0, reg_a0, reg_a0, ARMSHIFT_##type, shift);			\


#define arm_data_proc_reg_shift_imm(name,type,rn_type)						\
	arm_data_proc_reg_shift_imm_##rn_type(name,type)					\


#define arm_data_proc_reg_shift_reg_rn(name,type)						\
	generate_load_reg_pc(a0, rm, 12); /* DEBUG 12 should be 8? */           		\
	arm_generate_load_reg_pc_rn(a1, rn, 8);               					\
  	generate_load_reg(imm_temp, ((opcode >> 8) & 0x0F));                              	\
	ARM_##name##_REG_REGSHIFT(0, reg_a0, reg_a1, reg_a0, ARMSHIFT_##type, reg_imm_temp);	\

#define arm_data_proc_reg_shift_reg_no_rn(name,type)						\
	generate_load_reg_pc(a0, rm, 12); /* DEBUG 12 should be 8? */           		\
  	generate_load_reg(imm_temp, ((opcode >> 8) & 0x0F));                              	\
	ARM_##name##_REG_REGSHIFT(0, reg_a0, reg_a0, ARMSHIFT_##type, reg_imm_temp);		\


#define arm_data_proc_reg_shift_reg(name,type,rn_type)						\
	arm_data_proc_reg_shift_reg_##rn_type(name,type)					\


#define arm_data_proc_reg(name,rn_type)	                					\
	arm_decode_data_proc_reg();		        					\
  switch((opcode >> 4) & 0x07)                                                			\
  {                                                                           			\
    /* LSL imm */                                                             			\
    case 0x0:                                                                 			\
    {                                                                         			\
	arm_data_proc_reg_shift_imm(name,LSL,rn_type);						\
	break;                                                                  		\
    }                                                                         			\
                                                                              			\
    /* LSL reg */                                                             			\
    case 0x1:                                                                 			\
    {                                                                         			\
	arm_data_proc_reg_shift_reg(name,LSL,rn_type);						\
	break;                                                                  		\
    }                                                                         			\
                                                                              			\
    /* LSR imm */                                                             			\
    case 0x2:                                                                 			\
    {                                                                         			\
	arm_data_proc_reg_shift_imm(name,LSR,rn_type);						\
	break;                                                                  		\
    }                                                                         			\
                                                                              			\
    /* LSR reg */                                                             			\
    case 0x3:                                                                 			\
    {                                                                         			\
	arm_data_proc_reg_shift_reg(name,LSR,rn_type);						\
	break;                                                                  		\
    }                                                                         			\
                                                                              			\
    /* ASR imm */                                                             			\
    case 0x4:                                                                 			\
    {                                                                         			\
 	arm_data_proc_reg_shift_imm(name,ASR,rn_type);						\
	break;                                                                  		\
    }                                                                         			\
                                                                              			\
    /* ASR reg */                                                             			\
    case 0x5:                                                                 			\
    {                                                                         			\
	arm_data_proc_reg_shift_reg(name,ASR,rn_type);						\
	break;                                                                  		\
    }                                                                         			\
                                                                              			\
    /* ROR imm */                                                             			\
    case 0x6:                                                                 			\
    {                                                                         			\
	arm_data_proc_reg_shift_imm(name,ROR,rn_type);						\
	break;                                                                  		\
    }                                                                         			\
                                                                              			\
    /* ROR reg */                                                             			\
    case 0x7:                                                                 			\
    {                                                                         			\
	arm_data_proc_reg_shift_reg(name,ROR,rn_type);						\
	break;                                                                  		\
    }                                                                         			\
  }                                                                           			\


#define arm_data_proc_imm_rn(name)				      				\
  	arm_decode_data_proc_imm();		        					\
	arm_generate_load_reg_pc_rn(a1, rn, 8);         					\
	generate_load_imm(a0, imm);            							\
	ARM_##name##_REG_REG(0, reg_a0, reg_a1, reg_a0);					\
	
#define arm_data_proc_imm_no_rn(name)				     				\
  	arm_decode_data_proc_imm();		        					\
	generate_load_imm(a1, imm);            							\
	ARM_##name##_REG_REG(0, reg_a0, reg_a1);						\


#define arm_data_proc_imm(name,rn_type)                              				\
	arm_data_proc_imm_##rn_type(name);			      				\

#define arm_data_proc_reg_flags(name,rn_type)                      				\
  arm_decode_data_proc_reg();                                                 			\
  generate_load_rm_sh(no_flags);                                               			\
  arm_generate_load_reg_pc_##rn_type(a1, rn, 8);                                            	\
  generate_function_call(execute_##name);                                     			\


#define arm_data_proc_imm_flags(name,rn_type)                           			\
  arm_decode_data_proc_imm();                                                 			\
  generate_load_imm(a0, imm);                                                  			\
  arm_generate_load_reg_pc_##rn_type(a1, rn, 8);                                            	\
  generate_function_call(execute_##name);                                     			\


#define arm_data_proc_orr_reg(name,rn_type)							\
	arm_data_proc_reg(ORR,rn_type);								\

#define arm_data_proc_mov_reg(name,rn_type)							\
	arm_data_proc_reg(MOV,rn_type);								\

#define arm_data_proc_bic_reg(name,rn_type)							\
	arm_data_proc_reg(BIC,rn_type);								\

#define arm_data_proc_mvn_reg(name,rn_type)							\
	arm_data_proc_reg(MVN,rn_type);								\

#define arm_data_proc_and_reg(name,rn_type)							\
	arm_data_proc_reg(AND,rn_type);								\

#define arm_data_proc_eor_reg(name,rn_type)							\
	arm_data_proc_reg(EOR,rn_type);								\

#define arm_data_proc_sub_reg(name,rn_type)							\
	arm_data_proc_reg(SUB,rn_type);								\

#define arm_data_proc_rsb_reg(name,rn_type)							\
	arm_data_proc_reg(RSB,rn_type);								\

#define arm_data_proc_add_reg(name,rn_type)							\
	arm_data_proc_reg(ADD,rn_type);								\

#define arm_data_proc_adc_reg(name,rn_type)							\
	arm_data_proc_reg_flags(name,rn_type);							\

#define arm_data_proc_sbc_reg(name,rn_type)							\
	arm_data_proc_reg_flags(name,rn_type);							\

#define arm_data_proc_rsc_reg(name,rn_type)							\
	arm_data_proc_reg_flags(name,rn_type);							\


#define arm_data_proc_orr_imm(name,rn_type)							\
	arm_data_proc_imm(ORR,rn_type);								\

#define arm_data_proc_mov_imm(name,rn_type)							\
	arm_data_proc_imm(MOV,rn_type);								\

#define arm_data_proc_bic_imm(name,rn_type)							\
	arm_data_proc_imm(BIC,rn_type);								\

#define arm_data_proc_mvn_imm(name,rn_type)							\
	arm_data_proc_imm(MVN,rn_type);								\

#define arm_data_proc_and_imm(name,rn_type)							\
	arm_data_proc_imm(AND,rn_type);								\

#define arm_data_proc_eor_imm(name,rn_type)							\
	arm_data_proc_imm(EOR,rn_type);								\

#define arm_data_proc_sub_imm(name,rn_type)							\
	arm_data_proc_imm(SUB,rn_type);								\

#define arm_data_proc_rsb_imm(name,rn_type)							\
	arm_data_proc_imm(RSB,rn_type);								\

#define arm_data_proc_add_imm(name,rn_type)							\
	arm_data_proc_imm(ADD,rn_type);								\

#define arm_data_proc_adc_imm(name,rn_type)							\
	arm_data_proc_imm_flags(name,rn_type);							\

#define arm_data_proc_sbc_imm(name,rn_type)							\
	arm_data_proc_imm_flags(name,rn_type);							\

#define arm_data_proc_rsc_imm(name,rn_type)							\
	arm_data_proc_imm_flags(name,rn_type);							\




#define arm_data_proc_orrs_imm(name,rn_type)							\
	arm_data_proc_imm_flags(name,rn_type);							\

#define arm_data_proc_movs_imm(name,rn_type)							\
	arm_data_proc_imm_flags(name,rn_type);							\

#define arm_data_proc_bics_imm(name,rn_type)							\
	arm_data_proc_imm_flags(name,rn_type);							\

#define arm_data_proc_mvns_imm(name,rn_type)							\
	arm_data_proc_imm_flags(name,rn_type);							\

#define arm_data_proc_ands_imm(name,rn_type)							\
	arm_data_proc_imm_flags(name,rn_type);							\

#define arm_data_proc_eors_imm(name,rn_type)							\
	arm_data_proc_imm_flags(name,rn_type);							\

#define arm_data_proc_subs_imm(name,rn_type)							\
	arm_data_proc_imm_flags(name,rn_type);							\

#define arm_data_proc_rsbs_imm(name,rn_type)							\
	arm_data_proc_imm_flags(name,rn_type);							\

#define arm_data_proc_adds_imm(name,rn_type)							\
	arm_data_proc_imm_flags(name,rn_type);							\

#define arm_data_proc_adcs_imm(name,rn_type)							\
	arm_data_proc_imm_flags(name,rn_type);							\

#define arm_data_proc_sbcs_imm(name,rn_type)							\
	arm_data_proc_imm_flags(name,rn_type);							\

#define arm_data_proc_rscs_imm(name,rn_type)							\
	arm_data_proc_imm_flags(name,rn_type);							\







#define arm_data_proc_orrs_reg(name,rn_type)							\
	arm_data_proc_reg_flags(name,rn_type);							\

#define arm_data_proc_movs_reg(name,rn_type)							\
	arm_data_proc_reg_flags(name,rn_type);							\

#define arm_data_proc_bics_reg(name,rn_type)							\
	arm_data_proc_reg_flags(name,rn_type);							\

#define arm_data_proc_mvns_reg(name,rn_type)							\
	arm_data_proc_reg_flags(name,rn_type);							\

#define arm_data_proc_ands_reg(name,rn_type)							\
	arm_data_proc_reg_flags(name,rn_type);							\

#define arm_data_proc_eors_reg(name,rn_type)							\
	arm_data_proc_reg_flags(name,rn_type);							\

#define arm_data_proc_subs_reg(name,rn_type)							\
	arm_data_proc_reg_flags(name,rn_type);							\

#define arm_data_proc_rsbs_reg(name,rn_type)							\
	arm_data_proc_reg_flags(name,rn_type);							\

#define arm_data_proc_adds_reg(name,rn_type)							\
	arm_data_proc_reg_flags(name,rn_type);							\

#define arm_data_proc_adcs_reg(name,rn_type)							\
	arm_data_proc_reg_flags(name,rn_type);							\

#define arm_data_proc_sbcs_reg(name,rn_type)							\
	arm_data_proc_reg_flags(name,rn_type);							\

#define arm_data_proc_rscs_reg(name,rn_type)							\
	arm_data_proc_reg_flags(name,rn_type);							\



#define arm_data_proc_orrs_reg_flags(name,rn_type)						\
	arm_data_proc_reg_reg_flags(name,rn_type);						\

#define arm_data_proc_movs_reg_flags(name,rn_type)						\
	arm_data_proc_reg_reg_flags(name,rn_type);						\

#define arm_data_proc_bics_reg_flags(name,rn_type)						\
	arm_data_proc_reg_reg_flags(name,rn_type);						\

#define arm_data_proc_mvns_reg_flags(name,rn_type)						\
	arm_data_proc_reg_reg_flags(name,rn_type);						\

#define arm_data_proc_ands_reg_flags(name,rn_type)						\
	arm_data_proc_reg_reg_flags(name,rn_type);						\

#define arm_data_proc_eors_reg_flags(name,rn_type)						\
	arm_data_proc_reg_reg_flags(name,rn_type);						\

#define arm_data_proc_subs_reg_flags(name,rn_type)						\
	arm_data_proc_reg_reg_flags(name,rn_type);						\

#define arm_data_proc_rsbs_reg_flags(name,rn_type)						\
	arm_data_proc_reg_reg_flags(name,rn_type);						\

#define arm_data_proc_adds_reg_flags(name,rn_type)						\
	arm_data_proc_reg_reg_flags(name,rn_type);						\

#define arm_data_proc_adcs_reg_flags(name,rn_type)						\
	arm_data_proc_reg_reg_flags(name,rn_type);						\

#define arm_data_proc_sbcs_reg_flags(name,rn_type)						\
	arm_data_proc_reg_reg_flags(name,rn_type);						\

#define arm_data_proc_rscs_reg_flags(name,rn_type)						\
	arm_data_proc_reg_reg_flags(name,rn_type);						\


#define arm_data_proc(name, type, flags_op)                                   			\
{                                                                             			\
	arm_data_proc_##name##_##type(name,rn);               		      			\
	generate_store_reg_pc_##flags_op(rv, rd);			      			\
}                                                                             			\

#define arm_data_proc_test_reg_flags()                                             		\
  arm_decode_data_proc_reg();                                                 			\
  if(flag_status & 0x02)                                                      			\
  {                                                                           			\
    generate_load_rm_sh(flags)                                                			\
  }                                                                           			\
  else                                                                        			\
  {                                                                           			\
    generate_load_rm_sh(no_flags);                                            			\
  }                                                                           			\


#define arm_data_proc_test_reg()                                                   		\
  arm_decode_data_proc_reg();                                                 			\
  generate_load_rm_sh(no_flags)                                               			\

#define arm_data_proc_test_imm()                                                   		\
  arm_decode_data_proc_imm();                                                 			\
  generate_load_imm(a0, imm)                                                  			\

#define arm_data_proc_test(name, type)                                        			\
{                                                                             			\
  arm_data_proc_test_##type();                                                			\
  generate_load_reg_pc(a1, rn, 8);                                            			\
  generate_function_call(execute_##name);                                     			\
}                                                                             			\

#define arm_data_proc_unary(name, type, flags_op)                             			\
{                                                                             			\
	arm_data_proc_##name##_##type(name,no_rn);             		      			\
	generate_store_reg_pc_##flags_op(rv, rd);			      			\
}                                                                             			\

#define arm_data_proc_mov(type)                                               			\
{                                                                             			\
  arm_data_proc_##type();                                                     			\
  generate_store_reg_pc_no_flags(a0, rd);                                     			\
}                                                                             			\

u32 function_cc execute_mul_flags(u32 dest)
{
  calculate_z_flag(dest);
  calculate_n_flag(dest);
}

#define arm_multiply_flags_yes()                                              			\
  generate_function_call(execute_mul_flags)                                   			\

#define arm_multiply_flags_no(_dest)                                          			\

#define arm_multiply_add_no()                                             			\
  ARM_MUL(0, reg_a0, reg_a0, reg_a1);                                                      	\

#define arm_multiply_add_yes()                                                			\
  generate_load_reg(a2, rn);                                                  			\
  ARM_MLA(0, reg_a0, reg_a0, reg_a1, reg_a2);                                                   \

#define arm_multiply(add_op, flags)                                           			\
{                                                                             			\
  arm_decode_multiply();                                                      			\
  generate_load_reg(a0, rm);                                                  			\
  generate_load_reg(a1, rs);                                                  			\
  arm_multiply_add_##add_op();                                          			\
  generate_store_reg(a0, rd);                                                 			\
  arm_multiply_flags_##flags();                                               			\
}                                                                             			\

u32 function_cc execute_mul_long_flags(u32 dest_lo, u32 dest_hi)
{
  reg[REG_Z_FLAG] = (dest_lo == 0) & (dest_hi == 0);
  calculate_n_flag(dest_hi);
}

#define generate_multiply_s64(rdlo, rdhi, rm, rs)                                               \
	ARM_SMULL(0, (rdlo), (rdhi), (rm), (rs));		  				\

#define generate_multiply_u64(rdlo, rdhi, rm, rs)                                               \
	ARM_UMULL(0, (rdlo), (rdhi), (rm), (rs));		  				\

#define generate_multiply_s64_add(rdlo, rdhi, rm, rs)                                           \
	ARM_SMLAL(0, (rdlo), (rdhi), (rm), (rs));		  				\

#define generate_multiply_u64_add(rdlo, rdhi, rm, rs)                                           \
	ARM_UMLAL(0, (rdlo), (rdhi), (rm), (rs));		  				\

  
#define arm_multiply_long_flags_yes()                                         			\
  generate_function_call(execute_mul_long_flags)                              			\

#define arm_multiply_long_flags_no(_dest)                                     			\

#define arm_multiply_long_add_yes(name)                                       			\
  generate_load_reg(a0, rdlo);                                                			\
  generate_load_reg(a1, rdhi);                                                			\
  generate_multiply_##name(reg_a0, reg_a1, reg_s0, reg_a2)                                      \

#define arm_multiply_long_add_no(name)                                        			\
  generate_load_reg(a0, rdlo);                                                			\
  generate_load_reg(a1, rdhi);                                                			\
  generate_multiply_##name(reg_a0, reg_a1, reg_s0, reg_a2)                                      \

#define arm_multiply_long(name, add_op, flags)                                			\
{                                                                             			\
  arm_decode_multiply_long();                                                 			\
  generate_load_reg(s0, rm);                                                  			\
  generate_load_reg(a2, rs);                                                  			\
  arm_multiply_long_add_##add_op(name);                                       			\
  generate_store_reg(a0, rdlo);                                               			\
  generate_store_reg(a1, rdhi);                                               			\
  arm_multiply_long_flags_##flags();                                          			\
}                                                                             			\

u32 function_cc execute_read_cpsr()
{
  collapse_flags();
  return reg[REG_CPSR];
}

u32 function_cc execute_read_spsr()
{
  collapse_flags();
  return spsr[reg[CPU_MODE]];
}

#define arm_psr_read(op_type, psr_reg)                                        			\
  generate_function_call(execute_read_##psr_reg);                             			\
  generate_store_reg(rv, rd)                                                  			\

// store_mask and address are stored in the SAVE slots, since there's no real
// register space to nicely pass them.
#if 0
u32 function_cc execute_store_cpsr_body(u32 _cpsr)
{
  reg[REG_CPSR] = _cpsr;
  if(reg[REG_SAVE] & 0xFF)
  {
    set_cpu_mode(cpu_modes[_cpsr & 0x1F]);
    if((io_registers[REG_IE] & io_registers[REG_IF]) &&
     io_registers[REG_IME] && ((_cpsr & 0x80) == 0))
    {
      printf("interrupt retrigger, %x in\n", instruction_count);
      reg_mode[MODE_IRQ][6] = reg[REG_SAVE2] + 4;
      spsr[MODE_IRQ] = _cpsr;
      reg[REG_CPSR] = (_cpsr & 0xFFFFFF00) | 0xD2;
      set_cpu_mode(MODE_IRQ);
      return 0x00000018;
    }
  }

  return 0;
}
#else
u32 execute_store_cpsr_body(u32 _cpsr, u32 store_mask, u32 address)
{
  reg[REG_CPSR] = _cpsr;
  if(store_mask & 0xFF)
  {
    set_cpu_mode(cpu_modes[_cpsr & 0x1F]);
    if((io_registers[REG_IE] & io_registers[REG_IF]) &&
     io_registers[REG_IME] && ((_cpsr & 0x80) == 0))
    {
      reg_mode[MODE_IRQ][6] = address + 4;
      spsr[MODE_IRQ] = _cpsr;
      reg[REG_CPSR] = 0xD2;
      set_cpu_mode(MODE_IRQ);
      return 0x00000018;
    }
  }

  return 0;
}
#endif

#if 1
void function_cc execute_store_spsr(u32 new_spsr, u32 store_mask)
{
  u32 _spsr = spsr[reg[CPU_MODE]];
  spsr[reg[CPU_MODE]] = (new_spsr & store_mask) | (_spsr & (~store_mask));
}
#endif

#define arm_psr_load_new_reg()                                                			\
  generate_load_reg(a0, rm)                                                   			\

#define arm_psr_load_new_imm()                                                			\
  generate_load_imm(a0, imm)                                                  			\

#define arm_psr_store(op_type, psr_reg)                                       			\
  arm_psr_load_new_##op_type();                                               			\
  generate_load_imm(a1, psr_masks[psr_field]);                                			\
  generate_load_pc(a2, (pc + 4));                                             			\
  generate_function_call(execute_store_##psr_reg)                             			\

#define arm_psr(op_type, transfer_type, psr_reg)                              			\
{                                                                             			\
  arm_decode_psr_##op_type();                                                 			\
  arm_psr_##transfer_type(op_type, psr_reg);                                  			\
}                                                                             			\

#define aligned_address_mask8  0xF0000000
#define aligned_address_mask16 0xF0000001
#define aligned_address_mask32 0xF0000003

#define read_memory(size, type, address, dest)                                			\
{                                                                             			\
  u8 *map;                                                                    			\
                                                                              			\
  if(((address >> 24) == 0) && (reg[REG_PC] >= 0x4000))                       			\
  {                                                                           			\
    dest = *((type *)((u8 *)&bios_read_protect + (address & 0x03)));          			\
  }                                                                           			\
  else                                                                        			\
                                                                              			\
  if(((address & aligned_address_mask##size) == 0) &&                         			\
   (map = memory_map_read[address >> 15]))                                    			\
  {                                                                           			\
    dest = *((type *)((u8 *)map + (address & 0x7FFF)));                       			\
  }                                                                           			\
  else                                                                        			\
  {                                                                           			\
    dest = (type)read_memory##size(address);                                  			\
  }                                                                           			\
}                                                                             			\

#define read_memory_s16(address, dest)                                        			\
{                                                                             			\
  u8 *map;                                                                    			\
                                                                              			\
  if(((address >> 24) == 0) && (reg[REG_PC] >= 0x4000))                       			\
  {                                                                           			\
    dest = *((s16 *)((u8 *)&bios_read_protect + (address & 0x03)));           			\
  }                                                                           			\
  else                                                                        			\
                                                                              			\
  if(((address & aligned_address_mask16) == 0) &&                             			\
   (map = memory_map_read[address >> 15]))                                    			\
  {                                                                           			\
    dest = *((s16 *)((u8 *)map + (address & 0x7FFF)));                        			\
  }                                                                           			\
  else                                                                        			\
  {                                                                           			\
    dest = (s16)read_memory16_signed(address);                                			\
  }                                                                           			\
}                                                                             			\

#define access_memory_generate_read_function(mem_size, mem_type)              			\
u32 function_cc execute_load_##mem_type(u32 address)                          			\
{                                                                             			\
  u32 dest;                                                                   			\
  read_memory(mem_size, mem_type, address, dest);                             			\
  return dest;                                                                			\
}                                                                             			\

access_memory_generate_read_function(8, u8);
access_memory_generate_read_function(8, s8);
access_memory_generate_read_function(16, u16);
access_memory_generate_read_function(32, u32);

u32 function_cc execute_load_s16(u32 address)
{
  u32 dest;
  read_memory_s16(address, dest);
  return dest;
}

#define access_memory_generate_write_function(mem_size, mem_type)             			\
void function_cc execute_store_##mem_type(u32 address, u32 source)            			\
{                                                                             			\
  u8 *map;                                                                    			\
                                                                              			\
  if(((address & aligned_address_mask##mem_size) == 0) &&                     			\
   (map = memory_map_write[address >> 15]))                                   			\
  {                                                                           			\
    *((mem_type *)((u8 *)map + (address & 0x7FFF))) = source;                 			\
  }                                                                           			\
  else                                                                        			\
  {                                                                           			\
    write_memory##mem_size(address, source);                                  			\
  }                                                                           			\
}                                                                             			\

#define arm_access_memory_load(mem_type)                                      			\
  cycle_count += 2;                                                           			\
  generate_function_call(execute_load_##mem_type);                            			\
  generate_store_reg_pc_no_flags(rv, rd)                                      			\

#define arm_access_memory_store(mem_type)                                     			\
  cycle_count++;                                                              			\
  generate_load_reg_pc(a1, rd, 12);                                           			\
  generate_load_pc(a2, (pc + 4));                                             			\
  generate_function_call(execute_store_##mem_type)                            			\

#define no_op                                                                 			\

#define arm_access_memory_writeback_yes(off_op)                               			\
  reg[rn] = address off_op                                                   			\

#define arm_access_memory_writeback_no(off_op)                                			\

#define load_reg_op reg[rd]                                                   			\

#define store_reg_op reg_op                                                   			\

#define arm_access_memory_adjust_op_up      add
#define arm_access_memory_adjust_op_down    sub
#define arm_access_memory_reverse_op_up     sub
#define arm_access_memory_reverse_op_down   add

#define arm_access_memory_reg_pre(adjust_dir_op, reverse_dir_op)              			\
  generate_load_reg_pc(a0, rn, 8);                                            			\
  generate_##adjust_dir_op(a0, a1)                                            			\

#define arm_access_memory_reg_pre_wb(adjust_dir_op, reverse_dir_op)           			\
  arm_access_memory_reg_pre(adjust_dir_op, reverse_dir_op);                   			\
  generate_store_reg(a0, rn)                                                  			\

#define arm_access_memory_reg_post(adjust_dir_op, reverse_dir_op)             			\
  generate_load_reg(a0, rn);                                                  			\
  generate_##adjust_dir_op(a0, a1);                                           			\
  generate_store_reg(a0, rn);                                                 			\
  generate_##reverse_dir_op(a0, a1)                                           			\

#define arm_access_memory_imm_pre(adjust_dir_op, reverse_dir_op)              			\
  generate_load_reg_pc(a0, rn, 8);                                            			\
  generate_##adjust_dir_op##_load_imm(a0, offset)                                  		\

#define arm_access_memory_imm_pre_wb(adjust_dir_op, reverse_dir_op)           			\
  arm_access_memory_imm_pre(adjust_dir_op, reverse_dir_op);                   			\
  generate_store_reg(a0, rn)                                                  			\

#define arm_access_memory_imm_post(adjust_dir_op, reverse_dir_op)             			\
  generate_load_reg(a0, rn);                                                  			\
  generate_##adjust_dir_op##_load_imm(a0, offset);                                 		\
  generate_store_reg(a0, rn);                                                 			\
  generate_##reverse_dir_op##_load_imm(a0, offset)                                 		\


#define arm_data_trans_reg(adjust_op, adjust_dir_op, reverse_dir_op)          			\
  arm_decode_data_trans_reg();                                               			\
  generate_load_offset_sh();                                                  			\
  arm_access_memory_reg_##adjust_op(adjust_dir_op, reverse_dir_op)            			\

#define arm_data_trans_imm(adjust_op, adjust_dir_op, reverse_dir_op)          			\
  arm_decode_data_trans_imm();                                                			\
  arm_access_memory_imm_##adjust_op(adjust_dir_op, reverse_dir_op)            			\

#define arm_data_trans_half_reg(adjust_op, adjust_dir_op, reverse_dir_op)     			\
  arm_decode_half_trans_r();                                                  			\
  generate_load_reg(a1, rm);                                                  			\
  arm_access_memory_reg_##adjust_op(adjust_dir_op, reverse_dir_op)            			\

#define arm_data_trans_half_imm(adjust_op, adjust_dir_op, reverse_dir_op)     			\
  arm_decode_half_trans_of();                                                 			\
  arm_access_memory_imm_##adjust_op(adjust_dir_op, reverse_dir_op)            			\

#define arm_access_memory(access_type, direction, adjust_op, mem_type,        			\
 offset_type)                                                                 			\
{                                                                             			\
  arm_data_trans_##offset_type(adjust_op,                                     			\
   arm_access_memory_adjust_op_##direction,                                   			\
   arm_access_memory_reverse_op_##direction);                                 			\
                                                                              			\
  arm_access_memory_##access_type(mem_type);                                  			\
}                                                                            			\

#define word_bit_count(word)                                                  			\
  (bit_count[word >> 8] + bit_count[word & 0xFF])                             			\

#define sprint_no(access_type, pre_op, post_op, wb)                           			\

#define sprint_yes(access_type, pre_op, post_op, wb)                          			\
  /*printf("sbit on %s %s %s %s\n", #access_type, #pre_op, #post_op, #wb)*/       		\

u32 function_cc execute_aligned_load32(u32 address)
{
  u8 *map;
  if(!(address & 0xF0000000) && (map = memory_map_read[address >> 15]))
    return address32(map, address & 0x7FFF);
  else
    return read_memory32(address);
}

void function_cc execute_aligned_store32(u32 address, u32 source)
{
  u8 *map;

  if(!(address & 0xF0000000) && (map = memory_map_write[address >> 15]))
    address32(map, address & 0x7FFF) = source;
  else
    write_memory32(address, source);
}

#define arm_block_memory_load()                                               			\
  generate_function_call(execute_aligned_load32);                             			\
  generate_store_reg(rv, i)                                                   			\

#define arm_block_memory_store()                                              			\
  generate_load_reg_pc(a1, i, 8);                                             			\
  generate_function_call(execute_aligned_store32)                             			\

#define arm_block_memory_final_load()                                         			\
  arm_block_memory_load()                                                     			\

#define arm_block_memory_final_store()                                        			\
  generate_load_reg_pc(a1, i, 12);                                            			\
  generate_load_pc(a2, (pc + 4));                                             			\
  generate_function_call(execute_store_u32)                                   			\

#define arm_block_memory_adjust_pc_store()                                    			\

#define arm_block_memory_adjust_pc_load()                                     			\
  if(reg_list & 0x8000)                                                       			\
  {                                                                           			\
    generate_mov(a0, rv);                                                     			\
    generate_indirect_branch_arm();                                           			\
  }                                                                           			\

#define arm_block_memory_offset_down_a()                                      			\
  generate_sub_imm(s0, ((word_bit_count(reg_list) * 4) - 4))                 			\

#define arm_block_memory_offset_down_b()                                      			\
  generate_sub_imm(s0, (word_bit_count(reg_list) * 4))                       			\

#define arm_block_memory_offset_no()                                          			\

#define arm_block_memory_offset_up()                                          			\
  generate_add_imm(s0, 4)                                                			\

#define arm_block_memory_writeback_down()                                     			\
  generate_load_reg(a0, rn);                                                   			\
  generate_sub_imm(a0, (word_bit_count(reg_list) * 4));                      			\
  generate_store_reg(a0, rn)                                                  			\

#define arm_block_memory_writeback_up()                                       			\
  generate_load_reg(a0, rn);                                                  			\
  generate_add_imm(a0, (word_bit_count(reg_list) * 4));                       			\
  generate_store_reg(a0, rn)                                                  			\

#define arm_block_memory_writeback_no()								\

// Only emit writeback if the register is not in the list

#define arm_block_memory_writeback_load(writeback_type)                       			\
  if(!((reg_list >> rn) & 0x01))                                              			\
  {                                                                           			\
    arm_block_memory_writeback_##writeback_type();                            			\
  }                                                                           			\

#define arm_block_memory_writeback_store(writeback_type)                      			\
  arm_block_memory_writeback_##writeback_type()                               			\

#define arm_block_memory(access_type, offset_type, writeback_type, s_bit)     			\
{                                                                            			\
  arm_decode_block_trans();                                                   			\
  u32 offset = 0;                                                             			\
  u32 i;                                                                      			\
                                                                              			\
  generate_load_reg(s0, rn);                                                  			\
  arm_block_memory_offset_##offset_type();                                    			\
  arm_block_memory_writeback_##access_type(writeback_type);                   			\
  ARM_BIC_REG_IMM(0, reg_s0, reg_s0, 3, 0);                                                	\
                                                                              			\
  for(i = 0; i < 16; i++)                                                     			\
  {                                                                           			\
    if((reg_list >> i) & 0x01)                                                			\
    {                                                                         			\
      cycle_count++;                                                          			\
      generate_add_reg_reg_imm(a0, s0, offset)                                			\
      if(reg_list & ~((2 << i) - 1))                                          			\
      {                                                                       			\
        arm_block_memory_##access_type();                                     			\
        offset += 4;                                                          			\
      }                                                                       			\
      else                                                                    			\
      {                                                                       			\
        arm_block_memory_final_##access_type();                               			\
	break; /* DEBUG THIS ADDED BREAK! */							\
      }                                                                       			\
    }                                                                         			\
  }                                                                           			\
                                                                              			\
  arm_block_memory_adjust_pc_##access_type();                                 			\
}                                                                             			\

#define arm_swap(type)                                                        			\
{                                                                             			\
  arm_decode_swap();                                                          			\
  cycle_count += 3;                                                           			\
  generate_load_reg(a0, rn);                                                  			\
  generate_function_call(execute_load_##type);                                			\
  generate_mov(s0, rv);                                                       			\
  generate_load_reg(a0, rn);                                                  			\
  generate_load_reg(a1, rm);                                                  			\
  generate_function_call(execute_store_##type);                               			\
  generate_store_reg(s0, rd);                                                 			\
}                                                                             			\

#define thumb_rn_op_reg(_rn)                                                  			\
  generate_load_reg(a0, _rn)                                                  			\

#define thumb_rn_op_imm(_imm)                                                 			\
  generate_load_imm(a0, _imm)                                                 			\

// Types: add_sub, add_sub_imm, alu_op, imm
// Affects N/Z/C/V flags

#define thumb_data_proc(type, name, rn_type, _rd, _rs, _rn)                   			\
{                                                                             			\
  thumb_decode_##type();                                                      			\
  thumb_rn_op_##rn_type(_rn);                                                 			\
  generate_load_reg(a1, _rs);                                                 			\
  generate_function_call(execute_##name);                                     			\
  generate_store_reg(rv, _rd);                                                			\
}                                                                             			\

#define thumb_data_proc_test(type, name, rn_type, _rs, _rn)                   			\
{                                                                             			\
  thumb_decode_##type();                                                      			\
  thumb_rn_op_##rn_type(_rn);                                                 			\
  generate_load_reg(a1, _rs);                                                 			\
  generate_function_call(execute_##name);                                     			\
}                                                                             			\

#define thumb_data_proc_unary(type, name, rn_type, _rd, _rn)                  			\
{                                                                             			\
  thumb_decode_##type();                                                      			\
  thumb_rn_op_##rn_type(_rn);                                                 			\
  generate_function_call(execute_##name);                                     			\
  generate_store_reg(rv, _rd);                                                			\
}                                                                             			\

#define thumb_data_proc_mov(type, rn_type, _rd, _rn)                          			\
{                                                                            			\
  thumb_decode_##type();                                                      			\
  thumb_rn_op_##rn_type(_rn);                                                 			\
  generate_store_reg(a0, _rd);                                                			\
}                                                                             			\

#define generate_store_reg_pc_thumb(ireg)                                     			\
  generate_store_reg(ireg, rd);                                               			\
  if(rd == 15)                                                                			\
  {                                                                           			\
    generate_indirect_branch_cycle_update(thumb);                             			\
  }                                                                           			\

#define thumb_data_proc_hi(name)                                              			\
{                                                                             			\
  thumb_decode_hireg_op();                                                    			\
  generate_load_reg_pc(a0, rs, 4);                                            			\
  generate_load_reg_pc(a1, rd, 4);                                            			\
  generate_function_call(execute_##name);                                     			\
  generate_store_reg_pc_thumb(rv);                                            			\
}                                                                             			\

#define thumb_data_proc_test_hi(name)                                         			\
{                                                                            			\
  thumb_decode_hireg_op();                                                    			\
  generate_load_reg_pc(a0, rs, 4);                                            			\
  generate_load_reg_pc(a1, rd, 4);                                            			\
  generate_function_call(execute_##name);                                     			\
}                                                                             			\

#define thumb_data_proc_unary_hi(name)                                        			\
{                                                                             			\
  thumb_decode_hireg_op();                                                    			\
  generate_load_reg_pc(a0, rn, 4);                                            			\
  generate_function_call(execute_##name);                                     			\
  generate_store_reg_pc_thumb(rv);                                            			\
}                                                                             			\

#define thumb_data_proc_mov_hi()                                              			\
{                                                                             			\
  thumb_decode_hireg_op();                                                    			\
  generate_load_reg_pc(a0, rs, 4);                                            			\
  generate_store_reg_pc_thumb(a0);                                            			\
}                                                                             			\

#define thumb_load_pc(_rd)                                                    			\
{                                                                             			\
  thumb_decode_imm();                                                         			\
  generate_load_pc(a0, (((pc & ~2) + 4) + (imm * 4)));                        			\
  generate_store_reg(a0, _rd);                                                			\
}                                                                             			\

#define thumb_load_sp(_rd)                                                    			\
{                                                                             			\
  thumb_decode_imm();                                                         			\
  generate_load_reg(a0, 13);                                                  			\
  generate_add_load_imm(a0, (imm * 4));                                            		\
  generate_store_reg(a0, _rd);                                                			\
}                                                                             			\

#define thumb_adjust_sp(value)                                                			\
{                                                                             			\
  thumb_decode_add_sp();                                                      			\
  generate_load_reg(a0, 13);                                                  			\
  generate_add_load_imm(a0, (value));                                              		\
  generate_store_reg(a0, 13);                                                 			\
}                                                                             			\

// Decode types: shift, alu_op
// Operation types: lsl, lsr, asr, ror
// Affects N/Z/C flags

u32 function_cc execute_lsl_reg_op(u32 value, u32 shift)
{
  if(shift != 0)
  {
    if(shift > 31)
    {
      if(shift == 32)
        reg[REG_C_FLAG] = value & 0x01;
      else
        reg[REG_C_FLAG] = 0;

      value = 0;
    }
    else
    {
      reg[REG_C_FLAG] = (value >> (32 - shift)) & 0x01;
      value <<= shift;
    }
  }

  calculate_flags_logic(value);
  return value;
}

u32 function_cc execute_lsr_reg_op(u32 value, u32 shift)
{
  if(shift != 0)
  {
    if(shift > 31)
    {
      if(shift == 32)
        reg[REG_C_FLAG] = (value >> 31) & 0x01;
      else
        reg[REG_C_FLAG] = 0;

      value = 0;
    }
    else
    {
      reg[REG_C_FLAG] = (value >> (shift - 1)) & 0x01;
      value >>= shift;
    }
  }

  calculate_flags_logic(value);
  return value;
}

u32 function_cc execute_asr_reg_op(u32 value, u32 shift)
{
  if(shift != 0)
  {
    if(shift > 31)
    {
      value = (s32)value >> 31;
      reg[REG_C_FLAG] = value & 0x01;
    }
    else
    {
      reg[REG_C_FLAG] = (value >> (shift - 1)) & 0x01;
      value = (s32)value >> shift;
    }
  }

  calculate_flags_logic(value);
  return value;
}

u32 function_cc execute_ror_reg_op(u32 value, u32 shift)
{
  if(shift != 0)
  {
    reg[REG_C_FLAG] = (value >> (shift - 1)) & 0x01;
    ror(value, value, shift);
  }

  calculate_flags_logic(value);
  return value;
}

u32 function_cc execute_lsl_imm_op(u32 value, u32 shift)
{
  if(shift != 0)
  {
    reg[REG_C_FLAG] = (value >> (32 - shift)) & 0x01;
    value <<= shift;
  }

  calculate_flags_logic(value);
  return value;
}

u32 function_cc execute_lsr_imm_op(u32 value, u32 shift)
{
  if(shift != 0)
  {
    reg[REG_C_FLAG] = (value >> (shift - 1)) & 0x01;
    value >>= shift;
  }
  else
  {
    reg[REG_C_FLAG] = value >> 31;
    value = 0;
  }

  calculate_flags_logic(value);
  return value;
}

u32 function_cc execute_asr_imm_op(u32 value, u32 shift)
{
  if(shift != 0)
  {
    reg[REG_C_FLAG] = (value >> (shift - 1)) & 0x01;
    value = (s32)value >> shift;
  }
  else
  {
    value = (s32)value >> 31;
    reg[REG_C_FLAG] = value & 0x01;
  }

  calculate_flags_logic(value);
  return value;
}

u32 function_cc execute_ror_imm_op(u32 value, u32 shift)
{
  if(shift != 0)
  {
    reg[REG_C_FLAG] = (value >> (shift - 1)) & 0x01;
    ror(value, value, shift);
  }
  else
  {
    u32 c_flag = reg[REG_C_FLAG];
    reg[REG_C_FLAG] = value & 0x01;
    value = (value >> 1) | (c_flag << 31);
  }

  calculate_flags_logic(value);
  return value;
}

#define generate_shift_load_operands_reg_tst()							\
	generate_function_call(execute_tst_reg_op);						\

#define generate_shift_load_operands_reg_teq()							\
	generate_function_call(execute_teq_reg_op);						\

#define generate_shift_load_operands_reg_cmp()							\
	generate_function_call(execute_cmp_reg_op);						\

#define generate_shift_load_operands_reg_cmn()							\
	generate_function_call(execute_cmn_reg_op);						\


#define generate_shift_load_operands_reg()	                              			\
  generate_load_reg(a0, rd);                                                  			\
  generate_load_reg(a1, rs)                                                   			\
  /*generate_shift_load_operands_reg_##op_type();*/			      			\

#define generate_shift_load_operands_imm()                                    			\
  generate_load_reg(a0, rs);                                                 			\
  generate_load_imm(a1, imm)                                                  			\
  /*generate_shift_load_operands_imm_##op_type();*/			      			\

#define thumb_shift(decode_type, op_type, value_type)                         			\
{                                                                             			\
  thumb_decode_##decode_type();                                               			\
  generate_shift_load_operands_##value_type();                                			\
  generate_function_call(execute_##op_type##_##value_type##_op);             			\
  generate_store_reg(rv, rd);                                                 			\
}                                                                             			\

// Operation types: imm, mem_reg, mem_imm

#define thumb_access_memory_load(mem_type, reg_rd)                            			\
  cycle_count += 2;                                                           			\
  generate_function_call(execute_load_##mem_type);                            			\
  generate_store_reg(rv, reg_rd)                                              			\

#define thumb_access_memory_store(mem_type, reg_rd)                           			\
  cycle_count++;                                                              			\
  generate_load_reg(a1, reg_rd);                                              			\
  generate_load_pc(a2, (pc + 2));                                             			\
  generate_function_call(execute_store_##mem_type)                            			\

#define thumb_access_memory_generate_address_pc_relative(offset, reg_rb,      			\
 reg_ro)                                                                      			\
  generate_load_pc(a0, (offset))                                              			\

#define thumb_access_memory_generate_address_reg_imm(offset, reg_rb, reg_ro)  			\
  generate_load_reg(a0, reg_rb);                                              			\
  generate_add_load_imm(a0, (offset))                                              		\

#define thumb_access_memory_generate_address_reg_reg(offset, reg_rb, reg_ro)  			\
  generate_load_reg(a0, reg_rb);                                              			\
  generate_load_reg(a1, reg_ro);                                              			\
  generate_add(a0, a1)                                                        			\

#define thumb_access_memory(access_type, op_type, reg_rd, reg_rb, reg_ro,     			\
 address_type, offset, mem_type)                                             			\
{                                                                             			\
  thumb_decode_##op_type();                                                   			\
  thumb_access_memory_generate_address_##address_type(offset, reg_rb,         			\
   reg_ro);                                                                   			\
  thumb_access_memory_##access_type(mem_type, reg_rd);                        			\
}                                                                             			\

#define thumb_block_address_preadjust_up()                                    			\
  generate_add_imm(s0, (bit_count[reg_list] * 4))                             			\

#define thumb_block_address_preadjust_down()                                  			\
  generate_sub_imm(s0, (bit_count[reg_list] * 4))                             			\

#define thumb_block_address_preadjust_push_lr()                               			\
  generate_sub_imm(s0, ((bit_count[reg_list] + 1) * 4))                       			\

#define thumb_block_address_preadjust_no()                                    			\

#define thumb_block_address_postadjust_no(base_reg)                          			\
  generate_store_reg(s0, base_reg)                                            			\

#define thumb_block_address_postadjust_up(base_reg)                           			\
  generate_add_reg_reg_imm(a0, s0, (bit_count[reg_list] * 4));                			\
  generate_store_reg(a0, base_reg)                                            			\

#define thumb_block_address_postadjust_down(base_reg)                         			\
  generate_mov(a0, s0);                                                       			\
  generate_sub_imm(a0, (bit_count[reg_list] * 4));                            			\
  generate_store_reg(a0, base_reg)                                            			\

#define thumb_block_address_postadjust_pop_pc(base_reg)                       			\
  generate_add_reg_reg_imm(a0, s0, ((bit_count[reg_list] + 1) * 4));          			\
  generate_store_reg(a0, base_reg)                                            			\

#define thumb_block_address_postadjust_push_lr(base_reg)                      			\
  generate_store_reg(s0, base_reg)                                            			\

#define thumb_block_memory_extra_no()                                         			\

#define thumb_block_memory_extra_up()                                         			\

#define thumb_block_memory_extra_down()                                       			\

#define thumb_block_memory_extra_pop_pc()                                     			\
  generate_add_reg_reg_imm(a0, s0, (bit_count[reg_list] * 4));                			\
  generate_function_call(execute_aligned_load32);                             			\
  generate_store_reg(rv, REG_PC);                                             			\
  generate_mov(a0, rv);                                                       			\
  generate_indirect_branch_cycle_update(thumb)                                			\

#define thumb_block_memory_extra_push_lr(base_reg)                            			\
  generate_add_reg_reg_imm(a0, s0, (bit_count[reg_list] * 4));                			\
  generate_load_reg(a1, REG_LR);                                              			\
  generate_function_call(execute_aligned_store32)                             			\

#define thumb_block_memory_load()                                             			\
  generate_function_call(execute_aligned_load32);                             			\
  generate_store_reg(rv, i)                                                   			\

#define thumb_block_memory_store()                                            			\
  generate_load_reg(a1, i);                                                   			\
  generate_function_call(execute_aligned_store32)                             			\

#define thumb_block_memory_final_load()                                      			\
  thumb_block_memory_load()                                                   			\

#define thumb_block_memory_final_store()                                      			\
  generate_load_reg(a1, i);                                                   			\
  generate_load_pc(a2, (pc + 2));                                             			\
  generate_function_call(execute_store_u32)                                   			\

#define thumb_block_memory_final_no(access_type)                             			\
  thumb_block_memory_final_##access_type()                                    			\

#define thumb_block_memory_final_up(access_type)                              			\
  thumb_block_memory_final_##access_type()                                    			\

#define thumb_block_memory_final_down(access_type)                            			\
  thumb_block_memory_final_##access_type()                                    			\

#define thumb_block_memory_final_push_lr(access_type)                         			\
  thumb_block_memory_##access_type()                                          			\

#define thumb_block_memory_final_pop_pc(access_type)                          			\
  thumb_block_memory_##access_type()                                          			\

#define thumb_block_memory(access_type, pre_op, post_op, base_reg)            			\
{                                                                             			\
  thumb_decode_rlist();                                                       			\
  u32 i;                                                                      			\
  u32 offset = 0;                                                             			\
                                                                              			\
  generate_load_reg(s0, base_reg);                                            			\
  ARM_BIC_REG_IMM(0, reg_s0, reg_s0, 3, 0);                                                	\
  thumb_block_address_preadjust_##pre_op();                                   			\
  thumb_block_address_postadjust_##post_op(base_reg);                         			\
                                                                              			\
  for(i = 0; i < 8; i++)                                                      			\
  {                                                                           			\
    if((reg_list >> i) & 0x01)                                                			\
    {                                                                         			\
      cycle_count++;                                                          			\
      generate_add_reg_reg_imm(a0, s0, offset)                                			\
      if(reg_list & ~((2 << i) - 1))                                          			\
      {                                                                       			\
        thumb_block_memory_##access_type();                                   			\
        offset += 4;                                                          			\
      }                                                                       			\
      else                                                                    			\
      {                                                                       			\
        thumb_block_memory_final_##post_op(access_type);                      			\
	break; /* DEBUG THIS ADDED BREAK! */							\
      }                                                                       			\
    }                                                                         			\
  }                                                                           			\
                                                                              			\
  thumb_block_memory_extra_##post_op();                                       			\
}                                                                             			\


#define thumb_conditional_branch(condition)                                   			\
{                                                                             			\
  condition_check_type condition_check;                                       			\
  generate_cycle_update();                                                    			\
  generate_condition_##condition(a0, a1);                                     			\
  generate_conditional_branch_type(a0, a1);                                   			\
  generate_branch_no_cycle_update(                                            			\
   block_exits[block_exit_position].branch_source,                            			\
   block_exits[block_exit_position].branch_target);                           			\
  generate_branch_patch_conditional(backpatch_address, translation_ptr);      			\
  block_exit_position++;                                                      			\
}                                                                             			\

#define flags_vars(src_a, src_b)                                              			\
  u32 dest;                                                                   			\
  const u32 _sa = src_a;                                                      			\
  const u32 _sb = src_b                                                       			\

#define data_proc_generate_logic_function(name, expr)                         			\
u32 function_cc execute_##name(u32 rm, u32 rn)                                			\
{                                                                             			\
  return expr;                                                                			\
}                                                                             			\
                                                                              			\
u32 function_cc execute_##name##s(u32 rm, u32 rn)                             			\
{                                                                             			\
  u32 dest = expr;                                                            			\
  calculate_z_flag(dest);                                                     			\
  calculate_n_flag(dest);                                                     			\
  return expr;                                                                			\
}                                                                             			\

#define data_proc_generate_logic_unary_function(name, expr)                   			\
u32 function_cc execute_##name(u32 rm)                                        			\
{                                                                             			\
  return expr;                                                                			\
}                                                                             			\
                                                                              			\
u32 function_cc execute_##name##s(u32 rm)                                     			\
{                                                                             			\
  u32 dest = expr;                                                            			\
  calculate_z_flag(dest);                                                     			\
  calculate_n_flag(dest);                                                     			\
  return expr;                                                                			\
}                                                                             			\


#define data_proc_generate_sub_function(name, src_a, src_b)                   			\
u32 function_cc execute_##name(u32 rm, u32 rn)                                			\
{                                                                             			\
  return (src_a) - (src_b);                                                   			\
}                                                                             			\
                                                                              			\
u32 function_cc execute_##name##s(u32 rm, u32 rn)                             			\
{                                                                             			\
  flags_vars(src_a, src_b);                                                   			\
  dest = _sa - _sb;                                                           			\
  calculate_flags_sub(dest, _sa, _sb);                                        			\
  return dest;                                                                			\
}                                                                             			\

#define data_proc_generate_add_function(name, src_a, src_b)                   			\
u32 function_cc execute_##name(u32 rm, u32 rn)                                			\
{                                                                             			\
  return (src_a) + (src_b);                                                   			\
}                                                                             			\
                                                                              			\
u32 function_cc execute_##name##s(u32 rm, u32 rn)                             			\
{                                                                             			\
  flags_vars(src_a, src_b);                                                   			\
  dest = _sa + _sb;                                                           			\
  calculate_flags_add(dest, _sa, _sb);                                        			\
  return dest;                                                                			\
}                                                                             			\

#define data_proc_generate_sub_test_function(name, src_a, src_b)              			\
void function_cc execute_##name(u32 rm, u32 rn)                               			\
{                                                                             			\
  flags_vars(src_a, src_b);                                                   			\
  dest = _sa - _sb;                                                           			\
  calculate_flags_sub(dest, _sa, _sb);                                        			\
}                                                                             			\

#define data_proc_generate_add_test_function(name, src_a, src_b)              			\
void function_cc execute_##name(u32 rm, u32 rn)                               			\
{                                                                             			\
  flags_vars(src_a, src_b);                                                   			\
  dest = _sa + _sb;                                                           			\
  calculate_flags_add(dest, _sa, _sb);                                       			\
}                                                                             			\

#define data_proc_generate_logic_test_function(name, expr)                    			\
void function_cc execute_##name(u32 rm, u32 rn)                               			\
{                                                                             			\
  u32 dest = expr;                                                            			\
  calculate_z_flag(dest);                                                     			\
  calculate_n_flag(dest);                                                     			\
}                                                                             			\

u32 function_cc execute_neg(u32 rm)                                           			\
{                                                                             			\
  u32 dest = 0 - rm;                                                          			\
  calculate_flags_sub(dest, 0, rm);                                           			\
  return dest;                                                               			\
}                                                                             			\

// Execute functions

data_proc_generate_logic_function(and, rn & rm);
data_proc_generate_logic_function(eor, rn ^ rm);
data_proc_generate_logic_function(orr, rn | rm);
data_proc_generate_logic_function(bic, rn & (~rm));
data_proc_generate_logic_function(mul, rn * rm);
data_proc_generate_logic_unary_function(mov, rm);
data_proc_generate_logic_unary_function(mvn, ~rm);

data_proc_generate_sub_function(sub, rn, rm);
data_proc_generate_sub_function(rsb, rm, rn);
data_proc_generate_sub_function(sbc, rn - rm, (reg[REG_C_FLAG] ^ 1));
data_proc_generate_sub_function(rsc, rm + reg[REG_C_FLAG] - 1, rn);
data_proc_generate_add_function(add, rn, rm);
data_proc_generate_add_function(adc, rn, rm + reg[REG_C_FLAG]);

data_proc_generate_logic_test_function(tst, rn & rm);
data_proc_generate_logic_test_function(teq, rn ^ rm);
data_proc_generate_sub_test_function(cmp, rn, rm);
data_proc_generate_add_test_function(cmn, rn, rm);

u32 function_cc execute_swi(u32 pc)
{
  reg_mode[MODE_SUPERVISOR][6] = pc;
  collapse_flags();
  spsr[MODE_SUPERVISOR] = reg[REG_CPSR];
  reg[REG_CPSR] = (reg[REG_CPSR] & ~0x3F) | 0x13;
  set_cpu_mode(MODE_SUPERVISOR);
}

#define arm_conditional_block_header()                                        			\
{                                                                             			\
  condition_check_type condition_check;                                       			\
  generate_condition(a0, a1);                                                 			\
  generate_conditional_branch_type(a0, a1);                                   			\
}

#define arm_b()                                                               			\
  generate_branch()                                                           			\

#define arm_bl()                                                              			\
  generate_update_pc((pc + 4));                                               			\
  generate_store_reg(a0, REG_LR);                                             			\
  generate_branch()                                                           			\

#define arm_bx()                                                              			\
  arm_decode_branchx();                                                       			\
  generate_load_reg(a0, rn);                                                  			\
  generate_indirect_branch_dual();                                            			\

#define arm_swi()                                                             			\
  generate_swi_hle_handler((opcode >> 16) & 0xFF);                            			\
  generate_update_pc((pc + 4));                                               			\
  generate_function_call(execute_swi);                                        			\
  generate_branch()                                                           			\

#define thumb_b()                                                             			\
  generate_branch_cycle_update(                                               			\
   block_exits[block_exit_position].branch_source,                            			\
   block_exits[block_exit_position].branch_target);                           			\
  block_exit_position++                                                       			\

#define thumb_bl()                                                            			\
  generate_update_pc(((pc + 2) | 0x01));                                      			\
  generate_store_reg(a0, REG_LR);                                             			\
  generate_branch_cycle_update(                                               			\
   block_exits[block_exit_position].branch_source,                            			\
   block_exits[block_exit_position].branch_target);                           			\
  block_exit_position++                                                       			\

#define thumb_blh()                                                           			\
{                                                                             			\
  thumb_decode_branch();                                                      			\
  generate_update_pc(((pc + 2) | 0x01));                                      			\
  generate_load_reg(a1, REG_LR);                                              			\
  generate_store_reg(a0, REG_LR);                                             			\
  generate_mov(a0, a1);                                                       			\
  generate_add_load_imm(a0, (offset * 2));                                         		\
  generate_indirect_branch_cycle_update(thumb);                               			\
}                                                                             			\

#define thumb_bx()                                                            			\
{                                                                             			\
  thumb_decode_hireg_op();                                                    			\
  generate_load_reg_pc(a0, rs, 4);                                            			\
  generate_indirect_branch_cycle_update(dual);                                			\
}                                                                             			\

#define thumb_swi()                                                           			\
  generate_swi_hle_handler(opcode & 0xFF);                                    			\
  generate_update_pc((pc + 2));                                               			\
  generate_function_call(execute_swi);                                        			\
  generate_branch_cycle_update(                                               			\
   block_exits[block_exit_position].branch_source,                            			\
   block_exits[block_exit_position].branch_target);                           			\
  block_exit_position++                                                       			\

u8 swi_hle_handle[256] =
{
  0x0,    // SWI 0:  SoftReset
  0x0,    // SWI 1:  RegisterRAMReset
  0x0,    // SWI 2:  Halt
  0x0,    // SWI 3:  Stop/Sleep
  0x0,    // SWI 4:  IntrWait
  0x0,    // SWI 5:  VBlankIntrWait
  0x0,    // SWI 6:  Div
  0x0,    // SWI 7:  DivArm
  0x0,    // SWI 8:  Sqrt
  0x0,    // SWI 9:  ArcTan
  0x0,    // SWI A:  ArcTan2
  0x0,    // SWI B:  CpuSet
  0x0,    // SWI C:  CpuFastSet
  0x0,    // SWI D:  GetBIOSCheckSum
  0x0,    // SWI E:  BgAffineSet
  0x0,    // SWI F:  ObjAffineSet
  0x0,    // SWI 10: BitUnpack
  0x0,    // SWI 11: LZ77UnCompWram
  0x0,    // SWI 12: LZ77UnCompVram
  0x0,    // SWI 13: HuffUnComp
  0x0,    // SWI 14: RLUnCompWram
  0x0,    // SWI 15: RLUnCompVram
  0x0,    // SWI 16: Diff8bitUnFilterWram
  0x0,    // SWI 17: Diff8bitUnFilterVram
  0x0,    // SWI 18: Diff16bitUnFilter
  0x0,    // SWI 19: SoundBias
  0x0,    // SWI 1A: SoundDriverInit
  0x0,    // SWI 1B: SoundDriverMode
  0x0,    // SWI 1C: SoundDriverMain
  0x0,    // SWI 1D: SoundDriverVSync
  0x0,    // SWI 1E: SoundChannelClear
  0x0,    // SWI 1F: MidiKey2Freq
  0x0,    // SWI 20: SoundWhatever0
  0x0,    // SWI 21: SoundWhatever1
  0x0,    // SWI 22: SoundWhatever2
  0x0,    // SWI 23: SoundWhatever3
  0x0,    // SWI 24: SoundWhatever4
  0x0,    // SWI 25: MultiBoot
  0x0,    // SWI 26: HardReset
  0x0,    // SWI 27: CustomHalt
  0x0,    // SWI 28: SoundDriverVSyncOff
  0x0,    // SWI 29: SoundDriverVSyncOn
  0x0     // SWI 2A: SoundGetJumpList
};

void swi_hle_div()
{
  s32 result = (s32)reg[0] / (s32)reg[1];
  reg[0] = result;
  reg[1] = (s32)reg[0] % (s32)reg[1];
  reg[3] = (result ^ (result >> 31)) - (result >> 31);
}

#define generate_swi_hle_handler(_swi_number)                                 			\
{                                                                             			\
  u32 swi_number = _swi_number;                                               			\
  if(swi_hle_handle[swi_number])                                              			\
  {                                                                           			\
    /* Div */                                                                 			\
    if(swi_number == 0x06)                                                    			\
    {                                                                         			\
      generate_function_call(swi_hle_div);                                    			\
    }                                                                         			\
    break;                                                                    			\
  }                                                                           			\
}                                                                             			\

#define generate_translation_gate(type)                                       			\
  generate_update_pc(pc);                                                     			\
  generate_indirect_branch_no_cycle_update(type)                              			\

#define generate_step_debug()                                                 			\
  generate_load_imm(a0, pc);                                                  			\
  generate_function_call(step_debug_x86)                                      			\


extern void sys_icache_invalidate(const void* Addr, size_t len);

void CLEAR_INSN_CACHE(u8 *code, int size)
{
	sys_icache_invalidate((void*)code, size);
}

#endif