/*	
 *	framc62.c
 *
 *	P/ECE HuC6280 Emulator
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2001-2004 Naoyuki Sawa
 *
 *	* Mon Feb 23 04:28:00 JST 2004 Naoyuki Sawa
 *	- 作成開始。
 */
#include "clip.h"
#include "clipc62i.h"	/*HuC6280エミュレータ実装用マクロ*/

/* ※TODO: ページをまたいだ時の追加サイクルを考慮していません。
 *         実機よりも少ないサイクルで実行を完了してしまいます。
 */

/****************************************************************************
 *	HuC6280コア内蔵の外部関数
 ****************************************************************************/

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

#ifndef HUC6280_ASM	/****************************************************/

unsigned char
huc6280_internal_read(HUC6280* huc6280, unsigned short addr)
{
	return ((unsigned char*)(huc6280 + 1))[addr];
}
void
huc6280_internal_write(HUC6280* huc6280, unsigned short addr, unsigned char data)
{
	((unsigned char*)(huc6280 + 1))[addr] = data;
}

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

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

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

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

#ifndef HUC6280_ASM

void
huc6280_run(HUC6280* huc6280, int cycle)
{
	unsigned char code;
	const HUC6280OP* op;
	int arg1, arg2, arg3;
	arg1 = arg2 = arg3 = 0; /* 警告抑制 */

	CYCLE = cycle;
	while(!HALT && CYCLE > 0) {
#ifdef HUC6280_TRACE
		huc6280_dump(huc6280);
#endif /*HUC6280_TRACE*/
		HUC6280TRACE("%04x: ", PC);
		FETCH(code);
		op = &huc6280_op_table[code];
		switch(op->addr) {		// Name                           | Syntax
		/*===== operand bytes=0 =====*/
		case HUC6280_ACC:		// accumulator                    | a
			break;
		case HUC6280_IMP:		// implied                        |
			break;
		/*===== operand bytes=1 =====*/
		case HUC6280_IMM:		// immediate                      | #$nn
			FETCH(arg1);
			break;
		case HUC6280_ZPG:		// zero page                      | <$nn
			FETCH(arg1);
			arg1 |= 0x2000;
			break;
		case HUC6280_ZPX:		// zero page, x-indexed           | <$nn,x
			FETCH(arg1);
			arg1 += X;
			arg1 &= 0xff;
			arg1 |= 0x2000;
			break;
		case HUC6280_ZPY:		// zero page, y-indexed           | <$nn,y
			FETCH(arg1);
			arg1 += Y;
			arg1 &= 0xff;
			arg1 |= 0x2000;
			break;
		case HUC6280_ZPI:		// zero page indirect             | [$nn]
			FETCH(arg1);
			arg1 |= 0x2000;
			arg1 = READW(arg1);
			break;
		case HUC6280_IDX:		// zero page pre-indexed          | [$nn,x]
			FETCH(arg1);
			arg1 += X;
			arg1 &= 0xff;
			arg1 |= 0x2000;
			arg1 = READW(arg1);
			break;
		case HUC6280_IDY:		// zero page post-indexed         | [$nn],y
			FETCH(arg1);
			arg1 |= 0x2000;
			arg1 = READW(arg1);
			arg1 += Y;
			arg1 &= 0xffff;
			break;
		case HUC6280_REL:		// relative offset                | *
			FETCH(arg1);
			arg1 = PC + (char)arg1;
			arg1 &= 0xffff;
			break;
		/*===== operand bytes=2 =====*/
		case HUC6280_ABS:		// absolute                       | $nnnn
			FETCHW(arg1);
			break;
		case HUC6280_ABX:		// absolute x-indexed             | $nnnn,x
			FETCHW(arg1);
			arg1 += X;
			arg1 &= 0xffff;
			break;
		case HUC6280_ABY:		// absolute y-indexed             | $nnnn,y
			FETCHW(arg1);
			arg1 += Y;
			arg1 &= 0xffff;
			break;
		case HUC6280_IND:		// indirect                       | [$nnnn]
			FETCHW(arg1);
			arg1 = READW(arg1);
			break;
		case HUC6280_IAX:		// indirect, x-indexed            | [$nnnn,x]
			FETCHW(arg1);
			arg1 += X;
			arg1 &= 0xffff;
			arg1 = READW(arg1);
			break;
		case HUC6280_IMZ:		// immediate zero page            | #$nn,<$nn
			FETCH(arg1);
			FETCH(arg2);
			arg2 |= 0x2000;
			break;
		case HUC6280_IZX:		// immediate zero page, x-indexed | #$nn,<$nn,x
			FETCH(arg1);
			FETCH(arg2);
			arg2 += X;
			arg2 &= 0xff;
			arg2 |= 0x2000;
			break;
		case HUC6280_ZRL:		// zero page, relative offset     | <$nn,*
			FETCH(arg1);
			arg1 |= 0x2000;
			FETCH(arg2);
			arg2 = PC + (char)arg2;
			arg2 &= 0xffff;
			break;
		/*===== operand bytes=3 =====*/
		case HUC6280_IMA:		// immediate absolute             | #$nn,$nnnn
			FETCH(arg1);
			FETCHW(arg2);
			break;
		case HUC6280_IMX:		// immediate absolute, x-indexed  | #$nn,$nnnn,x
			FETCH(arg1);
			FETCHW(arg2);
			arg2 += X;
			arg2 &= 0xffff;
			break;
		/*===== operand bytes=6 =====*/
		case HUC6280_BLK:		// block transfer                 | $nnnn,$nnnn,$nnnn
			FETCHW(arg1);
			FETCHW(arg2);
			FETCHW(arg3);
			break;
#ifndef PIECE /* P/ECEでは高速RAMメモリ不足のためカット */
		default:
			DIE();
#endif /*PIECE*/
		}
		EXEC();
		HUC6280TRACE("\n");
	}
}

#endif /*HUC6280_ASM*/
