www.pudn.com > EloGbaR1.zip > opcodes.c


#define DEST_REG		arm->gp_reg [(OPCODE>>12)&0xF] 
#define BASE_REG		arm->gp_reg [(OPCODE>>16)&0xF] 
#define OP_REG			arm->gp_reg [(OPCODE&0xF)] 
#define SHFT_AMO_REG	arm->gp_reg [(OPCODE>>8)&0xF] 
 
#define HDT_CALC_IMM_OFFSET	((OPCODE&0xF00)>>4)|(OPCODE&0xF) 
 
__inline u32 DP_IMM_OPERAND (void) 
{		 
	u32 value = OPCODE; 
 
	__asm { 
		mov ecx, value 
		mov bl, cl 
		and ecx, 0xF00 
		shr ecx, 7		 
		ror ebx, cl 
		mov value, ebx 
	} 
		 
	return value; 
} 
 
//-------------Barrel-Shifter ("evil"(tm))---------------------------------------------- 
 
#define IMM_SHIFT	((OPCODE>>7)&0x1F) 
#define REG_SHIFT	(SHFT_AMO_REG&0xFF) 
 
__inline DP_REG_OPERAND (u32 shift) 
{ 
	u32 shift_amount = shift; 
	u32 op = OP_REG; 
	switch ((OPCODE>>5)&0x3)	 
	{							 
		case 0: return (op << shift_amount);	 
		case 1: if (shift_amount) return (op >> shift_amount); else return 0; 
		case 2:  
			if (shift_amount) { 
				if (op&0x80000000) 
					return ((0xFFFFFFFF<<(32-shift_amount))|(op>>shift_amount));  
				else 
					return (op >> shift_amount); 
			} 
			else { 
				if (op&0x80000000) return 0xFFFFFFFF; else return 0; 
			} 
		case 3:  
			if (shift_amount) { 
				return (op << (32-shift_amount)|(op>>shift_amount)); 
			} 
			else 
				return ((op>>1)|(CFLAG<<31)); 
	} 
	return 0; 
} 
 
__inline DP_REG_OPERAND_C (u32 shift) 
{ 
	u32 op = OP_REG; 
 
	switch ((OPCODE>>5)&0x3)	 
	{							 
		case 0: 
			CFLAG = (op&(0x80000000>>(shift-1))) ? (1):(0); 
			return (op << shift); 
		case 1:  
			if (shift) { 
				CFLAG = (op&(1<<(shift-1))) ? (1):(0); 
				return (op >> shift); 
			}  
			else { 
				CFLAG = op>>31; return 0; 
			} 
		case 2:  
			if (shift) { 
				CFLAG = (op&(1<<(shift-1))) ? (1):(0); 
				if (op&0x80000000) 
					return ((0xFFFFFFFF<<(32-shift))|(op>>shift));  
				else 
					return (op >> shift); 
			} else { 
				CFLAG = op>>31; 
				if (CFLAG) return 0xFFFFFFFF; else return 0; 
			} 
		case 3:  
			if (shift) { 
				CFLAG = (op&(1<<(shift-1))) ? (1):(0); 
				return (op << (32-shift)|(op>>shift)); 
			} 
			else { 
				if (CFLAG) { 
					CFLAG = op&0x1; 
					return ((op>>1)|0x80000000); 
				} 
				else { 
					CFLAG = op&0x1;	 
					return (op>>1); 
				} 
			} 
	} 
	return 0; 
} 
 
//-------------------------------------------------------------------------------------- 
 
//---------------------Flag macros------------------------------------------------------ 
 
#define TOPBIT 0x80000000 
 
// Arithmetic Data Processing  
__inline void SET_SUB_FLAGS (u32 a, u32 b, u32 c) 
{ 
	if (c) ZFLAG = 0; else ZFLAG = 1; 
	NFLAG = ((c&TOPBIT)>>31);  
	CFLAG = ((a&(~b))|(a&(~c))|((~b)&(~c)))>>31; 
	//VFLAG = ((a&~(b|c))|((~a)&b&c))>>31; 
	//VFLAG = ((a&(~b)&(~c))|((~a)&b&c))>>31; 
 
	VFLAG = ((a&~(b|c))|((b&c)&~a))>>31; 
} 
 
__inline void SET_ADD_FLAGS (u32 a, u32 b, u32 c) 
{ 
	if (c) ZFLAG = 0; else ZFLAG = 1; 
	NFLAG = (c>>31);  
	CFLAG = ((a&b)|(a&(~c))|(b&(~c)))>>31; 
	VFLAG = ((a&b&(~c))|((~a)&(~b)&c))>>31; 
} 
 
// Logical Data Processing (value is supposed to be 32 bit) 
#define SET_DP_LOG_FLAGS(value)\ 
	if (value) ZFLAG = 0; else ZFLAG = 1;\ 
	NFLAG = (value>>31) 
 
//-------------------------------------------------------------------------------------- 
 
/***********************************************************************************************/ 
/*									Opcodes													   */ 
/***********************************************************************************************/ 
 
int unknown_opcode(void )  
{ 
	return 1; 
} 
 
int ins_bpl (void) 
{ 
	arm->gp_reg [15] += ((OPCODE&0x7FFFFF)<<2); 
	fill_instruction_pipe(); return 3; 
} 
 
int ins_bmi (void) 
{ 
	arm->gp_reg [15] += (((OPCODE&0xFFFFFF)<<2)-0x4000000); 
	fill_instruction_pipe(); return 3; 
} 
 
int ins_blpl (void) 
{ 
	arm->gp_reg [14] = arm->gp_reg [15] - 4; 
	arm->gp_reg [15] += ((OPCODE&0xFFFFFF)<<2); 
	fill_instruction_pipe(); return 3; 
} 
 
int ins_blmi (void) 
{ 
	arm->gp_reg [14] = arm->gp_reg [15] - 4; 
	arm->gp_reg [15] += (((OPCODE&0xFFFFFF)<<2)-0x4000000); 
	fill_instruction_pipe(); return 3; 
} 
 
int ins_bx (void) 
{ 
	arm->gp_reg [15] = OP_REG & ~0x1; 
	if (OP_REG&0x1) { 
		CPSR |= T_BIT; 
		arm->state = OP_REG & 0x1; 
		exec = thumb_exec; 
		tfill_instruction_pipe(); 
	} 
	else { 
		CPSR &= ~T_BIT; 
		exec = arm_exec; 
		fill_instruction_pipe(); 
	} 
	return 3; 
} 
 
int ins_mul(void) 
{ 
	BASE_REG = OP_REG * SHFT_AMO_REG; 
	advance_instruction_pipe(); return 4; 
} 
 
int ins_muls(void) 
{ 
	BASE_REG = OP_REG * SHFT_AMO_REG; 
	SET_DP_LOG_FLAGS(BASE_REG); 
	advance_instruction_pipe(); return 4; 
} 
 
int ins_mla(void) 
{ 
	BASE_REG = (OP_REG * SHFT_AMO_REG) + DEST_REG; 
	advance_instruction_pipe();	return 4; 
} 
 
int ins_mlas(void) 
{ 
	BASE_REG = (OP_REG * SHFT_AMO_REG) + DEST_REG; 
	SET_DP_LOG_FLAGS(BASE_REG); 
	advance_instruction_pipe();	return 4; 
} 
 
