/*	
 *	clipz80.h
 *
 *	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
 *	- 作成開始。
 *	* Wed Nov 18 21:37:53 JST 2015 Naoyuki Sawa
 *	- 'extern "C" {'〜'}'で囲みました。.cppを含むWin32プロジェクトからもインクルード出来るようにするためです。
 */
#ifndef __CLIP_Z80_H__
#define __CLIP_Z80_H__

#ifdef  __cplusplus
extern "C" {
#endif//__cplusplus

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

/* Z80_ASMシンボル定義を読み込みます。
 * Z80_ASMシンボルの未定義/定義によるC/アセンブラコードの切り替えは、
 * Cソースファイル(*.c)とアセンブラソースファイル(*.s)から参照するので、
 * 別のインクルードファイルに分けています。
 * (C言語特有の定義を含むインクルードファイルをそのままアセンブラソースに
 *  インクルードすると、アセンブルエラーになってしまうため。)
 */
#include "clipz80a.h"

/* このシンボルを定義すると、全ての命令実行をトレース出力します。
 * このシンボルを定義しなければ、各命令実行はトレース出力しません。
 * 全ての命令実行をトレースするととても遅くなるので、通常は定義しないでください。
 * なお、このシンボルを定義しても、全体のトレースON指示“TRACE_ON=1”がなければ、
 * トレース出力は行われません。
 */
//#define Z80_TRACE

/********** これ以降は書き換えないでください **********/

/* P/ECE以外ではアセンブラコードは使用できません。
 */
#ifndef PIECE
#undef Z80_ASM
#endif /*PIECE*/

/* アセンブラコードは全命令トレースに対応していないので、
 * アセンブラコード使用時は確実に全命令トレースをOFFにします。
 */
#ifdef Z80_ASM
#undef Z80_TRACE
#endif /*Z80_ASM*/ 

#ifdef Z80_TRACE
#define Z80TRACE	TRACE
#else /*Z80_TRACE*/
#define Z80TRACE	1 ? ((void)0) : TRACE
#endif /*Z80_TRACE*/

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

typedef struct _Z80 Z80;

/*
 *	Z80コア外部関数の型定義
 */
typedef unsigned char Z80READPROC (Z80* z80, unsigned short addr);
typedef          void Z80WRITEPROC(Z80* z80, unsigned short addr, unsigned char data);
typedef unsigned char Z80INPROC   (Z80* z80, unsigned short addr);
typedef          void Z80OUTPROC  (Z80* z80, unsigned short addr, unsigned char data);

/*
 *	Z80コア
 */
/*typedef*/ struct _Z80 {
	/*===== レジスタ =====*/
	unsigned short af;		/* + 0, 2 */
	unsigned short bc;		/* + 2, 2 */
	unsigned short de;		/* + 4, 2 */
	unsigned short hl;		/* + 6, 2 */
	//
	unsigned short af2;		/* + 8, 2 */
	unsigned short bc2;		/* +10, 2 */
	unsigned short de2;		/* +12, 2 */
	unsigned short hl2;		/* +14, 2 */
	//
	unsigned short ix;		/* +16, 2 */
	unsigned short iy;		/* +18, 2 */
	unsigned short sp;		/* +20, 2 */
	unsigned short pc;		/* +22, 2 */
	//
	unsigned char r;		/* +24, 1 */
	unsigned char i;		/* +25, 1 */
	unsigned char _resv1[6];	/* +26, 6 */
	/*===== 内部状態 =====*/
	unsigned char iff1;		/* +32, 1 */
	unsigned char iff2;		/* +33, 1 */
	unsigned char im;		/* +34, 1 */
	unsigned char halt;		/* +35, 1 */
	int cycle;			/* +36, 4 */
	/*{{2005/01/07 INT要求保留対応のために追加*/
	unsigned char pending;		/* +40, 1 INT要求保留 (0:無し/1:有り) */
	unsigned char pending_no;	/* +41, 1 保留されているINT要求の番号 */
	/*}}2005/01/07 INT要求保留対応のために追加*/
	unsigned char _resv2[6];	/* +42, 6 */
	/*===== 外部関数 =====*/
	Z80READPROC* read;		/* +48, 4 */
	Z80WRITEPROC* write;		/* +52, 4 */
	Z80INPROC* in;			/* +56, 4 */
	Z80OUTPROC* out;		/* +60, 4 */
} /*Z80*/;				/* =64    */

/*
 *	インストラクション関数宣言
 */
typedef                void Z80OPPROC (Z80* z80, unsigned char code, unsigned char arg1, unsigned char arg2);
#define Z80FN_(OP, FN) void z80op_##FN(Z80* z80, unsigned char code, unsigned char arg1, unsigned char arg2);	/* 宣言用 */
#include "z80/list.h" /* [z80.xls]List!C10 */
Z80FN_("CB"   , CB   )
Z80FN_("ED"   , ED   )
Z80FN_("DD"   , DD   )
Z80FN_("FD"   , FD   )
Z80FN_("DDCB" , DDCB )
Z80FN_("FDCB" , FDCB )
Z80FN_("ERROR", ERROR)
#undef  Z80FN_
#define Z80FN_(OP, FN) void z80op_##FN(Z80* z80, unsigned char code, unsigned char arg1, unsigned char arg2)	/* 定義用 */

/*
 *	オペコードマップ・ニーモニックテーブル
 */
typedef struct _Z80OP {
	Z80OPPROC* proc;	/* + 0, 4 */
	unsigned char argc;	/* + 4, 1 */
	unsigned char cycle;	/* + 5, 1 */
	unsigned short name;	/* + 6, 2 z80_op_name_table[]内の文字列へのオフセットです */
} Z80OP;			/* = 8    */
#define Z80OP_(CODE, PROC, ARGC, CYCLE, NAME)	{ z80op_##PROC, 0x##ARGC, 0x##CYCLE, 0x##NAME },
extern const Z80OP z80_op_table[256/*XX*/];		/* XX */
extern const Z80OP z80_op_table_CB[256/*XX*/];		/* CB XX */
extern const Z80OP z80_op_table_ED[256/*XX*/];		/* ED XX */
extern const Z80OP z80_op_table_DD[256/*XX*/];		/* DD XX */
extern const Z80OP z80_op_table_FD[256/*XX*/];		/* FD XX */
extern const Z80OP z80_op_table_DDCB[256/*XX*/];	/* DD CB ?? XX */
extern const Z80OP z80_op_table_FDCB[256/*XX*/];	/* FD CB ?? XX */
extern const char z80_op_name_table[];			/* ニーモニックテーブル */

/****************************************************************************
 *	内部関数
 ****************************************************************************/

/* Z80リセット時に設定される、Z80コア内蔵のメインメモリREAD/WRITE・I/O IN/OUTの外部関数です。
 * アプリケーションから直接呼び出すことはありません。
 */
unsigned char z80_internal_read (Z80* z80, unsigned short addr);
         void z80_internal_write(Z80* z80, unsigned short addr, unsigned char data);
unsigned char z80_internal_in   (Z80* z80, unsigned short addr);
         void z80_internal_out  (Z80* z80, unsigned short addr, unsigned char data);

/* * 保留されているINT要求を検査し、マスカブル割り込みが許可されていたら割り込みを実行します。
 *   IFF1またはPENDINGが、0→1へ変化する可能性のある処理を行った後に、必ず呼び出してください。
 * * EI命令もIFF1を(0or1)→1へ変化させますが、特例として保留INT要求を検査しません!!
 *   {EI→RETI}という命令並びの、RETIにて保留INT要求を検査します。(Z80の仕様...たぶん。要確認)
 *   もしも割り込みルーチンの末尾が{EI→RETI}ではなく{EI→RET}となっていたら、保留INT要求は受け付けられません。
 *   現在の保留INT要求は単に無視されて、次に新しいINT要求が発行された時にあらためて割り込みを実行します。
 *   詳しくは、EIとRETIの実装を参照してください。
 */
void z80_check_pending(Z80* z80);

/****************************************************************************
 *	アプリケーション用関数
 ****************************************************************************/

/* Z80をリセットします。
 * [in]
 *	z80		Z80構造体。
 *	read		メインメモリREAD 外部関数 (NULL:コア内蔵関数を使用)
 *	write		メインメモリWRITE外部関数 (NULL:コア内蔵関数を使用)
 *	in		I/O         READ 外部関数 (NULL:コア内蔵関数を使用)
 *	out		I/O         WRITE外部関数 (NULL:コア内蔵関数を使用)
 * [note]
 *	* read,write,in,outにNULLを指定すると、コア内蔵の外部関数を使用します。
 *	  コア内蔵の外部関数は、次のような動作を行います。
 *	  ・READ	Z80構造体の直後に64KBのメインメモリが配置されていると仮定し、メインメモリを読み込みます。
 *	  ・WRITE	Z80構造体の直後に64KBのメインメモリが配置されていると仮定し、メインメモリに書き込みます。
 *	  ・IN		常に-1を返します。
 *	  ・OUT		何もしません。
 */
void z80_reset(Z80* z80, Z80READPROC* read, Z80WRITEPROC* write, Z80INPROC* in, Z80OUTPROC* out);

/* Z80を実行します。
 * [in]
 *	z80		Z80構造体。
 *	cycle		実行サイクル数。
 * [note]
 *	* 実行サイクル数がcycleに達するか、またはHALTされるまで実行します。
 *	  前者の場合、実際の実行サイクル数は、cycleよりも多くなる可能性があります。
 *	  後者の場合、実際の実行サイクル数は、cycleよりも少なくなる可能性があります。
 *	* この関数から戻ったとき、z80->cycleに残り実行サイクル数が格納されています。
 *	  例えば cycle=100 で呼び出し、実際には 105 サイクル実行した場合、  z80->cycle=-5 となります。
 *	  また、 cycle=100 で呼び出し、10 サイクル実行後に HALT した場合は、z80->cycle=90 となります。
 */
void z80_run(Z80* z80, int cycle);

/* マスク可能割り込みリクエストを発行します。
 * [in]
 *	z80		Z80構造体。
 *	no		割り込みモードによって意味が異なります。
 *			モード0: RST XXH 命令のオペコードを指定します。
 *			モード1: 意味を持ちません。
 *			モード2: 割り込みベクタの下位バイトを指定します。
 * [note]
 *	// * 割り込みが禁止されていたら、割り込みリクエストは無視されます。
 *	//   割り込みリクエストは保留されません。
 *	// ↓2005/01/07 INT要求保留対応
 *	* 割り込みが禁止されていたら、割り込みリクエストは保留されます。
 *	  割り込みが許可されたときに、割り込みが実行されます。
 */
void z80_int(Z80* z80, unsigned char no);

/* マスク不可割り込みリクエストを発行します。
 * [in]
 *	z80		Z80構造体。
 */
void z80_nmi(Z80* z80);

/* 標準エラー出力に、レジスタダンプを行います。
 * [in]
 *	z80		Z80構造体。
 */
void z80_dump(Z80* z80);

#ifdef PIECE
/* Z80を実行します。(スタック切替・高速版)
 * [in]
 *	z80		Z80構造体。
 *	cycle		実行サイクル数。
 * [note]
 *	* z80_run()との違いは、この関数の実行中のみ、スタックを0x0e00〜0x1000の高速RAMに切り換えることです。
 *	- 0x0e00〜0x1000は、P/ECEカーネルが同期的に高速RAMルーチンを転送して使用するエリアです。
 *	  例えば、pceLCDTrans()やpceFileWriteSct()等が、このエリアに高速RAMルーチンを転送します。
 *	  同期的に使用されるため、これらのAPIによって0x0e00〜0x1000が破壊されることを留意しておけば、
 *	  アプリケーションプログラムがこの領域を使うことも可能です。
 *	- z80_run()の実装は、call使用回数が非常に多いため、スタックを高速RAMに移すことには意味があります。
 *	  z80_run2()はスタックを0x1000に移した後、z80_run()を呼び出し、スタックを元に戻して処理を返します。
 *	- スタックエリアは0x0e00〜0x1000の512バイトしかないので、z80_run2()の使用には条件があります。
 *	  ・z80_run()とそこから呼ばれる命令処理関数は、大きなスタックフレームを確保してはいけません。
 *	    各命令処理の実装を変更する場合は、注意してください。
 *	  ・z80_run()から呼ばれる外部関数(READ/WRITE/IN/OUT)では、大きなスタックフレームを確保してはいけません。
 *	  ・スタックをたくさん消費するような割り込みルーチンとの併用は不可です。
 *	    スタックが0x0e00〜0x1000に切り替わっているときに割り込みが発生すると、スタックがあふれる恐れがあるからです。
 *	  ・z80_run2()を割り込みルーチン内で呼び出してはいけません。
 *	    前面で、pceLCDTrans()が0x0e00〜0x1000エリアを使用中である可能性があるからです。
 *	- 以上のような制約があるので、z80_run2()の使用には充分な注意が必要です。
 *	  z80_run()を使った場合に較べて、z80_run2()を使った場合の効果は、(※未測定)の高速化となります。
 */
void z80_run2(Z80* z80, int cycle);
#endif /*PIECE*/

#ifdef  __cplusplus
}//extern "C"
#endif//__cplusplus

#endif /*__CLIP_Z80_H__*/
