/*	
 *	clipc17.h
 *
 *	P/ECE EPSON S1C17702 Emulator
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2001-2010 Naoyuki Sawa
 *
 *	* Fri Dec 25 00:36:52 JST 2009 Naoyuki Sawa
 *	- 作成開始。
 */
#ifndef __CLIP_C17_H__
#define __CLIP_C17_H__

/* S1C17_TRACEシンボルを定義すると、トレース出力を行います。 */
//#define S1C17_TRACE

/****************************************************************************
 *	内部使用
 ****************************************************************************/

/* プロセッサ状態 */
//#define S1C17_MODE_USER	0	/* ユーザーモード */
#define S1C17_MODE_DEBUG	1	/* デバッグモード */
#define S1C17_MODE_HALT		2	/* HALTモード */
#define S1C17_MODE_SLEEP	3	/* SLEEPモード */
extern unsigned char s1c17_mode;

/* エミュレータサイクルカウント用 */
extern int s1c17_cycle;

/* デバイス初期化テーブル */
extern void (* const s1c17_init_tbl[])();

/* デバイス実行テーブル (16384サイクル毎に呼び出す) */
extern void (* const s1c17_exec_tbl[])();

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

int s1c17_memget(int size, int ofs, const void* base);
void s1c17_memput(int size, int ofs, int data, void* base);

/****************************************************************************
 *	CPU
 ****************************************************************************/

/* 命令テーブル */
typedef struct _s1c17_op {
	unsigned short mask;	/* + 0,2: 命令コードのマスク部分が、 */
	unsigned short code;	/* + 2,2: この値に一致したら、 */
	void (*fn1)();		/* + 4,4: 命令デコード処理を呼び出す。 */
	void (*fn2)();		/* + 8,4: 命令デコード処理が、命令実行処理を呼び出す。 */
	struct _s1c17_op* next;	/* +12,4: 次のエントリへのリンク (NULL = 終端) */
#ifdef S1C17_TRACE
	const char* name;	/* トレース用ニーモニック */
#endif /*S1C17_TRACE*/
} s1c17_op;			/* =16 */
extern s1c17_op s1c17_op_tbl[];
extern s1c17_op* s1c17_op_root; /* 最初のエントリへのリンク */

/* %psr形式 */
typedef struct _s1c17_psr {
	unsigned char n :1;	/* Negative */
	unsigned char z :1;	/* Zero */
	unsigned char v :1;	/* oVerflow */
	unsigned char c :1;	/* Carry */
	unsigned char ie:1;	/* Interrupt Enable */
	unsigned char il:1;	/* Interrupt Level */
} s1c17_psr;

/* CPUコア */
typedef struct _S1C17_CPU {
	int r[8];		/* + 0,32: %r0 - %r7 (D[31:24] = 0) */
	s1c17_psr psr;		/* +32, 1: %psr */
	int sp;			/* +36, 4: %sp (D[1:0] = 0) */
	int pc;			/* +40, 4: %pc (D[31:24] = 0, D[0] = 0) */
	//
	short ext1;		/* +44, 2: 最新のext命令のimm13 (-1 = 無し) */
	short ext2;		/* +46, 2: 一つ前のext命令のimm13 (-1 = 無し) */
} S1C17_CPU;			/* =48 */
extern S1C17_CPU s1c17_cpu;

/* コプロセッサ(乗除算器) */
typedef struct _S1C17_COPROCESSOR {
	unsigned char operating_mode;	/* 動作モード */
	unsigned char output_mode;	/* 出力モード */
	unsigned char overflow_flag;	/* オーバーフローフラグ */
	int arithmetic_result;		/* 演算結果レジスタ */
} S1C17_COPROCESSOR;
extern S1C17_COPROCESSOR s1c17_coprocessor;

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

void s1c17_cpu_init();
void s1c17_cpu_exec(); /* 1命令実行 */