int ins_mull(void) 
{ 
	INT64 temp64 = (INT64)OP_REG; 
 
	temp64 *= ((s32)SHFT_AMO_REG); 
 
	DEST_REG = (u32)(temp64 & 0xFFFFFFFF); 
	BASE_REG = (u32)((temp64>>32) & 0xFFFFFFFF);  
 
	advance_instruction_pipe();	return 4; 
} 
 
int ins_mulls(void) 
{ 
	INT64 temp64 = (INT64)OP_REG; 
 
	temp64 *= ((s32)SHFT_AMO_REG); 
 
	DEST_REG = (u32)(temp64 & 0xFFFFFFFF); 
	BASE_REG = (u32)((temp64>>32) & 0xFFFFFFFF);  
 
	if (!temp64)					ZFLAG = 1; else ZFLAG = 0; 
	if (temp64&0x8000000000000000)	NFLAG = 1; else NFLAG = 0; 
 
	advance_instruction_pipe();	return 4; 
} 
 
int ins_mull_unsigned(void) 
{ 
	UINT64 temp64 = (UINT64)OP_REG; 
 
	temp64 *= SHFT_AMO_REG; 
 
	DEST_REG = (u32)(temp64 & 0xFFFFFFFF); 
	BASE_REG = (u32)((temp64>>32) & 0xFFFFFFFF);  
 
	advance_instruction_pipe();	return 4; 
} 
 
int ins_mulls_unsigned(void) 
{ 
	UINT64 temp64 = (UINT64)OP_REG; 
 
	temp64 *= SHFT_AMO_REG; 
 
	DEST_REG = (u32)(temp64 & 0xFFFFFFFF); 
	BASE_REG = (u32)((temp64>>32)&0xFFFFFFFF);  
 
	if (!temp64)					ZFLAG = 1; else ZFLAG = 0; 
	if (temp64&0x8000000000000000)	NFLAG = 1; else NFLAG = 0; 
 
	advance_instruction_pipe();	return 4; 
} 
 
int ins_mlal(void) 
{ 
	INT64 temp64 = (INT64)OP_REG; 
	INT64 operand = (INT64)DEST_REG; 
	operand |= ((INT64)BASE_REG)<<32; 
		 
	temp64 = (temp64 * ((INT64)SHFT_AMO_REG)) + operand; 
 
	DEST_REG = (u32)(temp64 & 0xFFFFFFFF); 
	BASE_REG = (u32)((temp64>>32)&0xFFFFFFFF);  
	 
	advance_instruction_pipe();	return 4; 
} 
 
int ins_mlals(void) 
{ 
	INT64 temp64 = (INT64)OP_REG; 
	INT64 operand = (INT64)DEST_REG; 
	operand |= ((INT64)BASE_REG)<<32; 
		 
	temp64 = (temp64 * ((INT64)SHFT_AMO_REG)) + operand; 
 
	DEST_REG = (u32)(temp64 & 0xFFFFFFFF); 
	BASE_REG = (u32)((temp64>>32)&0xFFFFFFFF);  
 
	if (!temp64)					ZFLAG = 1; else ZFLAG = 0; 
	if (temp64&0x8000000000000000)	NFLAG = 1; else ZFLAG = 0; 
 
	advance_instruction_pipe();	return 4; 
} 
 
int ins_mlal_unsigned(void) 
{ 
	UINT64 temp64 = (UINT64)OP_REG; 
	UINT64 operand = (UINT64)DEST_REG; 
	operand |= ((UINT64)BASE_REG)<<32; 
 
	temp64 = (temp64 * ((UINT64)SHFT_AMO_REG)) + operand; 
 
	DEST_REG = (u32)(temp64 & 0xFFFFFFFF); 
	BASE_REG = (u32)((temp64>>32)&0xFFFFFFFF);  
	 
	advance_instruction_pipe();	return 4; 
} 
 
int ins_mlals_unsigned(void) 
{ 
	UINT64 temp64 = (UINT64)OP_REG; 
	UINT64 operand = (UINT64)DEST_REG; 
	operand |= ((UINT64)BASE_REG)<<32; 
 
	temp64 = (temp64 * ((UINT64)SHFT_AMO_REG)) + operand; 
 
	DEST_REG = (u32)(temp64 & 0xFFFFFFFF); 
	BASE_REG = (u32)((temp64>>32)&0xFFFFFFFF);  
 
	if (!temp64)					ZFLAG = 1; else ZFLAG = 0; 
	if (temp64&0x8000000000000000)	NFLAG = 1; else NFLAG = 0; 
 
	advance_instruction_pipe();	return 4; 
} 
 
/*------------------------------------------------------------- 
				Data Processing 
--------------------------------------------------------------*/ 
 
// AND 
 
int ins_and(void) 
{ 
	DEST_REG = BASE_REG & DP_REG_OPERAND(IMM_SHIFT); 
	 
	advance_instruction_pipe(); return 1; 
} 
 
int ins_and_reg(void) 
{ 
	DEST_REG = BASE_REG & DP_REG_OPERAND(REG_SHIFT); 
	 
	advance_instruction_pipe(); return 2; 
} 
 
int ins_and_imm(void) 
{ 
	DEST_REG = BASE_REG & DP_IMM_OPERAND(); 
	 
	advance_instruction_pipe(); return 1; 
} 
 
int ins_ands(void) 
{ 
	DEST_REG = BASE_REG & DP_REG_OPERAND_C(IMM_SHIFT); 
	SET_DP_LOG_FLAGS(DEST_REG); 
	 
	advance_instruction_pipe(); return 1; 
} 
 
int ins_ands_reg (void) 
{ 
	DEST_REG = BASE_REG & DP_REG_OPERAND_C(REG_SHIFT); 
	SET_DP_LOG_FLAGS(DEST_REG); 
	 
	advance_instruction_pipe(); return 2; 
} 
int ins_ands_imm(void) 
{ 
	DEST_REG = BASE_REG & DP_IMM_OPERAND(); 
	SET_DP_LOG_FLAGS(DEST_REG); 
	 
	advance_instruction_pipe(); return 1; 
} 
 
//--------------------------------------------------------------- 
 
// EOR 
 
int ins_eor(void) 
{ 
	DEST_REG = BASE_REG ^ DP_REG_OPERAND(IMM_SHIFT); 
	 
	advance_instruction_pipe();	return 1; 
} 
 
int ins_eor_reg (void) 
{ 
	DEST_REG = BASE_REG ^ DP_REG_OPERAND(REG_SHIFT); 
	 
	advance_instruction_pipe(); return 2; 
} 
 
int ins_eor_imm(void) 
{ 
	DEST_REG = BASE_REG ^ DP_IMM_OPERAND(); 
	 
	advance_instruction_pipe(); return 1; 
} 
 
int ins_eors(void) 
{ 
	DEST_REG = BASE_REG ^ DP_REG_OPERAND_C(IMM_SHIFT); 
	SET_DP_LOG_FLAGS(DEST_REG); 
	 
	advance_instruction_pipe(); return 1; 
} 
 
int ins_eors_reg (void) 
{ 
	DEST_REG = BASE_REG ^ DP_REG_OPERAND_C(REG_SHIFT); 
	SET_DP_LOG_FLAGS(DEST_REG); 
	 
	advance_instruction_pipe(); return 2; 
} 
 
int ins_eors_imm(void) 
{ 
	DEST_REG = BASE_REG ^ DP_IMM_OPERAND(); 
	SET_DP_LOG_FLAGS(DEST_REG); 
	 
	advance_instruction_pipe(); return 1; 
} 
 
