/*	
 *	clipc16.h
 *
 *	P/ECE CP1610 Emulator
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2001-2005 Naoyuki Sawa
 *
 *	* Sun May 15 21:34:00 JST 2005 Naoyuki Sawa
 *	- 作成開始。
 *	* Wed Nov 18 21:37:53 JST 2015 Naoyuki Sawa
 *	- 'extern "C" {'〜'}'で囲みました。.cppを含むWin32プロジェクトからもインクルード出来るようにするためです。
 */
#ifndef __CLIP_C16_H__
#define __CLIP_C16_H__

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

/* --------------
 * CP1610について
 * --------------
 *
 * * "The CP1610 is a compatible member of the Series 1600 Microprocessor products family."
 *   [General Instrument CP1610データシートより]
 * - CP1610は、General Instrument社の1600マイクロプロセッサファミリに属する一品種です。
 *
 * * "The processor is a CP1610 (CP1600 with a low clock rate (read: cheaper!)) running at 894.886 Khz."
 *   [「BlueTech」さんのサイトの「Intellivision(http://www.tripoint.org/kevtris/intv/)」のページ より]
 * - 1600マイクロプロセッサファミリには、ファミリ名と同じCP1600という品種も存在するようです。
 *   CP1610はCP1600の低速版(!)であり、Intellivisionにおいては894.886KHzのクロックで駆動されています。
 *   894.886KHzは、NTSCカラーサブキャリアクロックの四分の一です。
 * - ただし、ここで言う894.886KHzとはマイクロサイクルのことであり、供給クロックはその二倍だと思います。
 *   CP1610データシートの命令表には、次のような記述があります。
 *   "1 MICROCYCLE = 2 CLOCK CYCLES"
 * - CP1610の資料や、既存のエミュレーションプログラムは、全てマイクロサイクル単位で記述されています。
 *   本プログラムもそれに倣い、マイクロサイクル単位で記述することにします。
 */

/****************************************************************************
 *	定数・構造体
 ****************************************************************************/

typedef struct _CP1610 {
	unsigned short r[8];	/* + 0,16: R0,R1,R2,R3,R4,R5,R6,R7 */
	int sz;			/* +16, 4: S------- -------- SZZZZZZZ ZZZZZZZZ */
	int c;			/* +20, 4: -------- -------C -------- -------- */
	unsigned short ov;	/* +24, 2:                   V------- -------- */
	//
	unsigned char flags;	/* +26, 1: 各種フラグ (CP1610_*の組合せ) */
	unsigned char ebc;	/* +27, 1: External Branch Condition (0..15) */
	unsigned short iab;	/* +28, 2: 割り込みベクタ ($0000..$FFFF) */
	//			/* +30, 2: (パディング) */
	int cycle;		/* +32, 4 */
} CP1610;			/* =36 */
#define SIZEOF_CP1610		    36

/* CP1610.flags */
#define CP1610_IRQ	(1<<0)	/* 割り込みが要求されたら1 */
#define CP1610_IFF	(1<<1)	/* 割り込み許可状態ならば1 */
#define CP1610_DBD	(1<<2)	/* SDBD命令実行直後ならば1 */
#define CP1610_HLT	(1<<3)	/* HLT中ならば1 */

/****************************************************************************
 *	グローバル変数
 ****************************************************************************/

extern CP1610 cp1610; /* P/ECEの場合は高速RAMに配置 -> framc16a.s */

typedef struct _CP1610OP {
	void (*fn)();			/* +0,4: 命令を処理する関数 */
	unsigned char cycle;		/* +4,1: 消費サイクル数 */
	unsigned char dst;		/* +5,1: 転送先レジスタ、分岐方向(0/-1) */
	unsigned char src;		/* +6,1: 転送元レジスタ、Condition Code */
	unsigned char ni;		/* +7,1: bit0=割り込みマスク命令ならば1 */
					/*       bit1=SDBD修飾可能な命令ならば1 */
} CP1610OP;				/* =8 */
extern const CP1610OP cp1610op[0x400];	/* 命令テーブル */

/* Condition Code -> 分岐有り(1)/無し(0)対応表 */
extern const unsigned short cp1610_cond[16/*Condition Code*/];

/****************************************************************************
 *	アプリケーション定義
 ****************************************************************************/

#ifndef PIECE
int cp1610_read(int addr);		/* メモリRead */
void cp1610_write(int addr, int data);	/* メモリWrite */
#else /*PIECE*/
/* %r10 cp1610_read(%r12); */		/* メモリRead */
/* void cp1610_write(%r12, %r13); */	/* メモリWrite */
#endif /*PIECE*/

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

/* CPUをリセットします。
 * [in]
 *	iab		IAB=リセットベクタ。($0000..$FFFF)
 *			Intellivisionの場合、$1000を指定してください。
 * [note]
 *	* IABは、Interrupt Address to Busの略です。
 *	  #MSYNC信号によるリセットを受け付けた後、リセットを要求したデバイスから、
 *	  データバスを介してプログラム開始アドレスを取得する、という仕様です。
 */
void cp1610_reset(int iab);

/* ステータスワード値を取得します。
 * [out]
 *	戻り値		ステータスワード値。(S|Z|V|C|0|0|0|0)
 */
#define cp1610_get_status cp1610_get_status_C /* アセンブラ内部関数との名前衝突回避 */
int cp1610_get_status();

/* ステータスワード値を設定します。
 * [in]
 *	status		ステータスワード値。(S|Z|V|C|-|-|-|-)
 */
#define cp1610_set_status cp1610_set_status_C /* アセンブラ内部関数との名前衝突回避 */
void cp1610_set_status(int status);

/* EBC(External Branch Condition)を設定します。
 * [in]
 *	ebc		EBC。(0..15)
 * [note]
 *	* BEXT命令の分岐条件として参照します。
 *	* 実際のCP1610プロセッサには、4bitのEBC入力端子があるわけではありません。
 *	  BEXTの条件に指定された4bitのEBCコードを、CP1610がEBCA0-3端子から*出力*します。
 *	  外部のデコーダ(74150)がEBCA0-3を解釈し、条件に一致したらEBCI信号で応答します。
 *	  CP1610は、EBCI信号の応答があった場合のみ、BEXTの分岐を実行する、という仕組みです。
 */
void cp1610_set_ebc(int ebc);

/* CPUを実行します。
 * [in]
 *	cycle		実行サイクル数。
 */
void cp1610_run(int cycle);

/* 割り込みを要求します。
 * [in]
 *	iab		IAB=割り込みベクタ。($0000..$FFFF)
 *			Intellivisionの場合、$1004を指定してください。
 * [note]
 *	* IABは、Interrupt Address to Busの略です。
 *	  #INTR信号による割り込みを受け付けた後、割り込みを要求したデバイスから、
 *	  データバスを介して割り込みルーチンアドレスを取得する、という仕様です。
 */
void cp1610_irq(int iab);

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

#endif /*__CLIP_C16_H__*/
