//
// Copyright (c) 2004 K. Wilkins
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from
// the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
//    claim that you wrote the original software. If you use this software
//    in a product, an acknowledgment in the product documentation would be
//    appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
//    be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//

//////////////////////////////////////////////////////////////////////////////
//                       Handy - An Atari Lynx Emulator                     //
//                          Copyright (c) 1996,1997                         //
//                                 K. Wilkins                               //
//////////////////////////////////////////////////////////////////////////////
// 65C02 Macro definitions                                                  //
//////////////////////////////////////////////////////////////////////////////
//                                                                          //
// This file contains all of the required address mode and operand          //
// macro definitions for the 65C02 emulation                                //
//                                                                          //
//    K. Wilkins                                                            //
// August 1997                                                              //
//                                                                          //
//////////////////////////////////////////////////////////////////////////////
// Revision History:                                                        //
// -----------------                                                        //
//                                                                          //
// 01Aug1997 KW Document header added & class documented.                   //
//                                                                          //
//////////////////////////////////////////////////////////////////////////////

//
// Addressing mode decoding
//

#define	xIMMEDIATE()			{mOperand=mPC;mPC++;}
#define	xABSOLUTE()				{mOperand=CPU_PEEKW(mPC);mPC+=2;}
#define xZEROPAGE()				{mOperand=CPU_PEEK(mPC);mPC++;}
#define xZEROPAGE_X()			{mOperand=CPU_PEEK(mPC)+mX;mPC++;mOperand&=0xff;}
#define xZEROPAGE_Y()			{mOperand=CPU_PEEK(mPC)+mY;mPC++;mOperand&=0xff;}
#define xABSOLUTE_X()			{mOperand=CPU_PEEKW(mPC);mPC+=2;mOperand+=mX;mOperand&=0xffff;}
#define	xABSOLUTE_Y()			{mOperand=CPU_PEEKW(mPC);mPC+=2;mOperand+=mY;mOperand&=0xffff;}
#define xINDIRECT_ABSOLUTE_X()	{mOperand=CPU_PEEKW(mPC);mPC+=2;mOperand+=mX;mOperand&=0xffff;mOperand=CPU_PEEKW(mOperand);}
#define xRELATIVE()				{mOperand=CPU_PEEK(mPC);mPC++;mOperand=(mPC+mOperand)&0xffff;}
#define xINDIRECT_X()			{mOperand=CPU_PEEK(mPC);mPC++;mOperand=mOperand+mX;mOperand&=0x00ff;mOperand=CPU_PEEKW(mOperand);}
#define xINDIRECT_Y()			{mOperand=CPU_PEEK(mPC);mPC++;mOperand=CPU_PEEKW(mOperand);mOperand=mOperand+mY;mOperand&=0xffff;}
#define xINDIRECT_ABSOLUTE()	{mOperand=CPU_PEEKW(mPC);mPC+=2;mOperand=CPU_PEEKW(mOperand);}
#define xINDIRECT()				{mOperand=CPU_PEEK(mPC);mPC++;mOperand=CPU_PEEKW(mOperand);}

//
// Helper Macros
//
//#define SET_Z(m)				{ mZ=(m)?false:true; }
//#define SET_N(m)				{ mN=(m&0x80)?true:false; }
//#define SET_NZ(m)				SET_Z(m) SET_N(m)
#define SET_Z(m)				{ mZ=!(m); }
#define SET_N(m)				{ mN=(m)&0x80; }
#define SET_NZ(m)				{ mZ=!(m); mN=(m)&0x80; }
#define PULL(m)					{ mSP++; mSP&=0xff; m=CPU_PEEK(mSP+0x0100); }
#define PUSH(m)					{ CPU_POKE(0x0100+mSP,m); mSP--; mSP&=0xff; }
//
// Opcode execution 
//

//#define	xADC()\
//{\
//	UBYTE	value=CPU_PEEK(mOperand);\
//	UBYTE	oldA=mA;\
//	if(!mD)\
//	{\
//		SWORD sum=(SWORD)((SBYTE)mA)+(SWORD)((SBYTE)value)+(mC?1:0);\
//		mV=((sum > 127) || (sum < -128));\
//		sum=(SWORD)mA + (SWORD)value + (mC?1:0);\
//		mA=(UBYTE)sum;\
//		mC=(sum>0xff);\
//		SET_NZ(mA);\
//	}\
//	else\
//	{\
//		SWORD sum=mBCDTable[0][mA]+mBCDTable[0][value]+(mC?1:0);\
//		mC=(sum > 99);\
//		mA=mBCDTable[1][sum & 0xff];\
//		SET_NZ(mA);\
//		mV=((oldA^mA)&0x80) && ((mA^value)&0x80);\
//	}\
//}

