/*	
 *	clipsp2c.c
 *
 *	P/ECE SPC Driver V2
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2001-2004 Naoyuki Sawa
 *
 *	* Sun Oct 10 16:18:00 JST 2004 Naoyuki Sawa
 *	- 作成開始。
 *	* Sat Feb 20 21:07:39 JST 2016 Naoyuki Sawa
 *	- Win32プロジェクトに含めるとABSOLUTEとRELATIVEのマクロが重複している警告が出るのを回避しました。
 */
#include "clip.h"

/****************************************************************************
 *	
 ****************************************************************************/

// * Sat Feb 20 21:07:39 JST 2016 Naoyuki Sawa
// - Win32プロジェクトに含めるとABSOLUTEとRELATIVEのマクロが重複している警告が出るのを回避しました。
//   ＞C:\Home\Share\Piece\clip\clipsp2c.c(79) : warning C4005: 'ABSOLUTE' : ﾏｸﾛが再定義されました。
//   ＞        C:\Program Files (x86)\Microsoft Visual Studio\VC98\INCLUDE\wingdi.h(1501) : 'ABSOLUTE' の前の定義を確認してください
//   ＞C:\Home\Share\Piece\clip\clipsp2c.c(107) : warning C4005: 'RELATIVE' : ﾏｸﾛが再定義されました。
//   ＞        C:\Program Files (x86)\Microsoft Visual Studio\VC98\INCLUDE\wingdi.h(1502) : 'RELATIVE' の前の定義を確認してください
#ifdef  WIN32
#undef  ABSOLUTE
#undef  RELATIVE
#endif//WIN32

/****************************************************************************
 *	SPC2CPU
 ****************************************************************************/

/*
 *	SPC2CPU構造体のフィールドアクセス簡略表記
 */
#define PSW_P		(cpu->psw_p)
#define PSW_NZ		(cpu->psw_nz)
#define PSW_C		(cpu->psw_c)
#define PSW_CNZ		(*(unsigned short*)&cpu->psw_nz)
#define PSW_V		(cpu->psw_v)
#define X		(cpu->x)
#define A		(cpu->a)
#define Y		(cpu->y)
#define YA		(*(unsigned short*)&cpu->a)
#define SP		(cpu->sp)
#define PC		(cpu->pc)

/*
 *	よく使うアドレッシングモードのマクロ定義
 */
/* #inm */
#define INMEDIATE_DATA() do { \
	inm = *PC++; \
} while(0)
/* dp */
#define DIRECT_PAGE() do { \
	mem = PSW_P | *PC++; \
} while(0)
/* dp+X */
#define X_INDEXED_DIRECT_PAGE() do { \
	mem = PSW_P | (unsigned char)(*PC++ + X); \
} while(0)
/* dp+Y */
#define Y_INDEXED_DIRECT_PAGE() do { \
	mem = PSW_P | (unsigned char)(*PC++ + Y); \
} while(0)
/* (X) */
#define INDIRECT() do { \
	mem = PSW_P | X; \
} while(0)
/* (X)+ */
#define INDIRECT_AUTO_INCREMENT() do { \
	mem = PSW_P | X++; \
} while(0)
/* (X),(Y) */
#define INDIRECT_PAGE_TO_IP() do { \
	src = PSW_P | Y; \
	dst = PSW_P | X; \
} while(0)
/* dp(d),dp(s) */
#define DIRECT_PAGE_TO_DP() do { \
	src = PSW_P | *PC++; \
	dst = PSW_P | *PC++; \
} while(0)
/* dp,#inm */
#define INMEDIATE_DATA_TO_DP() do { \
	inm = *PC++; \
	mem = PSW_P | *PC++; \
} while(0)
/* labs */
#define ABSOLUTE() do { \
	mem  = *PC++; \
	mem |= *PC++ << 8; \
} while(0)
/* labs+X */
#define X_INDEXED_ABSOLUTE() do { \
	mem  = *PC++; \
	mem |= *PC++ << 8; \
	mem  = (unsigned short)(mem + X); \
} while(0)
/* labs+Y */
#define Y_INDEXED_ABSOLUTE() do { \
	mem  = *PC++; \
	mem |= *PC++ << 8; \
	mem  = (unsigned short)(mem + Y); \
} while(0)
/* (dp+X) */
#define X_INDEXED_INDIRECT() do { \
	mem = PSW_P | (unsigned char)(*PC++ + X); \
	mem = spc2ram[mem] | spc2ram[mem + 1] << 8; \
} while(0)
/* (dp)+Y */
#define INDIRECT_Y_INDEXED_INDIRECT() do { \
	mem = PSW_P | *PC++; \
	mem = spc2ram[mem] | spc2ram[mem + 1] << 8; \
	mem = (unsigned short)(mem + Y); \
} while(0)
/* rel */
#define RELATIVE() do { \
	tmp = (char)*PC++; \
	PC = &spc2ram[(unsigned short)(PC - spc2ram + tmp)]; \
} while(0)
/* (labs+X) */
#define X_INDEXED_ABSOLUTE_INDIRECT() do { \
	mem  = *PC++; \
	mem |= *PC++ << 8; \
	mem  = (unsigned short)(mem + X); \
	mem  = spc2ram[mem] | spc2ram[mem + 1] << 8; \
} while(0)
/* mem.bit */
#define ABSOLUTE_BOOLEAN_BIT() do { \
	bit   = *PC++; \
	bit  |= *PC++ << 8; \
	mem   = bit & 0x1fff; \
	bit >>= 13; \
} while(0)

/****************************************************************************
 *	
 ****************************************************************************/

#define DIV spc2cpu_DIV
void
spc2cpu_DIV()
{
	SPC2CPU* cpu = &spc2cpu;
	//
	int tmp;

	if(X) {
		tmp = YA;
		PSW_NZ = A = tmp / X;
		         Y = tmp % X;
		PSW_V = 0;
	} else {
		YA = -1;
		PSW_V = PSW_NZ = -1;
	}
}

#define PACK_PSW spc2cpu_PACK_PSW
int
spc2cpu_PACK_PSW()
{
	SPC2CPU* cpu = &spc2cpu;
	//
	int psw;

	psw = PSW_P >> 3;		/* 00P00000 */
	if(PSW_NZ) {
		psw |= PSW_NZ & 0x80;	/* N0P00000 */
	} else {
		psw |= 2;		/* 00P000Z0 */
	}
	psw |= PSW_C & 1;		/* N0P000ZC */
	psw |= (PSW_V & 0x80) >> 1;	/* NVP000ZC */

	return psw;
}

#define UNPACK_PSW spc2cpu_UNPACK_PSW
void
spc2cpu_UNPACK_PSW(int psw)
{
	SPC2CPU* cpu = &spc2cpu;

#ifdef SPC2_DEBUG
	/* NとZが両方セットされていたら、エラー終了することにします。
	 * 負値かつゼロということはありえませんから、通常のオペレーションではこのような状況はないはずです。
	 * 厳密には、割り込みからの復帰時にスタック上のPSWをPOPすると、絶対にありえないとは言い切れません。
	 * しかし、スーパーファミコンのSPC700は割り込みを利用しないので、絶対にないと考えても良さそうです。
	 */
	if((psw & 0x82) == 0x82) DIE();
#endif /*SPC2_DEBUG*/

	PSW_P = (psw & 0x20) << 3;		/* --P----- */
	if(psw & 2) {				/* ------Z- */
		PSW_NZ = 0;
	} else {
		PSW_NZ = 1 | (psw & 0x80);	/* N------- */
	}
	PSW_C = psw & 1;			/* -------C */
	PSW_V = (psw & 0x40) << 1;		/* -V------ */
}

#ifndef SPC2_ASM

#define READ spc2cpu_READ
static int
spc2cpu_READ(int addr)
{
	int data;

#ifdef SPC2_DEBUG
	if(addr < 0 || addr > 0xffff) DIE();
#endif /*SPC2_DEBUG*/

	if((addr >= 0xf0) && (addr <= 0xff)) {
		data = spc2drv_read(addr);
	} else {
		data = spc2ram[addr];
	}

	return data;
}