//--------------------------------------------------------------- 
 
// SUB 
 
int ins_sub(void)	 
{ 
	DEST_REG = BASE_REG - DP_REG_OPERAND(IMM_SHIFT); 
	 
	advance_instruction_pipe(); return 1; 
} 
 
int ins_sub_reg (void) 
{ 
	DEST_REG = BASE_REG - DP_REG_OPERAND(REG_SHIFT); 
	 
	advance_instruction_pipe(); return 2; 
} 
 
int ins_sub_imm(void) 
{ 
	DEST_REG = BASE_REG - DP_IMM_OPERAND(); 
	 
	advance_instruction_pipe(); return 1; 
} 
 
int ins_subs(void) 
{ 
	u32 op1 = BASE_REG; 
	u32 op2 = DP_REG_OPERAND(IMM_SHIFT); 
	DEST_REG = op1 - op2; 
	SET_SUB_FLAGS(op1, op2, DEST_REG); 
	 
	advance_instruction_pipe(); return 1; 
} 
 
int ins_subs_reg (void)  
{ 
	u32 op1 = BASE_REG; 
	u32 op2 = DP_REG_OPERAND(REG_SHIFT); 
	DEST_REG = op1 - op2; 
	SET_SUB_FLAGS(op1, op2, DEST_REG); 
	 
	advance_instruction_pipe(); return 2; 
} 
 
int ins_subs_imm(void) 
{ 
	u32 op1, op2; 
	 
	op1 = BASE_REG; 
	op2 = DP_IMM_OPERAND(); 
 
	DEST_REG = op1 - op2;	 
	SET_SUB_FLAGS(op1, op2, DEST_REG); 
	 
	advance_instruction_pipe();	return 1; 
} 
 
//--------------------------------------------------------------- 
 
// RSB 
 
int ins_rsb(void)	 
{ 
	DEST_REG = DP_REG_OPERAND(IMM_SHIFT) - BASE_REG; 
	 
	advance_instruction_pipe();	return 1; 
} 
 
int ins_rsb_reg (void) 
{ 
	DEST_REG = DP_REG_OPERAND(REG_SHIFT) - BASE_REG; 
	 
	advance_instruction_pipe(); return 2; 
} 
 
int ins_rsb_imm(void)	 
{ 
	DEST_REG = DP_IMM_OPERAND() - BASE_REG; 
	 
	advance_instruction_pipe(); return 1; 
} 
 
int ins_rsbs(void) 
{ 
	u32 op1 = BASE_REG; 
	u32 op2 = DP_REG_OPERAND(IMM_SHIFT); 
	DEST_REG = op2 - op1; 
	SET_SUB_FLAGS(op2, op1, DEST_REG); 
	 
	advance_instruction_pipe(); return 1; 
} 
 
int ins_rsbs_reg (void) 
{ 
	u32 op1 = BASE_REG; 
	u32 op2 = DP_REG_OPERAND(REG_SHIFT); 
	DEST_REG = op2 - op1; 
	SET_SUB_FLAGS(op2, op1, DEST_REG); 
	 
	advance_instruction_pipe(); return 2; 
} 
 
int ins_rsbs_imm(void) 
{ 
	u32 op1 = BASE_REG; 
	u32 op2 = DP_IMM_OPERAND(); 
	DEST_REG = op2 - op1; 
	SET_SUB_FLAGS(op2, op1, DEST_REG); 
	 
	advance_instruction_pipe(); return 1; 
} 
 
//--------------------------------------------------------------- 
 
// ADD 
 
int ins_add(void) 
{ 
	DEST_REG = BASE_REG + DP_REG_OPERAND(IMM_SHIFT); 
	 
	advance_instruction_pipe(); return 1; 
} 
 
int ins_add_reg(void) 
{ 
	DEST_REG = BASE_REG + DP_REG_OPERAND(REG_SHIFT); 
	 
	advance_instruction_pipe(); return 2; 
} 
 
int ins_add_imm(void) 
{ 
	DEST_REG = BASE_REG + DP_IMM_OPERAND(); 
	 
	advance_instruction_pipe();	return 1; 
} 
 
int ins_adds(void) 
{ 
	u32 op1 = BASE_REG; 
	u32 op2 = DP_REG_OPERAND(IMM_SHIFT); 
	DEST_REG = op1 + op2; 
	SET_ADD_FLAGS(op1, op2, DEST_REG); 
	 
	advance_instruction_pipe(); return 1; 
} 
 
int ins_adds_reg (void) 
{ 
	u32 op1 = BASE_REG; 
	u32 op2 = DP_REG_OPERAND(REG_SHIFT); 
	DEST_REG = op1 + op2; 
	SET_ADD_FLAGS(op1, op2, DEST_REG); 
	 
	advance_instruction_pipe(); return 2; 
} 
 
int ins_adds_imm(void) 
{ 
	u32 op1 = BASE_REG; 
	u32 op2 = DP_IMM_OPERAND(); 
	DEST_REG = op1 + op2; 
	SET_ADD_FLAGS(op1, op2, DEST_REG); 
	 
	advance_instruction_pipe(); return 1; 
} 
 
//--------------------------------------------------------------- 
 
// ADC 
 
int ins_adc(void) 
{ 
	DEST_REG = BASE_REG + DP_REG_OPERAND(IMM_SHIFT) + CFLAG; 
	 
	advance_instruction_pipe(); return 1; 
} 
 
int ins_adc_reg (void) 
{ 
	DEST_REG = BASE_REG + DP_REG_OPERAND(REG_SHIFT) + CFLAG; 
	 
	advance_instruction_pipe(); return 2; 
} 
 
int ins_adc_imm(void) 
{ 
	DEST_REG = BASE_REG + DP_IMM_OPERAND() + CFLAG; 
	 
	advance_instruction_pipe(); return 1; 
} 
 
int ins_adcs(void) 
{ 
	u32 op1 = BASE_REG; 
	u32 op2 = DP_REG_OPERAND(IMM_SHIFT); 
	DEST_REG = op1 + op2 + CFLAG; 
	SET_ADD_FLAGS(op1, op2, DEST_REG); 
	 
	advance_instruction_pipe(); return 1; 
} 
 
int ins_adcs_reg (void) 
{ 
	u32 op1 = BASE_REG; 
	u32 op2 = DP_REG_OPERAND(REG_SHIFT); 
	DEST_REG = op1 + op2 + CFLAG; 
	SET_ADD_FLAGS(op1, op2, DEST_REG); 
	 
	advance_instruction_pipe(); return 2; 
} 
 
int ins_adcs_imm(void) 
{ 
	u32 op1 = BASE_REG; 
	u32 op2 = DP_IMM_OPERAND(); 
	DEST_REG = op1 + op2 + CFLAG; 
	SET_ADD_FLAGS(op1, op2, DEST_REG); 
	 
	advance_instruction_pipe(); return 1; 
} 
 
//--------------------------------------------------------------- 
 
// SBC 
 
int ins_sbc(void) 
{ 
	DEST_REG = BASE_REG - DP_REG_OPERAND(IMM_SHIFT) - !CFLAG; 
	 
	advance_instruction_pipe(); return 1; 
} 
 
int ins_sbc_reg (void) 
{ 
	DEST_REG = BASE_REG - DP_REG_OPERAND(REG_SHIFT) - !CFLAG; 
	 
	advance_instruction_pipe(); return 2; 
} 
 