#define xADC()\
{\
	int value=CPU_PEEK(mOperand);\
	if(mD)\
	{\
		int c = mC?1:0;\
		int lo = (mA & 0x0f) + (value & 0x0f) + c;\
		int hi = (mA & 0xf0) + (value & 0xf0);\
		mV=0;\
		mC=0;\
		if (lo > 0x09)\
	    {\
		    hi += 0x10;\
			lo += 0x06;\
	    }\
		if (~(mA^value) & (mA^hi) & 0x80) mV=1;\
	    if (hi > 0x90) hi += 0x60;\
		if (hi & 0xff00) mC=1;\
		mA = (lo & 0x0f) + (hi & 0xf0);\
	}\
	else\
	{\
		int c = mC?1:0;\
		int sum = mA + value + c;\
	    mV=0;\
		mC=0;\
	    if (~(mA^value) & (mA^sum) & 0x80) mV=1;\
		if (sum & 0xff00) mC=1;\
	    mA = (UBYTE) sum;\
	}\
	SET_NZ(mA)\
}

#define xAND()\
{\
	mA&=CPU_PEEK(mOperand);\
	SET_NZ(mA);\
}

#define xASL()\
{\
	int value=CPU_PEEK(mOperand);\
	mC=value&0x80;\
	value<<=1;\
	value&=0xff;\
	SET_NZ(value);\
	CPU_POKE(mOperand,value);\
}

#define xASLA()\
{\
	mC=mA&0x80;\
	mA<<=1;\
	mA&=0xff;\
	SET_NZ(mA);\
}

#define xBCC()\
{\
	if(!mC)\
	{\
		int offset=(signed char)CPU_PEEK(mPC);\
		mPC++;\
		mPC+=offset;\
		mPC&=0xffff;\
	}\
	else\
	{\
		mPC++;\
		mPC&=0xffff;\
	}\
}

#define	xBCS()\
{\
	if(mC)\
	{\
		int offset=(signed char)CPU_PEEK(mPC);\
		mPC++;\
		mPC+=offset;\
		mPC&=0xffff;\
	}\
	else\
	{\
		mPC++;\
		mPC&=0xffff;\
	}\
}

#define	xBEQ()\
{\
	if(mZ)\
	{\
		int offset=(signed char)CPU_PEEK(mPC);\
		mPC++;\
		mPC+=offset;\
		mPC&=0xffff;\
	}\
	else\
	{\
		mPC++;\
		mPC&=0xffff;\
	}\
}

// This version of bit, not setting N and V status flags in immediate, seems to be correct.
// The same behaviour is reported on the 65C02 used in old Apple computers, at least.
// (From a pragmatic sense, using the normal version of bit for immediate
// mode breaks the title screen of "California Games" in a subtle way.)
#define	xBIT()\
{\
	int value=CPU_PEEK(mOperand);\
	SET_Z(mA&value);\
\
	if(mOpcode!=0x89)\
	{\
		mN=value&0x80;\
		mV=value&0x40;\
	}\
}

//
// DONT USE THIS VERSION OF BIT, IT BREAKS CALGAMES TITLE SCREEN !!!!
//
//#define	xBIT()\
//{\
//	int value=CPU_PEEK(mOperand);\
//	SET_Z(mA&value);\
//\
//	mN=value&0x80;\
//	mV=value&0x40;\
//}

#define	xBMI()\
{\
	if(mN)\
	{\
		int offset=(signed char)CPU_PEEK(mPC);\
		mPC++;\
		mPC+=offset;\
		mPC&=0xffff;\
	}\
	else\
	{\
		mPC++;\
		mPC&=0xffff;\
	}\
}

#define	xBNE()\
{\
	if(!mZ)\
	{\
		int offset=(signed char)CPU_PEEK(mPC);\
		mPC++;\
		mPC+=offset;\
		mPC&=0xffff;\
	}\
	else\
	{\
		mPC++;\
		mPC&=0xffff;\
	}\
}