#define WRITE spc2cpu_WRITE
static void
spc2cpu_WRITE(int addr, int data)
{
#ifdef SPC2_TRACE
	extern void spc2cpu_write_trace(int addr, int data);
	spc2cpu_write_trace(addr, data);
#endif /*SPC2_TRACE*/

#ifdef SPC2_DEBUG
	if(addr < 0 || addr > 0xffff) DIE();
#endif /*SPC2_DEBUG*/

	if((addr >= 0xf0) && (addr <= 0xff)) {
		/* spc2cpu_WRITE()が呼ばれるとき、dataの[32:8]は不定です。
		 * spc2drv_write()へ渡すdataの[32:8]は0でなければいけません。
		 * そのため、ここでdataの[32:8]を0クリアすることにします。
		 */
		spc2drv_write(addr, (unsigned char)data);
	} else {
		spc2ram[addr] = data;
	}
}

#define READW spc2cpu_READW
static int
spc2cpu_READW(int addr)
{
	return READ(addr) | READ(addr + 1) << 8;
}

#define WRITEW spc2cpu_WRITEW
static void
spc2cpu_WRITEW(int addr, int data)
{
	WRITE(addr    , data     );
	WRITE(addr + 1, data >> 8);
}

#define ADC spc2cpu_ADC
static int
spc2cpu_ADC(int a, int b)
{
	SPC2CPU* cpu = &spc2cpu;
	//
	int tmp;

	tmp = a + b + (PSW_C & 1);
	PSW_CNZ = tmp;
	PSW_V = ~(a ^ b) & (a ^ tmp);

	return tmp; /* 戻り値の[31:8]は不定です */
}

#define SBC spc2cpu_SBC
static int
spc2cpu_SBC(int a, int b)
{
	SPC2CPU* cpu = &spc2cpu;
	//
	int tmp;

	tmp = a - b - (~PSW_C & 1);
	PSW_CNZ = tmp ^ 0x100;
	PSW_V = (a ^ b) & (a ^ tmp);

	return tmp; /* 戻り値の[31:8]は不定です */
}

#define ADDW spc2cpu_ADDW
static int
spc2cpu_ADDW(int a, int b)
{
	SPC2CPU* cpu = &spc2cpu;
	//
	int tmp;

	tmp = a + b;
	PSW_CNZ = (tmp >> 8) | ((unsigned short)tmp != 0);
	PSW_V = (~(a ^ b) & (a ^ tmp)) >> 8;

	return tmp; /* 戻り値の[31:16]は不定です */
}

#define SUBW spc2cpu_SUBW
static int
spc2cpu_SUBW(int a, int b)
{
	SPC2CPU* cpu = &spc2cpu;
	//
	int tmp;

	tmp = a - b;
	PSW_CNZ = ((tmp >> 8) | ((unsigned short)tmp != 0)) ^ 0x100;
	PSW_V = ((a ^ b) & (a ^ tmp)) >> 8;

	return tmp; /* 戻り値の[31:16]は不定です */
}

#define BEQ(cond) spc2cpu_BEQ(cond)
static void
spc2cpu_BEQ(int cond)
{
	SPC2CPU* cpu = &spc2cpu;
	//
	int tmp;

	if(!cond) {
		RELATIVE();
	} else {
		PC++;
	}
}

#define BNE(cond) spc2cpu_BNE(cond)
static void
spc2cpu_BNE(int cond)
{
	SPC2CPU* cpu = &spc2cpu;
	//
	int tmp;

	if(cond) {
		RELATIVE();
	} else {
		PC++;
	}
}