/* ext拡張の共通処理 */
int s1c17_0_imm13_imm24();
int s1c17_0_imm13_imm16();
int s1c17_rb_rb_imm13_rb_imm24(int* rb);
int s1c17_sp_sp_imm13_sp_imm24();
void s1c17_increment_rb_x_imm13_imm24(int* rb, int x);
void s1c17_decrement_rb_x_imm13_imm24(int* rb, int x);
void s1c17_increment_sp_4_imm13_imm24();
void s1c17_decrement_sp_4_imm13_imm24();
int s1c17_imm7_imm20_imm24(int imm7);
int s1c17_imm7_imm16(int imm7);
int s1c17_sp_imm7_sp_imm20_sp_imm24(int imm7);
int s1c17_sign7_sign16(int sign7);
int s1c17_sign11_sign24(int sign10);
int s1c17_sign8_sign21_sign24(int sign7);

/* 算術演算命令の共通処理 */
int s1c17_add(int x, int y);
int s1c17_adc(int x, int y);
int s1c17_sub(int x, int y);
int s1c17_sbc(int x, int y);

/* アドレス演算命令の共通処理 */
int s1c17_add_a(int x, int y);
int s1c17_sub_a(int x, int y);
void s1c17_cmp_a(int x, int y);

/* 論理演算命令の共通処理 */
int s1c17_and(int x, int y);
int s1c17_or(int x, int y);
int s1c17_xor(int x, int y);
int s1c17_not(int x);

/* 分岐命令の共通処理 */
void s1c17_jpa(int x, int d);
void s1c17_jpr(int x, int d);
void s1c17_calla(int x, int d);
void s1c17_call(int x, int d);
void s1c17_int(int no);

/* シフト命令の共通処理 */
int s1c17_sr(int x, int y);
int s1c17_sa(int x, int y);
int s1c17_sl(int x, int y);

/* コプロセッサ命令の共通処理 */
void s1c17_ld_cw(int x, int y);
int s1c17_ld_ca(int x, int y);
void s1c17_ld_cf(int x, int y);

/****************************************************************************
 *	メモリマップ、バス制御
 ****************************************************************************/

/* デバイステーブル */
typedef struct _s1c17_device {
	int top;					/* + 0,4: 開始アドレス (-1 = 終端) */
	int end;					/* + 4,4: 終了アドレス */
	int size;					/* + 8,4: デバイスサイズ (1 = 8ビット, 2 = 16ビット, 4 = 32ビット) */
	int (*read)(int size, int ofs);			/* +12,4: 読み出しハンドラ (NULL = 無し) */
	void (*write)(int size, int ofs, int data);	/* +16,4: 書き込みハンドラ (NULL = 無し) */
	struct _s1c17_device* next;			/* +20,4: 次のエントリへのリンク (NULL = 終端) */
} s1c17_device;						/* =24 */
extern s1c17_device s1c17_device_tbl[];
extern s1c17_device* s1c17_device_root; /* 最初のエントリへのリンク */

/* ダミーデバイス */
extern s1c17_device s1c17_device_dummy;

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

void s1c17_bcu_init();
int s1c17_bcu_read(int size, int addr);
void s1c17_bcu_write(int size, int addr, int data);
s1c17_device* s1c17_device_select(int size, int addr); /* デバイス検索 */

/****************************************************************************
 *	内蔵RAM (デバイスサイズ = 32ビット)
 ****************************************************************************/

/* 内蔵RAM */
typedef struct _S1C17_IRAM {
	unsigned char m[0x3000];	/* 12Kバイト */
} S1C17_IRAM;
extern S1C17_IRAM s1c17_iram;

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

void s1c17_iram_init();
int s1c17_iram_read(int size, int ofs);
void s1c17_iram_write(int size, int ofs, int data);

/****************************************************************************
 *	16ビットタイマ (デバイスサイズ = 16ビット)
 ****************************************************************************/

/* 16ビットタイマ */
typedef struct _S1C17_T16 {
	struct {
		struct {
			unsigned short df    : 4;
			unsigned short       :12;
		} clk;			/*0x42x0(T16_CLKx)*/
		unsigned short tr;	/*0x42x2(T16_TRx)*/
		unsigned short tc;	/*0x42x4(T16_TCx)*/
		struct {
			unsigned short prun  : 1;
			unsigned short preser: 1;
			unsigned short       : 2;
			unsigned short trmd  : 1;
			unsigned short       : 3;
			unsigned short cksl  : 2;
			unsigned short ckactv: 1;
			unsigned short       : 5;
		} ctl;			/*0x42x6(T16_CTLx)*/
		struct {
			unsigned short t16if : 1;
			unsigned short       : 7;
			unsigned short t16ie : 1;
			unsigned short       : 7;
		} Int;			/*0x42x8(T16_INTx)*/
	} t16[3];
} S1C17_T16;
extern S1C17_T16 s1c17_t16;

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