#define	xBPL()\
{\
	if(!mN)\
	{\
		int offset=(signed char)CPU_PEEK(mPC);\
		mPC++;\
		mPC+=offset;\
		mPC&=0xffff;\
	}\
	else\
	{\
		mPC++;\
		mPC&=0xffff;\
	}\
}

#define	xBRA()\
{\
	int offset=(signed char)CPU_PEEK(mPC);\
	mPC++;\
	mPC+=offset;\
	mPC&=0xffff;\
}

//#define	xBRK()\
//{\
//	mPC++;\
//    PUSH(mPC>>8);\
//	PUSH(mPC&0xff);\
//	PUSH(PS()|0x10);\
//\
//	mD=FALSE;\
//	mI=TRUE;\
//\
//	mPC=CPU_PEEKW(IRQ_VECTOR);\
//}
#define	xBRK()\
{\
	mPC++;\
    PUSH(mPC>>8);\
	PUSH(mPC&0xff);\
	PUSH(PS()|0x10);\
\
	mD=FALSE;\
	mI=TRUE;\
\
	mPC=CPU_PEEKW(IRQ_VECTOR);\
}
// KW 4/11/98 B flag needed to be set IN the stack status word = 0x10.

#define	xBVC()\
{\
	if(!mV)\
	{\
		int offset=(signed char)CPU_PEEK(mPC);\
		mPC++;\
		mPC+=offset;\
		mPC&=0xffff;\
	}\
	else\
	{\
		mPC++;\
		mPC&=0xffff;\
	}\
}

#define	xBVS()\
{\
	if(mV)\
	{\
		int offset=(signed char)CPU_PEEK(mPC);\
		mPC++;\
		mPC+=offset;\
		mPC&=0xffff;\
	}\
	else\
	{\
		mPC++;\
		mPC&=0xffff;\
	}\
}

#define	xCLC()\
{\
	mC=FALSE;\
}

#define	xCLD()\
{\
	mD=FALSE;\
}

#define	xCLI()\
{\
	mI=FALSE;\
}

#define	xCLV()\
{\
	mV=FALSE;\
}

//
// Alternate CMP code
//
//#define	xCMP()\
//{\
//	UBYTE value=CPU_PEEK(mOperand);\
//	if(mA+0x100-value>0xff) mC=TRUE; else mC=FALSE;\
//	value=mA+0x100-value;\
//	mZ=!value;\
//	mN=value&0x0080;\
//}
//
//#define	xCPX()\
//{\
//	UBYTE value=CPU_PEEK(mOperand);\
//	if(mX+0x100-value>0xff) mC=TRUE; else mC=FALSE;\
//	value=mX+0x100-value;\
//	mZ=!value;\
//	mN=value&0x0080;\
//}
//
//#define	xCPY()\
//{\
//	UBYTE value=CPU_PEEK(mOperand);\
//	if(mY+0x100-value>0xff) mC=TRUE; else mC=FALSE;\
//	value=mY+0x100-value;\
//	mZ=!value;\
//	mN=value&0x0080;\
//}

//#define	xCMP()\
//{\
//	UWORD value=(UWORD)mA-CPU_PEEK(mOperand);\
//	SET_NZ(value);\
//	mC=!(value&0x0100);\
//}
#define	xCMP()\
{\
	int value=CPU_PEEK(mOperand);\
	mC=0;\
	if (mA >= value) mC=1;\
	SET_NZ((UBYTE)(mA - value))\
}

//#define	xCPX()\
//{\
//	UWORD value=(UWORD)mX-CPU_PEEK(mOperand);\
//	SET_NZ(value);\
//	mC=!(value&0x0100);\
//}
#define	xCPX()\
{\
	int value=CPU_PEEK(mOperand);\
	mC=0;\
	if (mX >= value) mC=1;\
	SET_NZ((UBYTE)(mX - value))\
}

//#define	xCPY()\
//{\
//	UWORD value=(UWORD)mY-CPU_PEEK(mOperand);\
//	SET_NZ(value);\
//	mC=!(value&0x0100);\
//}
#define	xCPY()\
{\
	int value=CPU_PEEK(mOperand);\
	mC=0;\
	if (mY >= value) mC=1;\
	SET_NZ((UBYTE)(mY - value))\
}

#define	xDEC()\
{\
	int value=CPU_PEEK(mOperand)-1;\
	value&=0xff;\
	CPU_POKE(mOperand,value);\
	SET_NZ(value);\
}

#define	xDECA()\
{\
	mA--;\
	mA&=0xff;\
	SET_NZ(mA);\
}

