/*	
 *	framz80.c
 *
 *	P/ECE Z80 Emulator
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2001-2003 Naoyuki Sawa
 *
 *	* Sat Nov 22 06:00:00 JST 2003 Naoyuki Sawa
 *	- 作成開始。
 */
#include "clip.h"
#include "clipz80i.h"	/*Z80エミュレータ実装用マクロ*/

/****************************************************************************
 *	Z80コア内蔵のメインメモリREAD/WRITE外部関数
 ****************************************************************************/

/* Z80構造体(64バイト)の直後にメインメモリが配置されていることを仮定します。
 * バイナリレイアウトが異なる場合や、バンク切替などの特例処理が必要な場合は、
 * アプリケーション定義の外部関数を用意してください。
 */

#ifndef Z80_ASM	/************************************************************/

unsigned char
z80_internal_read(Z80* z80, unsigned short addr)
{
	return ((unsigned char*)(z80 + 1))[addr];
}
void
z80_internal_write(Z80* z80, unsigned short addr, unsigned char data)
{
	((unsigned char*)(z80 + 1))[addr] = data;
}

#else	/********************************************************************/

asm("
	.code
	.align 1
	.global z80_internal_read
z80_internal_read:
	add %r12, %r13
	xld.ub %r10, [%r12+64]
	ret
");
asm("
	.code
	.align 1
	.global z80_internal_write
z80_internal_write:
	add %r12, %r13
	xld.b [%r12+64], %r14
	ret
");

#endif	/********************************************************************/

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

#ifndef Z80_ASM

/* Z80エミュレーションを実行します。
 * [in]
 *	z80		Z80構造体。
 *	cycle		実行サイクル数。
 * [note]
 *	* 実行サイクル数がcycleに達するか、またはHALTで終了します。
 */
void
z80_run(Z80* z80, int cycle)
{
	unsigned char code;
	const Z80OP* op;
	unsigned char arg1;
	unsigned char arg2;

	arg1 = arg2 = 0; /* 警告抑制 */
	CYCLE = cycle;
	while(!HALT && CYCLE > 0) {
#ifdef Z80_TRACE
		z80_dump(z80);
#endif /*Z80_TRACE*/
		Z80TRACE("%04x: ", PC);
		FETCH(code);
		op = &z80_op_table[code];
		if(op->argc >= 1) {
			FETCH(arg1);
			if(op->argc >= 2) {
				FETCH(arg2);
			}
		}
		EXEC();
		Z80TRACE("\n");
	}
}

/* CB XX 命令のテーブルジャンプ処理です。
 * [note]
 *	* CB XX 命令の引数は、0バイトです。
 */
Z80FN_("CB", CB)
{
	const Z80OP* op;

	FETCH(code);
	op = &z80_op_table_CB[code];
	ASSERT(op->argc == 0);
	EXEC();
}

/* ED XX 命令のテーブルジャンプ処理です。
 * [note]
 *	* ED XX 命令の引数は、0バイトまたは2バイトです。
 */
Z80FN_("ED", ED)
{
	const Z80OP* op;

	FETCH(code);
	op = &z80_op_table_ED[code];
	ASSERT(op->argc == 0 || op->argc == 2);
	if(op->argc) {
		FETCH(arg1);
		FETCH(arg2);
	}
	EXEC();
}

/* DD XX 命令のテーブルジャンプ処理です。
 */
Z80FN_("DD", DD)
{
	const Z80OP* op;

	FETCH(code);
	op = &z80_op_table_DD[code];
	if(op->argc >= 1) {
		FETCH(arg1);
		if(op->argc >= 2) {
			FETCH(arg2);
		}
	}
	EXEC();
}

/* FD XX 命令のテーブルジャンプ処理です。
 */
Z80FN_("FD", FD)
{
	const Z80OP* op;

	FETCH(code);
	op = &z80_op_table_FD[code];
	if(op->argc >= 1) {
		FETCH(arg1);
		if(op->argc >= 2) {
			FETCH(arg2);
		}
	}
	EXEC();
}

/* DD CB d XX 命令のテーブルジャンプ処理です。
 * [note]
 *	* DD CB d XX 命令の引数は1バイトです。
 *	  「引数、オペコード」の順であることに注意してください。
 */
Z80FN_("DDCB", DDCB)
{
	const Z80OP* op;

	FETCH(arg1);
	FETCH(code);
	op = &z80_op_table_DDCB[code];
	ASSERT(op->argc == 1);
	EXEC();
}

/* FD CB d XX 命令のテーブルジャンプ処理です。
 * [note]
 *	* FD CB d XX 命令の引数は1バイトです。
 *	  「引数、オペコード」の順であることに注意してください。
 */
Z80FN_("FDCB", FDCB)
{
	const Z80OP* op;

	FETCH(arg1);
	FETCH(code);
	op = &z80_op_table_FDCB[code];
	ASSERT(op->argc == 1);
	EXEC();
}

#endif /*Z80_ASM*/

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

///* パリティフラグ算出のための補助ルーチンです。
// * [in]
// *	n		調べる値。
// * [out]
// *	戻り値		1のビットが偶数個なら4を返します。
// *			1のビットが奇数個なら0を返します。
// * [note]
// *	* Z80のパリティフラグは偶数パリティです。
// *	* パリティフラグの位置はbit2なので、4or0を返します。
// */
//#ifndef Z80_ASM	/************************************************************/
//
//unsigned char
//z80_PARITY(unsigned char n)
//{
//	int p = 4;
//	while(n) {
//		if(n & 1) p ^= 4;
//		n >>= 1;
//	}
//	return p;
//}
//
//#else	/********************************************************************/
//
//asm("
//	.code
//	.align 1
//	.global z80_PARITY
//z80_PARITY:
//	swap %r12, %r12			; 調べる値を上位8ビットに移動。
//	xjreq.d z80_PARITY_L20		; 1のビットがなければ、ループに入りません。
//	ld.w %r10, 4			; 偶数パリティなので、初期状態でON。*delay*
//z80_PARITY_L10:
//	scan1 %r11, %r12		; 1のビット位置を検索。(必ず存在する)
//	sll %r12, %r11			; 見つかったビットを最上位へシフト。
//	sll %r12, 1			; 見つかったビットを左へ捨てる。
//	xjrne.d z80_PARITY_L10		; まだ1のビットが残っていたら、ループする。
//	xor %r10, 4			; 見つかったビット分のパリティ反転。*delay*
//z80_PARITY_L20:
//	ret
//");
//
//#endif	/********************************************************************/
//
//→2003/12/01 パリティビット変換テーブルの参照に置き換えたので、削除しました。

/****************************************************************************
 *	General-Purpose Arithmetic and CPU Control Group
 ****************************************************************************/

#ifndef Z80_ASM

/* 8ビット加算を行います。
 * [in/out]
 *	A <= A + n
 * [flags]
 *	S	0/1	Doc'd
 *	Z	0/1	Doc'd
 *	Y	0/1	UnDoc	結果のbit5をコピーします。
 *	H	0/1	Doc'd
 *	X	0/1	UnDoc	結果のbit3をコピーします。
 *	V	0/1	Doc'd
 *	N	0  	Doc'd
 *	C	0/1	Doc'd
 */
void
z80_ADD8(Z80* z80, unsigned char n)
{
	int tmp = A + n;
	F = (tmp & 0xa8) |				/* S,Y,X */
	    (!(tmp & 0xff) << 6) |			/* Z */
	    (((A & 0xf) + (n & 0xf)) & 0x10) |		/* H */
	    ((~(A ^ n) & (A ^ tmp) & 0x80) >> 5) |	/* V */
							/* N */
	    ((tmp >> 8) & 1);				/* C */
	A = tmp;
}

/* 8ビット加算(キャリー込み)を行います。
 * [in/out]
 *	A <= A + n + F(C)
 * [flags]
 *	S	0/1	Doc'd
 *	Z	0/1	Doc'd
 *	Y	0/1	UnDoc	結果のbit5をコピーします。
 *	H	0/1	Doc'd
 *	X	0/1	UnDoc	結果のbit3をコピーします。
 *	V	0/1	Doc'd
 *	N	0  	Doc'd
 *	C	0/1	Doc'd
 */
void
z80_ADC8(Z80* z80, unsigned char n)
{
	int c = F & 1;
	int tmp = A + n + c;
	F = (tmp & 0xa8) |				/* S,Y,X */
	    (!(tmp & 0xff) << 6) |			/* Z */
	    (((A & 0xf) + (n & 0xf) + c) & 0x10) |	/* H */
	    ((~(A ^ n) & (A ^ tmp) & 0x80) >> 5) |	/* V */
							/* N */
	    ((tmp >> 8) & 1);				/* C */
	A = tmp;
}

/* 8ビット減算を行います。
 * [in/out]
 *	A <= A - n
 * [flags]
 *	S	0/1	Doc'd
 *	Z	0/1	Doc'd
 *	Y	0/1	UnDoc	結果のbit5をコピーします。
 *	H	0/1	Doc'd
 *	X	0/1	UnDoc	結果のbit3をコピーします。
 *	V	0/1	Doc'd
 *	N	  1	Doc'd
 *	C	0/1	Doc'd
 */
void
z80_SUB8(Z80* z80, unsigned char n)
{
	int tmp = A - n;
	F = (tmp & 0xa8) |				/* S,Y,X */
	    (!(tmp & 0xff) << 6) |			/* Z */
	    (((A & 0xf) - (n & 0xf)) & 0x10) |		/* H */
	    (((A ^ n) & (A ^ tmp) & 0x80) >> 5) |	/* V */
	    2 |						/* N */
	    ((tmp >> 8) & 1);				/* C */
	A = tmp;
}

/* 8ビット減算(ボロー込み)を行います。
 * [in/out]
 *	A <= A - n - F(C)
 * [flags]
 *	S	0/1	Doc'd
 *	Z	0/1	Doc'd
 *	Y	0/1	UnDoc	結果のbit5をコピーします。
 *	H	0/1	Doc'd
 *	X	0/1	UnDoc	結果のbit3をコピーします。
 *	V	0/1	Doc'd
 *	N	  1	Doc'd
 *	C	0/1	Doc'd
 */
void
z80_SBC8(Z80* z80, unsigned char n)
{
	int c = F & 1;
	int tmp = A - n - c;
	F = (tmp & 0xa8) |				/* S,Y,X */
	    (!(tmp & 0xff) << 6) |			/* Z */
	    (((A & 0xf) - (n & 0xf) - c) & 0x10) |	/* H */
	    (((A ^ n) & (A ^ tmp) & 0x80) >> 5) |	/* V */
	    2 |						/* N */
	    ((tmp >> 8) & 1);				/* C */
	A = tmp;
}

/* 論理積を求めます。
 * [in/out]
 *	A <= A & n
 * [flags]
 *	S	0/1	Doc'd
 *	Z	0/1	Doc'd
 *	Y	0/1	UnDoc	結果のbit5をコピーします。
 *	H	  1	Doc'd
 *	X	0/1	UnDoc	結果のbit3をコピーします。
 *	P	0/1	Doc'd
 *	N	0  	Doc'd
 *	C	0  	Doc'd
 */
void
z80_AND(Z80* z80, unsigned char n)
{
	A &= n;
	F = (A & 0xa8) |	/* S,Y,X */
	    (!A << 6) |		/* Z */
	    0x10 |		/* H */
	    PARITY(A);		/* P */
				/* N */
				/* C */
}

/* 論理和を求めます。
 * [in/out]
 *	A <= A & n
 * [flags]
 *	S	0/1	Doc'd
 *	Z	0/1	Doc'd
 *	Y	0/1	UnDoc	結果のbit5をコピーします。
 *	H	0  	Doc'd
 *	X	0/1	UnDoc	結果のbit3をコピーします。
 *	P	0/1	Doc'd
 *	N	0  	Doc'd
 *	C	0  	Doc'd
 */
void
z80_OR(Z80* z80, unsigned char n)
{
	A |= n;
	F = (A & 0xa8) |	/* S,Y,X */
	    (!A << 6) |		/* Z */
				/* H */
	    PARITY(A);		/* P */
				/* N */
				/* C */
}

/* 排他論理和を求めます。
 * [in/out]
 *	A <= A ^ n
 * [flags]
 *	S	0/1	Doc'd
 *	Z	0/1	Doc'd
 *	Y	0/1	UnDoc	結果のbit5をコピーします。
 *	H	0  	Doc'd
 *	X	0/1	UnDoc	結果のbit3をコピーします。
 *	P	0/1	Doc'd
 *	N	0  	Doc'd
 *	C	0  	Doc'd
 */
void
z80_XOR(Z80* z80, unsigned char n)
{
	A ^= n;
	F = (A & 0xa8) |	/* S,Y,X */
	    (!A << 6) |		/* Z */
				/* H */
	    PARITY(A);		/* P */
				/* N */
				/* C */
}

/* 比較を行います。
 * [in/out]
 *	捨てる <= A - n
 * [flags]
 *	S	0/1	Doc'd
 *	Z	0/1	Doc'd
 *	Y	0/1	UnDoc	比較する値のbit5をコピーします。
 *	H	0/1	Doc'd
 *	X	0/1	UnDoc	比較する値のbit3をコピーします。
 *	V	0/1	Doc'd
 *	N	  1	Doc'd
 *	C	0/1	Doc'd
 * [note]
 *	* フラグレジスタのbit5,3は、結果ではなく比較対象値を反映します。
 *	  この命令だけ、未使用フラグビットの振る舞いが特殊です。要注意!!
 */
void
z80_CP(Z80* z80, unsigned char n)
{
	int tmp = A - n;
	F = (tmp & 0x80) |				/* S */
	    (n & 0x28) |				/* Y,X */
	    (!(tmp & 0xff) << 6) |			/* Z */
	    (((A & 0xf) - (n & 0xf)) & 0x10) |		/* H */
	    (((A ^ n) & (A ^ tmp) & 0x80) >> 5) |	/* V */
	    2 |						/* N */
	    ((tmp >> 8) & 1);				/* C */
}

/* 8ビット値をインクリメントします。
 * [in/out]
 *	戻り値 <= r + 1
 * [flags]
 *	S	0/1	Doc'd
 *	Z	0/1	Doc'd
 *	Y	0/1	UnDoc	結果のbit5をコピーします。
 *	H	0/1	Doc'd
 *	X	0/1	UnDoc	結果のbit3をコピーします。
 *	P	0/1	Doc'd
 *	N	0  	Doc'd
 *	C	---	Doc'd
 */
unsigned char
z80_INC8(Z80* z80, unsigned char r)
{
	r++;
	F = (r & 0xa8) |		/* S,Y,X */
	    (!r << 6) |			/* Z */
	    (!(r & 0xf) << 4) |		/* H */
	    ((r == 0x80) << 2) |	/* V */
					/* N */
	    (F & 1);			/* C */
	return r;
}

/* 8ビット値をデクリメントします。
 * [in/out]
 *	戻り値 <= r + 1
 * [flags]
 *	S	0/1	Doc'd
 *	Z	0/1	Doc'd
 *	Y	0/1	UnDoc	結果のbit5をコピーします。
 *	H	0/1	Doc'd
 *	X	0/1	UnDoc	結果のbit3をコピーします。
 *	P	0/1	Doc'd
 *	N	  1	Doc'd
 *	C	---	Doc'd
 */
unsigned char
z80_DEC8(Z80* z80, unsigned char r)
{
	r--;
	F = (r & 0xa8) |		/* S,Y,X */
	    (!r << 6) |			/* Z */
	    (((r & 0xf) == 0xf) << 4) |	/* H */
	    ((r == 0x7f) << 2) |	/* V */
	    2 |				/* N */
	    (F & 1);			/* C */
	return r;
}

/****************************************************************************
 *	16-Bit Arithmetic Group
 ****************************************************************************/

/* 16ビット加算を行います。
 * [in/out]
 *	戻り値 <= rr + nn
 * [flags]
 *	S	---	Doc'd
 *	Z	---	Doc'd
 *	Y	0/1	UnDoc	結果の上位バイトのbit5をコピーします。
 *	H	0/1	UnDoc	結果の上位バイトのハーフキャリーです。
 *	X	0/1	UnDoc	結果の上位バイトのbit3をコピーします。
 *	V	---	Doc'd
 *	N	  0	Doc'd
 *	C	0/1	Doc'd
 */
unsigned short
z80_ADD16(Z80* z80, unsigned short rr, unsigned short nn)
{
	int tmp = rr + nn;
	F = (F & 0xc4) |					/* S,Z,V */
	    ((tmp >> 8) & 0x28) |				/* Y,X */
	    ((((rr & 0xfff) + (nn & 0xfff)) >> 8) & 0x10) |	/* H */
								/* N */
	    ((tmp >> 16) & 1);					/* C */
	return tmp;
}

/* 16ビット加算(キャリー込み)を行います。
 * [in/out]
 *	戻り値 <= rr + nn + F(C)
 * [flags]
 *	S	0/1	Doc'd
 *	Z	0/1	Doc'd
 *	Y	0/1	UnDoc	結果の上位バイトのbit5をコピーします。
 *	H	0/1	UnDoc	結果の上位バイトのハーフキャリーです。
 *	X	0/1	UnDoc	結果の上位バイトのbit3をコピーします。
 *	V	0/1	Doc'd
 *	N	  0	Doc'd
 *	C	0/1	Doc'd
 */
unsigned short
z80_ADC16(Z80* z80, unsigned short rr, unsigned short nn)
{
	int c = F & 1;
	int tmp = rr + nn + c;
	F = ((tmp >> 8) & 0xa8) |				/* S,Y,X */
	    (!(tmp & 0xffff) << 6) |				/* Z */
	    ((((rr & 0xfff) + (nn & 0xfff) + c) >> 8) & 0x10) |	/* H */
	    ((~(rr ^ nn) & (rr ^ tmp) & 0x8000) >> 13) |	/* V */
								/* N */
	    ((tmp >> 16) & 1);					/* C */
	return tmp;
}

/* 16ビット減算(ボロー込み)を行います。
 * [in/out]
 *	戻り値 <= rr - nn - F(C)
 * [flags]
 *	S	0/1	Doc'd
 *	Z	0/1	Doc'd
 *	Y	0/1	UnDoc	結果の上位バイトのbit5をコピーします。
 *	H	0/1	UnDoc	結果の上位バイトのハーフキャリーです。
 *	X	0/1	UnDoc	結果の上位バイトのbit3をコピーします。
 *	V	0/1	Doc'd
 *	N	1  	Doc'd
 *	C	0/1	Doc'd
 */
unsigned short
z80_SBC16(Z80* z80, unsigned short rr, unsigned short nn)
{
	int c = F & 1;
	int tmp = rr - nn - c;
	F = ((tmp >> 8) & 0xa8) |				/* S,Y,X */
	    (!(tmp & 0xffff) << 6) |				/* Z */
	    ((((rr & 0xfff) - (nn & 0xfff) - c) >> 8) & 0x10) |	/* H */
	    (((rr ^ nn) & (rr ^ tmp) & 0x8000) >> 13) |		/* V */
	    2 |							/* N */
	    ((tmp >> 16) & 1);					/* C */
	return tmp;
}

#endif /*Z80_ASM*/

/****************************************************************************
 *	Rotate and Shift Group
 ****************************************************************************/

/* 左ローテート(キャリー込み)を行います。
 * [in/out]
 *	戻り値 <= RL r
 * [flags]
 *	S	0/1	Doc'd
 *	Z	0/1	Doc'd
 *	Y	0/1	UnDoc	結果のbit5をコピーします。
 *	H	0  	Doc'd
 *	X	0/1	UnDoc	結果のbit3をコピーします。
 *	P	0/1	Doc'd
 *	N	0  	Doc'd
 *	C	0/1	Doc'd
 */
unsigned char
z80_RL(Z80* z80, unsigned char r)
{
	unsigned char tmp = (r << 1) | (F & 1);
	F = (tmp & 0xa8) |	/* S,Y,X */
	    (!tmp << 6) |	/* Z */
				/* H */
	    PARITY(tmp) |	/* P */
				/* N */
	    (r >> 7);		/* C */
	return tmp;
}

/* 左ローテート(サーキュラ)を行います。
 * [in/out]
 *	戻り値 <= RLC r
 * [flags]
 *	S	0/1	Doc'd
 *	Z	0/1	Doc'd
 *	Y	0/1	UnDoc	結果のbit5をコピーします。
 *	H	0  	Doc'd
 *	X	0/1	UnDoc	結果のbit3をコピーします。
 *	P	0/1	Doc'd
 *	N	0  	Doc'd
 *	C	0/1	Doc'd
 */
unsigned char
z80_RLC(Z80* z80, unsigned char r)
{
	unsigned char tmp = (r << 1) | (r >> 7);
	F = (tmp & 0xa8) |	/* S,Y,X */
	    (!tmp << 6) |	/* Z */
				/* H */
	    PARITY(tmp) |	/* P */
				/* N */
	    (r >> 7);		/* C */
	return tmp;
}

/* 右ローテート(キャリー込み)を行います。
 * [in/out]
 *	戻り値 <= RR r
 * [flags]
 *	S	0/1	Doc'd
 *	Z	0/1	Doc'd
 *	Y	0/1	UnDoc	結果のbit5をコピーします。
 *	H	0  	Doc'd
 *	X	0/1	UnDoc	結果のbit3をコピーします。
 *	P	0/1	Doc'd
 *	N	0  	Doc'd
 *	C	0/1	Doc'd
 */
unsigned char
z80_RR(Z80* z80, unsigned char r)
{
	unsigned char tmp = (r >> 1) | (F << 7);
	F = (tmp & 0xa8) |	/* S,Y,X */
	    (!tmp << 6) |	/* Z */
				/* H */
	    PARITY(tmp) |	/* P */
				/* N */
	    (r & 1);		/* C */
	return tmp;
}

/* 右ローテート(サーキュラ)を行います。
 * [in/out]
 *	戻り値 <= RRC r
 * [flags]
 *	S	0/1	Doc'd
 *	Z	0/1	Doc'd
 *	Y	0/1	UnDoc	結果のbit5をコピーします。
 *	H	0  	Doc'd
 *	X	0/1	UnDoc	結果のbit3をコピーします。
 *	P	0/1	Doc'd
 *	N	0  	Doc'd
 *	C	0/1	Doc'd
 */
unsigned char
z80_RRC(Z80* z80, unsigned char r)
{
	unsigned char tmp = (r >> 1) | (r << 7);
	F = (tmp & 0xa8) |	/* S,Y,X */
	    (!tmp << 6) |	/* Z */
				/* H */
	    PARITY(tmp) |	/* P */
				/* N */
	    (r & 1);		/* C */
	return tmp;
}

/* 左算術シフトを行います。
 * [in/out]
 *	戻り値 <= (char)r << 1
 * [flags]
 *	S	0/1	Doc'd
 *	Z	0/1	Doc'd
 *	Y	0/1	UnDoc	結果のbit5をコピーします。
 *	H	0  	Doc'd
 *	X	0/1	UnDoc	結果のbit3をコピーします。
 *	P	0/1	Doc'd
 *	N	0  	Doc'd
 *	C	0/1	Doc'd
 */
unsigned char
z80_SLA(Z80* z80, unsigned char r)
{
	unsigned char tmp = r << 1;
	F = (tmp & 0xa8) |	/* S,Y,X */
	    (!tmp << 6) |	/* Z */
				/* H */
	    PARITY(tmp) |	/* P */
				/* N */
	    (r >> 7);		/* C */
	return tmp;
}

/* 右算術シフトを行います。
 * [in/out]
 *	戻り値 <= (char)r >> 1
 * [flags]
 *	S	0/1	Doc'd
 *	Z	0/1	Doc'd
 *	Y	0/1	UnDoc	結果のbit5をコピーします。
 *	H	0  	Doc'd
 *	X	0/1	UnDoc	結果のbit3をコピーします。
 *	P	0/1	Doc'd
 *	N	0  	Doc'd
 *	C	0/1	Doc'd
 */
unsigned char
z80_SRA(Z80* z80, unsigned char r)
{
	unsigned char tmp = (char)r >> 1;
	F = (tmp & 0xa8) |	/* S,Y,X */
	    (!tmp << 6) |	/* Z */
				/* H */
	    PARITY(tmp) |	/* P */
				/* N */
	    (r & 1);		/* C */
	return tmp;
}

/* 右論理シフトを行います。
 * [in/out]
 *	戻り値 <= (unsigned char)r >> 1
 * [flags]
 *	S	0/1	Doc'd
 *	Z	0/1	Doc'd
 *	Y	0/1	UnDoc	結果のbit5をコピーします。
 *	H	0  	Doc'd
 *	X	0/1	UnDoc	結果のbit3をコピーします。
 *	P	0/1	Doc'd
 *	N	0  	Doc'd
 *	C	0/1	Doc'd
 */
unsigned char
z80_SRL(Z80* z80, unsigned char r)
{
	unsigned char tmp = r >> 1;
	F = (tmp & 0xa8) |	/* S,Y,X */
	    (!tmp << 6) |	/* Z */
				/* H */
	    PARITY(tmp) |	/* P */
				/* N */
	    (r & 1);		/* C */
	return tmp;
}

/****************************************************************************
 *	Bit Set, Reset, and Test Group
 ****************************************************************************/

/* ビットテストを行います。
 * [in/out]
 *	捨てる <= r & (1 << n)
 * [flags]
 *	S	0/1	UnDoc	結果のbit7をコピーします。
 *	Z	0/1	Doc'd
 *	Y	???	UnDoc	複雑すぎてよくわかりません…(^^;
 *	H	  1	Doc'd
 *	X	???	UnDoc	複雑すぎてよくわかりません…(^^;
 *	P	0/1	UnDoc	Zフラグと同じ値。
 *	N	0  	Doc'd
 *	C	---	Doc'd
 */
void
z80_BIT(Z80* z80, unsigned char n, unsigned char r)
{
	unsigned char tmp = r & (1 << n);
	F = (tmp & 0x80) |		/* S */
	    (tmp ? 0x10 : 0x54) |	/* Z,H,P */
					/* N */
	    (F & 1);			/* C */
}

