/*******************************************************************************************
 NOTE: All registers are accessed directly, instead of using the SFR_R() function for speed
 Direct register access is availabe from the R_(register name) macros.. ex: R_ACC for the ACC
 with the exception of the PC
********************************************************************************************/

//ACALL code addr                           /* 1: aaa1 0001 */
INLINE void acall(void)
{
	UINT8 op = ROP(PC-1);					//Grab the opcode for ACALL
	UINT8 addr = ROP_ARG(PC++);				//Grab code address byte
	PUSH_PC									//Save PC to the stack
	//Thanks Gerrit for help with this! :)
	PC = (PC & 0xf800) | ((op & 0xe0) << 3) | addr;
}

//ADD A, #data                              /* 1: 0010 0100 */
INLINE void add_a_byte(void)
{
	UINT8 data = ROP_ARG(PC++);				//Grab data
	UINT8 result = R_ACC + data;			//Add data to accumulator
	DO_ADD_FLAGS(R_ACC,data,0)				//Set Flags
	SFR_W(ACC,result);						//Store 8 bit result of addtion in ACC
}

//ADD A, data addr                          /* 1: 0010 0101 */
INLINE void add_a_mem(void)
{
	UINT8 addr = ROP_ARG(PC++);				//Grab data address
	UINT8 data = IRAM_R(addr);				//Grab data from data address
	UINT8 result = R_ACC + data;			//Add data to accumulator
	DO_ADD_FLAGS(R_ACC,data,0);				//Set Flags
	SFR_W(ACC,result);						//Store 8 bit result of addtion in ACC
}

//ADD A, @R0/@R1                            /* 1: 0010 011i */
INLINE void add_a_ir(int r)
{
	UINT8 data = IRAM_IR(R_R(r));			//Grab data from memory pointed to by R0 or R1
	UINT8 result = R_ACC + data;			//Add data to accumulator
	DO_ADD_FLAGS(R_ACC,data,0);				//Set Flags
	SFR_W(ACC,result);						//Store 8 bit result of addtion in ACC
}

//ADD A, R0 to R7                           /* 1: 0010 1rrr */
INLINE void add_a_r(int r)
{
	UINT8 data = R_R(r);					//Grab data from R0 - R7
	UINT8 result = R_ACC + data;			//Add data to accumulator
	DO_ADD_FLAGS(R_ACC,data,0);				//Set Flags
	SFR_W(ACC,result);						//Store 8 bit result of addtion in ACC
}

//ADDC A, #data                             /* 1: 0011 0100 */
INLINE void addc_a_byte(void)
{
	UINT8 data = ROP_ARG(PC++);				//Grab data
	UINT8 result = R_ACC + data + GET_CY;	//Add data + carry flag to accumulator
	DO_ADD_FLAGS(R_ACC,data,GET_CY);		//Set Flags
	SFR_W(ACC,result);						//Store 8 bit result of addtion in ACC
}

//ADDC A, data addr                         /* 1: 0011 0101 */
INLINE void addc_a_mem(void)
{
	UINT8 addr = ROP_ARG(PC++);				//Grab data address
	UINT8 data = IRAM_R(addr);				//Grab data from data address
	UINT8 result = R_ACC + data + GET_CY;	//Add data + carry flag to accumulator
	DO_ADD_FLAGS(R_ACC,data,GET_CY);		//Set Flags
	SFR_W(ACC,result);						//Store 8 bit result of addtion in ACC
}

//ADDC A, @R0/@R1                           /* 1: 0011 011i */
INLINE void addc_a_ir(int r)
{
	UINT8 data = IRAM_IR(R_R(r));			//Grab data from memory pointed to by R0 or R1
	UINT8 result = R_ACC + data + GET_CY;	//Add data + carry flag to accumulator
	DO_ADD_FLAGS(R_ACC,data,GET_CY);		//Set Flags
	SFR_W(ACC,result);						//Store 8 bit result of addtion in ACC
}

//ADDC A, R0 to R7                          /* 1: 0011 1rrr */
INLINE void addc_a_r(int r)
{
	UINT8 data = R_R(r);					//Grab data from R0 - R7
	UINT8 result = R_ACC + data + GET_CY;	//Add data + carry flag to accumulator
	DO_ADD_FLAGS(R_ACC,data,GET_CY);		//Set Flags
	SFR_W(ACC,result);						//Store 8 bit result of addtion in ACC
}

//AJMP code addr                            /* 1: aaa0 0001 */
INLINE void ajmp(void)
{
	UINT8 op = ROP(PC-1);					//Grab the opcode for AJMP
	UINT8 addr = ROP_ARG(PC++);				//Grab code address byte
	//Thanks Gerrit for help with this! :)
	PC = (PC & 0xf800) | ((op & 0xe0) << 3) | addr;
}

//ANL data addr, A                          /* 1: 0101 0010 */
INLINE void anl_mem_a(void)
{
	UINT8 addr = ROP_ARG(PC++);				//Grab data address
	UINT8 data = IRAM_R(addr);				//Grab data from data address
	IRAM_W(addr,data & R_ACC);				//Set data address value to it's value Logical AND with ACC
}