int ins_sbc_imm(void) 
{ 
	DEST_REG = BASE_REG + DP_IMM_OPERAND() - !CFLAG; 
	 
	advance_instruction_pipe(); return 1; 
} 
 
int ins_sbcs(void) 
{ 
	u32 op1 = BASE_REG; 
	u32 op2 = DP_REG_OPERAND(IMM_SHIFT); 
	DEST_REG = op1 - op2 - !CFLAG; 
	SET_SUB_FLAGS(op1, op2, DEST_REG); 
	 
	advance_instruction_pipe(); return 1; 
} 
 
int ins_sbcs_reg (void) 
{ 
	u32 op1 = BASE_REG; 
	u32 op2 = DP_REG_OPERAND(REG_SHIFT); 
	DEST_REG = op1 - op2 - !CFLAG; 
	SET_SUB_FLAGS(op1, op2, DEST_REG); 
	 
	advance_instruction_pipe(); return 2; 
} 
 
int ins_sbcs_imm(void) 
{ 
	u32 op1 = BASE_REG; 
	u32 op2 = DP_IMM_OPERAND(); 
	DEST_REG = op1 - op2 - !CFLAG; 
	SET_SUB_FLAGS(op1, op2, DEST_REG); 
	 
	advance_instruction_pipe(); return 1; 
} 
 
//--------------------------------------------------------------- 
 
// RSC 
 
int ins_rsc(void)	 
{ 
	DEST_REG = DP_REG_OPERAND(IMM_SHIFT) - BASE_REG - !CFLAG; 
	 
	advance_instruction_pipe(); return 1; 
} 
 
int ins_rsc_reg (void) 
{ 
	DEST_REG = DP_REG_OPERAND(REG_SHIFT) - BASE_REG - !CFLAG; 
	 
	advance_instruction_pipe(); return 2; 
} 
 
int ins_rsc_imm(void) 
{ 
	DEST_REG = DP_IMM_OPERAND() - BASE_REG - !CFLAG; 
	 
	advance_instruction_pipe(); return 1; 
} 
 
int ins_rscs(void) 
{ 
	u32 op1 = BASE_REG; 
	u32 op2 = DP_REG_OPERAND(IMM_SHIFT); 
	DEST_REG = op2 - op1 - !CFLAG; 
	SET_SUB_FLAGS(op2, op1, DEST_REG); 
 
	advance_instruction_pipe(); return 1; 
} 
 
int ins_rscs_reg (void) 
{ 
	u32 op1 = BASE_REG; 
	u32 op2 = DP_REG_OPERAND(REG_SHIFT); 
	DEST_REG = op2 - op1 - !CFLAG; 
	SET_SUB_FLAGS(op2, op1, DEST_REG); 
	advance_instruction_pipe(); return 2; 
} 
 
int ins_rscs_imm(void) 
{ 
	u32 op1 = BASE_REG; 
	u32 op2 = DP_IMM_OPERAND(); 
	DEST_REG = op2 - op1 - !CFLAG; 
	SET_SUB_FLAGS(op2, op1, DEST_REG); 
 
	advance_instruction_pipe(); return 1; 
} 
 
//--------------------------------------------------------------------- 
 
// TST 
 
int ins_tst(void) 
{ 
	u32 temp = BASE_REG & DP_REG_OPERAND_C(IMM_SHIFT); 
	SET_DP_LOG_FLAGS (temp); 
	advance_instruction_pipe();	return 1; 
} 
 
int ins_tst_reg (void) 
{ 
	u32 temp = BASE_REG & DP_REG_OPERAND_C(REG_SHIFT); 
	SET_DP_LOG_FLAGS (temp); 
	advance_instruction_pipe(); 
	return 2; 
} 
 
int ins_tst_imm(void) 
{ 
	u32 temp = BASE_REG & DP_IMM_OPERAND(); 
	SET_DP_LOG_FLAGS (temp); 
	advance_instruction_pipe(); return 1; 
} 
 
//--------------------------------------------------------------------- 
 
// TEQ 
 
int ins_teq(void) 
{ 
	u32 temp = BASE_REG ^ DP_REG_OPERAND_C(IMM_SHIFT); 
	SET_DP_LOG_FLAGS (temp); 
	advance_instruction_pipe(); return 1; 
} 
 
int ins_teq_reg (void) 
{ 
	u32 temp = BASE_REG ^ DP_REG_OPERAND_C(REG_SHIFT); 
	SET_DP_LOG_FLAGS (temp); 
	advance_instruction_pipe(); return 2; 
} 
 
int ins_teq_imm(void) 
{ 
	u32 temp = BASE_REG ^ DP_IMM_OPERAND(); 
	SET_DP_LOG_FLAGS (temp); 
	advance_instruction_pipe(); return 1; 
} 
 
//--------------------------------------------------------------------- 
 
// CMP 
 
int ins_cmp(void) 
{ 
	u32 op1 = BASE_REG; 
	u32 op2 = DP_REG_OPERAND(IMM_SHIFT); 
	SET_SUB_FLAGS (op1, op2, op1 - op2); 
	advance_instruction_pipe(); return 1; 
} 
 
int ins_cmp_reg(void) 
{ 
	u32 op1 = BASE_REG; 
	u32 op2 = DP_REG_OPERAND(REG_SHIFT); 
	SET_SUB_FLAGS (op1, op2, op1 - op2); 
	advance_instruction_pipe(); return 2; 
} 
 
int ins_cmp_imm(void)	 
{ 
	u32 op1 = BASE_REG; 
	u32 op2 = DP_IMM_OPERAND(); 
	SET_SUB_FLAGS(op1, op2, op1 - op2); 
	advance_instruction_pipe(); return 1; 
} 
 
//--------------------------------------------------------------------- 
 
// CMN 
 
int ins_cmn(void) 
{ 
	u32 op1 = BASE_REG; 
	u32 op2 = DP_REG_OPERAND(IMM_SHIFT); 
	SET_ADD_FLAGS (op1, op2, op1 + op2); 
	advance_instruction_pipe(); return 1; 
} 
 
int ins_cmn_reg (void) 
{ 
	u32 op1 = BASE_REG; 
	u32 op2 = DP_REG_OPERAND(REG_SHIFT); 
	SET_ADD_FLAGS (op1, op2, op1 + op2); 
	advance_instruction_pipe(); return 2; 
} 
 
int ins_cmn_imm(void) 
{ 
	u32 op1 = BASE_REG; 
	u32 op2 = DP_IMM_OPERAND(); 
	SET_ADD_FLAGS(op1, op2, op1 + op2); 
	advance_instruction_pipe(); return 1; 
} 
 
//--------------------------------------------------------------------- 
 
// ORR 
 
int ins_orr(void) 
{ 
	DEST_REG = BASE_REG | DP_REG_OPERAND(IMM_SHIFT); 
	advance_instruction_pipe(); return 1; 
} 
 
int ins_orr_reg (void) 
{ 
	DEST_REG = BASE_REG | DP_REG_OPERAND(REG_SHIFT); 
	advance_instruction_pipe(); return 2; 
} 
 
int ins_orr_imm(void) 
{ 
	DEST_REG = BASE_REG | DP_IMM_OPERAND(); 
	advance_instruction_pipe(); return 1; 
} 
 