#define	xDEX()\
{\
	mX--;\
	mX&=0xff;\
	SET_NZ(mX);\
}

#define	xDEY()\
{\
	mY--;\
	mY&=0xff;\
	SET_NZ(mY);\
}

#define	xEOR()\
{\
	mA^=CPU_PEEK(mOperand);\
	SET_NZ(mA);\
}

#define	xINC()\
{\
	int value=CPU_PEEK(mOperand)+1;\
	value&=0xff;\
	CPU_POKE(mOperand,value);\
	SET_NZ(value);\
}

#define	xINCA()\
{\
	mA++;\
	mA&=0xff;\
	SET_NZ(mA);\
}

#define	xINX()\
{\
	mX++;\
	mX&=0xff;\
	SET_NZ(mX);\
}

#define	xINY()\
{\
	mY++;\
	mY&=0xff;\
	SET_NZ(mY);\
}

#define	xJMP()\
{\
	mPC=mOperand;\
}

#define	xJSR()\
{\
	PUSH((mPC-1)>>8);\
	PUSH((mPC-1)&0xff);\
	mPC=mOperand;\
}

#define	xLDA()\
{\
	mA=CPU_PEEK(mOperand);\
	SET_NZ(mA);\
}

#define	xLDX()\
{\
	mX=CPU_PEEK(mOperand);\
	SET_NZ(mX);\
}

#define	xLDY()\
{\
	mY=CPU_PEEK(mOperand);\
	SET_NZ(mY);\
}

#define	xLSR()\
{\
	int value=CPU_PEEK(mOperand);\
	mC=value&0x01;\
	value=(value>>1)&0x7f;\
	CPU_POKE(mOperand,value);\
	SET_NZ(value);\
}

#define	xLSRA()\
{\
	mC=mA&0x01;\
	mA=(mA>>1)&0x7f;\
	SET_NZ(mA);\
}

#define	xNOP()\
{\
}

#define	xORA()\
{\
	mA|=CPU_PEEK(mOperand);\
	SET_NZ(mA);\
}

#define	xPHA()\
{\
	PUSH(mA);\
}

#define	xPHP()\
{\
	PUSH(PS());\
}

#define	xPHX()\
{\
	PUSH(mX);\
}

#define	xPHY()\
{\
	PUSH(mY);\
}

#define	xPLA()\
{\
	PULL(mA);\
	SET_NZ(mA);\
}

#define	xPLP()\
{\
	int P;\
	PULL(P);\
	PS(P);\
}

#define	xPLX()\
{\
	PULL(mX);\
	SET_NZ(mX);\
}

#define	xPLY()\
{\
	PULL(mY);\
	SET_NZ(mY);\
}

#define	xROL()\
{\
	int value=CPU_PEEK(mOperand);\
	int oldC=mC;\
	mC=value&0x80;\
	value=(value<<1)|(oldC?1:0);\
	value&=0xff;\
	CPU_POKE(mOperand,value);\
	SET_NZ(value);\
}

#define	xROLA()\
{\
	int oldC=mC;\
	mC=mA&0x80;\
	mA=(mA<<1)|(oldC?1:0);\
	mA&=0xff;\
	SET_NZ(mA);\
}

#define	xROR()\
{\
	int value=CPU_PEEK(mOperand);\
	int oldC=mC;\
	mC=value&0x01;\
	value=((value>>1)&0x7f)|(oldC?0x80:0x00);\
	value&=0xff;\
	CPU_POKE(mOperand,value);\
	SET_NZ(value);\
}

#define	xRORA()\
{\
	int oldC=mC;\
	mC=mA&0x01;\
	mA=((mA>>1)&0x7f)|(oldC?0x80:0x00);\
	mA&=0xff;\
	SET_NZ(mA);\
}

#define	xRTI()\
{\
	int tmp;\
	PULL(tmp);\
	PS(tmp);\
	PULL(mPC);\
	PULL(tmp);\
	mPC|=tmp<<8;\
}

#define	xRTS()\
{\
	int tmp;\
	PULL(mPC);\
	PULL(tmp);\
	mPC|=tmp<<8;\
	mPC++;\
}