void s1c17_t16_init();
int s1c17_t16_0_read(int size, int ofs);
int s1c17_t16_1_read(int size, int ofs);
int s1c17_t16_2_read(int size, int ofs);
int s1c17_t16_read(int size, int ofs, int ch);
void s1c17_t16_0_write(int size, int ofs, int data);
void s1c17_t16_1_write(int size, int ofs, int data);
void s1c17_t16_2_write(int size, int ofs, int data);
void s1c17_t16_write(int size, int ofs, int data, int ch);
void s1c17_t16_exec(); /* 16384サイクル分実行 */

/****************************************************************************
 *	割り込みコントローラ (デバイスサイズ = 16ビット)
 ****************************************************************************/

/* 割り込みコントローラ */
typedef struct _S1C17_ITC {
	struct {
		unsigned short lv0;	/*0x4306(ITC_LV0)*/
		unsigned short lv1;	/*0x4308(ITC_LV1)*/
		unsigned short lv2;	/*0x430A(ITC_LV2)*/
		unsigned short lv3;	/*0x430C(ITC_LV3)*/
		unsigned short lv4;	/*0x430E(ITC_LV4)*/
		unsigned short lv5;	/*0x4310(ITC_LV5)*/
		unsigned short lv6;	/*0x4312(ITC_LV6)*/
		unsigned short lv7;	/*0x4314(ITC_LV7)*/
		unsigned short lv8;	/*0x4316(ITC_LV8)*/
	} itc;
} S1C17_ITC;
extern S1C17_ITC s1c17_itc;

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

void s1c17_itc_init();
int s1c17_itc_read(int size, int ofs);
void s1c17_itc_write(int size, int ofs, int data);
void s1c17_itc_irq(int no);

/****************************************************************************
 *	発振回路 (デバイスサイズ = 8ビット)
 ****************************************************************************/

/* 発振回路 */
typedef struct _S1C17_OSC {
	struct {
		struct {
			unsigned char clksrc   : 1;
			unsigned char hsclksel : 1;
			unsigned char          : 6;
		} src;		/*0x5060(OSC_SRC)*/
		struct {
			unsigned char osc3en   : 1;
			unsigned char osc1en   : 1;
			unsigned char ioscen   : 1;
			unsigned char          : 1;
			unsigned char osc3wt   : 2;
			unsigned char ioscwt   : 2;
		} ctl;		/*0x5061(OSC_CTL)*/
		struct {
			unsigned char nmife    : 1;
			unsigned char rstfe    : 1;
			unsigned char          : 6;
		} nfen;		/*0x5062(OSC_NFEN)*/
		struct {
			unsigned char lcken    : 1;
			unsigned char lcksrc   : 1;
			unsigned char lckdv    : 3;
			unsigned char          : 3;
		} lclk;		/*0x5063(OSC_LCLK)*/
		struct {
			unsigned char fout1e   : 1;
			unsigned char fouthe   : 1;
			unsigned char fouthd   : 2;
			unsigned char          : 4;
		} fout;		/*0x5064(OSC_FOUT)*/
		struct {
			unsigned char t8o1ce   : 1;
			unsigned char t8o1ck   : 3;
			unsigned char          : 4;
		} t8osc1;	/*0x5065(OSC_T8OSC1)*/
	} osc;
} S1C17_OSC;
extern S1C17_OSC s1c17_osc;

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

void s1c17_osc_init();
int s1c17_osc_read(int size, int ofs);
void s1c17_osc_write(int size, int ofs, int data);

/****************************************************************************
 *	LCDドライバ (デバイスサイズ = 8ビット)
 ****************************************************************************/