//ANL data addr, #data                      /* 1: 0101 0011 */
INLINE void anl_mem_byte(void)
{
	UINT8 addr = ROP_ARG(PC++);				//Grab data address
	UINT8 data = ROP_ARG(PC++);				//Grab data
	UINT8 srcdata = IRAM_R(addr);			//Grab data from data address
	IRAM_W(addr,srcdata & data);			//Set data address value to it's value Logical AND with Data
}

//ANL A, #data                              /* 1: 0101 0100 */
INLINE void anl_a_byte(void)
{
	UINT8 data = ROP_ARG(PC++);				//Grab data
	SFR_W(ACC,R_ACC & data);				//Set ACC to value of ACC Logical AND with Data
}

//ANL A, data addr                          /* 1: 0101 0101 */
INLINE void anl_a_mem(void)
{
	UINT8 addr = ROP_ARG(PC++);				//Grab data address
	UINT8 data = IRAM_R(addr);				//Grab data from data address
	SFR_W(ACC,R_ACC & data);				//Set ACC to value of ACC Logical AND with Data
}

//ANL A, @RO/@R1                            /* 1: 0101 011i */
INLINE void anl_a_ir(int r)
{
	UINT8 data = IRAM_IR(R_R(r));			//Grab data from address R0 or R1 points to
	SFR_W(ACC,R_ACC & data);				//Set ACC to value of ACC Logical AND with Data
}

//ANL A, RO to R7                           /* 1: 0101 1rrr */
INLINE void anl_a_r(int r)
{
	UINT8 data = R_R(r);					//Grab data from R0 - R7
	SFR_W(ACC,R_ACC & data);				//Set ACC to value of ACC Logical AND with Data
}

//ANL C, bit addr                           /* 1: 1000 0010 */
INLINE void anl_c_bitaddr(void)
{
	int cy = GET_CY;
	UINT8 addr = ROP_ARG(PC++);				//Grab bit address
	UINT8 bit = BIT_R(addr);				//Grab bit data from bit address
	SET_CY( (cy & bit) );					//Set Carry flag to Carry Flag Value Logical AND with Bit
}

//ANL C,/bit addr                           /* 1: 1011 0000 */
INLINE void anl_c_nbitaddr(void)
{
	int cy = GET_CY;
	UINT8 addr = ROP_ARG(PC++);				//Grab bit address
	UINT8 bit = BIT_R(addr);				//Grab bit data from bit address
	bit = ((~bit)&1);						//Complement bit
	SET_CY( (cy & bit) );					//Set Carry flag to Carry Flag Value Logical AND with Complemented Bit
}

//CJNE A, #data, code addr                  /* 1: 1011 0100 */
INLINE void cjne_a_byte(void)
{
	UINT8 data = ROP_ARG(PC++);				//Grab data
	INT8 rel_addr = ROP_ARG(PC++);			//Grab relative code address

	if(R_ACC != data)						//Jump if values are not equal
		PC = PC + rel_addr;

	//Set carry flag to 1 if 1st compare value is < 2nd compare value
	SET_CY( (R_ACC < data) );
}

//CJNE A, data addr, code addr              /* 1: 1011 0101 */
INLINE void cjne_a_mem(void)
{
	UINT8 addr = ROP_ARG(PC++);				//Grab data address
	INT8 rel_addr = ROP_ARG(PC++);			//Grab relative code address
	UINT8 data = IRAM_R(addr);				//Pull value from data address

	if(R_ACC != data)						//Jump if values are not equal
		PC = PC + rel_addr;

	//Set carry flag to 1 if 1st compare value is < 2nd compare value
	SET_CY( (R_ACC < data) );
}

//CJNE @R0/@R1, #data, code addr            /* 1: 1011 011i */
INLINE void cjne_ir_byte(int r)
{
	UINT8 data = ROP_ARG(PC++);				//Grab data
	INT8 rel_addr = ROP_ARG(PC++);			//Grab relative code address
	UINT8 srcdata = IRAM_IR(R_R(r));		//Grab value pointed to by R0 or R1

	if(srcdata != data)						//Jump if values are not equal
		PC = PC + rel_addr;

	//Set carry flag to 1 if 1st compare value is < 2nd compare value
	SET_CY( (srcdata < data) );
}

//CJNE R0 to R7, #data, code addr           /* 1: 1011 1rrr */
INLINE void cjne_r_byte(int r)
{
	UINT8 data = ROP_ARG(PC++);				//Grab data
	INT8 rel_addr = ROP_ARG(PC++);			//Grab relative code address
	UINT8 srcdata = R_R(r);					//Grab value of R0 - R7

	if(srcdata != data)						//Jump if values are not equal
		PC = PC + rel_addr;

	//Set carry flag to 1 if 1st compare value is < 2nd compare value
	SET_CY( (srcdata < data) );
}