int ins_orrs(void) 
{	 
	DEST_REG = BASE_REG | DP_REG_OPERAND_C(IMM_SHIFT); 
	SET_DP_LOG_FLAGS(DEST_REG); 
	advance_instruction_pipe();	return 1; 
} 
 
int ins_orrs_reg (void) 
{ 
	DEST_REG = BASE_REG | DP_REG_OPERAND_C(REG_SHIFT); 
	SET_DP_LOG_FLAGS(DEST_REG); 
	advance_instruction_pipe(); return 2; 
} 
 
int ins_orrs_imm(void) 
{ 
	DEST_REG = BASE_REG | DP_IMM_OPERAND(); 
	SET_DP_LOG_FLAGS(DEST_REG); 
	advance_instruction_pipe(); return 1; 
} 
 
//--------------------------------------------------------------------- 
 
// MOV 
 
int ins_mov(void) 
{ 
	DEST_REG = DP_REG_OPERAND(IMM_SHIFT); 
	if (((OPCODE>>12)&0xF)==0xF) { fill_instruction_pipe(); return 3; } 
	advance_instruction_pipe(); return 1; 
} 
 
int ins_mov_reg (void) 
{ 
	DEST_REG = DP_REG_OPERAND(REG_SHIFT); 
	if (((OPCODE>>12)&0xF)==0xF) { fill_instruction_pipe(); return 4; } 
	advance_instruction_pipe(); return 2; 
} 
 
int ins_mov_imm(void) 
{ 
	DEST_REG = DP_IMM_OPERAND(); 
	if (((OPCODE>>12)&0xF)==0xF) { fill_instruction_pipe();	return 4; } 
	advance_instruction_pipe(); return 1; 
} 
 
int ins_movs(void) 
{ 
	DEST_REG = DP_REG_OPERAND_C(IMM_SHIFT); 
	SET_DP_LOG_FLAGS(DEST_REG); 
	if (((OPCODE>>12)&0xF)==0xF) { fill_instruction_pipe(); return 3; } 
	advance_instruction_pipe();	return 1;	 
} 
 
int ins_movs_reg (void) 
{ 
	DEST_REG = DP_REG_OPERAND_C(REG_SHIFT); 
	SET_DP_LOG_FLAGS(DEST_REG); 
	if (((OPCODE>>12)&0xF)==0xF) { fill_instruction_pipe();	return 4; } 
	advance_instruction_pipe(); return 2; 
} 
 
int ins_movs_imm(void) 
{ 
	DEST_REG = DP_IMM_OPERAND(); 
	SET_DP_LOG_FLAGS(DEST_REG); 
	if (((OPCODE>>12)&0xF)==0xF) { fill_instruction_pipe();	return 4; } 
	advance_instruction_pipe(); return 1; 
} 
 
//--------------------------------------------------------------------- 
 
// BIC 
 
int ins_bic(void) 
{ 
	DEST_REG = BASE_REG & (~DP_REG_OPERAND(IMM_SHIFT)); 
	advance_instruction_pipe();	return 1; 
} 
 
int ins_bic_reg (void) 
{ 
	DEST_REG = BASE_REG & (~DP_REG_OPERAND(REG_SHIFT)); 
	advance_instruction_pipe(); return 2; 
} 
 
int ins_bic_imm(void) 
{ 
	DEST_REG = BASE_REG & (~DP_IMM_OPERAND()); 
	advance_instruction_pipe(); return 1; 
} 
 
int ins_bics(void) 
{ 
	DEST_REG = BASE_REG & (~DP_REG_OPERAND_C(IMM_SHIFT)); 
	SET_DP_LOG_FLAGS(DEST_REG); 
	advance_instruction_pipe(); return 1; 
} 
 
int ins_bics_reg (void) 
{ 
	DEST_REG = BASE_REG & (~DP_REG_OPERAND_C(REG_SHIFT)); 
	SET_DP_LOG_FLAGS(DEST_REG); 
	advance_instruction_pipe(); return 2; 
} 
 
int ins_bics_imm(void)	 
{ 
	DEST_REG = BASE_REG & (~DP_IMM_OPERAND()); 
	SET_DP_LOG_FLAGS(DEST_REG); 
	advance_instruction_pipe(); return 1; 
} 
 
//--------------------------------------------------------------------- 
 
// MVN 
 
int ins_mvn(void) 
{ 
	DEST_REG = (~DP_REG_OPERAND(IMM_SHIFT)); 
	advance_instruction_pipe(); return 1; 
} 
 
int ins_mvn_reg (void) 
{ 
	DEST_REG = (~DP_REG_OPERAND(REG_SHIFT)); 
	advance_instruction_pipe();	return 2; 
} 
 
int ins_mvn_imm(void)	 
{	 
	DEST_REG = ~DP_IMM_OPERAND(); 
	advance_instruction_pipe(); return 1; 
} 
 
int ins_mvns(void) 
{ 
	DEST_REG = (~DP_REG_OPERAND_C(IMM_SHIFT)); 
	SET_DP_LOG_FLAGS(DEST_REG); 
	advance_instruction_pipe(); return 1; 
} 
 
int ins_mvns_reg (void) 
{ 
	DEST_REG = (~DP_REG_OPERAND_C(REG_SHIFT)); 
	SET_DP_LOG_FLAGS(DEST_REG); 
	advance_instruction_pipe(); return 2; 
} 
 
int ins_mvns_imm(void) 
{ 
	DEST_REG = ~DP_IMM_OPERAND(); 
	SET_DP_LOG_FLAGS(DEST_REG); 
	advance_instruction_pipe();	return 1; 
} 
 
//--------------------------------------------------------------------- 
 
// MRS-MSR 
 
int ins_mrs_cpsr(void) 
{	 
	DEST_REG = CPSR; 
	advance_instruction_pipe();	return 1; 
} 
 
int ins_msr_cpsr(void) 
{ 
	CPSR = arm->gp_reg [(OPCODE&0xF)]; 
	advance_instruction_pipe(); return 1; 
} 
int ins_mrs_spsr(void)	 
{ 
	DEST_REG = arm->spsr [CPSR&0x1F]; 
	advance_instruction_pipe(); return 1; 
} 
 
int ins_msr_spsr(void) 
{ 
	arm->spsr [CPSR&0x1F] = arm->gp_reg [(OPCODE&0xF)]; 
	advance_instruction_pipe(); return 1; 
} 
 
int ins_msr_cpsr_imm(void) 
{ 
	CPSR = DP_IMM_OPERAND() & 0xF00000FF; 
	advance_instruction_pipe(); return 1; 
} 
 
int ins_msr_spsr_imm(void)	 
{ 
	arm->spsr [CPSR&0x1F] = DP_IMM_OPERAND() & 0xF00000FF; 
	advance_instruction_pipe(); return 1; 
} 
 
//--------------------------------------------------------------------- 
 
/*--------------------------------------------------------------------- 
					DATA TRANSFER 
----------------------------------------------------------------------*/ 
 
int ins_ldr_pre_up (void) 
{ 
	u32 offset = DP_REG_OPERAND(IMM_SHIFT); 
	 
	DEST_REG = read_word (BASE_REG + offset); 
	if (OPCODE&0x200000) BASE_REG += offset;	 
	if (((OPCODE>>12)&0xF)==15) fill_instruction_pipe(); else advance_instruction_pipe(); 
	return 1; 
} 
 