/* LCDドライバ */
typedef struct _S1C17_LCD {
	struct {
		struct {
			unsigned char dspc   : 2;
			unsigned char        : 2;
			unsigned char dsprev : 1;
			unsigned char dspar  : 1;
			unsigned char comrev : 1;
			unsigned char segrev : 1;
		} dctl;	/*0x50A0(LCD_DCTL)*/
		struct {
			unsigned char lc     : 4;
			unsigned char        : 4;
		} cadj;	/*0x50A1(LCD_CADJ)*/
		struct {
			unsigned char lduty  : 2;
			unsigned char        : 6;
		} cctl;	/*0x50A2(LCD_CCTL)*/
		struct {
			unsigned char        : 4;
			unsigned char lhvld  : 1;
			unsigned char        : 3;
		} vreg;	/*0x50A3(LCD_VREG)*/
		struct {
			unsigned char pbon   : 1;
			unsigned char vdsel  : 1;
			unsigned char        : 6;
		} pwr;	/*0x50A4(LCD_PWR)*/
		struct {
			unsigned char frmie  : 1;
			unsigned char        : 7;
		} msk;	/*0x50A5(LCD_IMSK)*/
		struct {
			unsigned char frmif  : 1;
			unsigned char        : 7;
		} iflg;	/*0x50A6(LCD_IFLG)*/
	} lcd;
	int frmi_cnt; /* フレーム割り込み処理用カウンタ */
} S1C17_LCD;
extern S1C17_LCD s1c17_lcd;

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

void s1c17_lcd_init();
int s1c17_lcd_read(int size, int ofs);
void s1c17_lcd_write(int size, int ofs, int data);
void s1c17_lcd_exec(); /* 16384サイクル分実行 */

/****************************************************************************
 *	Pポート (デバイスサイズ = 8ビット)
 ****************************************************************************/

/* Pポート */
typedef struct _S1C17_P {
	struct {
		unsigned char in;	/*0x52x0(Px_IN)*/
		unsigned char out;	/*0x52x1(Px_OUT)*/
		unsigned char oen;	/*0x52x2(Px_OEN)*/
		unsigned char pu;	/*0x52x3(Px_PU)*/
		unsigned char sm;	/*0x52x4(Px_SM)*/
		unsigned char imsk;	/*0x52x5(Px_IMSK)*/
		unsigned char edge;	/*0x52x6(Px_EDGE)*/
		unsigned char iflg;	/*0x52x7(Px_IFLG)*/
		unsigned char chat;	/*0x52x8(Px_CHAT)*/
		unsigned char krst;	/*0x52x9(Px_KRST)*/
		unsigned char ien;	/*0x52xA(Px_IEN)*/
	} p[4];
} S1C17_P;
extern S1C17_P s1c17_p;

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

void s1c17_p_init();
int s1c17_p_read(int size, int ofs);
void s1c17_p_write(int size, int ofs, int data);
void s1c17_p_exec();

/****************************************************************************
 *	MISCレジスタ (デバイスサイズ = 16ビット)
 ****************************************************************************/

/* MISCレジスタ */
typedef struct _S1C17_MISC {
	struct {
		unsigned short fl;	/*0x5320(MISC_FL)*/
		unsigned short osc1;	/*0x5322(MISC_OSC1)*/
		unsigned short prot;	/*0x5324(MISC_PROT)*/
		unsigned short iramsz;	/*0x5326(MISC_IRAMSZ)*/
		unsigned short ttbrl;	/*0x5328(MISC_TTBRL)*/
		unsigned short ttbrh;	/*0x532A(MISC_TTBRH)*/
		unsigned short psr;	/*0x532C(MISC_PSR)*/
	} misc;
} S1C17_MISC;
extern S1C17_MISC s1c17_misc;

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

void s1c17_misc_init();
int s1c17_misc_read(int size, int ofs);
void s1c17_misc_write(int size, int ofs, int data);

/****************************************************************************
 *	Flash (デバイスサイズ = 16ビット)
 ****************************************************************************/

/* Flash */
typedef struct _S1C17_FLASH {
	unsigned char m[0x20000];	/* 128Kバイト */
} S1C17_FLASH;
extern S1C17_FLASH s1c17_flash;

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