void
spc2cpu_run(int count)
{
	SPC2CPU* cpu = &spc2cpu;
	//
	int inm;
	int mem;
	int src;
	int dst;
	int bit;
	int tmp;

#ifdef SPC2_DEBUG
	if(count <= 0) DIE();
#endif /*SPC2_DEBUG*/

	do {
#ifdef SPC2_TRACE
		extern void spc2cpu_dump();
		spc2cpu_dump();
#endif /*SPC2_TRACE*/

		switch(*PC++) {

/*==========================================================================*
	1. 8-BIT DATA TRANSMISSION COMMANDS GROUP 1
 *==========================================================================*/

case 0xE8: /* MOV A,#inm */
	INMEDIATE_DATA();
	PSW_NZ = A = inm;
	break;

case 0xE6: /* MOV A,(X) */
	INDIRECT();
	PSW_NZ = A = READ(mem);
	break;

case 0xBF: /* MOV A,(X)+ */
	INDIRECT_AUTO_INCREMENT();
	PSW_NZ = A = READ(mem);
	break;

case 0xE4: /* MOV A,dp */
	DIRECT_PAGE();
	PSW_NZ = A = READ(mem);
	break;

case 0xF4: /* MOV A,dp+X */
	X_INDEXED_DIRECT_PAGE();
	PSW_NZ = A = READ(mem);
	break;

case 0xE5: /* MOV A,labs */
	ABSOLUTE();
	PSW_NZ = A = READ(mem);
	break;

case 0xF5: /* MOV A,labs+X */
	X_INDEXED_ABSOLUTE();
	PSW_NZ = A = READ(mem);
	break;

case 0xF6: /* MOV A,labs+Y */
	Y_INDEXED_ABSOLUTE();
	PSW_NZ = A = READ(mem);
	break;

case 0xE7: /* MOV A,(dp+X) */
	X_INDEXED_INDIRECT();
	PSW_NZ = A = READ(mem);
	break;

case 0xF7: /* MOV A,(dp)+Y */
	INDIRECT_Y_INDEXED_INDIRECT();
	PSW_NZ = A = READ(mem);
	break;

case 0xCD: /* MOV X,#inm */
	INMEDIATE_DATA();
	PSW_NZ = X = inm;
	break;

case 0xF8: /* MOV X,dp */
	DIRECT_PAGE();
	PSW_NZ = X = READ(mem);
	break;

case 0xF9: /* MOV X,dp+Y */
	Y_INDEXED_DIRECT_PAGE();
	PSW_NZ = X = READ(mem);
	break;

case 0xE9: /* MOV X,labs */
	ABSOLUTE();
	PSW_NZ = X = READ(mem);
	break;

case 0x8D: /* MOV Y,#inm */
	INMEDIATE_DATA();
	PSW_NZ = Y = inm;
	break;

case 0xEB: /* MOV Y,dp */
	DIRECT_PAGE();
	PSW_NZ = Y = READ(mem);
	break;

case 0xFB: /* MOV Y,dp+X */
	X_INDEXED_DIRECT_PAGE();
	PSW_NZ = Y = READ(mem);
	break;

case 0xEC: /* MOV Y,labs */
	ABSOLUTE();
	PSW_NZ = Y = READ(mem);
	break;

/*==========================================================================*
	2. 8-BIT DATA TRANSMISSION COMMANDS GROUP 2
 *==========================================================================*/

case 0xC6: /* MOV (X),A */
	INDIRECT();
	WRITE(mem, A);
	break;

case 0xAF: /* MOV (X)+,A */
	INDIRECT_AUTO_INCREMENT();
	WRITE(mem, A);
	break;

case 0xC4: /* MOV dp,A */
	DIRECT_PAGE();
	WRITE(mem, A);
	break;

case 0xD4: /* MOV dp+X,A */
	X_INDEXED_DIRECT_PAGE();
	WRITE(mem, A);
	break;

case 0xC5: /* MOV labs,A */
	ABSOLUTE();
	WRITE(mem, A);
	break;

case 0xD5: /* MOV labs+X,A */
	X_INDEXED_ABSOLUTE();
	WRITE(mem, A);
	break;

case 0xD6: /* MOV labs+Y,A */
	Y_INDEXED_ABSOLUTE();
	WRITE(mem, A);
	break;

case 0xC7: /* MOV (dp+X),A */
	X_INDEXED_INDIRECT();
	WRITE(mem, A);
	break;

case 0xD7: /* MOV (dp)+Y,A */
	INDIRECT_Y_INDEXED_INDIRECT();
	WRITE(mem, A);
	break;

case 0xD8: /* MOV dp,X */
	DIRECT_PAGE();
	WRITE(mem, X);
	break;

case 0xD9: /* MOV dp+Y,X */
	Y_INDEXED_DIRECT_PAGE();
	WRITE(mem, X);
	break;

case 0xC9: /* MOV labs,X */
	ABSOLUTE();
	WRITE(mem, X);
	break;

case 0xCB: /* MOV dp,Y */
	DIRECT_PAGE();
	WRITE(mem, Y);
	break;

case 0xDB: /* MOV dp+X,Y */
	X_INDEXED_DIRECT_PAGE();
	WRITE(mem, Y);
	break;

case 0xCC: /* MOV labs,Y */
	ABSOLUTE();
	WRITE(mem, Y);
	break;

/*==========================================================================*
	3. 8-BIT DATA TRANSMISSIN COMMANDS GROUP 3
 *==========================================================================*/

case 0x7D: /* MOV A,X */
	PSW_NZ = A = X;
	break;

case 0xDD: /* MOV A,Y */
	PSW_NZ = A = Y;
	break;

case 0x5D: /* MOV X,A */
	PSW_NZ = X = A;
	break;

case 0xFD: /* MOV Y,A */
	PSW_NZ = Y = A;
	break;

case 0x9D: /* MOV X,SP */
	PSW_NZ = X = SP - &spc2ram[0x100];
	break;

case 0xBD: /* MOV SP,X */
	SP = &spc2ram[0x100 | X];
	break;

case 0xFA: /* MOV dp(d),dp(s) */
	DIRECT_PAGE_TO_DP();
	WRITE(dst, READ(src));
	break;

case 0x8F: /* MOV dp,#inm */
	INMEDIATE_DATA_TO_DP();
	WRITE(mem, inm);
	break;

/*==========================================================================*
	4. 8-BIT ARITHMETIC OPERATION COMMANDS
 *==========================================================================*/

case 0x88: /* ADC A,#inm */
	INMEDIATE_DATA();
	A = ADC(A, inm);
	break;

case 0x86: /* ADC A,(X) */
	INDIRECT();
	A = ADC(A, READ(mem));
	break;

case 0x84: /* ADC A,dp */
	DIRECT_PAGE();
	A = ADC(A, READ(mem));
	break;

case 0x94: /* ADC A,dp+X */
	X_INDEXED_DIRECT_PAGE();
	A = ADC(A, READ(mem));
	break;

case 0x85: /* ADC A,labs */
	ABSOLUTE();
	A = ADC(A, READ(mem));
	break;

case 0x95: /* ADC A,labs+X */
	X_INDEXED_ABSOLUTE();
	A = ADC(A, READ(mem));
	break;

case 0x96: /* ADC A,labs+Y */
	Y_INDEXED_ABSOLUTE();
	A = ADC(A, READ(mem));
	break;

case 0x87: /* ADC A,(dp+X) */
	X_INDEXED_INDIRECT();
	A = ADC(A, READ(mem));
	break;

case 0x97: /* ADC A,(dp)+Y */
	INDIRECT_Y_INDEXED_INDIRECT();
	A = ADC(A, READ(mem));
	break;

case 0x99: /* ADC (X),(Y) */
	INDIRECT_PAGE_TO_IP();
	WRITE(dst, ADC(READ(dst), READ(src)));
	break;

case 0x89: /* ADC dp(d),dp(s) */
	DIRECT_PAGE_TO_DP();
	WRITE(dst, ADC(READ(dst), READ(src)));
	break;

case 0x98: /* ADC dp,#inm */
	INMEDIATE_DATA_TO_DP();
	WRITE(mem, ADC(READ(mem), inm));
	break;

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

case 0xA8: /* SBC A,#inm */
	INMEDIATE_DATA();
	A = SBC(A, inm);
	break;

case 0xA6: /* SBC A,(X) */
	INDIRECT();
	A = SBC(A, READ(mem));
	break;

case 0xA4: /* SBC A,dp */
	DIRECT_PAGE();
	A = SBC(A, READ(mem));
	break;

case 0xB4: /* SBC A,dp+X */
	X_INDEXED_DIRECT_PAGE();
	A = SBC(A, READ(mem));
	break;

case 0xA5: /* SBC A,labs */
	ABSOLUTE();
	A = SBC(A, READ(mem));
	break;

case 0xB5: /* SBC A,labs+X */
	X_INDEXED_ABSOLUTE();
	A = SBC(A, READ(mem));
	break;

case 0xB6: /* SBC A,labs+Y */
	Y_INDEXED_ABSOLUTE();
	A = SBC(A, READ(mem));
	break;

case 0xA7: /* SBC A,(dp+X) */
	X_INDEXED_INDIRECT();
	A = SBC(A, READ(mem));
	break;

case 0xB7: /* SBC A,(dp)+Y */
	INDIRECT_Y_INDEXED_INDIRECT();
	A = SBC(A, READ(mem));
	break;

case 0xB9: /* SBC (X),(Y) */
	INDIRECT_PAGE_TO_IP();
	WRITE(dst, SBC(READ(dst), READ(src)));
	break;

case 0xA9: /* SBC dp(d),dp(s) */
	DIRECT_PAGE_TO_DP();
	WRITE(dst, SBC(READ(dst), READ(src)));
	break;

case 0xB8: /* SBC dp,#inm */
	INMEDIATE_DATA_TO_DP();
	WRITE(mem, SBC(READ(mem), inm));
	break;

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

case 0x68: /* CMP A,#inm */
	INMEDIATE_DATA();
	PSW_CNZ = (A - inm) ^ 0x100;
	break;

case 0x66: /* CMP A,(X) */
	INDIRECT();
	PSW_CNZ = (A - READ(mem)) ^ 0x100;
	break;

case 0x64: /* CMP A,dp */
	DIRECT_PAGE();
	PSW_CNZ = (A - READ(mem)) ^ 0x100;
	break;

case 0x74: /* CMP A,dp+X */
	X_INDEXED_DIRECT_PAGE();
	PSW_CNZ = (A - READ(mem)) ^ 0x100;
	break;

case 0x65: /* CMP A,labs */
	ABSOLUTE();
	PSW_CNZ = (A - READ(mem)) ^ 0x100;
	break;

case 0x75: /* CMP A,labs+X */
	X_INDEXED_ABSOLUTE();
	PSW_CNZ = (A - READ(mem)) ^ 0x100;
	break;

case 0x76: /* CMP A,labs+Y */
	Y_INDEXED_ABSOLUTE();
	PSW_CNZ = (A - READ(mem)) ^ 0x100;
	break;

case 0x67: /* CMP A,(dp+X) */
	X_INDEXED_INDIRECT();
	PSW_CNZ = (A - READ(mem)) ^ 0x100;
	break;

case 0x77: /* CMP A,(dp)+Y */
	INDIRECT_Y_INDEXED_INDIRECT();
	PSW_CNZ = (A - READ(mem)) ^ 0x100;
	break;

case 0x79: /* CMP (X),(Y) */
	INDIRECT_PAGE_TO_IP();
	PSW_CNZ = (READ(dst) - READ(src)) ^ 0x100;
	break;

case 0x69: /* CMP dp(d),dp(s) */
	DIRECT_PAGE_TO_DP();
	PSW_CNZ = (READ(dst) - READ(src)) ^ 0x100;
	break;

case 0x78: /* CMP dp,#inm */
	INMEDIATE_DATA_TO_DP();
	PSW_CNZ = (READ(mem) - inm) ^ 0x100;
	break;

case 0xC8: /* CMP X,#inm */
	INMEDIATE_DATA();
	PSW_CNZ = (X - inm) ^ 0x100;
	break;

case 0x3E: /* CMP X,dp */
	DIRECT_PAGE();
	PSW_CNZ = (X - READ(mem)) ^ 0x100;
	break;

case 0x1E: /* CMP X,labs */
	ABSOLUTE();
	PSW_CNZ = (X - READ(mem)) ^ 0x100;
	break;

case 0xAD: /* CMP Y,#inm */
	INMEDIATE_DATA();
	PSW_CNZ = (Y - inm) ^ 0x100;
	break;

case 0x7E: /* CMP Y,dp */
	DIRECT_PAGE();
	PSW_CNZ = (Y - READ(mem)) ^ 0x100;
	break;

case 0x5E: /* CMP Y,labs */
	ABSOLUTE();
	PSW_CNZ = (Y - READ(mem)) ^ 0x100;
	break;

/*==========================================================================*
	5. 8-BIT LOGIC OPERATION COMMANDS
 *==========================================================================*/

case 0x28: /* AND A,#inm */
	INMEDIATE_DATA();
	PSW_NZ = A &= inm;
	break;

case 0x26: /* AND A,(X) */
	INDIRECT();
	PSW_NZ = A &= READ(mem);
	break;

case 0x24: /* AND A,dp */
	DIRECT_PAGE();
	PSW_NZ = A &= READ(mem);
	break;

case 0x34: /* AND A,dp+X */
	X_INDEXED_DIRECT_PAGE();
	PSW_NZ = A &= READ(mem);
	break;

case 0x25: /* AND A,labs */
	ABSOLUTE();
	PSW_NZ = A &= READ(mem);
	break;

case 0x35: /* AND A,labs+X */
	X_INDEXED_ABSOLUTE();
	PSW_NZ = A &= READ(mem);
	break;

case 0x36: /* AND A,labs+Y */
	Y_INDEXED_ABSOLUTE();
	PSW_NZ = A &= READ(mem);
	break;

case 0x27: /* AND A,(dp+X) */
	X_INDEXED_INDIRECT();
	PSW_NZ = A &= READ(mem);
	break;

case 0x37: /* AND A,(dp)+Y */
	INDIRECT_Y_INDEXED_INDIRECT();
	PSW_NZ = A &= READ(mem);
	break;

case 0x39: /* AND (X),(Y) */
	INDIRECT_PAGE_TO_IP();
	WRITE(dst, PSW_NZ = READ(dst) & READ(src));
	break;

case 0x29: /* AND dp(d),dp(s) */
	DIRECT_PAGE_TO_DP();
	WRITE(dst, PSW_NZ = READ(dst) & READ(src));
	break;

case 0x38: /* AND dp,#inm */
	INMEDIATE_DATA_TO_DP();
	WRITE(mem, PSW_NZ = READ(mem) & inm);
	break;

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

case 0x08: /* OR A,#inm */
	INMEDIATE_DATA();
	PSW_NZ = A |= inm;
	break;

case 0x06: /* OR A,(X) */
	INDIRECT();
	PSW_NZ = A |= READ(mem);
	break;

case 0x04: /* OR A,dp */
	DIRECT_PAGE();
	PSW_NZ = A |= READ(mem);
	break;

case 0x14: /* OR A,dp+X */
	X_INDEXED_DIRECT_PAGE();
	PSW_NZ = A |= READ(mem);
	break;

case 0x05: /* OR A,labs */
	ABSOLUTE();
	PSW_NZ = A |= READ(mem);
	break;

case 0x15: /* OR A,labs+X */
	X_INDEXED_ABSOLUTE();
	PSW_NZ = A |= READ(mem);
	break;

case 0x16: /* OR A,labs+Y */
	Y_INDEXED_ABSOLUTE();
	PSW_NZ = A |= READ(mem);
	break;

case 0x07: /* OR A,(dp+X) */
	X_INDEXED_INDIRECT();
	PSW_NZ = A |= READ(mem);
	break;

case 0x17: /* OR A,(dp)+Y */
	INDIRECT_Y_INDEXED_INDIRECT();
	PSW_NZ = A |= READ(mem);
	break;

case 0x19: /* OR (X),(Y) */
	INDIRECT_PAGE_TO_IP();
	WRITE(dst, PSW_NZ = READ(dst) | READ(src));
	break;

case 0x09: /* OR dp(d),dp(s) */
	DIRECT_PAGE_TO_DP();
	WRITE(dst, PSW_NZ = READ(dst) | READ(src));
	break;

case 0x18: /* OR dp,#inm */
	INMEDIATE_DATA_TO_DP();
	WRITE(mem, PSW_NZ = READ(mem) | inm);
	break;

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

case 0x48: /* EOR A,#inm */
	INMEDIATE_DATA();
	PSW_NZ = A ^= inm;
	break;

case 0x46: /* EOR A,(X) */
	INDIRECT();
	PSW_NZ = A ^= READ(mem);
	break;

case 0x44: /* EOR A,dp */
	DIRECT_PAGE();
	PSW_NZ = A ^= READ(mem);
	break;

case 0x54: /* EOR A,dp+X */
	X_INDEXED_DIRECT_PAGE();
	PSW_NZ = A ^= READ(mem);
	break;

case 0x45: /* EOR A,labs */
	ABSOLUTE();
	PSW_NZ = A ^= READ(mem);
	break;

case 0x55: /* EOR A,labs+X */
	X_INDEXED_ABSOLUTE();
	PSW_NZ = A ^= READ(mem);
	break;

case 0x56: /* EOR A,labs+Y */
	Y_INDEXED_ABSOLUTE();
	PSW_NZ = A ^= READ(mem);
	break;

case 0x47: /* EOR A,(dp+X) */
	X_INDEXED_INDIRECT();
	PSW_NZ = A ^= READ(mem);
	break;

case 0x57: /* EOR A,(dp)+Y */
	INDIRECT_Y_INDEXED_INDIRECT();
	PSW_NZ = A ^= READ(mem);
	break;

case 0x59: /* EOR (X),(Y) */
	INDIRECT_PAGE_TO_IP();
	WRITE(dst, PSW_NZ = READ(dst) ^ READ(src));
	break;

case 0x49: /* EOR dp(d),dp(s) */
	DIRECT_PAGE_TO_DP();
	WRITE(dst, PSW_NZ = READ(dst) ^ READ(src));
	break;

case 0x58: /* EOR dp,#inm */
	INMEDIATE_DATA_TO_DP();
	WRITE(mem, PSW_NZ = READ(mem) ^ inm);
	break;

/*==========================================================================*
	6. ADDITION & SUBTRACTION COMMANDS
 *==========================================================================*/

case 0xBC: /* INC A */
	PSW_NZ = A += 1;
	break;

case 0xAB: /* INC dp */
	DIRECT_PAGE();
	WRITE(mem, PSW_NZ = READ(mem) + 1);
	break;

case 0xBB: /* INC dp+X */
	X_INDEXED_DIRECT_PAGE();
	WRITE(mem, PSW_NZ = READ(mem) + 1);
	break;

case 0xAC: /* INC labs */
	ABSOLUTE();
	WRITE(mem, PSW_NZ = READ(mem) + 1);
	break;

case 0x3D: /* INC X */
	PSW_NZ = X += 1;
	break;

case 0xFC: /* INC Y */
	PSW_NZ = Y += 1;
	break;

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

case 0x9C: /* DEC A */
	PSW_NZ = A -= 1;
	break;

case 0x8B: /* DEC dp */
	DIRECT_PAGE();
	WRITE(mem, PSW_NZ = READ(mem) - 1);
	break;

case 0x9B: /* DEC dp-X */
	X_INDEXED_DIRECT_PAGE();
	WRITE(mem, PSW_NZ = READ(mem) - 1);
	break;

case 0x8C: /* DEC labs */
	ABSOLUTE();
	WRITE(mem, PSW_NZ = READ(mem) - 1);
	break;

case 0x1D: /* DEC X */
	PSW_NZ = X -= 1;
	break;

case 0xDC: /* DEC Y */
	PSW_NZ = Y -= 1;
	break;

/*==========================================================================*
	7. SHIFT, ROTATION COMMANDS
 *==========================================================================*/

case 0x1C: /* ASL A */
	A = (unsigned char)(PSW_CNZ = A << 1);
	break;

case 0x0B: /* ASL dp */
	DIRECT_PAGE();
	WRITE(mem, PSW_CNZ = READ(mem) << 1);
	break;

case 0x1B: /* ASL dp+X */
	X_INDEXED_DIRECT_PAGE();
	WRITE(mem, PSW_CNZ = READ(mem) << 1);
	break;

case 0x0C: /* ASL labs */
	ABSOLUTE();
	WRITE(mem, PSW_CNZ = READ(mem) << 1);
	break;

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

case 0x5C: /* LSR A */
	PSW_NZ = A = (PSW_C = A) >> 1;
	break;

case 0x4B: /* LSR dp */
	DIRECT_PAGE();
	WRITE(mem, PSW_NZ = (PSW_C = READ(mem)) >> 1);
	break;

case 0x5B: /* LSR dp+X */
	X_INDEXED_DIRECT_PAGE();
	WRITE(mem, PSW_NZ = (PSW_C = READ(mem)) >> 1);
	break;

case 0x4C: /* LSR labs */
	ABSOLUTE();
	WRITE(mem, PSW_NZ = (PSW_C = READ(mem)) >> 1);
	break;

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

case 0x3C: /* ROL A */
	A = (unsigned char)(PSW_CNZ = (A << 1) | (PSW_C & 1));
	break;

case 0x2B: /* ROL dp */
	DIRECT_PAGE();
	WRITE(mem, PSW_CNZ = (READ(mem) << 1) | (PSW_C & 1));
	break;

case 0x3B: /* ROL dp+X */
	X_INDEXED_DIRECT_PAGE();
	WRITE(mem, PSW_CNZ = (READ(mem) << 1) | (PSW_C & 1));
	break;

case 0x2C: /* ROL labs */
	ABSOLUTE();
	WRITE(mem, PSW_CNZ = (READ(mem) << 1) | (PSW_C & 1));
	break;

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

case 0x7C: /* ROR A */
	tmp = A;
	PSW_NZ = A = (tmp >> 1) | (PSW_C << 7);
	PSW_C = tmp;
	break;

case 0x6B: /* ROR dp */
	DIRECT_PAGE();
	tmp = READ(mem);
	WRITE(mem, PSW_NZ = (tmp >> 1) | (PSW_C << 7));
	PSW_C = tmp;
	break;

case 0x7B: /* ROR dp+X */
	X_INDEXED_DIRECT_PAGE();
	tmp = READ(mem);
	WRITE(mem, PSW_NZ = (tmp >> 1) | (PSW_C << 7));
	PSW_C = tmp;
	break;

case 0x6C: /* ROR labs */
	ABSOLUTE();
	tmp = READ(mem);
	WRITE(mem, PSW_NZ = (tmp >> 1) | (PSW_C << 7));
	PSW_C = tmp;
	break;

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

case 0x9F: /* XCN A */
	PSW_NZ = A = (A >> 4) | (A << 4);
	break;

/*==========================================================================*
	8. 16-BIT TRANSMISION COMMANDS
 *==========================================================================*/

case 0xBA: /* MOVW YA,dp */
	DIRECT_PAGE();
	YA = READW(mem);
	PSW_NZ = (YA >> 8) | (YA != 0);
	break;

case 0xDA: /* MOVW dp,YA */
	DIRECT_PAGE();
	WRITEW(mem, YA);
	break;

/*==========================================================================*
	9. 16-BIT OPERATION COMMANDS
 *==========================================================================*/

case 0x3A: /* INCW dp */
	DIRECT_PAGE();
	tmp = READW(mem) + 1;
	WRITEW(mem, tmp);
	PSW_NZ = (tmp >> 8) | ((unsigned short)tmp != 0);
	break;

case 0x1A: /* DECW dp */
	DIRECT_PAGE();
	tmp = READW(mem) - 1;
	WRITEW(mem, tmp);
	PSW_NZ = (tmp >> 8) | ((unsigned short)tmp != 0);
	break;

case 0x7A: /* ADDW YA,dp */
	DIRECT_PAGE();
	YA = ADDW(YA, READW(mem));
	break;

case 0x9A: /* SUBW YA,dp */
	DIRECT_PAGE();
	YA = SUBW(YA, READW(mem));
	break;

case 0x5A: /* CMPW YA,dp */
	DIRECT_PAGE();
	tmp = YA - READW(mem);
	PSW_CNZ = ((tmp >> 8) | ((unsigned short)tmp != 0)) ^ 0x100;
	break;

/*==========================================================================*
	10. MULTIPLICATION & DIVISON COMMANDS
 *==========================================================================*/

case 0xCF: /* MUL YA */
	YA = A * Y;
	PSW_NZ = (YA >> 8) | (YA != 0);
	break;

case 0x9E: /* DIV YA,X */
	DIV();
	break;

/*==========================================================================*
	11. DECIMAL COMPENSATION COMMANDS
 *==========================================================================*/

///※2004/10/11現在、二進化十進演算機能は未実装です。
///  ハーフキャリーフラグ(PSW(H))も実装していません。
///case 0xDF: /* DAA A */
///case 0xBE: /* DAS A */

/*==========================================================================*
	12. BRANCHING COMMANDS
 *==========================================================================*/

case 0x2F: /* BRA rel */
	RELATIVE();
	break;

case 0xF0: /* BEQ rel */
	BEQ(PSW_NZ);
	break;

case 0xD0: /* BNE rel */
	BNE(PSW_NZ);
	break;

case 0xB0: /* BCS rel */
	BNE(PSW_C & 1);
	break;

case 0x90: /* BCC rel */
	BEQ(PSW_C & 1);
	break;

case 0x70: /* BVS rel */
	BNE(PSW_V & 0x80);
	break;

case 0x50: /* BVC rel */
	BEQ(PSW_V & 0x80);
	break;

case 0x30: /* BMI rel */
	BNE(PSW_NZ & 0x80);
	break;

case 0x10: /* BPL rel */
	BEQ(PSW_NZ & 0x80);
	break;

case 0x03: /* BBS0 dp,rel */
	DIRECT_PAGE();
	BNE(READ(mem) & (1 << 0));
	break;

case 0x23: /* BBS1 dp,rel */
	DIRECT_PAGE();
	BNE(READ(mem) & (1 << 1));
	break;

case 0x43: /* BBS2 dp,rel */
	DIRECT_PAGE();
	BNE(READ(mem) & (1 << 2));
	break;

case 0x63: /* BBS3 dp,rel */
	DIRECT_PAGE();
	BNE(READ(mem) & (1 << 3));
	break;

case 0x83: /* BBS4 dp,rel */
	DIRECT_PAGE();
	BNE(READ(mem) & (1 << 4));
	break;

case 0xA3: /* BBS5 dp,rel */
	DIRECT_PAGE();
	BNE(READ(mem) & (1 << 5));
	break;

case 0xC3: /* BBS6 dp,rel */
	DIRECT_PAGE();
	BNE(READ(mem) & (1 << 6));
	break;

case 0xE3: /* BBS7 dp,rel */
	DIRECT_PAGE();
	BNE(READ(mem) & (1 << 7));
	break;

case 0x13: /* BBC0 dp,rel */
	DIRECT_PAGE();
	BEQ(READ(mem) & (1 << 0));
	break;

case 0x33: /* BBC1 dp,rel */
	DIRECT_PAGE();
	BEQ(READ(mem) & (1 << 1));
	break;

case 0x53: /* BBC2 dp,rel */
	DIRECT_PAGE();
	BEQ(READ(mem) & (1 << 2));
	break;

case 0x73: /* BBC3 dp,rel */
	DIRECT_PAGE();
	BEQ(READ(mem) & (1 << 3));
	break;

case 0x93: /* BBC4 dp,rel */
	DIRECT_PAGE();
	BEQ(READ(mem) & (1 << 4));
	break;

case 0xB3: /* BBC5 dp,rel */
	DIRECT_PAGE();
	BEQ(READ(mem) & (1 << 5));
	break;

case 0xD3: /* BBC6 dp,rel */
	DIRECT_PAGE();
	BEQ(READ(mem) & (1 << 6));
	break;

case 0xF3: /* BBC7 dp,rel */
	DIRECT_PAGE();
	BEQ(READ(mem) & (1 << 7));
	break;

case 0x2E: /* CBNE dp,rel */
	DIRECT_PAGE();
	BNE(A - READ(mem));
	break;

case 0xDE: /* CBNE dp+X,rel */
	X_INDEXED_DIRECT_PAGE();
	BNE(A - READ(mem));
	break;

case 0x6E: /* DBNZ dp,rel */
	DIRECT_PAGE();
	tmp = READ(mem);
	tmp--;
	WRITE(mem, tmp);
	BNE(tmp);
	break;

case 0xFE: /* DBNZ Y,rel */
	Y--;
	BNE(Y);
	break;

case 0x5F: /* JMP labs */
	ABSOLUTE();
	PC = &spc2ram[mem];
	break;

case 0x1F: /* JMP (labs+X) */
	X_INDEXED_ABSOLUTE_INDIRECT();
	PC = &spc2ram[mem];
	break;

/*==========================================================================*
	13. SUB-ROUTINE CALL RETURN COMMANDS
 *==========================================================================*/

case 0x3F: /* CALL labs */
	ABSOLUTE();
	tmp = PC - spc2ram;
	*SP-- = tmp >> 8;
	*SP-- = tmp;
	PC = &spc2ram[mem];
	break;

/* * PCALLとTCALL0-7の仕様は、WinSPCのソースを参考にしました。
 * - PCALL
 *   RAM[0xff00+OP1] の位置をCALLします。
 * - TCALL
 *   RAM[EXT[(15-TCALL番号)+0]|EXT[(15-TCALL番号)+1]<<8] の位置をCALLします。
 *
 * * 拡張RAMのベクタ並びは、次のとおりです。
 *   0x00-0x01: TCALL15のベクタ
 *   0x02-0x03: TCALL14のベクタ
 *   0x04-0x05: TCALL13のベクタ
 *   0x06-0x07: TCALL12のベクタ
 *   0x08-0x09: TCALL11のベクタ
 *   0x0a-0x0b: TCALL10のベクタ
 *   0x0c-0x0d: TCALL9のベクタ
 *   0x0e-0x0f: TCALL8のベクタ
 *   0x10-0x11: TCALL7のベクタ
 *   0x12-0x13: TCALL6のベクタ
 *   0x14-0x15: TCALL5のベクタ
 *   0x16-0x17: TCALL4のベクタ
 *   0x18-0x19: TCALL3のベクタ
 *   0x1a-0x1b: TCALL2のベクタ
 *   0x1c-0x1d: TCALL1のベクタ
 *   0x1e-0x1f: TCALL0のベクタ
 *   0x20-0x21: BRKのベクタ (2004/10/20現在、BRKは未実装)
 *   0x22-0x3f: 不明
 *
 * * エメラルドドラゴンがTCALLxを使っています。他にはまだ見つけられません。
 *   PCALLを使っているSPCファイルは、まだひとつも見つけられません。
 */

case 0x4F: /* PCALL upage */
	INMEDIATE_DATA();
	tmp = PC - spc2ram;
	*SP-- = tmp >> 8;
	*SP-- = tmp;
	PC = &spc2ram[0xff00 + inm];
	break;

#define TCALL(n) \
	tmp = PC - spc2ram; \
	*SP-- = tmp >> 8; \
	*SP-- = tmp; \
	PC = &spc2ram[spc2ext[((15 - (n)) << 1) + 0] | \
	              spc2ext[((15 - (n)) << 1) + 1] << 8]; \
	break;

case 0x01: /* TCALL0 */
	TCALL(0);
case 0x11: /* TCALL1 */
	TCALL(1);
case 0x21: /* TCALL2 */
	TCALL(2);
case 0x31: /* TCALL3 */
	TCALL(3);
case 0x41: /* TCALL4 */
	TCALL(4);
case 0x51: /* TCALL5 */
	TCALL(5);
case 0x61: /* TCALL6 */
	TCALL(6);
case 0x71: /* TCALL7 */
	TCALL(7);
case 0x81: /* TCALL8 */
	TCALL(8);
case 0x91: /* TCALL9 */
	TCALL(9);
case 0xA1: /* TCALL10 */
	TCALL(10);
case 0xB1: /* TCALL11 */
	TCALL(11);
case 0xC1: /* TCALL12 */
	TCALL(12);
case 0xD1: /* TCALL13 */
	TCALL(13);
case 0xE1: /* TCALL14 */
	TCALL(14);
case 0xF1: /* TCALL15 */
	TCALL(15);

///※スーパーファミコンのSPC700は、ハードウェア割り込み機能を持っていません。
///  BRKはソフトウェア割り込みですが、この機能も持っていないと推測しました。
///  従って、2004/10/11現在は未実装としてあります。
///case 0x0F: /* BRK */

case 0x6F: /* RET */
	tmp  = *++SP;
	tmp |= *++SP << 8;
	PC = &spc2ram[tmp];
	break;

///※スーパーファミコンのSPC700は、ハードウェア割り込み機能を持っていません。
///  RETIはハードウェア(およびソフトウェア)割り込みからの復帰命令なので、
///  スーパーファミコンのSPC700では利用されないはずです。
///  従って、2004/10/11現在は未実装としてあります。
///case 0x7F: /* RETI */

/*==========================================================================*
	14. STACK OPERATION COMMANDS
 *==========================================================================*/

case 0x2D: /* PUSH A */
	*SP-- = A;
	break;

case 0x4D: /* PUSH X */
	*SP-- = X;
	break;

case 0x6D: /* PUSH Y */
	*SP-- = Y;
	break;

case 0x0D: /* PUSH PSW */
	*SP-- = PACK_PSW();
	break;

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

case 0xAE: /* POP A */
	A = *++SP;
	break;

case 0xCE: /* POP X */
	X = *++SP;
	break;

case 0xEE: /* POP Y */
	Y = *++SP;
	break;

case 0x8E: /* POP PSW */
	UNPACK_PSW(*++SP);
	break;

/*==========================================================================*
	15. BIT OPERATION COMMANDS
 *==========================================================================*/

case 0x02: /* SET0 dp */
	DIRECT_PAGE();
	WRITE(mem, READ(mem) | (1 << 0));
	break;

case 0x22: /* SET1 dp */
	DIRECT_PAGE();
	WRITE(mem, READ(mem) | (1 << 1));
	break;

case 0x42: /* SET2 dp */
	DIRECT_PAGE();
	WRITE(mem, READ(mem) | (1 << 2));
	break;

case 0x62: /* SET3 dp */
	DIRECT_PAGE();
	WRITE(mem, READ(mem) | (1 << 3));
	break;

case 0x82: /* SET4 dp */
	DIRECT_PAGE();
	WRITE(mem, READ(mem) | (1 << 4));
	break;

case 0xA2: /* SET5 dp */
	DIRECT_PAGE();
	WRITE(mem, READ(mem) | (1 << 5));
	break;

case 0xC2: /* SET6 dp */
	DIRECT_PAGE();
	WRITE(mem, READ(mem) | (1 << 6));
	break;

case 0xE2: /* SET7 dp */
	DIRECT_PAGE();
	WRITE(mem, READ(mem) | (1 << 7));
	break;

case 0x12: /* CLR0 dp */
	DIRECT_PAGE();
	WRITE(mem, READ(mem) & ~(1 << 0));
	break;

case 0x32: /* CLR1 dp */
	DIRECT_PAGE();
	WRITE(mem, READ(mem) & ~(1 << 1));
	break;

case 0x52: /* CLR2 dp */
	DIRECT_PAGE();
	WRITE(mem, READ(mem) & ~(1 << 2));
	break;

case 0x72: /* CLR3 dp */
	DIRECT_PAGE();
	WRITE(mem, READ(mem) & ~(1 << 3));
	break;

case 0x92: /* CLR4 dp */
	DIRECT_PAGE();
	WRITE(mem, READ(mem) & ~(1 << 4));
	break;

case 0xB2: /* CLR5 dp */
	DIRECT_PAGE();
	WRITE(mem, READ(mem) & ~(1 << 5));
	break;

case 0xD2: /* CLR6 dp */
	DIRECT_PAGE();
	WRITE(mem, READ(mem) & ~(1 << 6));
	break;

case 0xF2: /* CLR7 dp */
	DIRECT_PAGE();
	WRITE(mem, READ(mem) & ~(1 << 7));
	break;

case 0x0E: /* TSET1 labs */
	ABSOLUTE();
	tmp = READ(mem);
	WRITE(mem, tmp | A);
	PSW_NZ = tmp & A;
	break;

case 0x4E: /* TCLR1 labs */
	ABSOLUTE();
	tmp = READ(mem);
	WRITE(mem, tmp & ~A);
	PSW_NZ = tmp & A;
	break;

case 0x4A: /* AND1 C,mem.bit */
	ABSOLUTE_BOOLEAN_BIT();
	PSW_C &= READ(mem) >> bit;
	break;

case 0x6A: /* AND1 C,/mem.bit */
	ABSOLUTE_BOOLEAN_BIT();
	PSW_C &= ~READ(mem) >> bit;
	break;

case 0x0A: /* OR1 C,mem.bit */
	ABSOLUTE_BOOLEAN_BIT();
	PSW_C |= READ(mem) >> bit;
	break;

case 0x2A: /* OR1 C,/mem.bit */
	ABSOLUTE_BOOLEAN_BIT();
	PSW_C |= ~READ(mem) >> bit;
	break;

case 0x8A: /* EOR1 C,mem.bit */
	ABSOLUTE_BOOLEAN_BIT();
	PSW_C ^= READ(mem) >> bit;
	break;

case 0xEA: /* NOT1 mem.bit */
	ABSOLUTE_BOOLEAN_BIT();
	WRITE(mem, READ(mem) ^ (1 << bit));
	break;

case 0xAA: /* MOV1 C,mem.bit */
	ABSOLUTE_BOOLEAN_BIT();
	PSW_C = READ(mem) >> bit;
	break;

case 0xCA: /* MOV1 mem.bit,C */
	ABSOLUTE_BOOLEAN_BIT();
	WRITE(mem, (READ(mem) & ~(1 << bit)) | (PSW_C & 1) << bit);
	break;

/*==========================================================================*
	16. PROGRAM STATUS FLAG OPERATION COMMANDS
 *==========================================================================*/

case 0x60: /* CLRC */
	PSW_C &= ~1;
	break;

case 0x80: /* SETC */
	PSW_C |=  1;
	break;

case 0xED: /* NOTC */
	PSW_C ^=  1;
	break;

case 0xE0: /* CLRV */
	PSW_V &= ~0x80;
	break;

case 0x20: /* CLRP */
	PSW_P = 0x000;
	break;

case 0x40: /* SETP */
	PSW_P = 0x100;
	break;

///※スーパーファミコンのSPC700は、ハードウェア割り込み機能を持っていません。
///  割り込み許可・禁止命令は利用されないはずです。
///  従って、2004/10/11現在は未実装としてあります。
///case 0xA0: /* EI */
///case 0xC0: /* DI */

/*==========================================================================*
	17. OTHER COMMANDS
 *==========================================================================*/

case 0x00: /* NOP */
	/** no job **/
	break;

///※スーパーファミコンのSPC700は、省電力機能を持っているかどうか不明です。
///  これらの命令が使われることはまずないだろうと推測しました。
///  従って、2004/10/11現在は未実装としてあります。
///case 0xEF: /* SLEEP */
///case 0xFF: /* STOP */

/*==========================================================================*

 *==========================================================================*/

		default:
			DIE();
		}
	} while(--count > 0);

}