int ins_ldr_pre_down (void) 
{ 
	u32 offset = DP_REG_OPERAND(IMM_SHIFT); 
 
	DEST_REG = read_word (BASE_REG - offset); 
	if (OPCODE&0x200000) BASE_REG -= offset; 
	if (((OPCODE>>12)&0xF)==15) fill_instruction_pipe(); else advance_instruction_pipe(); 
	return 1; 
} 
 
int ins_ldr_post_up (void) 
{ 
	u32 offset = DP_REG_OPERAND(IMM_SHIFT); 
	DEST_REG = read_word (BASE_REG); 
	BASE_REG += offset;		 
	if (((OPCODE>>12)&0xF)==15) fill_instruction_pipe(); else advance_instruction_pipe(); 
	return 1; 
} 
 
int ins_ldr_post_down (void) 
{ 
	u32 offset = DP_REG_OPERAND(IMM_SHIFT); 
	DEST_REG = read_word (BASE_REG); 
	BASE_REG -= offset;		 
	if (((OPCODE>>12)&0xF)==15) fill_instruction_pipe(); else advance_instruction_pipe(); 
	return 1; 
} 
 
int ins_ldr_imm_pre_up (void) 
{ 
	u32 offset = (OPCODE&0xFFF); 
	DEST_REG = read_word (BASE_REG + offset); 
	if (OPCODE&0x200000) BASE_REG += offset;	 
	if (((OPCODE>>12)&0xF)==15) fill_instruction_pipe(); else advance_instruction_pipe(); 
	return 3; 
} 
 
int ins_ldr_imm_pre_down (void) 
{ 
	u32 offset = (OPCODE&0xFFF); 
	DEST_REG = read_word (BASE_REG - offset); 
	if (OPCODE&0x200000) BASE_REG -= offset; 
	if (((OPCODE>>12)&0xF)==15) fill_instruction_pipe(); else advance_instruction_pipe(); 
	return 3; 
} 
 
int ins_ldr_imm_post_up (void) 
{ 
	u32 offset = (OPCODE&0xFFF); 
	DEST_REG = read_word (BASE_REG); 
	BASE_REG += offset; 
	if (((OPCODE>>12)&0xF)==15) fill_instruction_pipe(); else advance_instruction_pipe(); 
	return 3; 
} 
 
int ins_ldr_imm_post_down (void) 
{ 
	u32 offset = (OPCODE&0xFFF); 
	DEST_REG = read_word (BASE_REG); 
	BASE_REG -= offset; 
	if (((OPCODE>>12)&0xF)==15) fill_instruction_pipe(); else advance_instruction_pipe(); 
	return 3; 
} 
 
//---------------------------------------------------------------- 
 
int ins_ldrb_pre_up (void) 
{ 
	u32 offset = DP_REG_OPERAND(IMM_SHIFT); 
 
	DEST_REG = (u32)read_byte (BASE_REG + offset); 
	if (OPCODE&0x200000) BASE_REG += offset;	 
	advance_instruction_pipe(); return 1; 
} 
 
int ins_ldrb_pre_down (void) 
{ 
	u32 offset = DP_REG_OPERAND(IMM_SHIFT); 
 
	DEST_REG = (u32)read_byte (BASE_REG - offset); 
	if (OPCODE&0x200000) BASE_REG -= offset;	 
	advance_instruction_pipe(); return 1; 
} 
 
int ins_ldrb_post_up (void) 
{ 
	u32 offset = DP_REG_OPERAND(IMM_SHIFT); 
	DEST_REG = (u32)read_byte (BASE_REG); 
	BASE_REG += offset; 
	advance_instruction_pipe(); return 1; 
} 
 
int ins_ldrb_post_down (void) 
{ 
	u32 offset = DP_REG_OPERAND(IMM_SHIFT); 
	DEST_REG = (u32)read_byte (BASE_REG); 
	BASE_REG -= offset; 
	advance_instruction_pipe(); return 1; 
} 
 
int ins_ldrb_imm_pre_up (void) 
{ 
	u32 offset = (OPCODE&0xFFF); 
	DEST_REG = (u32)read_byte (BASE_REG + offset); 
	if (OPCODE&0x200000) BASE_REG += offset;	 
	advance_instruction_pipe(); return 3; 
} 
 
int ins_ldrb_imm_pre_down (void) 
{ 
	u32 offset = (OPCODE&0xFFF); 
	DEST_REG = (u32)read_byte (BASE_REG - offset); 
	if (OPCODE&0x200000) BASE_REG -= offset;	 
	advance_instruction_pipe(); return 3; 
} 
 
int ins_ldrb_imm_post_up (void) 
{ 
	u32 offset = (OPCODE&0xFFF); 
	DEST_REG = (u32)read_byte (BASE_REG); 
	BASE_REG += offset; 
	advance_instruction_pipe(); return 3; 
} 
 
int ins_ldrb_imm_post_down (void) 
{ 
	u32 offset = (OPCODE&0xFFF); 
	DEST_REG = (u32)read_byte (BASE_REG); 
	BASE_REG -= offset; 
	advance_instruction_pipe(); return 3; 
} 
 
int ins_str_pre_up (void) 
{ 
	u32 offset = DP_REG_OPERAND(IMM_SHIFT);	 
	if (((OPCODE>>12)&0xF)==15) write_word (BASE_REG + offset, DEST_REG+4); 
	else write_word (BASE_REG + offset, DEST_REG); 
	if (OPCODE&0x200000) BASE_REG += offset;	 
	advance_instruction_pipe(); return 1; 
} 
 
int ins_str_pre_down (void) 
{ 
	u32 offset = DP_REG_OPERAND(IMM_SHIFT); 
	if (((OPCODE>>12)&0xF)==15) write_word (BASE_REG - offset, DEST_REG+4); 
	else write_word (BASE_REG - offset, DEST_REG); 
	if (OPCODE&0x200000) BASE_REG -= offset;	 
	advance_instruction_pipe(); return 1; 
} 
 
int ins_str_post_up (void) 
{ 
	u32 offset = DP_REG_OPERAND(IMM_SHIFT); 
	if (((OPCODE>>12)&0xF)==15) write_word (BASE_REG, DEST_REG+4);  
	else write_word (BASE_REG, DEST_REG);  
	BASE_REG += offset; 
	advance_instruction_pipe(); return 1; 
} 
 
int ins_str_post_down (void) 
{ 
	u32 offset = DP_REG_OPERAND(IMM_SHIFT); 
	if (((OPCODE>>12)&0xF)==15) write_word (BASE_REG, DEST_REG+4);  
	else write_word (BASE_REG, DEST_REG);  
	BASE_REG -= offset; 
	advance_instruction_pipe(); return 1; 
} 
 
int ins_str_imm_pre_up (void) 
{ 
	u32 offset = (OPCODE&0xFFF); 
	if (((OPCODE>>12)&0xF)==15) write_word (BASE_REG + offset, DEST_REG+4); 
	else write_word (BASE_REG + offset, DEST_REG); 
	if (OPCODE&0x200000) BASE_REG += offset;	 
	advance_instruction_pipe(); return 2; 
} 
 
int ins_str_imm_pre_down (void) 
{ 
	u32 offset = (OPCODE&0xFFF); 
	if (((OPCODE>>12)&0xF)==15) write_word (BASE_REG - offset, DEST_REG+4); 
	else write_word (BASE_REG - offset, DEST_REG); 
	if (OPCODE&0x200000) BASE_REG -= offset;	 
	advance_instruction_pipe(); return 2; 
} 
 