void s1c17_flash_init();
int s1c17_flash_read(int size, int ofs);
void s1c17_flash_write(int size, int ofs, int data);

/****************************************************************************
 *	表示RAM (デバイスサイズ = 8ビット)
 ****************************************************************************/

/* 表示RAM */
typedef struct _S1C17_SRAM {
	unsigned char m[6][0x60];	/* 576バイト */
} S1C17_SRAM;
extern S1C17_SRAM s1c17_sram;

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

void s1c17_sram_init();
int s1c17_sram_read(int size, int ofs);
void s1c17_sram_write(int size, int ofs, int data);

/****************************************************************************
 *	オンチップデバッガ
 ****************************************************************************/

/* オンチップデバッガ */
typedef struct _S1C17_DBG {
	struct {
		int ttbr;			/*0xFFFF80(TTBR)*/
		unsigned char idir;		/*0xFFFF84(IDIR)*/
		unsigned char reserved1[11];
		int dbram;			/*0xFFFF90(DBRAM)*/
		unsigned char reserved2[12];
		struct {
			unsigned char dm  : 1;	/* Debug Mode Bit */
			unsigned char se  : 1;	/* Single Step Enable Bit */
			unsigned char ibe0: 1;	/* Instruction Break #0 Enable Bit */
			unsigned char ibe1: 1;	/* Instruction Break #1 Enable Bit */
			unsigned char dr  : 1;	/* Debug Request Flag */
			unsigned char ibe2: 1;	/* Instruction Break #2 Enable Bit */
			unsigned char ibe3: 1;	/* Instruction Break #3 Enable Bit */
			unsigned char ibe4: 1;	/* Instruction Break #4 Enable Bit */
		} dcr;				/*0xFFFFA0(DCR)*/
		unsigned char reserved3[15];
		int IBAR0;			/*0xFFFFB0(IBAR0)*/
		int IBAR1;			/*0xFFFFB4(IBAR1)*/
		int IBAR2;			/*0xFFFFB8(IBAR2)*/
		int IBAR3;			/*0xFFFFBC(IBAR3)*/
		unsigned char ssr;		/*0xFFFFC0(SSR)*/
		unsigned char reserved4[1];
		unsigned char sdr;		/*0xFFFFC2(SDR)*/
		unsigned char reserved5[13];
		int IBAR4;			/*0xFFFFD0(IBAR4)*/
	} dbg;
} S1C17_DBG;
extern S1C17_DBG s1c17_dbg;

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

void s1c17_dbg_init();
int s1c17_dbg_read(int size, int ofs);
void s1c17_dbg_write(int size, int ofs, int data);

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

/* ■初期化手順
 * ①s1c17_flash_load()を呼び出して、フラッシュROMをロードする。
 * ②s1c17_init()を呼び出す。
 *   CPUの初期化がフラッシュROM上のベクタテーブルに依存しているので、①と②の順序は必須。
 * ③必要に応じてs1c17_port_get()を呼び出して、リセット直後の入力ポートの状態を設定する。
 *   s1c17_init()は入力ポート状態もクリアするので、③の後で②を行うと効果が消えてしまう。
 * ■実行手順
 * ①必要に応じてs1c17_port_set()を呼び出し、入力ポート状態を変更する。
 * ②s1c17_exec()を呼び出し、一定時間分のエミュレーションを実行する。
 *   たとえば1/30秒分ならば、引数には8000000/30を指定する。
 * ③必要に応じてs1c17_port_get()を呼び出し、出力ポート状態を取得する。
 * ④s1c17_lcd_image()を呼び出し、LCDイメージを取得する。
 *   イメージ形式は、PIECE_BMP,1bitマスク無しのバッファ形式に互換。
 * ⑤①に戻る。
 */

void s1c17_flash_load(int addr, const void* data, int size);
void s1c17_init();
void s1c17_exec(int cycle);
int s1c17_port_get(int port);
void s1c17_port_set(int port, int data);
int s1c17_lcd_image(unsigned char buff[/*32*/][72 / 8]);

#endif /*__CLIP_C17_H__*/
