//---------------------------------------------------------------------------
// NEOPOP : Emulator as in Dreamland
//
// Copyright (c) 2001-2002 by neopop_uk
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
//	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. See also the license.txt file for
//	additional informations.
//---------------------------------------------------------------------------

/*
//---------------------------------------------------------------------------
//=========================================================================

	TLCS900h_interpret_src.c

//=========================================================================
//---------------------------------------------------------------------------

  History of changes:
  ===================

20 JUL 2002 - neopop_uk
=======================================
- Cleaned and tidied up for the source release

24 JUL 2002 - neopop_uk
=======================================
- Fixed S flag in "RRC (mem)"

25 JUL 2002 - neopop_uk
=======================================
- Removed unneeded Long mode from EX.

28 JUL 2002 - neopop_uk
=======================================
- Improved the LDIR/LDDR/CPIR/CPDR instructions so that they
	finish with the correct register settings, even if there is
	a memory error.
- Converted DIV/DIVS to use the generic function

16 AUG 2002 - neopop_uk
=======================================
- Replaced 'second & 7' with 'R', clearer, faster - and for some reason
	more accurate... oh well!
- Fixed V flag emulation of INC/DEC, fixes "Cotton" menus

21 AUG 2002 - neopop_uk
=======================================
- Fixed "RR (mem)" - It was actually the [REG] version that hadn't been
	changed to use memory accesses!

30 AUG 2002 - neopop_uk
=======================================
- Fixed "DIV RR,(mem)" in long mode, wrong operand size.

04 SEP 2002 - neopop_uk
=======================================
- Fixed GCC compatibility.

//---------------------------------------------------------------------------
*/

#include "../neopop.h"
#include "TLCS900h_interpret.h"
#include "TLCS900h_registers.h"
#include "../mem.h"

