/*	
 *	clipc17.c
 *
 *	P/ECE EPSON S1C17702 Emulator
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2001-2016 Naoyuki Sawa
 *
 *	* Fri Dec 25 00:36:52 JST 2009 Naoyuki Sawa
 *	- 作成開始。
 *	* Sat May 28 21:20:19 JST 2016 Naoyuki Sawa
 *	- s1c17_swap_rd_rs()のバグを修正しました。
 *	  上位バイトと下位バイトをそれぞれバイトとして取り出して入れ替えて格納するのだから、取り出した下位バイトを右シフトする必要は有りませんでした。
 *	  これまでたまたまswapを使っていなくて気付かなかったのだと思います。
 *	  今回、Visual Studio 2015でコンパイルしていて、下位バイト(符号無し8bit値)を8ビット右シフトするのは不正、という警告が出て気付きました。
 *	  古いコンパイラよりも警告機能が強力になっていて助かりました。
 */
#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) {
//{{2016/05/28変更:s1c17_swap_rd_rs()のバグを修正しました。
//	*rd = (((unsigned char*)rs)[0] << 8) | (((unsigned char*)rs)[1] >> 8);
//↓2016/05/28変更:s1c17_swap_rd_rs()のバグを修正しました。
	*rd = (((unsigned char*)rs)[0] << 8) |  ((unsigned char*)rs)[1];
	//                                      ~~~~~~~~~~~~~~~~~~~~~~~上位バイトと下位バイトをそれぞれバイトとして取り出して入れ替えて格納するのだから、取り出した下位バイトを右シフトする必要は有りませんでした。これまでたまたまswapを使っていなくて気付かなかったのだと思います。今回、Visual Studio 2015でコンパイルしていて、下位バイト(符号無し8bit値)を8ビット右シフトするのは不正、という警告が出て気付きました。古いコンパイラよりも警告機能が強力になっていて助かりました。
//}}2016/05/28変更:s1c17_swap_rd_rs()のバグを修正しました。
}
/* 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;
}