//CLR bit addr                              /* 1: 1100 0010 */
INLINE void clr_bitaddr(void)
{
	UINT8 addr = ROP_ARG(PC++);				//Grab bit address
	BIT_W(addr,0);							//Clear bit at specified bit address
}

//CLR C                                     /* 1: 1100 0011 */
INLINE void clr_c(void)
{
	SET_CY(0);								//Clear Carry Flag
}

//CLR A                                     /* 1: 1110 0100 */
INLINE void clr_a(void)
{
	SFR_W(ACC,0);							//Clear Accumulator
}

//CPL bit addr                              /* 1: 1011 0010 */
INLINE void cpl_bitaddr(void)
{
	UINT8 addr = ROP_ARG(PC++);				//Grab bit address
	UINT8 data = (~BIT_R(addr))&1;
	BIT_W(addr,data);						//Complement bit at specified bit address
}

//CPL C                                     /* 1: 1011 0011 */
INLINE void cpl_c(void)
{
	UINT8 bit = (~GET_CY)&1;				//Complement Carry Flag
	SET_CY(bit);
}

//CPL A                                     /* 1: 1111 0100 */
INLINE void cpl_a(void)
{
	UINT8 data = ((~R_ACC)&0xff);
	SFR_W(ACC,data);						//Complement Accumulator
}

//DA A                                      /* 1: 1101 0100 */
INLINE void da_a(void)
{
/*From several sources, since none said the same thing:
 The decimal adjust instruction is associated with the use of the ADD and ADDC instructions.
 The eight-bit value in the accumulator is adjusted to form two BCD digits of four bits each.
 If the accumulator contents bits 0-3 are greater than 9, OR the AC flag is set, then six is added to
 produce a proper BCD digit.
 If the carry is set, OR the four high bits 4-7 exceed nine, six is added to the value of these bits.
 The carry flag will be set if the result is > 0x99, but not cleared otherwise */

 UINT16 new_acc = R_ACC;
 if(GET_AC || ((R_ACC & 0x0f) > 9))
	 new_acc += 0x06;
 if(GET_CY || ((new_acc & 0xf0) > 9))
	 new_acc += 0x60;
 SFR_W(ACC,new_acc&0xff);
 if(new_acc > 0x99)
	SET_CY(1);
}

//DEC A                                     /* 1: 0001 0100 */
INLINE void dec_a(void)
{
	SFR_W(ACC,R_ACC-1);
}

//DEC data addr                             /* 1: 0001 0101 */
INLINE void dec_mem(void)
{
	UINT8 addr = ROP_ARG(PC++);				//Grab data address
	UINT8 data = IRAM_R(addr);
	IRAM_W(addr,data-1);
}

//DEC @R0/@R1                               /* 1: 0001 011i */
INLINE void dec_ir(int r)
{
	UINT8 data = IRAM_IR(R_R(r));
	IRAM_W(R_R(r),data-1);
}

//DEC R0 to R7                              /* 1: 0001 1rrr */
INLINE void dec_r(int r)
{
	R_R(r) = R_R(r) - 1;
}

//DIV AB                                    /* 1: 1000 0100 */
INLINE void div_ab(void)
{
	if( R_B == 0 ) {
		//Overflow flag is set!
		SET_OV(1);
		//Really the values are undefined according to the manual, but we'll just leave them as is..
		//SFR_W(ACC,0xff);
		//SFR_W(B,0xff);
	}
	else {
		int a = (int)R_ACC/R_B;
		int b = (int)R_ACC%R_B;
		//A gets quotient byte, B gets remainder byte
		SFR_W(ACC,a);
		SFR_W(B,  b);
		//Overflow flag is cleared
		SET_OV(0);
	}
	//Carry Flag is always cleared
	SET_CY(0);
}

//DJNZ data addr, code addr                 /* 1: 1101 0101 */
INLINE void djnz_mem(void)
{
	UINT8 addr = ROP_ARG(PC++);				//Grab data address
	INT8 rel_addr = ROP_ARG(PC++);			//Grab relative code address
	IRAM_W(addr,IRAM_R(addr) - 1);			//Decrement value contained at data address
	if(IRAM_R(addr) != 0)					//Branch if contents of data address is not 0
		PC = PC + rel_addr;
}

//DJNZ R0 to R7,code addr                   /* 1: 1101 1rrr */
INLINE void djnz_r(int r)
{
	INT8 rel_addr = ROP_ARG(PC++);			//Grab relative code address
	R_R(r) = R_R(r) - 1;					//Decrement value
	if(R_R(r) != 0)							//Branch if contents of R0 - R7 is not 0
		PC = PC + rel_addr;
}

//INC A                                     /* 1: 0000 0100 */
INLINE void inc_a(void)
{
	SFR_W(ACC,R_ACC+1);
}

//INC data addr                             /* 1: 0000 0101 */
INLINE void inc_mem(void)
{
	UINT8 addr = ROP_ARG(PC++);				//Grab data address
	UINT8 data = IRAM_R(addr);
	IRAM_W(addr,data+1);
}