//#define	xSBC()\
//{\
//	UBYTE oldA=mA;\
//	if(!mD)\
//	{\
//		UBYTE value=~(CPU_PEEK(mOperand));\
//		SWORD difference=(SWORD)((SBYTE)mA)+(SWORD)((SBYTE)value)+(mC?1:0);\
//		mV=((difference>127)||(difference<-128));\
//		difference=((SWORD)mA)+((SWORD)value)+ (mC?1:0);\
//		mA=(UBYTE)difference;\
//		mC=(difference>0xff);\
//		SET_NZ(mA);\
//	}\
//	else\
//	{\
//		UBYTE value=CPU_PEEK(mOperand);\
//		SWORD difference=mBCDTable[0][mA]-mBCDTable[0][value]-(mC?0:1);\
//		if(difference<0) difference+=100;\
//		mA=mBCDTable[1][difference];\
//		mC=(oldA>=(value+(mC?0:1)));\
//		mV=((oldA^mA)&0x80)&&((mA^value)&0x80);\
//		SET_NZ(mA);\
//	}\
//}

#define	xSBC()\
{\
	int value=CPU_PEEK(mOperand);\
	if (mD)\
	{\
		int c = mC?0:1;\
		int sum = mA - value - c;\
		int lo = (mA & 0x0f) - (value & 0x0f) - c;\
		int hi = (mA & 0xf0) - (value & 0xf0);\
	    mV=0;\
		mC=0;\
	    if ((mA^value) & (mA^sum) & 0x80) mV=1;\
	    if (lo & 0xf0) lo -= 6;\
	    if (lo & 0x80) hi -= 0x10;\
	    if (hi & 0x0f00) hi -= 0x60;\
	    if ((sum & 0xff00) == 0) mC=1;\
	    mA = (lo & 0x0f) + (hi & 0xf0);\
	}\
	else\
	{\
		int c = mC?0:1;\
		int sum = mA - value - c;\
	    mV=0;\
		mC=0;\
	    if ((mA^value) & (mA^sum) & 0x80) mV=1;\
	    if ((sum & 0xff00) == 0) mC=1;\
	    mA = (UBYTE) sum;\
	}\
	SET_NZ(mA)\
}

#define	xSEC()\
{\
	mC=true;\
}

#define	xSED()\
{\
	mD=true;\
}

#define	xSEI()\
{\
	mI=true;\
}

#define	xSTA()\
{\
	CPU_POKE(mOperand,mA);\
}

#define	xSTP()\
{\
	gSystemCPUSleep=TRUE;\
}

#define	xSTX()\
{\
	CPU_POKE(mOperand,mX);\
}

#define	xSTY()\
{\
	CPU_POKE(mOperand,mY);\
}

#define	xSTZ()\
{\
	CPU_POKE(mOperand,0);\
}

#define	xTAX()\
{\
	mX=mA;\
	SET_NZ(mX);\
}

#define	xTAY()\
{\
	mY=mA;\
	SET_NZ(mY);\
}

#define	xTRB()\
{\
	int value=CPU_PEEK(mOperand);\
	SET_Z(mA&value);\
	value=value&(mA^0xff);\
	CPU_POKE(mOperand,value);\
}
//
// THE COMMENTED OUT CODE IS DERIVED FROM THE MAME 65C02 MODEL AND
// LOOKS TO BE INCORRECT i.e When plugged into Handy things stop working
//
//#define	xTRB()\
//{\
//	int value=CPU_PEEK(mOperand);\
//	value &= ~mA;\
//	SET_NZ(value);\
//	CPU_POKE(mOperand,value);\
//}

#define	xTSB()\
{\
	int value=CPU_PEEK(mOperand);\
	SET_Z(mA&value);\
	value=value|mA;\
	CPU_POKE(mOperand,value);\
}
//
// THE COMMENTED OUT CODE IS DERIVED FROM THE MAME 65C02 MODEL AND
// LOOKS TO BE INCORRECT i.e When plugged into Handy things stop working
//
//#define	xTSB()\
//{\
//	int value=CPU_PEEK(mOperand);\
//	value |= mA;\
//	SET_NZ(value);\
//	CPU_POKE(mOperand,value);\
//}

#define	xTSX()\
{\
	mX=mSP;\
	SET_NZ(mX);\
}

#define	xTXA()\
{\
	mA=mX;\
	SET_NZ(mA);\
}

#define	xTXS()\
{\
	mSP=mX;\
}

#define	xTYA()\
{\
	mA=mY;\
	SET_NZ(mA);\
}

#define	xWAI()\
{\
	gSystemCPUSleep=TRUE;\
}