int ins_str_imm_post_up (void) 
{ 
	u32 offset = (OPCODE&0xFFF); 
	if (((OPCODE>>12)&0xF)==15) write_word (BASE_REG, DEST_REG+4);  
	else write_word (BASE_REG, DEST_REG);  
	BASE_REG += offset; 
	advance_instruction_pipe(); return 2; 
} 
 
int ins_str_imm_post_down (void) 
{ 
	u32 offset = (OPCODE&0xFFF); 
	if (((OPCODE>>12)&0xF)==15) write_word (BASE_REG, DEST_REG+4);  
	else write_word (BASE_REG, DEST_REG); 
	BASE_REG -= offset; 
	advance_instruction_pipe(); return 2; 
} 
 
int ins_strb_pre_up (void) 
{ 
	u32 offset = DP_REG_OPERAND(IMM_SHIFT); 
	write_byte (BASE_REG + offset, (u8)DEST_REG);  
	if (OPCODE&0x200000) BASE_REG += offset;	 
	advance_instruction_pipe(); return 1; 
} 
 
int ins_strb_pre_down (void) 
{ 
	u32 offset = DP_REG_OPERAND(IMM_SHIFT); 
	write_byte (BASE_REG - offset, (u8)DEST_REG);  
	if (OPCODE&0x200000) BASE_REG -= offset;	 
	advance_instruction_pipe(); return 1; 
} 
 
int ins_strb_post_up (void) 
{ 
	u32 offset = DP_REG_OPERAND(IMM_SHIFT); 
	write_byte (BASE_REG, (u8)DEST_REG);  
	BASE_REG += offset; 
	advance_instruction_pipe(); return 1; 
} 
 
int ins_strb_post_down (void) 
{ 
	u32 offset = DP_REG_OPERAND(IMM_SHIFT); 
	write_byte (BASE_REG, (u8)DEST_REG);  
	BASE_REG -= offset; 
	advance_instruction_pipe(); return 1; 
} 
 
int ins_strb_imm_pre_up (void) 
{ 
	u32 offset = (OPCODE&0xFFF); 
	write_byte (BASE_REG + offset, (u8)DEST_REG); 
	if (OPCODE&0x200000) BASE_REG += offset;	 
	advance_instruction_pipe(); return 2; 
} 
 
int ins_strb_imm_pre_down (void) 
{ 
	u32 offset = (OPCODE&0xFFF); 
	write_byte (BASE_REG - offset, (u8)DEST_REG); 
	if (OPCODE&0x200000) BASE_REG -= offset;	 
	advance_instruction_pipe(); return 2; 
} 
 
int ins_strb_imm_post_up (void) 
{ 
	u32 offset = (OPCODE&0xFFF); 
	write_byte (BASE_REG, (u8)DEST_REG);  
	BASE_REG += offset; 
	advance_instruction_pipe(); return 2; 
} 
 
int ins_strb_imm_post_down (void) 
{ 
	u32 offset = (OPCODE&0xFFF); 
	write_byte (BASE_REG, (u8)DEST_REG);  
	BASE_REG -= offset; 
	advance_instruction_pipe(); return 2; 
} 
 
//----------------------------------------------------------------------- 
 
int ins_ldrh_pre (void) 
{ 
	u32 offset = arm->gp_reg [OPCODE&0xF]; 
	 
	if (OPCODE&0x800000) { 
		DEST_REG = (u32)read_hword (BASE_REG + offset); 
		if (OPCODE&0x200000) BASE_REG += offset;	 
	} 
	else { 
		DEST_REG = (u32)read_hword (BASE_REG - offset); 
		if (OPCODE&0x200000) BASE_REG -= offset;	 
	} 
 
	advance_instruction_pipe(); 
	return 3; 
} 
 
int ins_ldrh_post (void) 
{ 
	u32 offset = arm->gp_reg [OPCODE&0xF]; 
	 
	DEST_REG = read_hword (BASE_REG); 
	if (OPCODE&0x800000) BASE_REG += offset; else BASE_REG -= offset; 
 
	advance_instruction_pipe(); 
	return 3; 
} 
 
int ins_ldrsb (void) 
{ 
	u32 offset = arm->gp_reg [OPCODE&0xF]; 
	 
	if (OPCODE&0x1000000) { 
		if (OPCODE&0x800000) { 
			DEST_REG = (s32)read_byte (BASE_REG + offset); 
			if (OPCODE&0x200000) 
				BASE_REG += offset;	 
		} 
		else { 
			DEST_REG = (s32)read_byte (BASE_REG - offset); 
			if (OPCODE&0x200000) 
				BASE_REG -= offset;	 
		} 
	} 
	else { 
		DEST_REG = (s32)read_byte (BASE_REG); 
		if (OPCODE&0x800000) BASE_REG += offset; else BASE_REG -= offset; 
	} 
	advance_instruction_pipe(); 
	return 3; 
} 
 
int ins_ldrsh (void) 
{ 
	u32 offset = arm->gp_reg [OPCODE&0xF]; 
	u16 temp; 
 
	if (OPCODE&0x1000000) { 
		if (OPCODE&0x800000) { 
			temp = read_hword (BASE_REG + offset); 
			 
			if (temp&0x8000) { 
				DEST_REG = 0 - temp; 
			} 
			else { 
				DEST_REG = temp; 
			} 
			 
			if (OPCODE&0x200000) 
				BASE_REG += offset;	 
		} 
		else { 
			temp = read_hword (BASE_REG - offset); 
			 
			if (temp&0x8000) { 
				DEST_REG = 0 - temp; 
			} 
			else { 
				DEST_REG = temp; 
			} 
 
			if (OPCODE&0x200000) 
				BASE_REG -= offset;	 
		} 
	} 
	else { 
		temp = read_hword (BASE_REG); 
 
		if (temp&0x8000) { 
			DEST_REG = 0 - temp; 
		} 
		else { 
			DEST_REG = temp; 
		} 
 
		if (OPCODE&0x800000) BASE_REG += offset; else BASE_REG -= offset; 
	} 
	advance_instruction_pipe(); 
	return 3; 
} 
 
int ins_strh_pre (void) 
{ 
	u32 offset = arm->gp_reg [OPCODE&0xF]; 
	 
	if (OPCODE&0x800000) { 
		write_hword (BASE_REG+offset, (u16)DEST_REG); 
		if (OPCODE&0x200000) 
			BASE_REG += offset;	 
	} 
	else { 
		write_hword (BASE_REG-offset, (u16)DEST_REG); 
		if (OPCODE&0x200000) 
			BASE_REG -= offset;	 
	} 
 
	advance_instruction_pipe(); 
	return 2; 
} 
 
int ins_strh_post (void) 
{ 
	u32 offset = arm->gp_reg [OPCODE&0xF]; 
 
	write_hword (BASE_REG, (u16)DEST_REG); 
	if (OPCODE&0x800000) BASE_REG += offset; else BASE_REG -= offset; 
 
	advance_instruction_pipe(); 
	return 2; 
} 
 
int ins_ldrh_imm_pre (void) 
{ 
	u32 offset = ((OPCODE&0xF00)>>4)|(OPCODE&0xF); 
	 
	if (OPCODE&0x800000) { 
		DEST_REG = read_hword (BASE_REG + offset); 
		if (OPCODE&0x200000) 
			BASE_REG += offset;	 
	} 
	else { 
		DEST_REG = read_hword (BASE_REG - offset); 
		if (OPCODE&0x200000) 
			BASE_REG -= offset;	 
	} 
 
	advance_instruction_pipe(); 
	return 3; 
} 
 