//INC @R0/@R1                               /* 1: 0000 011i */
INLINE void inc_ir(int r)
{
	UINT8 data = IRAM_IR(R_R(r));
	IRAM_W(R_R(r),data+1);
}

//INC R0 to R7                              /* 1: 0000 1rrr */
INLINE void inc_r(int r)
{
	UINT8 data = R_R(r);
	R_R(r) = data + 1;
}

//INC DPTR                                  /* 1: 1010 0011 */
INLINE void inc_dptr(void)
{
	UINT16 dptr = (R_DPTR)+1;
	DPTR_W(dptr);
}

//JB  bit addr, code addr                   /* 1: 0010 0000 */
INLINE void jb(void)
{
	UINT8 addr = ROP_ARG(PC++);				//Grab bit address
	INT8 rel_addr = ROP_ARG(PC++);			//Grab relative code address
	if(BIT_R(addr))							//If bit set at specified bit address, jump
		PC = PC + rel_addr;
}

//JBC bit addr, code addr                   /* 1: 0001 0000 */
INLINE void jbc(void)
{
	UINT8 addr = ROP_ARG(PC++);				//Grab bit address
	INT8 rel_addr = ROP_ARG(PC++);			//Grab relative code address
	if(BIT_R(addr))	{						//If bit set at specified bit address, jump
		PC = PC + rel_addr;
		BIT_W(addr,0);						//Clear Bit also
	}
}

//JC code addr                              /* 1: 0100 0000 */
INLINE void jc(void)
{
	INT8 rel_addr = ROP_ARG(PC++);			//Grab relative code address
	if(GET_CY)								//Jump if Carry Flag Set
		PC = PC + rel_addr;
}

//JMP @A+DPTR                               /* 1: 0111 0011 */
INLINE void jmp_iadptr(void)
{
	PC = R_ACC+R_DPTR;
}

//JNB bit addr, code addr                   /* 1: 0011 0000 */
INLINE void jnb(void)
{
	UINT8 addr = ROP_ARG(PC++);				//Grab bit address
	INT8 rel_addr = ROP_ARG(PC++);			//Grab relative code address
	if(!BIT_R(addr))						//If bit NOT set at specified bit address, jump
		PC = PC + rel_addr;
}

//JNC code addr                             /* 1: 0101 0000 */
INLINE void jnc(void)
{
	INT8 rel_addr = ROP_ARG(PC++);			//Grab relative code address
	if(!GET_CY)								//Jump if Carry Flag not set
		PC = PC + rel_addr;
}

//JNZ code addr                             /* 1: 0111 0000 */
INLINE void jnz(void)
{
	INT8 rel_addr = ROP_ARG(PC++);			//Grab relative code address
	if(R_ACC != 0)							//Branch if ACC is not 0
		PC = PC+rel_addr;
}

//JZ code addr                              /* 1: 0110 0000 */
INLINE void jz(void)
{
	INT8 rel_addr = ROP_ARG(PC++);			//Grab relative code address
	if(R_ACC == 0)							//Branch if ACC is 0
		PC = PC+rel_addr;
}

//LCALL code addr                           /* 1: 0001 0010 */
INLINE void lcall(void)
{
	UINT8 addr_hi, addr_lo;
	addr_hi = ROP_ARG(PC++);
	addr_lo = ROP_ARG(PC++);
	PUSH_PC
	PC = (UINT16)((addr_hi<<8) | addr_lo);
}

//LJMP code addr                            /* 1: 0000 0010 */
INLINE void ljmp(void)
{
	UINT8 addr_hi, addr_lo;
	addr_hi = ROP_ARG(PC++);
	addr_lo = ROP_ARG(PC++);
	PC = (UINT16)((addr_hi<<8) | addr_lo);
}

//MOV A, #data                              /* 1: 0111 0100 */
INLINE void mov_a_byte(void)
{
	UINT8 data = ROP_ARG(PC++);				//Grab data
	SFR_W(ACC,data);						//Store data to ACC
}

//MOV A, data addr                          /* 1: 1110 0101 */
INLINE void mov_a_mem(void)
{
	UINT8 addr = ROP_ARG(PC++);				//Grab data address
	SFR_W(ACC,IRAM_R(addr));				//Store contents of data address to ACC
}

//MOV A,@RO/@R1                             /* 1: 1110 011i */
INLINE void mov_a_ir(int r)
{
	SFR_W(ACC,IRAM_IR(R_R(r)));				//Store contents of address pointed by R0 or R1 to ACC
}

//MOV A,R0 to R7                            /* 1: 1110 1rrr */
INLINE void mov_a_r(int r)
{
	SFR_W(ACC,R_R(r));						//Store contents of R0 - R7 to ACC
}

//MOV data addr, #data                      /* 1: 0111 0101 */
INLINE void mov_mem_byte(void)
{
	UINT8 addr = ROP_ARG(PC++);				//Grab data address
	UINT8 data = ROP_ARG(PC++);				//Grab data
	IRAM_W(addr,data);						//Store data to data address location
}