#else /*SPC2_ASM*/

/* アセンブラ版エラー終了 */
void
spc2cpu_DIE(int code)
{
	die("spc2cpu_DIE(%02x)", code);
}

#endif /*SPC2_ASM*/

void
spc2cpu_init(int pc, int a, int x, int y, int psw, int sp)
{
	SPC2CPU* cpu = &spc2cpu;

	if(pc < 0 || pc > 0xffff) DIE(); PC = &spc2ram[        pc];
	if(sp < 0 || sp >   0xff) DIE(); SP = &spc2ram[0x100 | sp];
	if( a < 0 ||  a >   0xff) DIE(); A = a;
	if( x < 0 ||  x >   0xff) DIE(); X = x;
	if( y < 0 ||  y >   0xff) DIE(); Y = y;
	UNPACK_PSW(psw);
}

#ifdef SPC2_TRACE

/* レジスタダンプ出力を行います。
 * C言語版・アセンブラ版両方から利用します。
 */
void
spc2cpu_dump()
{
	static const char* inst[256] = {
		/*00*/ "NOP",
		/*01*/ "TCALL0",
		/*02*/ "SET0 dp",
		/*03*/ "BBS0 dp,rel",
		/*04*/ "OR A,dp",
		/*05*/ "OR A,labs",
		/*06*/ "OR A,(X)",
		/*07*/ "OR A,(dp+X)",
		/*08*/ "OR A,#inm",
		/*09*/ "OR dp(d),dp(s)",
		/*0A*/ "OR1 C,mem.bit",
		/*0B*/ "ASL dp",
		/*0C*/ "ASL labs",
		/*0D*/ "PUSH PSW",
		/*0E*/ "TSET1 labs",
		/*0F*/ "BRK",
		/*10*/ "BPL rel",
		/*11*/ "TCALL1",
		/*12*/ "CLR0 dp",
		/*13*/ "BBC0 dp,rel",
		/*14*/ "OR A,dp+X",
		/*15*/ "OR A,labs+X",
		/*16*/ "OR A,labs+Y",
		/*17*/ "OR A,(dp)+Y",
		/*18*/ "OR dp,#inm",
		/*19*/ "OR (X),(Y)",
		/*1A*/ "DECW dp",
		/*1B*/ "ASL dp+X",
		/*1C*/ "ASL A",
		/*1D*/ "DEC X",
		/*1E*/ "CMP X,labs",
		/*1F*/ "JMP (labs+X)",
		/*20*/ "CLRP",
		/*21*/ "TCALL2",
		/*22*/ "SET1 dp",
		/*23*/ "BBS1 dp,rel",
		/*24*/ "AND A,dp",
		/*25*/ "AND A,labs",
		/*26*/ "AND A,(X)",
		/*27*/ "AND A,(dp+X)",
		/*28*/ "AND A,#inm",
		/*29*/ "AND dp(d),dp(s)",
		/*2A*/ "OR1 C,/mem.bit",
		/*2B*/ "ROL dp",
		/*2C*/ "ROL labs",
		/*2D*/ "PUSH A",
		/*2E*/ "CBNE dp,rel",
		/*2F*/ "BRA rel",
		/*30*/ "BMI rel",
		/*31*/ "TCALL3",
		/*32*/ "CLR1 dp",
		/*33*/ "BBC1 dp,rel",
		/*34*/ "AND A,dp+X",
		/*35*/ "AND A,labs+X",
		/*36*/ "AND A,labs+Y",
		/*37*/ "AND A,(dp)+Y",
		/*38*/ "AND dp,#inm",
		/*39*/ "AND (X),(Y)",
		/*3A*/ "INCW dp",
		/*3B*/ "ROL dp+X",
		/*3C*/ "ROL A",
		/*3D*/ "INC X",
		/*3E*/ "CMP X,dp",
		/*3F*/ "CALL labs",
		/*40*/ "SETP",
		/*41*/ "TCALL4",
		/*42*/ "SET2 dp",
		/*43*/ "BBS2 dp,rel",
		/*44*/ "EOR A,dp",
		/*45*/ "EOR A,labs",
		/*46*/ "EOR A,(X)",
		/*47*/ "EOR A,(dp+X)",
		/*48*/ "EOR A,#inm",
		/*49*/ "EOR dp(d),dp(s)",
		/*4A*/ "AND1 C,mem.bit",
		/*4B*/ "LSR dp",
		/*4C*/ "LSR labs",
		/*4D*/ "PUSH X",
		/*4E*/ "TCLR1 labs",
		/*4F*/ "PCALL upage",
		/*50*/ "BVC rel",
		/*51*/ "TCALL5",
		/*52*/ "CLR2 dp",
		/*53*/ "BBC2 dp,rel",
		/*54*/ "EOR A,dp+X",
		/*55*/ "EOR A,labs+X",
		/*56*/ "EOR A,labs+Y",
		/*57*/ "EOR A,(dp)+Y",
		/*58*/ "EOR dp,#inm",
		/*59*/ "EOR (X),(Y)",
		/*5A*/ "CMPW YA,dp",
		/*5B*/ "LSR dp+X",
		/*5C*/ "LSR A",
		/*5D*/ "MOV X,A",
		/*5E*/ "CMP Y,labs",
		/*5F*/ "JMP labs",
		/*60*/ "CLRC",
		/*61*/ "TCALL6",
		/*62*/ "SET3 dp",
		/*63*/ "BBS3 dp,rel",
		/*64*/ "CMP A,dp",
		/*65*/ "CMP A,labs",
		/*66*/ "CMP A,(X)",
		/*67*/ "CMP A,(dp+X)",
		/*68*/ "CMP A,#inm",
		/*69*/ "CMP dp(d),dp(s)",
		/*6A*/ "AND1 C,/mem.bit",
		/*6B*/ "ROR dp",
		/*6C*/ "ROR labs",
		/*6D*/ "PUSH Y",
		/*6E*/ "DBNZ dp,rel",
		/*6F*/ "RET",
		/*70*/ "BVS rel",
		/*71*/ "TCALL7",
		/*72*/ "CLR3 dp",
		/*73*/ "BBC3 dp,rel",
		/*74*/ "CMP A,dp+X",
		/*75*/ "CMP A,labs+X",
		/*76*/ "CMP A,labs+Y",
		/*77*/ "CMP A,(dp)+Y",
		/*78*/ "CMP dp,#inm",
		/*79*/ "CMP (X),(Y)",
		/*7A*/ "ADDW YA,dp",
		/*7B*/ "ROR dp+X",
		/*7C*/ "ROR A",
		/*7D*/ "MOV A,X",
		/*7E*/ "CMP Y,dp",
		/*7F*/ "RETI",
		/*80*/ "SETC",
		/*81*/ "TCALL8",
		/*82*/ "SET4 dp",
		/*83*/ "BBS4 dp,rel",
		/*84*/ "ADC A,dp",
		/*85*/ "ADC A,labs",
		/*86*/ "ADC A,(X)",
		/*87*/ "ADC A,(dp+X)",
		/*88*/ "ADC A,#inm",
		/*89*/ "ADC dp(d),dp(s)",
		/*8A*/ "EOR1 C,mem.bit",
		/*8B*/ "DEC dp",
		/*8C*/ "DEC labs",
		/*8D*/ "MOV Y,#inm",
		/*8E*/ "POP PSW",
		/*8F*/ "MOV dp,#inm",
		/*90*/ "BCC rel",
		/*91*/ "TCALL9",
		/*92*/ "CLR4 dp",
		/*93*/ "BBC4 dp,rel",
		/*94*/ "ADC A,dp+X",
		/*95*/ "ADC A,labs+X",
		/*96*/ "ADC A,labs+Y",
		/*97*/ "ADC A,(dp)+Y",
		/*98*/ "ADC dp,#inm",
		/*99*/ "ADC (X),(Y)",
		/*9A*/ "SUBW YA,dp",
		/*9B*/ "DEC dp+X",
		/*9C*/ "DEC A",
		/*9D*/ "MOV X,SP",
		/*9E*/ "DIV YA,X",
		/*9F*/ "XCN A",
		/*A0*/ "EI",
		/*A1*/ "TCALL10",
		/*A2*/ "SET5 dp",
		/*A3*/ "BBS5 dp,rel",
		/*A4*/ "SBC A,dp",
		/*A5*/ "SBC A,labs",
		/*A6*/ "SBC A,(X)",
		/*A7*/ "SBC A,(dp+X)",
		/*A8*/ "SBC A,#inm",
		/*A9*/ "SBC dp(d),dp(s)",
		/*AA*/ "MOV1 C,mem.bit",
		/*AB*/ "INC dp",
		/*AC*/ "INC labs",
		/*AD*/ "CMP Y,#inm",
		/*AE*/ "POP A",
		/*AF*/ "MOV (X)+,A",
		/*B0*/ "BCS rel",
		/*B1*/ "TCALL11",
		/*B2*/ "CLR5 dp",
		/*B3*/ "BBC5 dp,rel",
		/*B4*/ "SBC A,dp+X",
		/*B5*/ "SBC A,labs+X",
		/*B6*/ "SBC A,labs+Y",
		/*B7*/ "SBC A,(dp)+Y",
		/*B8*/ "SBC dp,#inm",
		/*B9*/ "SBC (X),(Y)",
		/*BA*/ "MOVW YA,dp",
		/*BB*/ "INC dp+X",
		/*BC*/ "INC A",
		/*BD*/ "MOV SP,X",
		/*BE*/ "DAS A",
		/*BF*/ "MOV A,(X)+",
		/*C0*/ "DI",
		/*C1*/ "TCALL12",
		/*C2*/ "SET6 dp",
		/*C3*/ "BBS6 dp,rel",
		/*C4*/ "MOV dp,A",
		/*C5*/ "MOV labs,A",
		/*C6*/ "MOV (X),A",
		/*C7*/ "MOV (dp+X),A",
		/*C8*/ "CMP X,#inm",
		/*C9*/ "MOV labs,X",
		/*CA*/ "MOV1 mem.bit,C",
		/*CB*/ "MOV dp,Y",
		/*CC*/ "MOV labs,Y",
		/*CD*/ "MOV X,#inm",
		/*CE*/ "POP X",
		/*CF*/ "MUL YA",
		/*D0*/ "BNE rel",
		/*D1*/ "TCALL13",
		/*D2*/ "CLR6 dp",
		/*D3*/ "BBC6 dp,rel",
		/*D4*/ "MOV dp+X,A",
		/*D5*/ "MOV labs+X,A",
		/*D6*/ "MOV labs+Y,A",
		/*D7*/ "MOV (dp)+Y,A",
		/*D8*/ "MOV dp,X",
		/*D9*/ "MOV dp+Y,X",
		/*DA*/ "MOVW dp,YA",
		/*DB*/ "MOV dp+X,Y",
		/*DC*/ "DEC Y",
		/*DD*/ "MOV A,Y",
		/*DE*/ "CBNE dp+X,rel",
		/*DF*/ "DAA A",
		/*E0*/ "CLRV",
		/*E1*/ "TCALL14",
		/*E2*/ "SET7 dp",
		/*E3*/ "BBS7 dp,rel",
		/*E4*/ "MOV A,dp",
		/*E5*/ "MOV A,labs",
		/*E6*/ "MOV A,(X)",
		/*E7*/ "MOV A,(dp+X)",
		/*E8*/ "MOV A,#inm",
		/*E9*/ "MOV X,labs",
		/*EA*/ "NOT1 mem.bit",
		/*EB*/ "MOV Y,dp",
		/*EC*/ "MOV Y,labs",
		/*ED*/ "NOTC",
		/*EE*/ "POP Y",
		/*EF*/ "SLEEP",
		/*F0*/ "BEQ rel",
		/*F1*/ "TCALL15",
		/*F2*/ "CLR7 dp",
		/*F3*/ "BBC7 dp,rel",
		/*F4*/ "MOV A,dp+X",
		/*F5*/ "MOV A,labs+X",
		/*F6*/ "MOV A,labs+Y",
		/*F7*/ "MOV A,(dp)+Y",
		/*F8*/ "MOV X,dp",
		/*F9*/ "MOV X,dp+Y",
		/*FA*/ "MOV dp(d),dp(s)",
		/*FB*/ "MOV Y,dp+X",
		/*FC*/ "INC Y",
		/*FD*/ "MOV Y,A",
		/*FE*/ "DBNZ Y,rel",
		/*FF*/ "STOP",
	};
	SPC2CPU* cpu = &spc2cpu;

	/*ライブラリの中なのでTRACEマクロは仕様不可。直接traceを使います。 */
#if 1
	/* Long形式 */
	trace("%04x | %02x | %-16s | A:%02x X:%02x Y:%02x SP:%02x PSW:%02x(%c%c%c---%c%c)\n",
		PC - spc2ram, *PC, inst[*PC], A, X, Y, SP - &spc2ram[0x100], PACK_PSW(),
		 PSW_NZ & 0x80 ? 'N' : '-',
		 PSW_V  & 0x80 ? 'V' : '-',
		 PSW_P         ? 'P' : '-',
		!PSW_NZ        ? 'Z' : '-',
		 PSW_C  &    1 ? 'C' : '-');
#else
	/* Short形式 */
	trace("%02x %02x %02x %02x %02x %02x\n", *PC, A, X, Y, SP - &spc2ram[0x100], PACK_PSW());
#endif
}

/* 書き込みトレース出力を行います。
 * C言語版・アセンブラ版両方から利用します。
 */
void
spc2cpu_write_trace(int addr, int data)
{
	/*ライブラリの中なのでTRACEマクロは仕様不可。直接traceを使います。 */
	trace("WR %04x %02x\n", addr, (unsigned char)data/*[31:8]は不定でも構いません*/);
}

#endif /*SPC2_TRACE*/