int ins_ldrh_imm_post (void) 
{ 
	u32 offset = ((OPCODE&0xF00)>>4)|(OPCODE&0xF); 
	 
	DEST_REG = read_hword (BASE_REG); 
	if (OPCODE&0x800000) BASE_REG += offset; else BASE_REG -= offset; 
 
	advance_instruction_pipe(); 
	return 3; 
} 
 
int ins_ldrsb_imm (void) 
{ 
	u32 offset = ((OPCODE&0xF00)>>4)|(OPCODE&0xF); 
	 
	if (OPCODE&0x1000000) { 
		if (OPCODE&0x800000) { 
			DEST_REG = (s32)read_byte (BASE_REG + offset); 
			if (OPCODE&0x200000) 
				BASE_REG += offset;	 
		} 
		else { 
			DEST_REG = (s32)read_byte (BASE_REG - offset); 
			if (OPCODE&0x200000) 
				BASE_REG -= offset;	 
		} 
	} 
	else { 
		DEST_REG = (s32)read_byte (BASE_REG); 
		if (OPCODE&0x800000) BASE_REG += offset; else BASE_REG -= offset; 
	} 
	advance_instruction_pipe(); 
	return 3; 
} 
 
int ins_ldrsh_imm (void) 
{ 
	u32 offset = ((OPCODE&0xF00)>>4)|(OPCODE&0xF); 
	u16 temp; 
	 
	if (OPCODE&0x1000000) { 
		if (OPCODE&0x800000) { 
			temp = read_hword (BASE_REG + offset); 
			 
			if (temp&0x8000) { 
				DEST_REG = 0 - temp; 
			} 
			else { 
				DEST_REG = temp; 
			} 
 
			if (OPCODE&0x200000) 
				BASE_REG += offset;	 
		} 
		else { 
			temp = read_hword (BASE_REG - offset); 
 
			if (temp&0x8000) { 
				DEST_REG = 0 - temp; 
			} 
			else { 
				DEST_REG = temp; 
			} 
 
			if (OPCODE&0x200000) 
				BASE_REG -= offset;	 
		} 
	} 
	else { 
		temp = read_hword (BASE_REG); 
 
		if (temp&0x8000) { 
			DEST_REG = 0 - temp; 
		} 
		else { 
			DEST_REG = temp; 
		} 
 
		if (OPCODE&0x800000) BASE_REG += offset; else BASE_REG -= offset; 
	} 
	advance_instruction_pipe(); 
	return 3; 
} 
 
int ins_strh_imm_pre (void) 
{ 
	u32 offset = ((OPCODE&0xF00)>>4)|(OPCODE&0xF); 
	 
	if (OPCODE&0x800000) { 
		write_hword (BASE_REG+offset, (u16)DEST_REG); 
		if (OPCODE&0x200000) 
			BASE_REG += offset;	 
	} 
	else { 
		write_hword (BASE_REG-offset, (u16)DEST_REG); 
		if (OPCODE&0x200000) 
			BASE_REG -= offset;	 
	} 
	advance_instruction_pipe(); 
	return 2; 
} 
 
int ins_strh_imm_post (void) 
{ 
	u32 offset = ((OPCODE&0xF00)>>4)|(OPCODE&0xF); 
	write_hword (BASE_REG, (u16)DEST_REG); 
	if (OPCODE&0x800000) BASE_REG += offset; else BASE_REG -= offset; 
	advance_instruction_pipe(); 
	return 2; 
} 
 
int ins_stm (void) 
{ 
	int i; 
	u32 offset=0; 
	int n=0; 
 
	if (OPCODE&0x1000000) { 
 
		if (OPCODE&0x800000) { 
	 
			for (i=0; i<16; i++) { 
 
				if (OPCODE&(0x1<gp_reg [i]); 
				} 
			} 
		} 
		else { 
 
			for (i=15; i>=0; i--) { 
				 
				if (OPCODE&(0x1<gp_reg [i]); 
				} 
			} 
		}	 
	} 
	else { 
 
		if (OPCODE&0x800000) { 
	 
			for (i=0; i<16; i++) { 
 
				if (OPCODE&(0x1<gp_reg [i]); 
					if (OPCODE&0x200000) BASE_REG += 4; else offset += 4; 
				} 
			} 
		} 
		else { 
 
			for (i=15; i>=0; i--) { 
				 
				if (OPCODE&(0x1<gp_reg [i]); 
					if (OPCODE&0x200000) BASE_REG -= 4; else offset += 4; 
				} 
			} 
		}	 
	} 
	advance_instruction_pipe(); 
	return (2+n); 
} 
 
int ins_ldm (void) 
{ 
	u32 temp; 
	u32 update_base = 0; 
	u32 i; 
	s32 offset=0; 
	u32 n=0; 
 
		if (OPCODE&0x1000000) { 
 
		if (OPCODE&0x800000) { 
	 
			for (i=0; i<16; i++) { 
 
				if (OPCODE&(0x1<>16)&0xF)) arm->gp_reg [i] = read_word (BASE_REG+offset); 
					else {temp = read_word (BASE_REG+offset); update_base = 1;} 
				} 
			} 
		} 
		else { 
 
			for (i=15; i>=0; i--) { 
				 
				if (OPCODE&(0x1<>16)&0xF)) arm->gp_reg [i] = read_word (BASE_REG-offset); 
					else {temp = read_word (BASE_REG+offset); update_base = 1;} 
				} 
			} 
		}	 
	} 
	else { 
 
		if (OPCODE&0x800000) { 
	 
			for (i=0; i<16; i++) { 
 
				if (OPCODE&(0x1<>16)&0xF)) arm->gp_reg [i] = read_word (BASE_REG+offset); 
					else {temp = read_word (BASE_REG+offset); update_base = 1;} 
					if (OPCODE&0x200000) BASE_REG += 4; else offset += 4; 
				} 
			} 
		} 
		else { 
 
			for (i=15; i>=0; i--) { 
				 
				if (OPCODE&(0x1<>16)&0xF)) arm->gp_reg [i] = read_word (BASE_REG-offset); 
					else {temp = read_word (BASE_REG+offset); update_base = 1;} 
					if (OPCODE&0x200000) BASE_REG -= 4; else offset += 4; 
				} 
			} 
		}	 
	} 
 
	if (update_base) BASE_REG = temp; 
 
	if (OPCODE & 0x8000) { 
		fill_instruction_pipe(); 
	} 
	else { 
		advance_instruction_pipe(); 
	} 
 
	return (n+1); 
} 
 
int ins_swi (void) 
{ 
	advance_instruction_pipe(); 
	return 1; 
} 
 
int ins_swp (void) 
{ 
	u32 temp; 
	temp = read_word (BASE_REG); 
	write_word (BASE_REG, OP_REG); 
	DEST_REG = temp; 
	advance_instruction_pipe(); return 4; 
} 
 
int ins_swpb (void) 
{ 
	u8 temp; 
	temp = read_byte (BASE_REG); 
	write_byte (BASE_REG, (u8)OP_REG); 
	DEST_REG = temp; 
	advance_instruction_pipe(); return 4; 
}