//MOV data addr, data addr                  /* 1: 1000 0101 */
INLINE void mov_mem_mem(void)
{
	//1st address is src, 2nd is dst, but the mov command works as mov dst,src)
	UINT8 src,dst;
	src = ROP_ARG(PC++);					//Grab source data address
	dst = ROP_ARG(PC++);					//Grab destination data address
	IRAM_W(dst,IRAM_R(src));				//Read source address contents and store to destination address
}

//MOV @R0/@R1, #data                        /* 1: 0111 011i */
INLINE void mov_ir_byte(int r)
{
	UINT8 data = ROP_ARG(PC++);				//Grab data
	IRAM_IW(R_R(r),data);					//Store data to address pointed by R0 or R1
}

//MOV R0 to R7, #data                       /* 1: 0111 1rrr */
INLINE void mov_r_byte(int r)
{
	UINT8 data = ROP_ARG(PC++);				//Grab data
	R_R(r) = data;							//Store to R0 - R7
}

//MOV data addr, @R0/@R1                    /* 1: 1000 011i */
INLINE void mov_mem_ir(int r)
{
	UINT8 addr = ROP_ARG(PC++);				//Grab data address
	IRAM_W(addr,IRAM_IR(R_R(r)));			//Store contents pointed to by R0 or R1 to data address
}

//MOV data addr,R0 to R7                    /* 1: 1000 1rrr */
INLINE void mov_mem_r(int r)
{
	UINT8 addr = ROP_ARG(PC++);				//Grab data address
	IRAM_W(addr,R_R(r));					//Store contents of R0 - R7 to data address
}

//MOV DPTR, #data16                         /* 1: 1001 0000 */
INLINE void mov_dptr_byte(void)
{
	UINT8 data_hi, data_lo;
	data_hi = ROP_ARG(PC++);				//Grab hi byte
	data_lo = ROP_ARG(PC++);				//Grab lo byte
	DPTR_W((UINT16)((data_hi<<8)|data_lo));	//Store to DPTR
}

//MOV bit addr, C                           /* 1: 1001 0010 */
INLINE void mov_bitaddr_c(void)
{
	UINT8 addr = ROP_ARG(PC++);				//Grab bit address
	BIT_W(addr,GET_CY);						//Store Carry Flag to Bit Address
}

//MOV @R0/@R1, data addr                    /* 1: 1010 011i */
INLINE void mov_ir_mem(int r)
{
	UINT8 addr = ROP_ARG(PC++);				//Grab data address
	IRAM_IW(R_R(r),IRAM_R(addr));			//Store data from data address to address pointed to by R0 or R1
}

//MOV R0 to R7, data addr                   /* 1: 1010 1rrr */
INLINE void mov_r_mem(int r)
{
	UINT8 addr = ROP_ARG(PC++);				//Grab data address
	R_R(r) = IRAM_R(addr);					//Store to R0 - R7
}

//MOV data addr, A                          /* 1: 1111 0101 */
INLINE void mov_mem_a(void)
{
	UINT8 addr = ROP_ARG(PC++);				//Grab data address
	IRAM_W(addr,R_ACC);						//Store A to data address
}

//MOV @R0/@R1, A                            /* 1: 1111 011i */
INLINE void mov_ir_a(int r)
{
	IRAM_IW(R_R(r),R_ACC);					//Store A to location pointed to by R0 or R1
}

//MOV R0 to R7, A                           /* 1: 1111 1rrr */
INLINE void mov_r_a(int r)
{
	R_R(r) = R_ACC;							//Store A to R0-R7
}

//MOVC A, @A + PC                           /* 1: 1000 0011 */
INLINE void movc_a_iapc(void)
{
	UINT8 data;
	data = CODEMEM_R(R_ACC+PC);				//Move a byte from CODE(Program) Memory and store to ACC
	SFR_W(ACC,data);
}

//MOV C, bit addr                           /* 1: 1010 0010 */
INLINE void mov_c_bitaddr(void)
{
	UINT8 addr = ROP_ARG(PC++);				//Grab bit address
	SET_CY( (BIT_R(addr)) );				//Store Bit from Bit Address to Carry Flag
}

//MOVC A, @A + DPTR                         /* 1: 1001 0011 */
INLINE void movc_a_iadptr(void)
{
	UINT8 data;
	data = CODEMEM_R(R_ACC+R_DPTR);			//Move a byte from CODE(Program) Memory and store to ACC
	SFR_W(ACC,data);
}

//MOVX A,@DPTR                              /* 1: 1110 0000 */
//(Move External Ram 16 bit address to A)
INLINE void movx_a_idptr(void)
{
//  UINT8 byte = DATAMEM_R(R_DPTR);         //Grab 1 byte from External DATA memory pointed to by dptr
	UINT32 addr = ERAM_ADDR(R_DPTR,0xFFFF);
	UINT8 byte = DATAMEM_R(addr);			//Grab 1 byte from External DATA memory pointed to by dptr
	SFR_W(ACC,byte);						//Store to ACC
}