namespace TLCS900H
{

//=========================================================================

//===== PUSH (mem)
void srcPUSH()
{
	switch(size)
	{
	case 0:	push8(loadB(mem));	break;
	case 1: push16(loadW(mem)); break;
	}
	cycles = 7;
}

//===== RLD A,(mem)
void srcRLD()
{
	uint8 al = REGA & 0xF, m, mh, ml;

	m = loadB(mem);
	mh = (m & 0xF0) >> 4;
	ml = (m & 0x0F) << 4;
	
	REGA = (REGA & 0xF0) | mh;
	storeB(mem, ml | al);

	SETFLAG_S(REGA & 0x80);
	SETFLAG_Z(REGA == 0);
	SETFLAG_H0
	SETFLAG_N0
	parityB(REGA);

	cycles = 12;
}

//===== RRD A,(mem)
void srcRRD()
{
	uint8 al = (REGA & 0xF) << 4, m, mh, ml;

	m = loadB(mem);
	mh = (m & 0xF0) >> 4;
	ml = m & 0x0F;
	
	REGA = (REGA & 0xF0) | ml;
	storeB(mem, al | mh);

	SETFLAG_S(REGA & 0x80);
	SETFLAG_Z(REGA == 0);
	SETFLAG_H0
	SETFLAG_N0
	parityB(REGA);

	cycles = 12;
}

//===== LDI
void srcLDI()
{
	uint8 dst = 2/*XDE*/, src = 3/*XHL*/;
	if ((first & 0xF) == 5) { dst = 4/*XIX*/; src = 5/*XIY*/; }

	switch(size)
	{
	case 0:
		storeB(regL(dst), loadB(regL(src)));
		regL(dst) += 1;
		regL(src) += 1;
		break;

	case 1:
		storeW(regL(dst), loadW(regL(src)));
		regL(dst) += 2;
		regL(src) += 2;
		break;
	}

	REGBC --;
	SETFLAG_V(REGBC);

	SETFLAG_H0;
	SETFLAG_N0;
	cycles = 10;
}

//===== LDIR
void srcLDIR()
{
	uint8 dst = 2/*XDE*/, src = 3/*XHL*/;
	if ((first & 0xF) == 5) { dst = 4/*XIX*/; src = 5/*XIY*/; }

	cycles = 10;

	do
	{
		switch(size)
		{
		case 0:	if (debug_abort_memory == false)
					storeB(regL(dst), loadB(regL(src)));
			regL(dst) += 1;
			regL(src) += 1;
			break;

		case 1:	if (debug_abort_memory == false)
					storeW(regL(dst), loadW(regL(src)));
			regL(dst) += 2;
			regL(src) += 2;
			break;
		}

		REGBC --;
		SETFLAG_V(REGBC);

		cycles += 14;
	}
	while (FLAG_V);

	SETFLAG_H0;
	SETFLAG_N0;
}

//===== LDD
void srcLDD()
{
	uint8 dst = 2/*XDE*/, src = 3/*XHL*/;
	if ((first & 0xF) == 5) { dst = 4/*XIX*/; src = 5/*XIY*/; }

	switch(size)
	{
	case 0:
		storeB(regL(dst), loadB(regL(src)));
		regL(dst) -= 1;
		regL(src) -= 1;
		break;

	case 1:
		storeW(regL(dst), loadW(regL(src)));
		regL(dst) -= 2;
		regL(src) -= 2;
		break;
	}

	REGBC --;
	SETFLAG_V(REGBC);

	SETFLAG_H0;
	SETFLAG_N0;
	cycles = 10;
}

//===== LDDR
void srcLDDR()
{
	uint8 dst = 2/*XDE*/, src = 3/*XHL*/;
	if ((first & 0xF) == 5)	{ dst = 4/*XIX*/; src = 5/*XIY*/; }

	cycles = 10;

	do
	{
		switch(size)
		{
		case 0:
			if (debug_abort_memory == false)
				storeB(regL(dst), loadB(regL(src)));
			regL(dst) -= 1;
			regL(src) -= 1;
			break;

		case 1:
			if (debug_abort_memory == false)
				storeW(regL(dst), loadW(regL(src)));
			regL(dst) -= 2;
			regL(src) -= 2;
			break;
		}

		REGBC --;
		SETFLAG_V(REGBC);

		cycles += 14;
	}
	while (FLAG_V);

	SETFLAG_H0;
	SETFLAG_N0;
}

//===== CPI
void srcCPI()
{
	uint8 R = first & 7;

	switch(size)
	{
	case 0: generic_SUB_B(REGA, loadB(regL(R)));
			regL(R) ++; break;

	case 1:	generic_SUB_W(REGWA, loadW(regL(R)));
			regL(R) += 2; break;
	}

	REGBC --;
	SETFLAG_V(REGBC);

	cycles = 8;
}

//===== CPIR
void srcCPIR()
{
	uint8 R = first & 7;

	cycles = 10;

	do
	{
		switch(size)
		{
		case 0:	if (debug_abort_memory == false)
					generic_SUB_B(REGA, loadB(regL(R)));
				regL(R) ++; break;

		case 1:	if (debug_abort_memory == false)
					generic_SUB_W(REGWA, loadW(regL(R)));
				regL(R) += 2; break;
		}

		REGBC --;
		SETFLAG_V(REGBC);

		cycles += 14;
	}
	while (FLAG_V && (FLAG_Z == false));
}

//===== CPD
void srcCPD()
{
	uint8 R = first & 7;

	switch(size)
	{
	case 0:	generic_SUB_B(REGA, loadB(regL(R)));
			regL(R) --;	break;

	case 1:	generic_SUB_W(REGWA, loadW(regL(R)));
			regL(R) -= 2; break;
	}

	REGBC --;
	SETFLAG_V(REGBC);

	cycles = 8;
}

//===== CPDR
void srcCPDR()
{
	uint8 R = first & 7;

	cycles = 10;

	do
	{
		switch(size)
		{
		case 0:	if (debug_abort_memory == false)
					generic_SUB_B(REGA, loadB(regL(R)));
				regL(R) -= 1; break;

		case 1: if (debug_abort_memory == false)
					generic_SUB_W(REGWA, loadW(regL(R)));
				regL(R) -= 2; break;
		}

		REGBC --;
		SETFLAG_V(REGBC);

		cycles += 14;
	}
	while (FLAG_V && (FLAG_Z == false));
}

//===== LD (nn),(mem)
void srcLD16m()
{
	switch(size)
	{
	case 0:	storeB(fetch16(), loadB(mem)); break;
	case 1: storeW(fetch16(), loadW(mem)); break;
	}

	cycles = 8;
}

//===== LD R,(mem)
void srcLD()
{
	switch(size)
	{
	case 0: regB(R) = loadB(mem); cycles = 4; break;
	case 1: regW(R) = loadW(mem); cycles = 4; break;
	case 2: regL(R) = loadL(mem); cycles = 6; break;
	}
}

//===== EX (mem),R
void srcEX()
{
	switch(size)
	{
	case 0:	{	uint8 temp = regB(R); 
				regB(R) = loadB(mem); 
				storeB(mem, temp); break;		}

	case 1:	{	uint16 temp = regW(R); 
				regW(R) = loadW(mem); 
				storeW(mem, temp); break;		}
	}

	cycles = 6;
}

//===== ADD (mem),#
void srcADDi()
{
	switch(size)
	{
	case 0:	storeB(mem, generic_ADD_B(loadB(mem), FETCH8)); cycles = 7;break;
	case 1:	storeW(mem, generic_ADD_W(loadW(mem), fetch16())); cycles = 8;break;
	}
}

//===== ADC (mem),#
void srcADCi()
{
	switch(size)
	{
	case 0:	storeB(mem, generic_ADC_B(loadB(mem), FETCH8)); cycles = 7;break;
	case 1:	storeW(mem, generic_ADC_W(loadW(mem), fetch16())); cycles = 8;break;
	}
}

//===== SUB (mem),#
void srcSUBi()
{
	switch(size)
	{
	case 0:	storeB(mem, generic_SUB_B(loadB(mem), FETCH8)); cycles = 7;break;
	case 1:	storeW(mem, generic_SUB_W(loadW(mem), fetch16())); cycles = 8;break;
	}
}

//===== SBC (mem),#
void srcSBCi()
{
	switch(size)
	{
	case 0:	storeB(mem, generic_SBC_B(loadB(mem), FETCH8)); cycles = 7;break;
	case 1:	storeW(mem, generic_SBC_W(loadW(mem), fetch16())); cycles = 8;break;
	}
}

//===== AND (mem),#
void srcANDi()
{
	switch(size)
	{
	case 0: {	uint8 result = loadB(mem) & FETCH8;
				storeB(mem, result);
				SETFLAG_S(result & 0x80);
				SETFLAG_Z(result == 0);
				parityB(result);
				cycles = 7;
				break; }

	case 1: {	uint16 result = loadW(mem) & fetch16();
				storeW(mem, result);
				SETFLAG_S(result & 0x8000);
				SETFLAG_Z(result == 0);
				parityW(result);
				cycles = 8;
				break; }
	}

	SETFLAG_H1;
	SETFLAG_N0;
	SETFLAG_C0;
}

//===== OR (mem),#
void srcORi()
{
	switch(size)
	{
	case 0: {	uint8 result = loadB(mem) | FETCH8;
				storeB(mem, result);
				SETFLAG_S(result & 0x80);
				SETFLAG_Z(result == 0);
				parityB(result);
				cycles = 7;
				break; }

	case 1: {	uint16 result = loadW(mem) | fetch16();
				storeW(mem, result);
				SETFLAG_S(result & 0x8000);
				SETFLAG_Z(result == 0);
				parityW(result);
				cycles = 8;
				break; }
	}

	SETFLAG_H0;
	SETFLAG_N0;
	SETFLAG_C0;
}

//===== XOR (mem),#
void srcXORi()
{
	switch(size)
	{
	case 0: {	uint8 result = loadB(mem) ^ FETCH8;
				storeB(mem, result);
				SETFLAG_S(result & 0x80);
				SETFLAG_Z(result == 0);
				parityB(result);
				cycles = 7;
				break; }

	case 1: {	uint16 result = loadW(mem) ^ fetch16();
				storeW(mem, result);
				SETFLAG_S(result & 0x8000);
				SETFLAG_Z(result == 0);
				parityW(result);
				cycles = 8;
				break; }
	}

	SETFLAG_H0;
	SETFLAG_N0;
	SETFLAG_C0;
}

//===== CP (mem),#
void srcCPi()
{
	switch(size)
	{
	case 0:	generic_SUB_B(loadB(mem), FETCH8);	break;
	case 1:	generic_SUB_W(loadW(mem), fetch16());	break;
	}
	
	cycles = 6;
}

//===== MUL RR,(mem)
void srcMUL()
{
	uint8 target = get_RR_Target();
	if (target == 0x80)
	{
		instruction_error("src: MUL bad \'RR\' dst code");
		return;
	}

	switch(size)
	{
	case 0: rCodeW(target) = (rCodeW(target) & 0xFF) * loadB(mem);
		cycles = 18; break;
	case 1: rCodeL(target) = (rCodeL(target) & 0xFFFF) * loadW(mem);
		cycles = 26; break;
	}
}

//===== MULS RR,(mem)
void srcMULS()
{
	uint8 target = get_RR_Target();
	if (target == 0x80)
	{
		instruction_error("src: MUL bad \'RR\' dst code");
		return;
	}

	switch(size)
	{
	case 0: rCodeW(target) = (int8)(rCodeW(target) & 0xFF) * (int8)loadB(mem);
		cycles = 18; break;
	case 1: rCodeL(target) = (int16)(rCodeL(target) & 0xFFFF) * (int16)loadW(mem);
		cycles = 26; break;
	}
}

//===== DIV RR,(mem)
void srcDIV()
{
	uint8 target = get_RR_Target();
	if (target == 0x80)
	{
		instruction_error("src: DIV bad \'RR\' dst code");
		return;
	}

	switch(size)
	{
	case 0: {	rCodeW(target) = generic_DIV_B(rCodeW(target), loadB(mem));
				cycles = 22;
				break;	}
				
	case 1: {	rCodeL(target) = generic_DIV_W(rCodeL(target), loadW(mem));
				cycles = 30;
				break;	}
	}
}

//===== DIVS RR,(mem)
void srcDIVS()
{
	uint8 target = get_RR_Target();
	if (target == 0x80)
	{
		instruction_error("src: DIVS bad \'RR\' dst code");
		return;
	}

	switch(size)
	{
	case 0: {	rCodeW(target) = generic_DIVS_B(rCodeW(target), loadB(mem));
				cycles = 24;
				break;	}

	case 1: {	rCodeL(target) = generic_DIVS_W(rCodeL(target), loadW(mem));
				cycles = 32;
				break;	}
	}
}

//===== INC #3,(mem)
void srcINC()
{
	uint8 val = R;
	if (val == 0)
		val = 8;

	switch(size)
	{
	case 0: {	uint8 dst = loadB(mem);
				uint32 resultC = dst + val;
				uint8 half = (dst & 0xF) + val;
				uint8 result = (uint8)(resultC & 0xFF);
				SETFLAG_Z(result == 0);
				SETFLAG_H(half > 0xF);
				SETFLAG_S(result & 0x80);
				SETFLAG_N0;

				if (((int8)dst >= 0) && ((int8)result < 0))
				{SETFLAG_V1} else {SETFLAG_V0}

				storeB(mem, result);
				break; }

	case 1: {	uint16 dst = loadW(mem);
				uint32 resultC = dst + val;
				uint8 half = (dst & 0xF) + val;
				uint16 result = (uint16)(resultC & 0xFFFF);
				SETFLAG_Z(result == 0);
				SETFLAG_H(half > 0xF);
				SETFLAG_S(result & 0x8000);
				SETFLAG_N0;

				if (((int16)dst >= 0) && ((int16)result < 0))
				{SETFLAG_V1} else {SETFLAG_V0}

				storeW(mem, result);
				break; }
	}

	cycles = 6;
}

//===== DEC #3,(mem)
void srcDEC()
{
	uint8 val = R;
	if (val == 0)
		val = 8;

	switch(size)
	{
	case 0: {	uint8 dst = loadB(mem);
				uint32 resultC = dst - val;
				uint8 half = (dst & 0xF) - val;
				uint8 result = (uint8)(resultC & 0xFF);
				SETFLAG_Z(result == 0);
				SETFLAG_H(half > 0xF);
				SETFLAG_S(result & 0x80);
				SETFLAG_N1;

				if (((int8)dst < 0) && ((int8)result >= 0))
				{SETFLAG_V1} else {SETFLAG_V0}

				storeB(mem, result);
				break; }

	case 1: {	uint16 dst = loadW(mem);
				uint32 resultC = dst - val;
				uint8 half = (dst & 0xF) - val;
				uint16 result = (uint16)(resultC & 0xFFFF);
				SETFLAG_Z(result == 0);
				SETFLAG_H(half > 0xF);
				SETFLAG_S(result & 0x8000);
				SETFLAG_N1;

				if (((int16)dst < 0) && ((int16)result >= 0))
				{SETFLAG_V1} else {SETFLAG_V0}

				storeW(mem, result);
				break; }
	}

	cycles = 6;
}

//===== RLC (mem)
void srcRLC()
{
	switch(size)
	{
	case 0:	{	uint8 result = loadB(mem);
				SETFLAG_C(result & 0x80);
				result <<= 1;
				if (FLAG_C) result |= 1;
				storeB(mem, result);
				SETFLAG_S(result & 0x80);
				SETFLAG_Z(result == 0);
				parityB(result);
				break; }
		
	case 1:	{	uint16 result = loadW(mem);
				SETFLAG_C(result & 0x8000);
				result <<= 1;
				if (FLAG_C) result |= 1;
				storeW(mem, result);
				SETFLAG_S(result & 0x8000);
				SETFLAG_Z(result == 0);
				parityW(result);
				break; }
	}

	SETFLAG_H0;
	SETFLAG_N0;

	cycles = 8;
}

//===== RRC (mem)
void srcRRC()
{
	switch(size)
	{
	case 0:	{	uint8 data = loadB(mem), result;
				SETFLAG_C(data & 1);
				result = data >> 1;
				if (FLAG_C) result |= 0x80;
				storeB(mem, result);
				SETFLAG_S(result & 0x80);
				SETFLAG_Z(result == 0);
				parityB(result);
				break; }
		
	case 1:	{	uint16 data = loadW(mem), result;
				SETFLAG_C(data & 1);
				result = data >> 1;
				if (FLAG_C) result |= 0x8000;
				storeW(mem, result);
				SETFLAG_S(result & 0x8000);
				SETFLAG_Z(result == 0);
				parityW(result);
				break; }
	}

	SETFLAG_H0;
	SETFLAG_N0;

	cycles = 8;
}

//===== RL (mem)
void srcRL()
{
	bool tempC;

	switch(size)
	{
	case 0:	{	uint8 result = loadB(mem);
				tempC = FLAG_C;
				SETFLAG_C(result & 0x80);
				result <<= 1;
				if (tempC) result |= 1;
				storeB(mem, result);
				SETFLAG_S(result & 0x80);
				SETFLAG_Z(result == 0);
				parityB(result);
				break; }
		
	case 1:	{	uint16 result = loadW(mem);
				tempC = FLAG_C;
				SETFLAG_C(result & 0x8000);
				result <<= 1;
				if (tempC) result |= 1;
				storeW(mem, result);
				SETFLAG_S(result & 0x8000);
				SETFLAG_Z(result == 0);
				parityW(result);
				break; }
	}

	cycles = 8;
}

//===== RR (mem)
void srcRR()
{
	bool tempC;

	switch(size)
	{
	case 0:	{	uint8 result = loadB(mem);
				tempC = FLAG_C;
				SETFLAG_C(result & 1);
				result >>= 1;
				if (tempC) result |= 0x80;
				storeB(mem, result);
				SETFLAG_S(result & 0x80);
				SETFLAG_Z(result == 0);
				parityB(result);
				break; }
		
	case 1:	{	uint16 result = loadW(mem);
				tempC = FLAG_C;
				SETFLAG_C(result & 1);
				result >>= 1;
				if (tempC) result |= 0x8000;
				storeW(mem, result);
				SETFLAG_S(result & 0x8000);
				SETFLAG_Z(result == 0);
				parityW(result);
				break; }
	}

	cycles = 8;
}

//===== SLA (mem)
void srcSLA()
{
	switch(size)
	{
	case 0:	{	uint8 result, data = loadB(mem);
				SETFLAG_C(data & 0x80);
				result = ((int8)data << 1);
				SETFLAG_S(result & 0x80);
				storeB(mem, result);
				SETFLAG_Z(result == 0);
				parityB(result);
				break;	}

	case 1:	{	uint16 result, data = loadW(mem);
				SETFLAG_C(data & 0x8000);
				result = ((int16)data << 1);
				SETFLAG_S(result & 0x8000);
				storeW(mem, result);
				SETFLAG_Z(result == 0);
				parityW(result);
				break;	}
	}

	SETFLAG_H0;
	SETFLAG_N0;

	cycles = 8;
}

//===== SRA (mem)
void srcSRA()
{
	switch(size)
	{
	case 0:	{	uint8 result, data = loadB(mem);
				SETFLAG_C(data & 0x1);
				result = ((int8)data >> 1);
				SETFLAG_S(result & 0x80);
				storeB(mem, result);
				SETFLAG_Z(result == 0);
				parityB(result);
				break;	}
	
	case 1:	{	uint16 result, data = loadW(mem);
				SETFLAG_C(data & 0x1);
				result = ((int16)data >> 1);
				SETFLAG_S(result & 0x8000);
				storeW(mem, result);
				SETFLAG_Z(result == 0);
				parityW(result);
				break;	}
	}

	SETFLAG_H0;
	SETFLAG_N0;

	cycles = 8;
}

//===== SLL (mem)
void srcSLL()
{
	switch(size)
	{
	case 0:	{	uint8 result, data = loadB(mem);
				SETFLAG_C(data & 0x80);
				result = (data << 1);
				SETFLAG_S(result & 0x80);
				storeB(mem, result);
				SETFLAG_Z(result == 0);
				parityB(result);
				break;	}
	
	case 1:	{	uint16 result, data = loadW(mem);
				SETFLAG_C(data & 0x8000);
				result = (data << 1);
				SETFLAG_S(result & 0x8000);
				storeW(mem, result);
				SETFLAG_Z(result == 0);
				parityW(result);
				break;	}
	}

	SETFLAG_H0;
	SETFLAG_N0;

	cycles = 8;
}

//===== SRL (mem)
void srcSRL()
{
	switch(size)
	{
	case 0:	{	uint8 result, data = loadB(mem);
				SETFLAG_C(data & 0x01);
				result = (data >> 1);
				SETFLAG_S(result & 0x80);
				storeB(mem, result);
				SETFLAG_Z(result == 0);
				parityB(result);
				break;	}

	case 1:	{	uint16 result, data = loadW(mem);
				SETFLAG_C(data & 0x0001);
				result = (data >> 1);
				SETFLAG_S(result & 0x8000);
				storeW(mem, result);
				SETFLAG_Z(result == 0);
				parityW(result);
				break;	}
	}

	SETFLAG_H0;
	SETFLAG_N0;

	cycles = 8;
}

//===== ADD R,(mem)
void srcADDRm()
{
	switch(size)
	{
	case 0: regB(R) = generic_ADD_B(regB(R), loadB(mem)); cycles = 4;break;
	case 1: regW(R) = generic_ADD_W(regW(R), loadW(mem)); cycles = 4;break;
	case 2: regL(R) = generic_ADD_L(regL(R), loadL(mem)); cycles = 6;break;
	}
}

//===== ADD (mem),R
void srcADDmR()
{
	switch(size)
	{
	case 0:	storeB(mem, generic_ADD_B(loadB(mem), regB(R))); cycles = 6;break;
	case 1:	storeW(mem, generic_ADD_W(loadW(mem), regW(R))); cycles = 6;break;
	case 2:	storeL(mem, generic_ADD_L(loadL(mem), regL(R))); cycles = 10;break;
	}
}

//===== ADC R,(mem)
void srcADCRm()
{
	switch(size)
	{
	case 0: regB(R) = generic_ADC_B(regB(R), loadB(mem)); cycles = 4;break;
	case 1: regW(R) = generic_ADC_W(regW(R), loadW(mem)); cycles = 4;break;
	case 2: regL(R) = generic_ADC_L(regL(R), loadL(mem)); cycles = 6;break;
	}
}

//===== ADC (mem),R
void srcADCmR()
{
	switch(size)
	{
	case 0:	storeB(mem, generic_ADC_B(loadB(mem), regB(R))); cycles = 6;break;
	case 1:	storeW(mem, generic_ADC_W(loadW(mem), regW(R))); cycles = 6;break;
	case 2:	storeL(mem, generic_ADC_L(loadL(mem), regL(R))); cycles = 10;break;
	}
}

//===== SUB R,(mem)
void srcSUBRm()
{
	switch(size)
	{
	case 0: regB(R) = generic_SUB_B(regB(R), loadB(mem)); cycles = 4;break;
	case 1: regW(R) = generic_SUB_W(regW(R), loadW(mem)); cycles = 4;break;
	case 2: regL(R) = generic_SUB_L(regL(R), loadL(mem)); cycles = 6;break;
	}
}

//===== SUB (mem),R
void srcSUBmR()
{
	switch(size)
	{
	case 0:	storeB(mem, generic_SUB_B(loadB(mem), regB(R))); cycles = 6;break;
	case 1:	storeW(mem, generic_SUB_W(loadW(mem), regW(R))); cycles = 6;break;
	case 2:	storeL(mem, generic_SUB_L(loadL(mem), regL(R))); cycles = 10;break;
	}
}

//===== SBC R,(mem)
void srcSBCRm()
{
	switch(size)
	{
	case 0: regB(R) = generic_SBC_B(regB(R), loadB(mem)); cycles = 4;break;
	case 1: regW(R) = generic_SBC_W(regW(R), loadW(mem)); cycles = 4;break;
	case 2: regL(R) = generic_SBC_L(regL(R), loadL(mem)); cycles = 6;break;
	}
}

//===== SBC (mem),R
void srcSBCmR()
{
	switch(size)
	{
	case 0:	storeB(mem, generic_SBC_B(loadB(mem), regB(R))); cycles = 6;break;
	case 1:	storeW(mem, generic_SBC_W(loadW(mem), regW(R))); cycles = 6;break;
	case 2:	storeL(mem, generic_SBC_L(loadL(mem), regL(R))); cycles = 10;break;
	}
}

//===== AND R,(mem)
void srcANDRm()
{
	switch(size)
	{
	case 0:	{	uint8 result = regB(R) & loadB(mem);
				regB(R) = result;
				SETFLAG_Z(result == 0);
				SETFLAG_S(result & 0x80);
				parityB(result);
				cycles = 4;
				break; }
	
	case 1: {	uint16 result = regW(R) & loadW(mem);
				regW(R) = result;
				SETFLAG_Z(result == 0);
				SETFLAG_S(result & 0x8000);
				parityW(result);
				cycles = 4;
				break; }

	case 2:	{	uint32 result = regL(R) & loadL(mem);
				regL(R) = result;
				SETFLAG_Z(result == 0);
				SETFLAG_S(result & 0x80000000);
				cycles = 6;
				break; }
	}

	SETFLAG_H1;
	SETFLAG_N0;
	SETFLAG_C0;
}

//===== AND (mem),R
void srcANDmR()
{
	switch(size)
	{
	case 0:	{	uint8 result = regB(R) & loadB(mem);
				storeB(mem, result);
				SETFLAG_Z(result == 0);
				SETFLAG_S(result & 0x80);
				parityB(result);
				cycles = 6;
				break; }
	
	case 1: {	uint16 result = regW(R) & loadW(mem);
				storeW(mem, result);
				SETFLAG_Z(result == 0);
				SETFLAG_S(result & 0x8000);
				parityW(result);
				cycles = 6;
				break; }

	case 2:	{	uint32 result = regL(R) & loadL(mem);
				storeL(mem, result);
				SETFLAG_Z(result == 0);
				SETFLAG_S(result & 0x80000000);
				cycles = 10;
				break; }
	}

	SETFLAG_H1;
	SETFLAG_N0;
	SETFLAG_C0;
}

//===== XOR R,(mem)
void srcXORRm()
{
	switch(size)
	{
	case 0:	{	uint8 result = regB(R) ^ loadB(mem);
				regB(R) = result;
				SETFLAG_Z(result == 0);
				SETFLAG_S(result & 0x80);
				parityB(result);
				cycles = 4;
				break; }
	
	case 1: {	uint16 result = regW(R) ^ loadW(mem);
				regW(R) = result;
				SETFLAG_Z(result == 0);
				SETFLAG_S(result & 0x8000);
				parityW(result);
				cycles = 4;
				break; }

	case 2:	{	uint32 result = regL(R) ^ loadL(mem);
				regL(R) = result;
				SETFLAG_Z(result == 0);
				SETFLAG_S(result & 0x80000000);
				cycles = 6;
				break; }
	}

	SETFLAG_H0;
	SETFLAG_N0;
	SETFLAG_C0;
}

//===== XOR (mem),R
void srcXORmR()
{
	switch(size)
	{
	case 0:	{	uint8 result = regB(R) ^ loadB(mem);
				storeB(mem, result);
				SETFLAG_Z(result == 0);
				SETFLAG_S(result & 0x80);
				parityB(result);
				cycles = 6;
				break; }
	
	case 1: {	uint16 result = regW(R) ^ loadW(mem);
				storeW(mem, result);
				SETFLAG_Z(result == 0);
				SETFLAG_S(result & 0x8000);
				parityW(result);
				cycles = 6;
				break; }

	case 2:	{	uint32 result = regL(R) ^ loadL(mem);
				storeL(mem, result);
				SETFLAG_Z(result == 0);
				SETFLAG_S(result & 0x80000000);
				cycles = 10;
				break; }
	}

	SETFLAG_H0;
	SETFLAG_N0;
	SETFLAG_C0;
}

//===== OR R,(mem)
void srcORRm()
{
	switch(size)
	{
	case 0:	{	uint8 result = regB(R) | loadB(mem);
				regB(R) = result;
				SETFLAG_Z(result == 0);
				SETFLAG_S(result & 0x80);
				parityB(result);
				cycles = 4;
				break; }
	
	case 1: {	uint16 result = regW(R) | loadW(mem);
				regW(R) = result;
				SETFLAG_Z(result == 0);
				SETFLAG_S(result & 0x8000);
				parityW(result);
				cycles = 4;
				break; }

	case 2:	{	uint32 result = regL(R) | loadL(mem);
				regL(R) = result;
				SETFLAG_Z(result == 0);
				SETFLAG_S(result & 0x80000000);
				cycles = 6;
				break; }
	}

	SETFLAG_H0;
	SETFLAG_N0;
	SETFLAG_C0;
}

//===== OR (mem),R
void srcORmR()
{
	switch(size)
	{
	case 0:	{	uint8 result = regB(R) | loadB(mem);
				storeB(mem, result);
				SETFLAG_Z(result == 0);
				SETFLAG_S(result & 0x80);
				parityB(result);
				cycles = 6;
				break; }
	
	case 1: {	uint16 result = regW(R) | loadW(mem);
				storeW(mem, result);
				SETFLAG_Z(result == 0);
				SETFLAG_S(result & 0x8000);
				parityW(result);
				cycles = 6;
				break; }

	case 2:	{	uint32 result = regL(R) | loadL(mem);
				storeL(mem, result);
				SETFLAG_Z(result == 0);
				SETFLAG_S(result & 0x80000000);
				cycles = 10;
				break; }
	}

	SETFLAG_H0;
	SETFLAG_N0;
	SETFLAG_C0;
}

//===== CP R,(mem)
void srcCPRm()
{
	switch(size)
	{
	case 0: generic_SUB_B(regB(R), loadB(mem)); cycles = 4; break;
	case 1: generic_SUB_W(regW(R), loadW(mem)); cycles = 4; break;
	case 2: generic_SUB_L(regL(R), loadL(mem)); cycles = 6; break;
	}
}

//===== CP (mem),R
void srcCPmR()
{
	switch(size)
	{
	case 0: generic_SUB_B(loadB(mem), regB(R));		break;
	case 1: generic_SUB_W(loadW(mem), regW(R));		break;
	case 2: generic_SUB_L(loadL(mem), regL(R));		break;
	}
	
	cycles = 6;
}
}
//=============================================================================
