/*	
 *	clipc17.c
 *
 *	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
 *	- 作成開始。
 */
#include "clip.h"

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

/* プロセッサ状態 */
unsigned char s1c17_mode;

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

/* デバイス初期化テーブル */
void (* const s1c17_init_tbl[])() = {
	s1c17_bcu_init,
	s1c17_iram_init,
	s1c17_t16_init,
	s1c17_itc_init,
	s1c17_osc_init,
	s1c17_lcd_init,
	s1c17_p_init,
	s1c17_misc_init,
	s1c17_flash_init,
	s1c17_sram_init,
	s1c17_dbg_init,
	NULL, /* 終端 */
};

/* デバイス実行テーブル (16384サイクル毎に呼び出す) */
void (* const s1c17_exec_tbl[])() = {
	s1c17_t16_exec,
	s1c17_p_exec,
	s1c17_lcd_exec,
	NULL, /* 終端 */
};

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

#ifndef PIECE
int s1c17_memget(int size, int ofs, const void* base) {
	void* p = (char*)base + ofs;
	switch(size) {
	case 1:       return *(unsigned  char*)p;
	case 2:       return *(unsigned short*)p;
	default/*4*/: return *(           int*)p;
	}
}
void s1c17_memput(int size, int ofs, int data, void* base) {
	void* p = (char*)base + ofs;
	switch(size) {
	case 1:       *( char*)p = data; return;
	case 2:       *(short*)p = data; return;
	default/*4*/: *(  int*)p = data; return;
	}
}
#else /*PIECE*/
int s1c17_memget(int size, int ofs, const void* base);
void s1c17_memput(int size, int ofs, int data, void* base);
asm("
		.code
		.align		1
		.global		s1c17_memget
		.global		s1c17_memput
		;//-------------------------------------;//
s1c17_memget:
		add		%r13, %r14		;// %r13 := p = base + ofs
		cmp		%r12, 2
		jreq		s1c17_memget_HALF	;// if(size == 2) goto HALF
		jrgt		s1c17_memget_WORD	;// if(size >  2) goto WORD
;//s1c17_memget_BYTE:
		ld.ub		%r10, [%r13]		;// return *(unsigned  char*)p
		ret
s1c17_memget_HALF:
		ld.uh		%r10, [%r13]		;// return *(unsigned short*)p
		ret
s1c17_memget_WORD:
		ld.w		%r10, [%r13]		;// return *(           int*)p
		ret
		;//-------------------------------------;//
s1c17_memput:
		add		%r13, %r15		;// %r13 := p = base + ofs
		cmp		%r12, 2
		jreq		s1c17_memput_HALF	;// if(size == 2) goto HALF
		jrgt		s1c17_memput_WORD	;// if(size >  2) goto WORD
;//s1c17_memput_BYTE:
		ld.b		[%r13], %r14		;// *(unsigned  char*)p = data
		ret					;// return
s1c17_memput_HALF:
		ld.h		[%r13], %r14		;// *(unsigned short*)p = data
		ret					;// return
s1c17_memput_WORD:
		ld.w		[%r13], %r14		;// *(           int*)p = data
		ret					;// return
");
#endif /*PIECE*/

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

/* 命令デコード処理、命令実行処理のプロトタイプ */
#define S1C17_OP(mask,code,fn1,fn2,name) void fn1(), fn2();
#include "s1c17/op.h"
#undef S1C17_OP

/* 命令テーブル */
s1c17_op s1c17_op_tbl[] = {
#ifdef S1C17_TRACE
#define S1C17_OP(mask,code,fn1,fn2,name) {mask,code,fn1,fn2,NULL,name},
#else /*S1C17_TRACE*/
#define S1C17_OP(mask,code,fn1,fn2,name) {mask,code,fn1,fn2},
#endif /*S1C17_TRACE*/
#include "s1c17/op.h"
#undef S1C17_OP
};
s1c17_op* s1c17_op_root; /* 最初のエントリへのリンク */

/* CPUコア */
S1C17_CPU s1c17_cpu;

/* コプロセッサ(乗除算器) */
S1C17_COPROCESSOR s1c17_coprocessor;

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

void s1c17_cpu_init() {
	int i;

	/* 命令テーブルを初期化 */
	s1c17_op_root = &s1c17_op_tbl[0];
	for(i = 0; i < ARRAY_SIZE(s1c17_op_tbl) - 1; i++) {
		s1c17_op_tbl[i].next = &s1c17_op_tbl[i + 1];
	}
	s1c17_op_tbl[i].next = NULL; /* 終端 */

	/* CPUコアを初期化 */
	memset(&s1c17_cpu, 0, sizeof s1c17_cpu);
	s1c17_cpu.pc = s1c17_bcu_read(4, s1c17_bcu_read(4, 0xFFFF80/*TTBR*/));
	s1c17_cpu.pc = (unsigned)(s1c17_cpu.pc << 8) >> 8;
	s1c17_cpu.pc &= ~1;
	s1c17_cpu.ext1 = s1c17_cpu.ext2 = -1;

	/* コプロセッサ(乗除算器)を初期化 */
	memset(&s1c17_coprocessor, 0, sizeof s1c17_coprocessor);
}

/*--------------------------------------------------------------------------*/
/* 命令実行処理 */

/* ld.b %rd,%rs */
void s1c17_ld_b_rd_rs(int* rd, int* rs) {
	*rd = (unsigned short)(char)*rs;
}
/* ld.b %rd,[%rb] */
void s1c17_ld_b_rd_IrbI(int* rd, int* rb) {
	*rd = (unsigned short)(char)s1c17_bcu_read(1, s1c17_rb_rb_imm13_rb_imm24(rb));
}
/* ld.b %rd,[%rb]+ */
void s1c17_ld_b_rd_IrbIp(int* rd, int* rb) {
	*rd = (unsigned short)(char)s1c17_bcu_read(1, *rb);
	s1c17_increment_rb_x_imm13_imm24(rb, 1);
}
/* ld.b %rd,[%rb]- */
void s1c17_ld_b_rd_IrbIm(int* rd, int* rb) {
	*rd = (unsigned short)(char)s1c17_bcu_read(1, *rb);
	s1c17_decrement_rb_x_imm13_imm24(rb, 1);
}
/* ld.b %rd,-[%rb] */
void s1c17_ld_b_rd_mIrbI(int* rd, int* rb) {
	s1c17_decrement_rb_x_imm13_imm24(rb, 1);
	*rd = (unsigned short)(char)s1c17_bcu_read(1, *rb);
}
/* ld.b %rd,[%sp+imm7] */
void s1c17_ld_b_rd_Isp_imm7I(int* rd, int imm7) {
	*rd = (unsigned short)(char)s1c17_bcu_read(1, s1c17_sp_imm7_sp_imm20_sp_imm24(imm7));
}
/* ld.b %rd,[imm7] */
void s1c17_ld_b_rd_Iimm7I(int* rd, int imm7) {
	*rd = (unsigned short)(char)s1c17_bcu_read(1, s1c17_imm7_imm20_imm24(imm7));
}
/* ld.b [%rb],%rs */
void s1c17_ld_b_IrbI_rs(int* rs, int* rb) {
	s1c17_bcu_write(1, s1c17_rb_rb_imm13_rb_imm24(rb), *rs);
}
/* ld.b [%rb]+,%rs */
void s1c17_ld_b_IrbIp_rs(int* rs, int* rb) {
	s1c17_bcu_write(1, *rb, *rs);
	s1c17_increment_rb_x_imm13_imm24(rb, 1);
}
/* ld.b [%rb]-,%rs */
void s1c17_ld_b_IrbIm_rs(int* rs, int* rb) {
	s1c17_bcu_write(1, *rb, *rs);
	s1c17_decrement_rb_x_imm13_imm24(rb, 1);
}
/* ld.b -[%rb],%rs */
void s1c17_ld_b_mIrbI_rs(int* rs, int* rb) {
	s1c17_decrement_rb_x_imm13_imm24(rb, 1);
	s1c17_bcu_write(1, *rb, *rs);
}
/* ld.b [%sp+imm7],%rs */
void s1c17_ld_b_Isp_imm7I_rs(int* rs, int imm7) {
	s1c17_bcu_write(1, s1c17_sp_imm7_sp_imm20_sp_imm24(imm7), *rs);
}
/* ld.b [imm7],%rs */
void s1c17_ld_b_Iimm7I_rs(int* rs, int imm7) {
	s1c17_bcu_write(1, s1c17_imm7_imm20_imm24(imm7), *rs);
}
/* ld.ub %rd,%rs */
void s1c17_ld_ub_rd_rs(int* rd, int* rs) {
	*rd = (unsigned char)*rs;
}
/* ld.ub %rd,[%rb] */
void s1c17_ld_ub_rd_IrbI(int* rd, int* rb) {
	*rd = s1c17_bcu_read(1, s1c17_rb_rb_imm13_rb_imm24(rb));
}
/* ld.ub %rd,[%rb]+ */
void s1c17_ld_ub_rd_IrbIp(int* rd, int* rb) {
	*rd = s1c17_bcu_read(1, *rb);
	s1c17_increment_rb_x_imm13_imm24(rb, 1);
}
/* ld.ub %rd,[%rb]- */
void s1c17_ld_ub_rd_IrbIm(int* rd, int* rb) {
	*rd = s1c17_bcu_read(1, *rb);
	s1c17_decrement_rb_x_imm13_imm24(rb, 1);
}
/* ld.ub %rd,-[%rb] */
void s1c17_ld_ub_rd_mIrbI(int* rd, int* rb) {
	s1c17_decrement_rb_x_imm13_imm24(rb, 1);
	*rd = s1c17_bcu_read(1, *rb);
}
/* ld.ub %rd,[%sp+imm7] */
void s1c17_ld_ub_rd_Isp_imm7I(int* rd, int imm7) {
	*rd = s1c17_bcu_read(1, s1c17_sp_imm7_sp_imm20_sp_imm24(imm7));
}
/* ld.ub %rd,[imm7] */
void s1c17_ld_ub_rd_Iimm7I(int* rd, int imm7) {
	*rd = s1c17_bcu_read(1, s1c17_imm7_imm20_imm24(imm7));
}
/* ld %rd,%rs */
void s1c17_ld_rd_rs(int* rd, int* rs) {
	*rd = (unsigned short)*rs;
}
/* ld %rd,sign7 */
void s1c17_ld_rd_sign7(int* rd, int sign7) {
	*rd = (unsigned short)s1c17_sign7_sign16(sign7);
}
/* ld %rd,[%rb] */
void s1c17_ld_rd_IrbI(int* rd, int* rb) {
	*rd = s1c17_bcu_read(2, s1c17_rb_rb_imm13_rb_imm24(rb));
}
/* ld %rd,[%rb]+ */
void s1c17_ld_rd_IrbIp(int* rd, int* rb) {
	*rd = s1c17_bcu_read(2, *rb);
	s1c17_increment_rb_x_imm13_imm24(rb, 2);
}
/* ld %rd,[%rb]- */
void s1c17_ld_rd_IrbIm(int* rd, int* rb) {
	*rd = s1c17_bcu_read(2, *rb);
	s1c17_decrement_rb_x_imm13_imm24(rb, 2);
}
/* ld %rd,-[%rb] */
void s1c17_ld_rd_mIrbI(int* rd, int* rb) {
	s1c17_decrement_rb_x_imm13_imm24(rb, 2);
	*rd = s1c17_bcu_read(2, *rb);
}
/* ld %rd,[%sp+imm7] */
void s1c17_ld_rd_Isp_imm7I(int* rd, int imm7) {
	*rd = s1c17_bcu_read(2, s1c17_sp_imm7_sp_imm20_sp_imm24(imm7));
}
/* ld %rd,[imm7] */
void s1c17_ld_rd_Iimm7I(int* rd, int imm7) {
	*rd = s1c17_bcu_read(2, s1c17_imm7_imm20_imm24(imm7));
}
/* ld [%rb],%rs */
void s1c17_ld_IrbI_rs(int* rs, int* rb) {
	s1c17_bcu_write(2, s1c17_rb_rb_imm13_rb_imm24(rb), *rs);
}
/* ld [%rb]+,%rs */
void s1c17_ld_IrbIp_rs(int* rs, int* rb) {
	s1c17_bcu_write(2, *rb, *rs);
	s1c17_increment_rb_x_imm13_imm24(rb, 2);
}
/* ld [%rb]-,%rs */
void s1c17_ld_IrbIm_rs(int* rs, int* rb) {
	s1c17_bcu_write(2, *rb, *rs);
	s1c17_decrement_rb_x_imm13_imm24(rb, 2);
}
/* ld -[%rb],%rs */
void s1c17_ld_mIrbI_rs(int* rs, int* rb) {
	s1c17_decrement_rb_x_imm13_imm24(rb, 2);
	s1c17_bcu_write(2, *rb, *rs);
}
/* ld [%sp+imm7],%rs */
void s1c17_ld_Isp_imm7I_rs(int* rs, int imm7) {
	s1c17_bcu_write(2, s1c17_sp_imm7_sp_imm20_sp_imm24(imm7), *rs);
}
/* ld [imm7],%rs */
void s1c17_ld_Iimm7I_rs(int* rs, int imm7) {
	s1c17_bcu_write(2, s1c17_imm7_imm20_imm24(imm7), *rs);
}
/* ld.a %rd,%rs */
void s1c17_ld_a_rd_rs(int* rd, int* rs) {
	*rd = *rs;
}
/* ld.a %rd,imm7 */
void s1c17_ld_a_rd_imm7(int* rd, int imm7) {
	*rd = s1c17_imm7_imm20_imm24(imm7);
}
/* ld.a %rd,[%rb] */
void s1c17_ld_a_rd_IrbI(int* rd, int* rb) {
	*rd = s1c17_bcu_read(4, s1c17_rb_rb_imm13_rb_imm24(rb));
	*rd = (unsigned)(*rd << 8) >> 8;
}
/* ld.a %rd,[%rb]+ */
void s1c17_ld_a_rd_IrbIp(int* rd, int* rb) {
	*rd = s1c17_bcu_read(4, *rb);
	*rd = (unsigned)(*rd << 8) >> 8;
	s1c17_increment_rb_x_imm13_imm24(rb, 4);
}
/* ld.a %rd,[%rb]- */
void s1c17_ld_a_rd_IrbIm(int* rd, int* rb) {
	*rd = s1c17_bcu_read(4, *rb);
	*rd = (unsigned)(*rd << 8) >> 8;
	s1c17_decrement_rb_x_imm13_imm24(rb, 4);
}
/* ld.a %rd,-[%rb] */
void s1c17_ld_a_rd_mIrbI(int* rd, int* rb) {
	s1c17_decrement_rb_x_imm13_imm24(rb, 4);
	*rd = s1c17_bcu_read(4, *rb);
	*rd = (unsigned)(*rd << 8) >> 8;
}
/* ld.a %rd,[%sp+imm7] */
void s1c17_ld_a_rd_Isp_imm7I(int* rd, int imm7) {
	*rd = s1c17_bcu_read(4, s1c17_sp_imm7_sp_imm20_sp_imm24(imm7));
	*rd = (unsigned)(*rd << 8) >> 8;
}
/* ld.a %rd,[imm7] */
void s1c17_ld_a_rd_Iimm7I(int* rd, int imm7) {
	*rd = s1c17_bcu_read(4, s1c17_imm7_imm20_imm24(imm7));
	*rd = (unsigned)(*rd << 8) >> 8;
}
/* ld.a [%rb],%rs */
void s1c17_ld_a_IrbI_rs(int* rs, int* rb) {
	s1c17_bcu_write(4, s1c17_rb_rb_imm13_rb_imm24(rb), *rs);
}
/* ld.a [%rb]+,%rs */
void s1c17_ld_a_IrbIp_rs(int* rs, int* rb) {
	s1c17_bcu_write(4, *rb, *rs);
	s1c17_increment_rb_x_imm13_imm24(rb, 4);
}
/* ld.a [%rb]-,%rs */
void s1c17_ld_a_IrbIm_rs(int* rs, int* rb) {
	s1c17_bcu_write(4, *rb, *rs);
	s1c17_decrement_rb_x_imm13_imm24(rb, 4);
}
/* ld.a -[%rb],%rs */
void s1c17_ld_a_mIrbI_rs(int* rs, int* rb) {
	s1c17_decrement_rb_x_imm13_imm24(rb, 4);
	s1c17_bcu_write(4, *rb, *rs);
}
/* ld.a [%sp+imm7],%rs */
void s1c17_ld_a_Isp_imm7I_rs(int* rs, int imm7) {
	s1c17_bcu_write(4, s1c17_sp_imm7_sp_imm20_sp_imm24(imm7), *rs);
}
/* ld.a [imm7],%rs */
void s1c17_ld_a_Iimm7I_rs(int* rs, int imm7) {
	s1c17_bcu_write(4, s1c17_imm7_imm20_imm24(imm7), *rs);
}
/* ld.a %rd,%sp */
void s1c17_ld_a_rd_sp(int* rd) {
	*rd = s1c17_cpu.sp;
}
/* ld.a %rd,%pc */
void s1c17_ld_a_rd_pc(int* rd) {
	*rd = s1c17_cpu.pc;
}
/* ld.a %rd,[%sp] */
void s1c17_ld_a_rd_IspI(int* rd) {
	*rd = s1c17_bcu_read(4, s1c17_sp_sp_imm13_sp_imm24());
	*rd = (unsigned)(*rd << 8) >> 8;
}
/* ld.a %rd,[%sp]+ */
void s1c17_ld_a_rd_IspIp(int* rd) {
	*rd = s1c17_bcu_read(4, s1c17_cpu.sp);
	*rd = (unsigned)(*rd << 8) >> 8;
	s1c17_increment_sp_4_imm13_imm24();
}
/* ld.a %rd,[%sp]- */
void s1c17_ld_a_rd_IspIm(int* rd) {
	*rd = s1c17_bcu_read(4, s1c17_cpu.sp);
	*rd = (unsigned)(*rd << 8) >> 8;
	s1c17_decrement_sp_4_imm13_imm24();
}
/* ld.a %rd,-[%sp] */
void s1c17_ld_a_rd_mIspI(int* rd) {
	s1c17_decrement_sp_4_imm13_imm24();
	*rd = s1c17_bcu_read(4, s1c17_cpu.sp);
	*rd = (unsigned)(*rd << 8) >> 8;
}
/* ld.a [%sp],%rs */
void s1c17_ld_a_IspI_rs(int* rs) {
	s1c17_bcu_write(4, s1c17_sp_sp_imm13_sp_imm24(), *rs);
}
/* ld.a [%sp]+,%rs */
void s1c17_ld_a_IspIp_rs(int* rs) {
	s1c17_bcu_write(4, s1c17_cpu.sp, *rs);
	s1c17_increment_sp_4_imm13_imm24();
}
/* ld.a [%sp]-,%rs */
void s1c17_ld_a_IspIm_rs(int* rs) {
	s1c17_bcu_write(4, s1c17_cpu.sp, *rs);
	s1c17_decrement_sp_4_imm13_imm24();
}
/* ld.a -[%sp],%rs */
void s1c17_ld_a_mIspI_rs(int* rs) {
	s1c17_decrement_sp_4_imm13_imm24();
	s1c17_bcu_write(4, s1c17_cpu.sp, *rs);
}
/* ld.a %sp,%rs */
void s1c17_ld_a_sp_rs(int* rs) {
	s1c17_cpu.sp = *rs;
	s1c17_cpu.sp &= ~3;
}
/* ld.a %sp,imm7 */
void s1c17_ld_a_sp_imm7(int imm7) {
	s1c17_cpu.sp = s1c17_imm7_imm20_imm24(imm7);
	s1c17_cpu.sp &= ~3;
}
/* add %rd,%rs */
void s1c17_add_rd_rs(int* rd, int* rs) {
	if(s1c17_cpu.ext1 == -1) {
		*rd = s1c17_add(*rd, *rs);
	} else {
		*rd = s1c17_add(*rs, s1c17_0_imm13_imm16());
	}
}
/* add/c %rd,%rs */
void s1c17_add_c_rd_rs(int* rd, int* rs) {
	if(s1c17_cpu.psr.c) {
		s1c17_add_rd_rs(rd, rs);
		s1c17_cpu.psr.c = 1;
	}
}
/* add/nc %rd,%rs */
void s1c17_add_nc_rd_rs(int* rd, int* rs) {
	if(!s1c17_cpu.psr.c) {
		s1c17_add_rd_rs(rd, rs);
		s1c17_cpu.psr.c = 0;
	}
}
/* add %rd,imm7 */
void s1c17_add_rd_imm7(int* rd, int imm7) {
	*rd = s1c17_add(*rd, s1c17_imm7_imm16(imm7));
}
/* add.a %rd,%rs */
void s1c17_add_a_rd_rs(int* rd, int* rs) {
	if(s1c17_cpu.ext1 == -1) {
		*rd = s1c17_add_a(*rd, *rs);
	} else {
		*rd = s1c17_add_a(*rs, s1c17_0_imm13_imm24());
	}
}
/* add.a/c %rd,%rs */
void s1c17_add_a_c_rd_rs(int* rd, int* rs) {
	if(s1c17_cpu.psr.c) {
		s1c17_add_a_rd_rs(rd, rs);
	}
}
/* add.a/nc %rd,%rs */
void s1c17_add_a_nc_rd_rs(int* rd, int* rs) {
	if(!s1c17_cpu.psr.c) {
		s1c17_add_a_rd_rs(rd, rs);
	}
}
/* add.a %sp,%rs */
void s1c17_add_a_sp_rs(int* rs) {
	if(s1c17_cpu.ext1 == -1) {
		s1c17_cpu.sp = s1c17_add_a(s1c17_cpu.sp, *rs);
	} else {
		s1c17_cpu.sp = s1c17_add_a(*rs, s1c17_0_imm13_imm24());
	}
	s1c17_cpu.sp &= ~3;
}
/* add.a %rd,imm7 */
void s1c17_add_a_rd_imm7(int* rd, int imm7) {
	*rd = s1c17_add_a(*rd, s1c17_imm7_imm20_imm24(imm7));
}
/* add.a %sp,imm7 */
void s1c17_add_a_sp_imm7(int imm7) {
	s1c17_cpu.sp = s1c17_add_a(s1c17_cpu.sp, s1c17_imm7_imm20_imm24(imm7));
	s1c17_cpu.sp &= ~3;
}
/* adc %rd,%rs */
void s1c17_adc_rd_rs(int* rd, int* rs) {
	if(s1c17_cpu.ext1 == -1) {
		*rd = s1c17_adc(*rd, *rs);
	} else {
		*rd = s1c17_adc(*rs, s1c17_0_imm13_imm16());
	}
}
/* adc/c %rd,%rs */
void s1c17_adc_c_rd_rs(int* rd, int* rs) {
	if(s1c17_cpu.psr.c) {
		s1c17_adc_rd_rs(rd, rs);
		s1c17_cpu.psr.c = 1;
	}
}
/* adc/nc %rd,%rs */
void s1c17_adc_nc_rd_rs(int* rd, int* rs) {
	if(!s1c17_cpu.psr.c) {
		s1c17_adc_rd_rs(rd, rs);
		s1c17_cpu.psr.c = 0;
	}
}
/* adc %rd,imm7 */
void s1c17_adc_rd_imm7(int* rd, int imm7) {
	*rd = s1c17_adc(*rd, s1c17_imm7_imm16(imm7));
}
/* sub %rd,%rs */
void s1c17_sub_rd_rs(int* rd, int* rs) {
	if(s1c17_cpu.ext1 == -1) {
		*rd = s1c17_sub(*rd, *rs);
	} else {
		*rd = s1c17_sub(*rs, s1c17_0_imm13_imm16());
	}
}
/* sub/c %rd,%rs */
void s1c17_sub_c_rd_rs(int* rd, int* rs) {
	if(s1c17_cpu.psr.c) {
		s1c17_sub_rd_rs(rd, rs);
		s1c17_cpu.psr.c = 1;
	}
}
/* sub/nc %rd,%rs */
void s1c17_sub_nc_rd_rs(int* rd, int* rs) {
	if(!s1c17_cpu.psr.c) {
		s1c17_sub_rd_rs(rd, rs);
		s1c17_cpu.psr.c = 0;
	}
}
/* sub %rd,imm7 */
void s1c17_sub_rd_imm7(int* rd, int imm7) {
	*rd = s1c17_sub(*rd, s1c17_imm7_imm16(imm7));
}
/* sub.a %rd,%rs */
void s1c17_sub_a_rd_rs(int* rd, int* rs) {
	if(s1c17_cpu.ext1 == -1) {
		*rd = s1c17_sub_a(*rd, *rs);
	} else {
		*rd = s1c17_sub_a(*rs, s1c17_0_imm13_imm24());
	}
}
/* sub.a/c %rd,%rs */
void s1c17_sub_a_c_rd_rs(int* rd, int* rs) {
	if(s1c17_cpu.psr.c) {
		s1c17_sub_a_rd_rs(rd, rs);
	}
}
/* sub.a/nc %rd,%rs */
void s1c17_sub_a_nc_rd_rs(int* rd, int* rs) {
	if(!s1c17_cpu.psr.c) {
		s1c17_sub_a_rd_rs(rd, rs);
	}
}
/* sub.a %sp,%rs */
void s1c17_sub_a_sp_rs(int* rs) {
	if(s1c17_cpu.ext1 == -1) {
		s1c17_cpu.sp = s1c17_sub_a(s1c17_cpu.sp, *rs);
	} else {
		s1c17_cpu.sp = s1c17_sub_a(*rs, s1c17_0_imm13_imm24());
	}
	s1c17_cpu.sp &= ~3;
}
/* sub.a %rd,imm7 */
void s1c17_sub_a_rd_imm7(int* rd, int imm7) {
	*rd = s1c17_sub_a(*rd, s1c17_imm7_imm20_imm24(imm7));
}
/* sub.a %sp,imm7 */
void s1c17_sub_a_sp_imm7(int imm7) {
	s1c17_cpu.sp = s1c17_sub_a(s1c17_cpu.sp, s1c17_imm7_imm20_imm24(imm7));
	s1c17_cpu.sp &= ~3;
}
/* sbc %rd,%rs */
void s1c17_sbc_rd_rs(int* rd, int* rs) {
	if(s1c17_cpu.ext1 == -1) {
		*rd = s1c17_sbc(*rd, *rs);
	} else {
		*rd = s1c17_sbc(*rs, s1c17_0_imm13_imm16());
	}
}
/* sbc/c %rd,%rs */
void s1c17_sbc_c_rd_rs(int* rd, int* rs) {
	if(s1c17_cpu.psr.c) {
		s1c17_sbc_rd_rs(rd, rs);
		s1c17_cpu.psr.c = 1;
	}
}
/* sbc/nc %rd,%rs */
void s1c17_sbc_nc_rd_rs(int* rd, int* rs) {
	if(!s1c17_cpu.psr.c) {
		s1c17_sbc_rd_rs(rd, rs);
		s1c17_cpu.psr.c = 0;
	}
}
/* sbc %rd,imm7 */
void s1c17_sbc_rd_imm7(int* rd, int imm7) {
	*rd = s1c17_sbc(*rd, s1c17_imm7_imm16(imm7));
}
/* cmp %rd,%rs */
void s1c17_cmp_rd_rs(int* rd, int* rs) {
	if(s1c17_cpu.ext1 == -1) {
		s1c17_sub(*rd, *rs);
	} else {
		s1c17_sub(*rs, s1c17_0_imm13_imm16());
	}
}
/* cmp/c %rd,%rs */
void s1c17_cmp_c_rd_rs(int* rd, int* rs) {
	if(s1c17_cpu.psr.c) {
		s1c17_cmp_rd_rs(rd, rs);
		s1c17_cpu.psr.c = 1;
	}
}
/* cmp/nc %rd,%rs */
void s1c17_cmp_nc_rd_rs(int* rd, int* rs) {
	if(!s1c17_cpu.psr.c) {
		s1c17_cmp_rd_rs(rd, rs);
		s1c17_cpu.psr.c = 0;
	}
}
/* cmp %rd,sign7 */
void s1c17_cmp_rd_sign7(int* rd, int sign7) {
	s1c17_sub(*rd, s1c17_sign7_sign16(sign7));
}
/* cmp.a %rd,%rs */
void s1c17_cmp_a_rd_rs(int* rd, int* rs) {
	if(s1c17_cpu.ext1 == -1) {
		s1c17_cmp_a(*rd, *rs);
	} else {
		s1c17_cmp_a(*rs, s1c17_0_imm13_imm24());
	}
}
/* cmp.a/c %rd,%rs */
void s1c17_cmp_a_c_rd_rs(int* rd, int* rs) {
	if(s1c17_cpu.psr.c) {
		s1c17_cmp_a_rd_rs(rd, rs);
		s1c17_cpu.psr.c = 1;
	}
}
/* cmp.a/nc %rd,%rs */
void s1c17_cmp_a_nc_rd_rs(int* rd, int* rs) {
	if(!s1c17_cpu.psr.c) {
		s1c17_cmp_a_rd_rs(rd, rs);
		s1c17_cpu.psr.c = 0;
	}
}
/* cmp.a %rd,imm7 */
void s1c17_cmp_a_rd_imm7(int* rd, int imm7) {
	s1c17_cmp_a(*rd, s1c17_imm7_imm20_imm24(imm7));
}
/* cmc %rd,%rs */
void s1c17_cmc_rd_rs(int* rd, int* rs) {
	if(s1c17_cpu.ext1 == -1) {
		s1c17_sbc(*rd, *rs);
	} else {
		s1c17_sbc(*rs, s1c17_0_imm13_imm16());
	}
}
/* cmc/c %rd,%rs */
void s1c17_cmc_c_rd_rs(int* rd, int* rs) {
	if(s1c17_cpu.psr.c) {
		s1c17_cmc_rd_rs(rd, rs);
		s1c17_cpu.psr.c = 1;
	}
}
/* cmc/nc %rd,%rs */
void s1c17_cmc_nc_rd_rs(int* rd, int* rs) {
	if(!s1c17_cpu.psr.c) {
		s1c17_cmc_rd_rs(rd, rs);
		s1c17_cpu.psr.c = 0;
	}
}
/* cmc %rd,sign7 */
void s1c17_cmc_rd_sign7(int* rd, int sign7) {
	s1c17_sbc(*rd, s1c17_sign7_sign16(sign7));
}
/* and %rd,%rs */
void s1c17_and_rd_rs(int* rd, int* rs) {
	if(s1c17_cpu.ext1 == -1) {
		*rd = s1c17_and(*rd, *rs);
	} else {
		*rd = s1c17_and(*rs, s1c17_0_imm13_imm16());
	}
}
/* and/c %rd,%rs */
void s1c17_and_c_rd_rs(int* rd, int* rs) {
	if(s1c17_cpu.psr.c) {
		s1c17_and_rd_rs(rd, rs);
	}
}
/* and/nc %rd,%rs */
void s1c17_and_nc_rd_rs(int* rd, int* rs) {
	if(!s1c17_cpu.psr.c) {
		s1c17_and_rd_rs(rd, rs);
	}
}
/* and %rd,sign7 */
void s1c17_and_rd_sign7(int* rd, int sign7) {
	*rd = s1c17_and(*rd, s1c17_sign7_sign16(sign7));
}
/* or %rd,%rs */
void s1c17_or_rd_rs(int* rd, int* rs) {
	if(s1c17_cpu.ext1 == -1) {
		*rd = s1c17_or(*rd, *rs);
	} else {
		*rd = s1c17_or(*rs, s1c17_0_imm13_imm16());
	}
}
/* or/c %rd,%rs */
void s1c17_or_c_rd_rs(int* rd, int* rs) {
	if(s1c17_cpu.psr.c) {
		s1c17_or_rd_rs(rd, rs);
	}
}
/* or/nc %rd,%rs */
void s1c17_or_nc_rd_rs(int* rd, int* rs) {
	if(!s1c17_cpu.psr.c) {
		s1c17_or_rd_rs(rd, rs);
	}
}
/* or %rd,sign7 */
void s1c17_or_rd_sign7(int* rd, int sign7) {
	*rd = s1c17_or(*rd, s1c17_sign7_sign16(sign7));
}
/* xor %rd,%rs */
void s1c17_xor_rd_rs(int* rd, int* rs) {
	if(s1c17_cpu.ext1 == -1) {
		*rd = s1c17_xor(*rd, *rs);
	} else {
		*rd = s1c17_xor(*rs, s1c17_0_imm13_imm16());
	}
}
/* xor/c %rd,%rs */
void s1c17_xor_c_rd_rs(int* rd, int* rs) {
	if(s1c17_cpu.psr.c) {
		s1c17_xor_rd_rs(rd, rs);
	}
}
/* xor/nc %rd,%rs */
void s1c17_xor_nc_rd_rs(int* rd, int* rs) {
	if(!s1c17_cpu.psr.c) {
		s1c17_xor_rd_rs(rd, rs);
	}
}
/* xor %rd,sign7 */
void s1c17_xor_rd_sign7(int* rd, int sign7) {
	*rd = s1c17_xor(*rd, s1c17_sign7_sign16(sign7));
}
/* not %rd,%rs */
void s1c17_not_rd_rs(int* rd, int* rs) {
	if(s1c17_cpu.ext1 == -1) {
		*rd = s1c17_not(*rs);
	} else {
		*rd = s1c17_not(s1c17_0_imm13_imm16());
	}
}
/* not/c %rd,%rs */
void s1c17_not_c_rd_rs(int* rd, int* rs) {
	if(s1c17_cpu.psr.c) {
		s1c17_not_rd_rs(rd, rs);
	}
}
/* not/nc %rd,%rs */
void s1c17_not_nc_rd_rs(int* rd, int* rs) {
	if(!s1c17_cpu.psr.c) {
		s1c17_not_rd_rs(rd, rs);
	}
}
/* not %rd,sign7 */
void s1c17_not_rd_sign7(int* rd, int sign7) {
	*rd = s1c17_not(s1c17_sign7_sign16(sign7));
}
/* jpr(.d) sign10 */
void s1c17_jpr_sign10(int d, int sign10) {
	s1c17_jpr(s1c17_sign11_sign24(sign10), d);
}
/* jpr(.d) %rb */
void s1c17_jpr_rb(int d, int* rb) {
	s1c17_jpr(*rb, d);
}
/* jpa(.d) imm7 */
void s1c17_jpa_imm7(int d, int imm7) {
	s1c17_jpa(s1c17_imm7_imm20_imm24(imm7), d);
}
/* jpa(.d) %rb */
void s1c17_jpa_rb(int d, int* rb) {
	s1c17_jpa(*rb, d);
}
/* jrgt(.d) sign7 */
void s1c17_jrgt_sign7(int d, int sign7) {
	if(!(s1c17_cpu.psr.z | (s1c17_cpu.psr.n ^ s1c17_cpu.psr.v))) {
		s1c17_jpr(s1c17_sign8_sign21_sign24(sign7), d);
	}
}
/* jrge(.d) sign7 */
void s1c17_jrge_sign7(int d, int sign7) {
	if(!(s1c17_cpu.psr.n ^ s1c17_cpu.psr.v)) {
		s1c17_jpr(s1c17_sign8_sign21_sign24(sign7), d);
	}
}
/* jrlt(.d) sign7 */
void s1c17_jrlt_sign7(int d, int sign7) {
	if(s1c17_cpu.psr.n ^ s1c17_cpu.psr.v) {
		s1c17_jpr(s1c17_sign8_sign21_sign24(sign7), d);
	}
}
/* jrle(.d) sign7 */
void s1c17_jrle_sign7(int d, int sign7) {
	if(s1c17_cpu.psr.z | (s1c17_cpu.psr.n ^ s1c17_cpu.psr.v)) {
		s1c17_jpr(s1c17_sign8_sign21_sign24(sign7), d);
	}
}
/* jrugt(.d) sign7 */
void s1c17_jrugt_sign7(int d, int sign7) {
	if(!(s1c17_cpu.psr.z | s1c17_cpu.psr.c)) {
		s1c17_jpr(s1c17_sign8_sign21_sign24(sign7), d);
	}
}
/* jruge(.d) sign7 */
void s1c17_jruge_sign7(int d, int sign7) {
	if(!s1c17_cpu.psr.c) {
		s1c17_jpr(s1c17_sign8_sign21_sign24(sign7), d);
	}
}
/* jrult(.d) sign7 */
void s1c17_jrult_sign7(int d, int sign7) {
	if(s1c17_cpu.psr.c) {
		s1c17_jpr(s1c17_sign8_sign21_sign24(sign7), d);
	}
}
/* jrule(.d) sign7 */
void s1c17_jrule_sign7(int d, int sign7) {
	if(s1c17_cpu.psr.z | s1c17_cpu.psr.c) {
		s1c17_jpr(s1c17_sign8_sign21_sign24(sign7), d);
	}
}
/* jreq(.d) sign7 */
void s1c17_jreq_sign7(int d, int sign7) {
	if(s1c17_cpu.psr.z) {
		s1c17_jpr(s1c17_sign8_sign21_sign24(sign7), d);
	}
}
/* jrne(.d) sign7 */
void s1c17_jrne_sign7(int d, int sign7) {
	if(!s1c17_cpu.psr.z) {
		s1c17_jpr(s1c17_sign8_sign21_sign24(sign7), d);
	}
}
/* call(.d) sign10 */
void s1c17_call_sign10(int d, int sign10) {
	s1c17_call(s1c17_sign11_sign24(sign10), d);
}
/* call(.d) %rb */
void s1c17_call_rb(int d, int* rb) {
	s1c17_call(*rb, d);
}
/* calla(.d) imm7 */
void s1c17_calla_imm7(int d, int imm7) {
	s1c17_calla(s1c17_imm7_imm20_imm24(imm7), d);
}
/* calla(.d) %rb */
void s1c17_calla_rb(int d, int* rb) {
	s1c17_calla(*rb, d);
}
/* ret(.d)  */
void s1c17_ret(int d) {
	s1c17_psr psr = s1c17_cpu.psr;
	s1c17_reti(d);
	s1c17_cpu.psr = psr;
}
/* int imm5 */
void s1c17_int_imm5(int imm5) {
	s1c17_int(imm5);
}
/* intl imm5,imm3 */
void s1c17_intl_imm5_imm3(int imm3, int imm5) {
	s1c17_int(imm5);
	s1c17_cpu.psr.il = imm3;
}
/* reti(.d)  */
void s1c17_reti(int d) {
	int x = s1c17_bcu_read(4, s1c17_cpu.sp);
	s1c17_cpu.sp += 4;
	if(d) {
		s1c17_cpu.ext1 = s1c17_cpu.ext2 = -1; /* 分岐命令に対するextが遅延スロットに影響しないよう消す。s1c17_ext_imm13()がextを消す前にここへ来るため必要 */
		s1c17_cpu_exec();
	}
	s1c17_cpu.pc = (unsigned)(x << 8) >> 8;
	s1c17_cpu.pc &= ~1;
	*(unsigned char*)&s1c17_cpu.psr = x >> 24;
}
/* brk  */
void s1c17_brk() {
	int dbram = s1c17_bcu_read(4, 0xFFFF90/*DBRAM*/);
	s1c17_bcu_write(4, dbram + 0, s1c17_cpu.pc | (*(unsigned char*)&s1c17_cpu.psr << 24));
	s1c17_bcu_write(4, dbram + 4, s1c17_cpu.r[0]);
	s1c17_cpu.pc = (s1c17_bcu_read(2, 0x5326/*MISC_IRAMSZ*/) & 0x100/*DBADR*/) ? 0x0 : 0xFFFC00;
	s1c17_cpu.psr.ie = 0;
}
/* retd  */
void s1c17_retd() {
	int dbram = s1c17_bcu_read(4, 0xFFFF90/*DBRAM*/);
	int x = s1c17_bcu_read(4, dbram + 0);
	s1c17_cpu.pc = (unsigned)(x << 8) >> 8;
	s1c17_cpu.pc &= ~1;
	*(unsigned char*)&s1c17_cpu.psr = x >> 24;
	s1c17_cpu.r[0] = s1c17_bcu_read(4, dbram + 4);
	s1c17_cpu.r[0] = (unsigned)(s1c17_cpu.r[0] << 8) >> 8;
}
/* ext imm13 */
void s1c17_ext_imm13(int imm13) {
	s1c17_cpu.ext2 = s1c17_cpu.ext1;
	s1c17_cpu.ext1 = imm13;
	s1c17_cpu_exec();
	s1c17_cpu.ext1 = s1c17_cpu.ext2 = -1; /* このextの効果を消す。後続の命令がjreqやadd/cなどの場合、extを使用しない場合があるので、ここでまとめて消すのが確実 */
}
/* sr %rd,%rs */
void s1c17_sr_rd_rs(int* rd, int* rs) {
	*rd = s1c17_sr(*rd, *rs);
}
/* sr %rd,imm7 */
void s1c17_sr_rd_imm7(int* rd, int imm7) {
	*rd = s1c17_sr(*rd, s1c17_imm7_imm20_imm24(imm7));
}
/* sa %rd,%rs */
void s1c17_sa_rd_rs(int* rd, int* rs) {
	*rd = s1c17_sa(*rd, *rs);
}
/* sa %rd,imm7 */
void s1c17_sa_rd_imm7(int* rd, int imm7) {
	*rd = s1c17_sa(*rd, s1c17_imm7_imm20_imm24(imm7));
}
/* sl %rd,%rs */
void s1c17_sl_rd_rs(int* rd, int* rs) {
	*rd = s1c17_sl(*rd, *rs);
}
/* sl %rd,imm7 */
void s1c17_sl_rd_imm7(int* rd, int imm7) {
	*rd = s1c17_sl(*rd, s1c17_imm7_imm20_imm24(imm7));
}
/* swap %rd,%rs */
void s1c17_swap_rd_rs(int* rd, int* rs) {
	*rd = (((unsigned char*)rs)[0] << 8) | (((unsigned char*)rs)[1] >> 8);
}
/* cv.ab %rd,%rs */
void s1c17_cv_ab_rd_rs(int* rd, int* rs) {
	*rd = (char)*rs;
}
/* cv.as %rd,%rs */
void s1c17_cv_as_rd_rs(int* rd, int* rs) {
	*rd = (short)*rs;
}
/* cv.al %rd,%rs */
void s1c17_cv_al_rd_rs(int* rd, int* rs) {
	*rd = (unsigned short)*rd | (*rs << 16);
}
/* cv.la %rd,%rs */
void s1c17_cv_la_rd_rs(int* rd, int* rs) {
	*rd = *rs >> 16;
}
/* cv.ls %rd,%rs */
void s1c17_cv_ls_rd_rs(int* rd, int* rs) {
	*rd = (unsigned)(short)*rs >> 16;
}
/* nop  */
void s1c17_nop() {
	/** no job **/
}
/* halt  */
void s1c17_halt() {
	if(!s1c17_mode) { /* デバッグモードからの遷移を防止 */
		s1c17_mode = S1C17_MODE_HALT;
	}
}
/* slp  */
void s1c17_slp() {
	if(!s1c17_mode) { /* デバッグモードからの遷移を防止 */
		s1c17_mode = S1C17_MODE_SLEEP;
	}
}
/* ei  */
void s1c17_ei() {
	s1c17_cpu.psr.ie = 1;
}
/* di  */
void s1c17_di() {
	s1c17_cpu.psr.ie = 0;
}
/* ld.cw %rd,%rs */
void s1c17_ld_cw_rd_rs(int* rd, int* rs) {
	s1c17_ld_cw(*rd, *rs);
}
/* ld.cw %rd,imm7 */
void s1c17_ld_cw_rd_imm7(int* rd, int imm7) {
	s1c17_ld_cw(*rd, s1c17_imm7_imm20_imm24(imm7));
}
/* ld.ca %rd,%rs */
void s1c17_ld_ca_rd_rs(int* rd, int* rs) {
	*rd = s1c17_ld_ca(*rd, *rs);
}
/* ld.ca %rd,imm7 */
void s1c17_ld_ca_rd_imm7(int* rd, int imm7) {
	*rd = s1c17_ld_ca(*rd, s1c17_imm7_imm20_imm24(imm7));
}
/* ld.cf %rd,%rs */
void s1c17_ld_cf_rd_rs(int* rd, int* rs) {
	s1c17_ld_cf(*rd, *rs);
}
/* ld.cf %rd,imm7 */
void s1c17_ld_cf_rd_imm7(int* rd, int imm7) {
	s1c17_ld_cf(*rd, s1c17_imm7_imm20_imm24(imm7));
}

/*--------------------------------------------------------------------------*/
/* コプロセッサ命令の共通処理 */

void s1c17_ld_cw(int x, int y) {
	s1c17_coprocessor.operating_mode = y & 15;
	s1c17_coprocessor.output_mode = (y >> 4) & 7;
	if(!s1c17_coprocessor.operating_mode) {
		/* Initialization mode 0 */
		s1c17_coprocessor.arithmetic_result = 0;
	}
}
int s1c17_ld_ca(int x, int y) {
	if(s1c17_coprocessor.operating_mode != 3) {
		s1c17_coprocessor.overflow_flag = 0;
	}
	if(s1c17_coprocessor.operating_mode & 1) {
		x = (short)x;
		y = (short)y;
	} else {
		x = (unsigned short)x;
		y = (unsigned short)y;
	}
	switch(s1c17_coprocessor.operating_mode) {
	//case 0: /* Initialization mode 0 */
	//case 1: /* Initialization mode 1 */
	//case 2: /* Initialization mode 2 */
	//case 3: /* Arithmetic results reading mode */
	case 4: /* Unsigned multiplication mode */
	case 5: /* Signed multiplication mode */
		s1c17_coprocessor.arithmetic_result = x * y;
		break;
	case 7: /* Signed product-sum operation mode */
		x *= y;
		     y = s1c17_coprocessor.arithmetic_result;
		         s1c17_coprocessor.arithmetic_result += x;
		s1c17_coprocessor.overflow_flag = (~(x ^ y) & (x ^ s1c17_coprocessor.arithmetic_result)) < 0;
		break;
	case 8: /* Unsigned division mode */
	case 9: /* Signed division mode */
		if(y) {
			((short*)&s1c17_coprocessor.arithmetic_result)[0] = x / y;
			((short*)&s1c17_coprocessor.arithmetic_result)[1] = x % y;
		} else {
			((short*)&s1c17_coprocessor.arithmetic_result)[0] = -1;
			((short*)&s1c17_coprocessor.arithmetic_result)[1] = x;
		}
		break;
	}
	s1c17_cpu.psr.n = 0;
	s1c17_cpu.psr.z = 0;
	s1c17_cpu.psr.v = s1c17_coprocessor.overflow_flag;
	s1c17_cpu.psr.c = 0;
	if(!s1c17_coprocessor.output_mode) {
		/* Last 16-bit output mode */
		return ((unsigned short*)&s1c17_coprocessor.arithmetic_result)[0];
	} else {
		/* First 16-bit output mode */
		return ((unsigned short*)&s1c17_coprocessor.arithmetic_result)[1];
	}
}
void s1c17_ld_cf(int x, int y) {
	if(s1c17_coprocessor.operating_mode != 3) {
		s1c17_coprocessor.overflow_flag = 0;
	}
	switch(s1c17_coprocessor.operating_mode) {
	case 1: /* Initialization mode 1 */
		((short*)&s1c17_coprocessor.arithmetic_result)[0] = y;
		((short*)&s1c17_coprocessor.arithmetic_result)[1] = 0;
		break;
	case 2: /* Initialization mode 2 */
		((short*)&s1c17_coprocessor.arithmetic_result)[0] = y;
		((short*)&s1c17_coprocessor.arithmetic_result)[1] = x;
		break;
	}
	s1c17_cpu.psr.n = 0;
	s1c17_cpu.psr.z = 0;
	s1c17_cpu.psr.v = s1c17_coprocessor.overflow_flag;
	s1c17_cpu.psr.c = 0;
}

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

/* デバイステーブル */
s1c17_device s1c17_device_tbl[] = {
	/* 内蔵RAMエリア */
	{0x000000,0x002FFF,4,s1c17_iram_read  ,s1c17_iram_write  },
	/* 内蔵周辺回路エリア1 */
//	{0x004000,0x00401F},						//reserved
//	{0x004020,0x00403F,1,s1c17_psc_read   ,s1c17_psc_write   },	//プリスケーラ
//	{0x004040,0x0040FF},						//reserved
//	{0x004100,0x00413F,1,s1c17_uart_read  ,s1c17_uart_write  },	//UART
//	{0x004140,0x0041FF},						//reserved
//	{0x004200,0x00421F,2,s1c17_t8f_0_read ,s1c17_t8f_0_write },	//8ビットタイマ Ch.0
	{0x004220,0x00423F,2,s1c17_t16_0_read ,s1c17_t16_0_write },	//16ビットタイマ Ch.0
	{0x004240,0x00425F,2,s1c17_t16_1_read ,s1c17_t16_1_write },	//16ビットタイマ Ch.1
	{0x004260,0x00427F,2,s1c17_t16_2_read ,s1c17_t16_2_write },	//16ビットタイマ Ch.2
//	{0x004280,0x00429F,2,s1c17_t8f_1_read ,s1c17_t8f_1_write },	//8ビットタイマ Ch.1
//	{0x0042A0,0x0042FF},						//reserved
	{0x004300,0x00431F,2,s1c17_itc_read   ,s1c17_itc_write   },	//割り込みコントローラ
//	{0x004320,0x00433F,2,s1c17_spi_read   ,s1c17_spi_write   },	//SPI
//	{0x004340,0x00435F,2,s1c17_i2c_read   ,s1c17_i2c_write   },	//I2C
//	{0x004360,0x0043FF},						//reserved
	/* 内蔵周辺回路エリア2 */
//	{0x005000,0x00501F,1,s1c17_ct_read    ,s1c17_ct_write    },	//計時タイマ
//	{0x005020,0x00503F,1,s1c17_swt_read   ,s1c17_swt_write   },	//ストップウォッチタイマ
//	{0x005040,0x00505F,1,s1c17_wdt_read   ,s1c17_wdt_write   },	//ウォッチドッグタイマ
	{0x005060,0x00507F,1,s1c17_osc_read   ,s1c17_osc_write   },	//発振回路
//	{0x005080,0x00509F,1,s1c17_clg_read   ,s1c17_clg_write   },	//クロックジェネレータ
	{0x0050A0,0x0050BF,1,s1c17_lcd_read   ,s1c17_lcd_write   },	//LCDドライバ
//	{0x0050C0,0x0050DF,1,s1c17_t8osc1_read,s1c17_t8osc1_write},	//8ビットOSC1タイマ
//	{0x0050E0,0x0050FF},						//reserved
//	{0x005100,0x00511F,1,s1c17_svd_read   ,s1c17_svd_write   },	//SVD回路
//	{0x005120,0x00513F,1,s1c17_vd1_read   ,s1c17_vd1_write   },	//電源制御回路
//	{0x005140,0x0051FF},						//reserved
	{0x005200,0x00527F,1,s1c17_p_read     ,s1c17_p_write     },	//Pポート
//	{0x005280,0x00529F},						//reserved
//	{0x0052A0,0x0052BF,1,s1c17_pmux_read  ,s1c17_pmux_write  },	//ポートMUX
//	{0x0052C0,0x0052FF},						//reserved
//	{0x005300,0x00531F,2,s1c17_t16e_0_read,s1c17_t16e_0_write},	//PWM&キャプチャタイマ Ch.0
	{0x005320,0x00533F,2,s1c17_misc_read  ,s1c17_misc_write  },	//MISCレジスタ
//	{0x005340,0x00535F,2,s1c17_remc_read  ,s1c17_remc_write  },	//リモートコントローラ
//	{0x005360,0x00537F,2,s1c17_t16e_1_read,s1c17_t16e_1_write},	//PWM&キャプチャタイマ Ch.1
//	{0x005380,0x005FFF},						//reserved
	/* Flashエリア */
	{0x008000,0x027FFF,2,s1c17_flash_read ,s1c17_flash_write },
	/* 表\示RAMエリア */
	{0x080000,0x08055F,1,s1c17_sram_read  ,s1c17_sram_write  },
	/* コアI/O予\約エリア */
//	{0xFFFC00,0xFFFF7F},						//ミニモニタ
	{0xFFFF80,0xFFFFFF,4,s1c17_dbg_read   ,s1c17_dbg_write   },	//オンチップデバッガ
};
s1c17_device* s1c17_device_root; /* 最初のエントリへのリンク */

/* ダミーデバイス */
static int s1c17_dummy_read(int size, int ofs) { return 0; }
static void s1c17_dummy_write(int size, int ofs, int data) { /** no job **/ }
s1c17_device s1c17_device_dummy = {0,0,4,s1c17_dummy_read,s1c17_dummy_write};

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

void s1c17_bcu_init() {
	int i;
	/* デバイステーブルを初期化 */
	s1c17_device_root = &s1c17_device_tbl[0];
	for(i = 0; i < ARRAY_SIZE(s1c17_device_tbl) - 1; i++) {
		s1c17_device_tbl[i].next = &s1c17_device_tbl[i + 1];
	}
	s1c17_device_tbl[i].next = NULL; /* 終端 */
}

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

/* 内蔵RAM */
S1C17_IRAM s1c17_iram;

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

void s1c17_iram_init() {
	memset(&s1c17_iram, 0, sizeof s1c17_iram);
}

#ifndef PIECE
int s1c17_iram_read(int size, int ofs) {
	return s1c17_memget(size, ofs, s1c17_iram.m);
}
void s1c17_iram_write(int size, int ofs, int data) {
	s1c17_memput(size, ofs, data, s1c17_iram.m);
}
#else /*PIECE*/
int s1c17_iram_read(int size, int ofs);
void s1c17_iram_write(int size, int ofs, int data);
asm("
		.code
		.align		1
		.global		s1c17_iram_read
		.global		s1c17_iram_write
		;//-------------------------------------;//
s1c17_iram_read:
		Xld.w		%r14, s1c17_iram
		Xjp		s1c17_memget
		;//-------------------------------------;//
s1c17_iram_write:
		Xld.w		%r15, s1c17_iram
		Xjp		s1c17_memput
");
#endif /*PIECE*/

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

/* 16ビットタイマ */
S1C17_T16 s1c17_t16;

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

void s1c17_t16_init() {
	static const unsigned char init[] = {
		0x00,0x00,	/*0x42x0(T16_CLKx)*/
		0x00,0x00,	/*0x42x2(T16_TRx)*/
		0xFF,0xFF,	/*0x42x4(T16_TCx)*/
		0x00,0x04,	/*0x42x6(T16_CTLx)*/
		0x00,0x00,	/*0x42x8(T16_INTx)*/
	};
	if(sizeof s1c17_t16.t16[0] != sizeof init) {
		DIE();
	}
	memset(&s1c17_t16, 0, sizeof s1c17_t16);
	memcpy(&s1c17_t16.t16[0], init, sizeof init);
	memcpy(&s1c17_t16.t16[1], init, sizeof init);
	memcpy(&s1c17_t16.t16[2], init, sizeof init);
}
int s1c17_t16_0_read(int size, int ofs) {
	return s1c17_t16_read(size, ofs, 0);
}
int s1c17_t16_1_read(int size, int ofs) {
	return s1c17_t16_read(size, ofs, 1);
}
int s1c17_t16_2_read(int size, int ofs) {
	return s1c17_t16_read(size, ofs, 2);
}
int s1c17_t16_read(int size, int ofs, int ch) {
	int data = 0;
	if(ofs < sizeof s1c17_t16.t16[0]) {
//		switch(ofs & ~1) {
//		case 0x00:/*0x42x0(T16_CLKx)*/
//		case 0x02:/*0x42x2(T16_TRx)*/
//		case 0x04:/*0x42x4(T16_TCx)*/
//		case 0x06:/*0x42x6(T16_CTLx)*/
//		case 0x08:/*0x42x8(T16_INTx)*/
//		}
		memcpy(&data, &((unsigned char*)&s1c17_t16.t16[ch])[ofs], size);
	}
	return data;
}
void s1c17_t16_0_write(int size, int ofs, int data) {
	s1c17_t16_write(size, ofs, data, 0);
}
void s1c17_t16_1_write(int size, int ofs, int data) {
	s1c17_t16_write(size, ofs, data, 1);
}
void s1c17_t16_2_write(int size, int ofs, int data) {
	s1c17_t16_write(size, ofs, data, 2);
}
void s1c17_t16_write(int size, int ofs, int data, int ch) {
	if(ofs < sizeof s1c17_t16.t16) {
		if(ofs == 0x08/*0x42x8(T16_INTx)*/) {
			if(data & 1/*T16IF*/) {
				s1c17_t16.t16[ch].Int.t16if = 0; /* Reset by writing 1 */
				data &= ~1/*T16IF*/;
			}
		}
		memcpy(&((unsigned char*)&s1c17_t16.t16[ch])[ofs], &data, size);
		switch(ofs & ~1) {
//		case 0x00:/*0x42x0(T16_CLKx)*/
//		case 0x02:/*0x42x2(T16_TRx)*/
//		case 0x04:/*0x42x4(T16_TCx)*/
		case 0x06:/*0x42x6(T16_CTLx)*/
			if(s1c17_t16.t16[ch].ctl.preser) {
				s1c17_t16.t16[ch].tc = s1c17_t16.t16[ch].tr;
				s1c17_t16.t16[ch].ctl.preser = 0; /* 0 when being read */
			}
			break;
//		case 0x08:/*0x42x8(T16_INTx)*/
		}
	}
}
void s1c17_t16_exec() { /* 16384サイクル分実行 */
	int ch;
	for(ch = 0; ch < 3; ch++) {
		if(s1c17_t16.t16[ch].ctl.prun) {
			int x = 16384 >> s1c17_t16.t16[ch].clk.df;
			if(s1c17_t16.t16[ch].tc >= x) {
				s1c17_t16.t16[ch].tc -= x;
			} else {
				if(s1c17_t16.t16[ch].ctl.trmd) { /* One shot */
					s1c17_t16.t16[ch].tc = s1c17_t16.t16[ch].tr; /* One shotの場合もプリセットする。(S1C17702テクニカルマニュアル「11.3 カウントモード」参照) */
					s1c17_t16.t16[ch].ctl.prun = 0;
				} else { /* Repeat */
					do {
						x -= s1c17_t16.t16[ch].tc + 1;
						s1c17_t16.t16[ch].tc = s1c17_t16.t16[ch].tr;
					} while(s1c17_t16.t16[ch].tc < x); /* 16384サイクル中に複数回アンダーフローした場合のために繰り返し検査。まとめて一回の割り込みとして扱う */
					s1c17_t16.t16[ch].tc -= x;
				}
				if(s1c17_t16.t16[ch].Int.t16ie) {
					s1c17_t16.t16[ch].Int.t16if = 1;
				}
			}
		}
		if(s1c17_t16.t16[ch].Int.t16if) {
			s1c17_itc_irq(13 + ch);
		}
	}
}

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

/* 割り込みコントローラ */
S1C17_ITC s1c17_itc;

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

void s1c17_itc_init() {
	static const unsigned char init[] = {
		0x00,0x00,	/*0x4306(ITC_LV0)*/
		0x00,0x00,	/*0x4308(ITC_LV1)*/
		0x00,0x00,	/*0x430A(ITC_LV2)*/
		0x00,0x00,	/*0x430C(ITC_LV3)*/
		0x00,0x00,	/*0x430E(ITC_LV4)*/
		0x00,0x00,	/*0x4310(ITC_LV5)*/
		0x00,0x00,	/*0x4312(ITC_LV6)*/
		0x00,0x00,	/*0x4314(ITC_LV7)*/
		0x00,0x00,	/*0x4316(ITC_LV8)*/
	};
	if(sizeof s1c17_itc.itc != sizeof init) {
		DIE();
	}
	memset(&s1c17_itc, 0, sizeof s1c17_itc);
	memcpy(&s1c17_itc.itc, init, sizeof init);
}
int s1c17_itc_read(int size, int ofs) {
	int data = 0;
	ofs -= 0x06;/*0x4306(ITC_LV0)*/
	if((unsigned)ofs < sizeof s1c17_itc.itc) {
		memcpy(&data, &((unsigned char*)&s1c17_itc.itc)[ofs], size);
	}
	return data;
}
void s1c17_itc_write(int size, int ofs, int data) {
	ofs -= 0x06;/*0x4306(ITC_LV0)*/
	if((unsigned)ofs < sizeof s1c17_itc.itc) {
		memcpy(&((unsigned char*)&s1c17_itc.itc)[ofs], &data, size);
	}
}
void s1c17_itc_irq(int no) {
	if(s1c17_mode != S1C17_MODE_DEBUG) { /* デバッグモード中は、ハードウェア割り込み、NMIを受け付けない */
		int lv = s1c17_cpu.psr.il; /* NMIだった場合のために、初期値を現在の割り込みレベルとしておく */
		if(no >= 4) { /* マスク可能\割り込み */
			if(no <= 21) { /* ハードウェア割り込み */
				lv = ((unsigned char*)&s1c17_itc.itc)[no - 4] & 7;
				/* このハードウェア割り込みを受け付けるかどうかに関係無く、HALT、SLEEPモードを解除する */
				s1c17_mode = 0;
			}
			if(!s1c17_cpu.psr.ie || (lv <= s1c17_cpu.psr.il)) {
				return; /* ここまで */
			}
		}
		s1c17_int(no);
		s1c17_cpu.psr.il = lv; /* 受け付けた割り込みのレベルにセット(NMIは割り込みレベルを変更しない) */
	}
}

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

/* 発振回路 */
S1C17_OSC s1c17_osc;

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

void s1c17_osc_init() {
	static const unsigned char init[] = {
		0x00,	/*0x5060(OSC_SRC)*/
		0x04,	/*0x5061(OSC_CTL)*/
		0x02,	/*0x5062(OSC_NFEN)*/
		0x02,	/*0x5063(OSC_LCLK)*/
		0x00,	/*0x5064(OSC_FOUT)*/
		0x00,	/*0x5065(OSC_T8OSC1)*/
	};
	if(sizeof s1c17_osc.osc != sizeof init) {
		DIE();
	}
	memset(&s1c17_osc, 0, sizeof s1c17_osc);
	memcpy(&s1c17_osc.osc, init, sizeof init);
}
int s1c17_osc_read(int size, int ofs) {
	int data = 0;
	if((unsigned)ofs < sizeof s1c17_osc.osc) {
//		switch(ofs) {
//		case 0x00:/*0x5060(OSC_SRC)*/
//		case 0x01:/*0x5061(OSC_CTL)*/
//		case 0x02:/*0x5062(OSC_NFEN)*/
//		case 0x03:/*0x5063(OSC_LCLK)*/
//		case 0x04:/*0x5064(OSC_FOUT)*/
//		case 0x05:/*0x5065(OSC_T8OSC1)*/
//		}
		memcpy(&data, &((unsigned char*)&s1c17_osc.osc)[ofs], size);
	}
	return data;
}
void s1c17_osc_write(int size, int ofs, int data) {
	if((unsigned)ofs < sizeof s1c17_osc.osc) {
		memcpy(&((unsigned char*)&s1c17_osc.osc)[ofs], &data, size);
//		switch(ofs) {
//		case 0x00:/*0x5060(OSC_SRC)*/
//		case 0x01:/*0x5061(OSC_CTL)*/
//		case 0x02:/*0x5062(OSC_NFEN)*/
//		case 0x03:/*0x5063(OSC_LCLK)*/
//		case 0x04:/*0x5064(OSC_FOUT)*/
//		case 0x05:/*0x5065(OSC_T8OSC1)*/
//		}
	}
}

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

/* LCDドライバ */
S1C17_LCD s1c17_lcd;

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

void s1c17_lcd_init() {
	static const unsigned char init[] = {
		0xD0,	/*0x50A0(LCD_DCTL)*/
		0x00,	/*0x50A1(LCD_CADJ)*/
		0x02,	/*0x50A2(LCD_CCTL)*/
		0x00,	/*0x50A3(LCD_VREG)*/
		0x00,	/*0x50A4(LCD_PWR)*/
		0x00,	/*0x50A5(LCD_IMSK)*/
		0x00,	/*0x50A6(LCD_IFLG)*/
	};
	if(sizeof s1c17_lcd.lcd != sizeof init) {
		DIE();
	}
	memset(&s1c17_lcd, 0, sizeof s1c17_lcd);
	memcpy(&s1c17_lcd.lcd, init, sizeof init);
}
int s1c17_lcd_read(int size, int ofs) {
	int data = 0;
	if((unsigned)ofs < sizeof s1c17_lcd.lcd) {
//		switch(ofs) {
//		case 0x00:/*0x50A0(LCD_DCTL)*/
//		case 0x01:/*0x50A1(LCD_CADJ)*/
//		case 0x02:/*0x50A2(LCD_CCTL)*/
//		case 0x03:/*0x50A3(LCD_VREG)*/
//		case 0x04:/*0x50A4(LCD_PWR)*/
//		case 0x05:/*0x50A5(LCD_IMSK)*/
//		case 0x06:/*0x50A6(LCD_IFLG)*/
//		}
		memcpy(&data, &((unsigned char*)&s1c17_lcd.lcd)[ofs], size);
	}
	return data;
}
void s1c17_lcd_write(int size, int ofs, int data) {
	if((unsigned)ofs < sizeof s1c17_lcd.lcd) {
		if(ofs == 0x06/*0x50A6(LCD_IFLG)*/) {
			if(data & 1/*FRMIF*/) {
				s1c17_lcd.lcd.iflg.frmif = 0; /* Reset by writing 1 */
				data &= ~1/*FRMIF*/;
			}
		}
		memcpy(&((unsigned char*)&s1c17_lcd.lcd)[ofs], &data, size);
//		switch(ofs) {
//		case 0x00:/*0x50A0(LCD_DCTL)*/
//		case 0x01:/*0x50A1(LCD_CADJ)*/
//		case 0x02:/*0x50A2(LCD_CCTL)*/
//		case 0x03:/*0x50A3(LCD_VREG)*/
//		case 0x04:/*0x50A4(LCD_PWR)*/
//		case 0x05:/*0x50A5(LCD_IMSK)*/
//		case 0x06:/*0x50A6(LCD_IFLG)*/
//		}
	}
}
void s1c17_lcd_exec() { /* 16384サイクル分実行 */
	/* フレーム割り込み */
	if(s1c17_osc.osc.lclk.lcken && s1c17_lcd.lcd.msk.frmie) {
		/* フレーム周波数 = fHSCLK / 512 * LCKDV [Hz] (S1C17702テクニカルマニュアル「22.3 LCDクロック」参照)
		 *                = fHSCLK / 512 * (1 / (32 << s1c17_osc.osc.lclk.lckdv))
		 *                = fHSCLK / (16384 << s1c17_osc.osc.lclk.lckdv)
		 * 本関数は16384サイクル毎に呼び出されるので、(1<<s1c17_osc.osc.lclk.lckdv)回毎にフレーム割り込みを生成すれば良い。
		 */
		int x = 1 << s1c17_osc.osc.lclk.lckdv;
		s1c17_lcd.frmi_cnt++;
		while(s1c17_lcd.frmi_cnt >= x) {
			s1c17_lcd.frmi_cnt -= x;
			s1c17_lcd.lcd.iflg.frmif = 1;
		}
	}
	if(s1c17_lcd.lcd.iflg.frmif) {
		s1c17_itc_irq(10);
	}
}

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

/* Pポート */
S1C17_P s1c17_p;

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

void s1c17_p_init() {
	static const unsigned char init[] = {
		0xFF,	/*0x52x0(Px_IN)*/
		0x00,	/*0x52x1(Px_OUT)*/
		0x00,	/*0x52x2(Px_OEN)*/
		0xFF,	/*0x52x3(Px_PU)*/
		0xFF,	/*0x52x4(Px_SM)*/
		0x00,	/*0x52x5(Px_IMSK)*/
		0x00,	/*0x52x6(Px_EDGE)*/
		0x00,	/*0x52x7(Px_IFLG)*/
		0x00,	/*0x52x8(Px_CHAT)*/
		0x00,	/*0x52x9(Px_KRST)*/
		0xFF,	/*0x52xA(Px_IEN)*/
	};
	if(sizeof s1c17_p.p[0] != sizeof init) {
		DIE();
	}
	memset(&s1c17_p, 0, sizeof s1c17_p);
	memcpy(&s1c17_p.p[0], init, sizeof init);
	memcpy(&s1c17_p.p[1], init, sizeof init);
	memcpy(&s1c17_p.p[2], init, sizeof init);
	memcpy(&s1c17_p.p[3], init, sizeof init);
}
int s1c17_p_read(int size, int ofs) {
	int data = 0;
	int port = ofs >> 4;
	ofs &= 0x0F;
	if((port < 4) && (ofs < sizeof s1c17_p.p[0])) {
//		switch(ofs) {
//		case 0x00:/*0x52x0(Px_IN)*/
//		case 0x01:/*0x52x1(Px_OUT)*/
//		case 0x02:/*0x52x2(Px_OEN)*/
//		case 0x03:/*0x52x3(Px_PU)*/
//		case 0x04:/*0x52x4(Px_SM)*/
//		case 0x05:/*0x52x5(Px_IMSK)*/
//		case 0x06:/*0x52x6(Px_EDGE)*/
//		case 0x07:/*0x52x7(Px_IFLG)*/
//		case 0x08:/*0x52x8(Px_CHAT)*/
//		case 0x09:/*0x52x9(Px_KRST)*/
//		case 0x0A:/*0x52xA(Px_IEN)*/
//		}
		data = ((unsigned char*)&s1c17_p.p[port])[ofs];
	}
	return data;
}
void s1c17_p_write(int size, int ofs, int data) {
	int port = ofs >> 4;
	ofs &= 0x0F;
	if((port < 4) && (ofs < sizeof s1c17_p.p[0])) {
		if(ofs == 0x07/*0x52x7(Px_IFLG)*/) {
			s1c17_p.p[port].iflg &= ~data; /* Reset by writing 1 */
		} else {
			((unsigned char*)&s1c17_p.p[port])[ofs] = data;
		}
//		switch(ofs) {
//		case 0x00:/*0x52x0(Px_IN)*/
//		case 0x01:/*0x52x1(Px_OUT)*/
//		case 0x02:/*0x52x2(Px_OEN)*/
//		case 0x03:/*0x52x3(Px_PU)*/
//		case 0x04:/*0x52x4(Px_SM)*/
//		case 0x05:/*0x52x5(Px_IMSK)*/
//		case 0x06:/*0x52x6(Px_EDGE)*/
//		case 0x07:/*0x52x7(Px_IFLG)*/
//		case 0x08:/*0x52x8(Px_CHAT)*/
//		case 0x09:/*0x52x9(Px_KRST)*/
//		case 0x0A:/*0x52xA(Px_IEN)*/
//		}
	}
}
void s1c17_p_exec() {
	if(s1c17_p.p[0].iflg) {
		s1c17_itc_irq(4);
	}
	if(s1c17_p.p[1].iflg) {
		s1c17_itc_irq(5);
	}
}

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

/* MISCレジスタ */
S1C17_MISC s1c17_misc;

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

void s1c17_misc_init() {
	static const unsigned char init[] = {
		0x03,0x03,	/*0x5320(MISC_FL)*/
		0x00,0x00,	/*0x5322(MISC_OSC1)*/
		0x00,0x00,	/*0x5324(MISC_PROT)*/
		0x00,0x00,	/*0x5326(MISC_IRAMSZ)*/
		0x00,0x80,	/*0x5328(MISC_TTBRL)*/
		0x00,0x00,	/*0x532A(MISC_TTBRH)*/
		0x00,0x00,	/*0x532C(MISC_PSR)*/
	};
	if(sizeof s1c17_misc.misc != sizeof init) {
		DIE();
	}
	memset(&s1c17_misc, 0, sizeof s1c17_misc);
	memcpy(&s1c17_misc.misc, init, sizeof init);
}
int s1c17_misc_read(int size, int ofs) {
	int data = 0;
	if(ofs < sizeof s1c17_misc.misc) {
		switch(ofs & ~1) {
//		case 0x00:/*0x5320(MISC_FL)*/
//		case 0x02:/*0x5322(MISC_OSC1)*/
//		case 0x04:/*0x5324(MISC_PROT)*/
//		case 0x06:/*0x5326(MISC_IRAMSZ)*/
//		case 0x08:/*0x5328(MISC_TTBRL)*/
//		case 0x0A:/*0x532A(MISC_TTBRH)*/
		case 0x0C:/*0x532C(MISC_PSR)*/
			s1c17_misc.misc.psr = *(unsigned char*)&s1c17_cpu.psr;
			break;
		}
		memcpy(&data, &((unsigned char*)&s1c17_misc.misc)[ofs], size);
	}
	return data;
}
void s1c17_misc_write(int size, int ofs, int data) {
	if(ofs < sizeof s1c17_misc.misc) {
		memcpy(&((unsigned char*)&s1c17_misc.misc)[ofs], &data, size);
//		switch(ofs & ~1) {
//		case 0x00:/*0x5320(MISC_FL)*/
//		case 0x02:/*0x5322(MISC_OSC1)*/
//		case 0x04:/*0x5324(MISC_PROT)*/
//		case 0x06:/*0x5326(MISC_IRAMSZ)*/
//		case 0x08:/*0x5328(MISC_TTBRL)*/
//		case 0x0A:/*0x532A(MISC_TTBRH)*/
//		case 0x0C:/*0x532C(MISC_PSR)*/
//		}
	}
}

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

/* Flash */
S1C17_FLASH s1c17_flash;

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

void s1c17_flash_init() {
	/* ※TODO:フラッシュ書き換えのシーケンスのみ初期化せよ。フラッシュの内容はリセット前にロードしているので、クリアするな */
}

#ifndef PIECE
int s1c17_flash_read(int size, int ofs) {
	return s1c17_memget(size, ofs, s1c17_flash.m);
}
#else /*PIECE*/
int s1c17_flash_read(int size, int ofs);
asm("
		.code
		.align		1
		.global		s1c17_flash_read
s1c17_flash_read:
		Xld.w		%r14, s1c17_flash
		Xjp		s1c17_memget
");
#endif /*PIECE*/

void s1c17_flash_write(int size, int ofs, int data) {
	/* ※TODO:フラッシュ書き換えのシーケンスに対応せよ */
}

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

/* 表\示RAM */
S1C17_SRAM s1c17_sram;

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

void s1c17_sram_init() {
	memset(&s1c17_sram, 0, sizeof s1c17_sram);
}

#ifndef PIECE
int s1c17_sram_read(int size, int ofs) {
	int data = 0;
	if((unsigned char)ofs < 0x60) {
		data = s1c17_sram.m[ofs >> 8][(unsigned char)ofs];
	}
	return data;
}
void s1c17_sram_write(int size, int ofs, int data) {
	if((unsigned char)ofs < 0x60) {
		s1c17_sram.m[ofs >> 8][(unsigned char)ofs] = data;
	}
}
#else /*PIECE*/
int s1c17_sram_read(int size, int ofs);
void s1c17_sram_write(int size, int ofs, int data);
asm("
		.code
		.align		1
		.global		s1c17_sram_read
		.global		s1c17_sram_write
		;//-------------------------------------;//
s1c17_sram_read:
		ld.ub		%r4, %r13			;// %r4  := (unsigned char)ofs
		Xld.w		%r5, 0x60			;// %r5  := 0x60
		cmp		%r4, %r5			;// if((unsigned char)ofs >= 0x60)
		jrge		s1c17_sram_read_RET_0		;//   return 0
		sra		%r13, 8				;// %r13 :=  ofs >> 8
		mlt.h		%r13, %r5			;// %alr := (ofs >> 8) * 0x60
		ld.w		%r13, %alr			;// %r13 := (ofs >> 8) * 0x60
		add		%r13, %r4			;// %r13 := (ofs >> 8) * 0x60 + (unsigned char)ofs
		ext		s1c17_sram@ah
		ext		s1c17_sram@al
		ld.b		%r10, [%r13]			;// %r10 := data = s1c17_sram.m[ofs >> 8][(unsigned char)ofs]
		ret						;// return data
s1c17_sram_read_RET_0:
		ret.d						;// return 0
		ld.w		%r10, 0				;// %r10 := 0	*delay*
		;//-------------------------------------;//
s1c17_sram_write:
		ld.ub		%r4, %r13			;// %r4  := (unsigned char)ofs
		Xld.w		%r5, 0x60			;// %r5  := 0x60
		cmp		%r4, %r5			;// if((unsigned char)ofs >= 0x60)
		jrge		s1c17_sram_write_RET		;//   return
		sra		%r13, 8				;// %r13 :=  ofs >> 8
		mlt.h		%r13, %r5			;// %alr := (ofs >> 8) * 0x60
		ld.w		%r13, %alr			;// %r13 := (ofs >> 8) * 0x60
		add		%r13, %r4			;// %r13 := (ofs >> 8) * 0x60 + (unsigned char)ofs
		ext		s1c17_sram@ah
		ext		s1c17_sram@al
		ld.b		[%r13], %r14			;// s1c17_sram.m[ofs >> 8][(unsigned char)ofs] := data
s1c17_sram_write_RET:
		ret
");
#endif /*PIECE*/

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

/* オンチップデバッガ */
S1C17_DBG s1c17_dbg;

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

void s1c17_dbg_init() {
	static const unsigned char init[] = {
		0x00,0x80,0x00,0x00,	/*0xFFFF80(TTBR)*/
		0x10,			/*0xFFFF84(IDIR)*/
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0xC0,0x2F,0x00,0x00,	/*0xFFFF90(DBRAM)*/
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,			/*0xFFFFA0(DCR)*/
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,	/*0xFFFFB0(IBAR0)*/
		0x00,0x00,0x00,0x00,	/*0xFFFFB4(IBAR1)*/
		0x00,0x00,0x00,0x00,	/*0xFFFFB8(IBAR2)*/
		0x00,0x00,0x00,0x00,	/*0xFFFFBC(IBAR3)*/
		0x06,			/*0xFFFFC0(SSR)*/
		0x00,
		0x00,			/*0xFFFFC2(SDR)*/
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,	/*0xFFFFD0(IBAR4)*/
	};
	if(sizeof s1c17_dbg.dbg != sizeof init) {
		DIE();
	}
	memset(&s1c17_dbg, 0, sizeof s1c17_dbg);
	memcpy(&s1c17_dbg.dbg, init, sizeof init);
}
int s1c17_dbg_read(int size, int ofs) {
	int data = 0;
	if(ofs < sizeof s1c17_dbg.dbg) {
		switch(ofs & ~3) {
		case 0x00:/*0xFFFF80(TTBR)*/
			s1c17_dbg.dbg.ttbr = s1c17_bcu_read(size, 0x5328/*dbg_TTBRL,dbg_TTBRH*/ + (ofs & 3));
			break;
//		case 0x04:/*0xFFFF84(IDIR)*/
//		case 0x10:/*0xFFFF90(DBRAM)*/
		case 0x20:/*0xFFFFA0(DCR)*/
			s1c17_dbg.dbg.dcr.dm = (s1c17_mode == S1C17_MODE_DEBUG);
			break;
//		case 0x30:/*0xFFFFB0(IBAR0)*/
//		case 0x34:/*0xFFFFB4(IBAR1)*/
//		case 0x38:/*0xFFFFB8(IBAR2)*/
//		case 0x3C:/*0xFFFFBC(IBAR3)*/
//		case 0x40:/*0xFFFFC0(SSR)*/
//		case 0x42:/*0xFFFFC2(SDR)*/
//		case 0x50:/*0xFFFFD0(IBAR4)*/
		}
		memcpy(&data, &((unsigned char*)&s1c17_dbg.dbg)[ofs], size);
	}
	return data;
}
void s1c17_dbg_write(int size, int ofs, int data) {
	if(ofs < sizeof s1c17_dbg.dbg) {
		if(ofs == 0x20/*0xFFFFA0(DCR)*/) {
			if(data & 0x10/*DR*/) {
				s1c17_dbg.dbg.dcr.dr = 0; /* Reset by writing 1 */
				data &= ~0x10/*DR*/;
			}
		}
		memcpy(&((unsigned char*)&s1c17_dbg.dbg)[ofs], &data, size);
//		switch(ofs & ~3) {
//		case 0x00:/*0xFFFF80(TTBR)*/
//		case 0x04:/*0xFFFF84(IDIR)*/
//		case 0x10:/*0xFFFF90(DBRAM)*/
//		case 0x20:/*0xFFFFA0(DCR)*/
//		case 0x30:/*0xFFFFB0(IBAR0)*/
//		case 0x34:/*0xFFFFB4(IBAR1)*/
//		case 0x38:/*0xFFFFB8(IBAR2)*/
//		case 0x3C:/*0xFFFFBC(IBAR3)*/
//		case 0x40:/*0xFFFFC0(SSR)*/
//		case 0x42:/*0xFFFFC2(SDR)*/
//		case 0x50:/*0xFFFFD0(IBAR4)*/
//		}
	}
}

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

void
s1c17_flash_load(int addr, const void* data, int size)
{
	if((addr < 0x008000) || (addr + size > 0x028000)) {
		DIE();
	}
	memcpy(&s1c17_flash.m[addr - 0x008000], data, size);
}

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

void
s1c17_init()
{
	void (* const *pfn)() = s1c17_init_tbl;

	s1c17_mode = 0;
	s1c17_cycle = 0;

	/* デバイス初期化 */
	while(*pfn) {
		(*pfn++)();
	}

	/* CPU初期化 */
	s1c17_cpu_init(); /* 他に依存しているので、最後に初期化する */
}

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

void
s1c17_exec(int cycle)
{
	int i;

#ifdef DEBUG
	for(i = 0; i < 8; i++) {
		if(s1c17_cpu.r[i] & ~0xFFFFFF) DIE();
	}
	if(s1c17_cpu.pc & ~0xFFFFFE) DIE();
	if(s1c17_cpu.sp & ~0xFFFFFC) DIE();
#endif /*DEBUG*/

	/* - 16384サイクル分の周辺回路を実行した後、16384サイクル分のCPUを実行することにしました。
	 *   1サイクルづつ実行すると、周辺回路の実行関数呼び出しオーバーヘッドが大きすぎるためです。(特にT16)
	 * - 16384サイクルとした理由は、プリスケーラクロックの最大分周で、処理の都合が良いためです。
	 *   8MHzクロックの場合、約1/500秒に相当し、充分短い間隔だと思います。
	 */
	s1c17_cycle += cycle;
	if(s1c17_cycle >= 0) {
		do {
			/* デバイス実行 (16384サイクル分) */
			void (* const *pfn)() = s1c17_exec_tbl;
			while(*pfn) {
				(*pfn++)();
			}

			/* CPU実行 (16384サイクル分) */
			/* 1命令平均2サイクルで概算し、16384サイクル当たり8192命令を実行することにしました。
			 * なお、ext命令の実行時間は後続命令に含め、遅延スロットの実行時間は先行命令に含めた概算です。
			 * バスウェイトや、インターロックも考慮すると、3サイクル以上に見積もっても良いかも知れません。
			 * (※S1C17のインターロック条件は不明ですが…)
			 */
			i = 16384 / 2/*調整可*/;
			do {
				if(s1c17_mode >= S1C17_MODE_HALT) {
					break;
				}
				s1c17_cpu_exec();
			} while(--i);

		} while((s1c17_cycle -= 16384) >= 0);
	}
}

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

int
s1c17_port_get(int port)
{
	return s1c17_p.p[port].out;
}

void
s1c17_port_set(int port, int data)
{
	int e = s1c17_p.p[port].in ^ data; /* 1 = 立ち上がり、または、立ち下がりエッジ */
	s1c17_p.p[port].in = data;
	if(port <= 1) { /* ポート割り込み機能\を持っているのはP0とP1のみ */
		int e0 = e &  data; /* 1 = 立ち上がりエッジ */
		int e1 = e & ~data; /* 1 = 立ち下がりエッジ */
		e0 &= ~s1c17_p.p[port].edge; /* 1 = 立ち上がりエッジ、かつ、立ち上がりエッジが選択されている */
		e1 &=  s1c17_p.p[port].edge; /* 1 = 立ち下がりエッジ、かつ、立ち下がりエッジが選択されている */
		e = (e0 | e1) & s1c17_p.p[port].imsk; /* 1 = ポート割り込み発生 */
		s1c17_p.p[port].iflg |= e; /* 1 = 割り込み要因あり */
	}
}

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

/* PIECE_BMP形式(1bit)でLCD画像を取得。
 * 1ライン4バイト単位にパディングすれば、Windows BMP形式(1bit)としても使えます。
 */
void s1c17_lcd_image_sub(unsigned char buff[/*32*/][72 / 8]) {
	unsigned char* src = &s1c17_sram.m[0][0];
	unsigned char* dst = &buff[0][0];
	int y = 32 / 8; /* 表\示領域32ラインを8ラインづつ処理 */
	do {
		int x = 72 / 8; /* 表\示領域72ピクセルを8ピクセルづつ処理 */
		do {
			int a[8];
			int i;
			for(i = 0; i < 8; i++) { /* 8ライン×8ピクセルのデータを取得 */
				a[i] = *src++;
			}
			for(i = 0; i < 8; i++) { /* ラインとピクセルの並びを入れ替え */
				int b = 0; /* 警告抑制 */
				int j;
				for(j = 0; j < 8; j++) {
					b <<= 1;
					b |= a[j] & 1;
					a[j] >>= 1;
				}
				*dst = b;
				dst += 72 / 8; /* 1ライン下へ */
			}
			dst -= 72 - (8 / 8); /* 8ライン上の、8ピクセル右へ */
		} while(--x);
		dst += 72 - (72 / 8); /* 8ライン下の、72ピクセル左へ */
		src += 96 - 72; /* 未使用領域 */
	} while(--y);
}
int s1c17_lcd_image(unsigned char buff[/*32*/][72 / 8]) {
	int param;
	switch(s1c17_lcd.lcd.dctl.dspc) {
	case 1: /* 通常表\示 */			/* DSPREVの影響を受ける */
		s1c17_lcd_image_sub(buff);
		if(s1c17_lcd.lcd.dctl.dsprev) { /* 1 = Normal, 0 = Reverse */
			param = DRW_CLR(3, 0);	/* 1の色 = 黒, 0の色 = 白 */
		} else {
			param = DRW_CLR(0, 3);	/* 1の色 = 白, 0の色 = 黒 */
		}
		break;
	case 2: /* 全点灯 */			/* DSPREVの影響を受ける */
		if(s1c17_lcd.lcd.dctl.dsprev) { /* 1 = Normal, 0 = Reverse */
			param = DRW_CLR(3, 3);	/* 1の色 = 黒, 0の色 = 黒 */
		} else {
			param = DRW_CLR(0, 0);	/* 1の色 = 白, 0の色 = 白 */
		}
		break;
	default/*0,3*/: /* 表\示Off, 全消灯 */	/* DSPREVの影響を受けない */
		param = DRW_CLR(0, 0);		/* 1 = 白, 0 = 白 */
		break;
	}
	if(!s1c17_lcd.lcd.dctl.segrev) { /* 1 = Normal, 0 = Reverse */
		param |= DRW_REVX;
	}
	if(!s1c17_lcd.lcd.dctl.comrev) { /* 1 = Normal, 0 = Reverse */
		param |= DRW_REVY;
	}
	return param;
}