//MOVX A, @R0/@R1                           /* 1: 1110 001i */
//(Move External Ram 8 bit address to A)
INLINE void movx_a_ir(int r)
{
	UINT32 addr = ERAM_ADDR(R_R(r),0xFF);	//Grab address by reading location pointed to by R0 or R1
	UINT8 byte = DATAMEM_R(addr);			//Grab 1 byte from External DATA memory pointed to by address
	SFR_W(ACC,byte);						//Store to ACC
}

//MOVX @DPTR,A                              /* 1: 1111 0000 */
//(Move A to External Ram 16 bit address)
INLINE void movx_idptr_a(void)
{
//  DATAMEM_W(R_DPTR, R_ACC);               //Store ACC to External DATA memory address pointed to by DPTR
	UINT32 addr = ERAM_ADDR(R_DPTR,0xFFFF);
	DATAMEM_W(addr, R_ACC);				//Store ACC to External DATA memory address pointed to by DPTR
}

//MOVX @R0/@R1,A                            /* 1: 1111 001i */
//(Move A to External Ram 8 bit address)
INLINE void movx_ir_a(int r)
{
	UINT32 addr = ERAM_ADDR(R_R(r),0xFF);   //Grab address by reading location pointed to by R0 or R1
	DATAMEM_W(addr, R_ACC);					//Store ACC to External DATA memory address
}

//MUL AB                                    /* 1: 1010 0100 */
INLINE void mul_ab(void)
{
	UINT16 result = R_ACC * R_B;
	//A gets lo bits, B gets hi bits of result
	SFR_W(B,(UINT8)((result & 0xFF00) >> 8));
	SFR_W(ACC,(UINT8)(result & 0x00FF));
	//Set flags
	SET_OV( ((result & 0x100) >> 8) );		//Set/Clear Overflow Flag if result > 255
	SET_CY(0);								//Carry Flag always cleared
}

//NOP                                       /* 1: 0000 0000 */
INLINE void nop(void)
{
}

//ORL data addr, A                          /* 1: 0100 0010 */
INLINE void orl_mem_a(void)
{
	UINT8 addr = ROP_ARG(PC++);				//Grab data address
	UINT8 data = IRAM_R(addr);				//Grab data from data address
	IRAM_W(addr,data | R_ACC);				//Set data address value to it's value Logical OR with ACC
}

//ORL data addr, #data                      /* 1: 0100 0011 */
INLINE void orl_mem_byte(void)
{
	UINT8 addr = ROP_ARG(PC++);				//Grab data address
	UINT8 data = ROP_ARG(PC++);				//Grab data
	UINT8 srcdata = IRAM_R(addr);			//Grab data from data address
	IRAM_W(addr,srcdata | data);			//Set data address value to it's value Logical OR with Data
}

//ORL A, #data                              /* 1: 0100 0100 */
INLINE void orl_a_byte(void)
{
	UINT8 data = ROP_ARG(PC++);				//Grab data
	SFR_W(ACC,R_ACC | data);				//Set ACC to value of ACC Logical OR with Data
}

//ORL A, data addr                          /* 1: 0100 0101 */
INLINE void orl_a_mem(void)
{
	UINT8 addr = ROP_ARG(PC++);				//Grab data address
	UINT8 data = IRAM_R(addr);				//Grab data from data address
	SFR_W(ACC,R_ACC | data);				//Set ACC to value of ACC Logical OR with Data
}

//ORL A, @RO/@R1                            /* 1: 0100 011i */
INLINE void orl_a_ir(int r)
{
	UINT8 data = IRAM_IR(R_R(r));			//Grab data from address R0 or R1 points to
	SFR_W(ACC,R_ACC | data);				//Set ACC to value of ACC Logical OR with Data
}

//ORL A, RO to R7                           /* 1: 0100 1rrr */
INLINE void orl_a_r(int r)
{
	UINT8 data = R_R(r);					//Grab data from R0 - R7
	SFR_W(ACC,R_ACC | data);				//Set ACC to value of ACC Logical OR with Data
}

//ORL C, bit addr                           /* 1: 0111 0010 */
INLINE void orl_c_bitaddr(void)
{
	int cy = GET_CY;
	UINT8 addr = ROP_ARG(PC++);				//Grab bit address
	UINT8 bit = BIT_R(addr);				//Grab bit data from bit address
	SET_CY( (cy | bit) );					//Set Carry flag to Carry Flag Value Logical OR with Bit
}

//ORL C, /bit addr                          /* 1: 1010 0000 */
INLINE void orl_c_nbitaddr(void)
{
	int cy = GET_CY;
	UINT8 addr = ROP_ARG(PC++);				//Grab bit address
	UINT8 bit = BIT_R(addr);				//Grab bit data from bit address
	bit = ((~bit)&1);						//Complement bit
	SET_CY( (cy | bit) );					//Set Carry flag to Carry Flag Value Logical OR with Complemented Bit
}

//POP data addr                             /* 1: 1101 0000 */
INLINE void pop(void)
{
	UINT8 addr = ROP_ARG(PC++);				//Grab data address
	IRAM_W(addr, IRAM_IR(R_SP));			//Store to contents of data addr, data pointed to by Stack - IRAM_IR needed to access upper 128 bytes of stack
	//IRAM_IW(addr, IRAM_IR(R_SP));         //Store to contents of data addr, data pointed to by Stack - doesn't work, sfr's are not restored this way and it's not an indirect access anyway
	SFR_W(SP,R_SP-1);						//Decrement SP
}

//PUSH data addr                            /* 1: 1100 0000 */
INLINE void push(void)
{
	UINT8 addr = ROP_ARG(PC++);				//Grab data address
	UINT8 tmpSP = R_SP;						//Grab and Increment Stack Pointer
	tmpSP++;								// ""
	SFR_W(SP,tmpSP);						// ""
    if (tmpSP == R_SP)						//Ensure it was able to write to new stack location
		IRAM_IW(tmpSP, IRAM_R(addr));		//Store to stack contents of data address - IRAM_IW needed to store to upper 128 bytes of stack, however, can't use IRAM_IR because that won't store the sfrs and it's not an indirect access anyway
}

//RET                                       /* 1: 0010 0010 */
INLINE void ret(void)
{
	POP_PC
}

//RETI                                      /* 1: 0011 0010 */
INLINE void reti(void)
{
	POP_PC
	CLEAR_CURRENT_IRQ
}

//RL A                                      /* 1: 0010 0011 */
INLINE void rl_a(void)
{
	//Left Shift A, Bit 7 carries to Bit 0
	int carry = ((R_ACC & 0x80) >> 7);
	int data = (R_ACC<<1) & 0xfe;
	SFR_W(ACC, data | carry);
}

//RLC A                                     /* 1: 0011 0011 */
INLINE void rlc_a(void)
{
	//Left Shift A, Bit 7 goes to Carry Flag, Original Carry Flag goes to Bit 0 of ACC
	int carry = ((R_ACC & 0x80) >> 7);
	int data = ((R_ACC<<1) & 0xfe) | GET_CY;
	SFR_W(ACC, data);
	SET_CY(carry);
}

//RR A                                      /* 1: 0000 0011 */
INLINE void rr_a(void)
{
	//Right Shift A, Bit 0 carries to Bit 7
	int carry = ((R_ACC & 1) << 7);
	int data = (R_ACC>>1) & 0x7f;
	SFR_W(ACC, data | carry);
}

//RRC A                                     /* 1: 0001 0011 */
INLINE void rrc_a(void)
{
	//Right Shift A, Bit 0 goes to Carry Flag, Bit 7 of ACC gets set to original Carry Flag
	int carry = (R_ACC & 1);
	int data = ((R_ACC>>1) & 0x7f) | (GET_CY<<7);
	SFR_W(ACC, data);
	SET_CY(carry);
}

//SETB C                                    /* 1: 1101 0011 */
INLINE void setb_c(void)
{
	SET_CY(1);		//Set Carry Flag
}

//SETB bit addr                             /* 1: 1101 0010 */
INLINE void setb_bitaddr(void)
{
	UINT8 addr = ROP_ARG(PC++);				//Grab bit address
	BIT_W(addr,1);							//Set Bit at Bit Address
}

//SJMP code addr                            /* 1: 1000 0000 */
INLINE void sjmp(void)
{
	INT8 rel_addr = ROP_ARG(PC++);			//Grab relative code address
	PC = PC + rel_addr;						//Update PC
}

//SUBB A, #data                             /* 1: 1001 0100 */
INLINE void subb_a_byte(void)
{
	UINT8 data = ROP_ARG(PC++);				//Grab data
	UINT8 result = R_ACC - data - GET_CY;	//Subtract data & carry flag from accumulator
	DO_SUB_FLAGS(R_ACC,data,GET_CY);		//Set Flags
	SFR_W(ACC,result);						//Store 8 bit result of addtion in ACC

}

//SUBB A, data addr                         /* 1: 1001 0101 */
INLINE void subb_a_mem(void)
{
	UINT8 addr = ROP_ARG(PC++);				//Grab data address
	UINT8 data = IRAM_R(addr);				//Grab data from data address
	UINT8 result = R_ACC - data - GET_CY;	//Subtract data & carry flag from accumulator
	DO_SUB_FLAGS(R_ACC,data,GET_CY);		//Set Flags
	SFR_W(ACC,result);						//Store 8 bit result of addtion in ACC
}

//SUBB A, @R0/@R1                           /* 1: 1001 011i */
INLINE void subb_a_ir(int r)
{
	UINT8 data = IRAM_IR(R_R(r));			//Grab data from memory pointed to by R0 or R1
	UINT8 result = R_ACC - data - GET_CY;	//Subtract data & carry flag from accumulator
	DO_SUB_FLAGS(R_ACC,data,GET_CY);		//Set Flags
	SFR_W(ACC,result);						//Store 8 bit result of addtion in ACC
}

//SUBB A, R0 to R7                          /* 1: 1001 1rrr */
INLINE void subb_a_r(int r)
{
	UINT8 data = R_R(r);					//Grab data from R0 - R7
	UINT8 result = R_ACC - data - GET_CY;	//Subtract data & carry flag from accumulator
	DO_SUB_FLAGS(R_ACC,data,GET_CY);		//Set Flags
	SFR_W(ACC,result);						//Store 8 bit result of addtion in ACC
}

//SWAP A                                    /* 1: 1100 0100 */
INLINE void swap_a(void)
{
	UINT8 a_nib_lo, a_nib_hi;
	a_nib_hi = (R_ACC & 0x0f) << 4;			//Grab lo byte of ACC and move to hi
	a_nib_lo = (R_ACC & 0xf0) >> 4;			//Grab hi byte of ACC and move to lo
	SFR_W(ACC, a_nib_hi | a_nib_lo);
}

//XCH A, data addr                          /* 1: 1100 0101 */
INLINE void xch_a_mem(void)
{
	UINT8 addr = ROP_ARG(PC++);				//Grab data address
	UINT8 data = IRAM_R(addr);				//Grab data
	UINT8 oldACC = R_ACC;					//Hold value of ACC
	SFR_W(ACC,data);						//Sets ACC to data
	IRAM_W(addr,oldACC);					//Sets data address to old value of ACC
}

//XCH A, @RO/@R1                            /* 1: 1100 011i */
INLINE void xch_a_ir(int r)
{
	UINT8 data = IRAM_IR(R_R(r));			//Grab data pointed to by R0 or R1
	UINT8 oldACC = R_ACC;					//Hold value of ACC
	SFR_W(ACC,data);						//Sets ACC to data
	IRAM_W(R_R(r),oldACC);					//Sets data address to old value of ACC
}

//XCH A, RO to R7                           /* 1: 1100 1rrr */
INLINE void xch_a_r(int r)
{
	UINT8 data = R_R(r);					//Grab data from R0-R7
	UINT8 oldACC = R_ACC;					//Hold value of ACC
	SFR_W(ACC,data);						//Sets ACC to data
	R_R(r) = oldACC;						//Sets data address to old value of ACC
}

//XCHD A, @R0/@R1                           /* 1: 1101 011i */
INLINE void xchd_a_ir(int r)
{
	UINT8 acc, ir_data;
	ir_data = IRAM_IR(R_R(r));				//Grab data pointed to by R0 or R1
	acc = R_ACC;							//Grab ACC value
	SFR_W(ACC, (acc & 0xf0) | (ir_data & 0x0f) );		//Set ACC to lower nibble of data pointed to by R0 or R1
	IRAM_W(R_R(r), (ir_data & 0xf0) | (acc & 0x0f) );	//Set data pointed to by R0 or R1 to lower nibble of ACC
}

//XRL data addr, A                          /* 1: 0110 0010 */
INLINE void xrl_mem_a(void)
{
	UINT8 addr = ROP_ARG(PC++);				//Grab data address
	UINT8 data = IRAM_R(addr);				//Grab data from data address
	IRAM_W(addr,data ^ R_ACC);				//Set data address value to it's value Logical XOR with ACC
}

//XRL data addr, #data                      /* 1: 0110 0011 */
INLINE void xrl_mem_byte(void)
{
	UINT8 addr = ROP_ARG(PC++);				//Grab data address
	UINT8 data = ROP_ARG(PC++);				//Grab data
	UINT8 srcdata = IRAM_R(addr);			//Grab data from data address
	IRAM_W(addr,srcdata ^ data);			//Set data address value to it's value Logical XOR with Data
}

//XRL A, #data                              /* 1: 0110 0100 */
INLINE void xrl_a_byte(void)
{
	UINT8 data = ROP_ARG(PC++);				//Grab data
	SFR_W(ACC,R_ACC ^ data);				//Set ACC to value of ACC Logical XOR with Data
}

//XRL A, data addr                          /* 1: 0110 0101 */
INLINE void xrl_a_mem(void)
{
	UINT8 addr = ROP_ARG(PC++);				//Grab data address
	UINT8 data = IRAM_R(addr);				//Grab data from data address
	SFR_W(ACC,R_ACC ^ data);				//Set ACC to value of ACC Logical XOR with Data
}

//XRL A, @R0/@R1                            /* 1: 0110 011i */
INLINE void xrl_a_ir(int r)
{
	UINT8 data = IRAM_IR(R_R(r));			//Grab data from address R0 or R1 points to
	SFR_W(ACC,R_ACC ^ data);				//Set ACC to value of ACC Logical XOR with Data
}

//XRL A, R0 to R7                           /* 1: 0110 1rrr */
INLINE void xrl_a_r(int r)
{
	UINT8 data = R_R(r);					//Grab data from R0 - R7
	SFR_W(ACC,R_ACC ^ data);				//Set ACC to value of ACC Logical XOR with Data
}

//illegal opcodes
INLINE void illegal(void)
{
	LOG(("i8051 #%d: illegal opcode at 0x%03x: %02x\n", cpu_getactivecpu(), PC, ROP(PC)));
}
