;//
;//	ksvec200.s
;//
;//	カーネルサービステーブルの空き領域(200～247)に転送するルーチン
;//
;//	CLiP - Common Library for P/ECE
;//	Copyright (C) 2014 Naoyuki Sawa
;//
;//	* Sat Jan 03 00:38:41 JST 2015 Naoyuki Sawa
;//	- 1st リリース。
;//	- 当モジュールのサイズは、(247-200+1)*4=192バイト(0xC0バイト)以内でなくてはなりません。		//2014/01/03現在、ぴったり192バイトです。
;//	- 当モジュール内の処理は、リロケータブルでなくてはなりません。
;//	* Thu Jun 16 20:40:56 JST 2016 Naoyuki Sawa
;//	- memcpyの先頭に、(dest==src)ならば何もせずに帰る判定を追加しました。
;//	  この判定を行っても行わなくても結果は同じですが、'memcpy(foo,foo,65536)'のような呼び出しが行われた場合に大幅に時間を節約出来るので、この判定を行う事にしました。
;//	- 上記の判定を追加すると2命令増加するので、既存のコードを2命令節約する必要が生じました。
;//	  'xsub %r15,%r14,3',及び,'xsub %r15,%r14,7'を行っている所を、'ld.w %r15,%r14',及び,'sub %r15,3'と'sub %r15,7'に変更すると、1命令節約出来る事に気付きました。
;//	  上記の処理を行っている箇所は、memcpyとmemsetに有ったので、それぞれから1命令づつ節約して2命令節約して、前述の追加の2命令と相殺しました。
;//	- 以上の変更の結果、全体のコードサイズは192バイトのままで、これまでと変わっていません。		//2016/06/16現在、ぴったり192バイトです。
;//	- cliplibc.cのアセンブラ版memmoveの実装の下に、「memcpy,memmove,memsetのテストプログラム」を追記しました。
;//	  本日(2016/06/16)時点で、VC++6.0とP/ECEで結果が一致する事を確認しました。
;//	  もし今後memcpy,memmove,memsetを変更する場合は、このテストプログラムを使って動作確認を行って下さい。
;//
		.code
		.align		1
		.global		memcpy
		.global		memset
		.global		__divsi3
		.global		__modsi3
		.global		__udivsi3
		.global		__umodsi3
;//=============================================================;//
memcpy:								;//	memcpy()をksvec200.sの先頭で定義する必要が有ります。cstart.cのpceAppInit00()が、memcpy()がksvec200.sの先頭で定義されていることに依存しているからです。
	;//{{2016/06/16変更:memcpyの先頭に、(dest==src)ならば何もせずに帰る判定を追加しました。
	;//	cmp		%r14, 3				;//
	;//	jrule.d		memcpy_BYTE			;//
	;//	ld.w		%r10, %r12			;//							*delay*
	;//↓2016/06/16変更:memcpyの先頭に、(dest==src)ならば何もせずに帰る判定を追加しました。
		cmp		%r12, %r13			;//	┬(dest==src)ならば何もせずに帰ります。この判定を行っても行わなくても結果は同じですが、'memcpy(foo,foo,65536)'のような呼び出しが行われた場合に大幅に時間を節約出来るので、この判定を行う事にしました。
		jreq.d		memcpy_RET			;//	┘
		ld.w		%r10, %r12			;//							*delay*
		cmp		%r14, 3				;//
		jrule		memcpy_BYTE			;//
	;//}}2016/06/16変更:memcpyの先頭に、(dest==src)ならば何もせずに帰る判定を追加しました。
		ld.w		%r9, %r12			;//
		or		%r9, %r13			;//
		and		%r9, 3				;//
	;//{{2016/06/16変更:memcpyの先頭に、(dest==src)ならば何もせずに帰る判定を追加しました。
	;//	jreq		memcpy_WORD			;//
	;//↓2016/06/16変更:memcpyの先頭に、(dest==src)ならば何もせずに帰る判定を追加しました。
		jreq.d		memcpy_WORD			;//
		ld.w		%r15, %r14			;//							*delay*		memcpy_WORDへもmemcpy_HALFへも分岐せずに、memcpy_BYTEへフォールスルーした場合は、この行の処理は無駄処理になりますが、害は有りません。
	;//}}2016/06/16変更:memcpyの先頭に、(dest==src)ならば何もせずに帰る判定を追加しました。
		and		%r9, 1				;//
		jreq		memcpy_HALF			;//
memcpy_BYTE:							;//
		sub		%r14, 1				;//
		jrult		memcpy_RET			;//
		ld.b		%r9, [%r13]+			;//
		ld.b		[%r12]+, %r9			;//
		jrugt.d		-2				;//
		sub		%r14, 1				;//							*delay*
memcpy_RET:							;//
		ret						;//
		;//---------------------------------------------;//
memcpy_HALF:							;//
	;//{{2016/06/16変更:memcpyの先頭に、(dest==src)ならば何もせずに帰る判定を追加しました。
	;//	xsub		%r15, %r14, 3			;//
	;//↓2016/06/16変更:memcpyの先頭に、(dest==src)ならば何もせずに帰る判定を追加しました。
		sub		%r15, 3				;//
	;//}}2016/06/16変更:memcpyの先頭に、(dest==src)ならば何もせずに帰る判定を追加しました。
		ld.h		%r9, [%r13]+			;//
		ld.h		[%r12]+, %r9			;//
		jrugt.d		-2				;//
		sub		%r15, 2				;//							*delay*
		jp.d		memcpy_BYTE			;//
		and		%r14, 1				;//							*delay*
		;//---------------------------------------------;//
memcpy_WORD:							;//
	;//{{2016/06/16変更:memcpyの先頭に、(dest==src)ならば何もせずに帰る判定を追加しました。
	;//	xsub		%r15, %r14, 7			;//
	;//↓2016/06/16変更:memcpyの先頭に、(dest==src)ならば何もせずに帰る判定を追加しました。
		sub		%r15, 7				;//
	;//}}2016/06/16変更:memcpyの先頭に、(dest==src)ならば何もせずに帰る判定を追加しました。
		ld.w		%r9, [%r13]+			;//
		ld.w		[%r12]+, %r9			;//
		jrugt.d		-2				;//
		sub		%r15, 4				;//							*delay*
		jp.d		memcpy_BYTE			;//
		and		%r14, 3				;//							*delay*
;//=============================================================;//
memset:								;//
		cmp		%r14, 3				;//%r14 := count <=> 3
		jrule.d		memset_BYTE			;//if(count < 3) {
		ld.w		%r10, %r12			;//%r10 := src						*delay*
	;//{{2016/06/16変更:memcpyの先頭に、(dest==src)ならば何もせずに帰る判定を追加しました。
	;//	xand		%r9, %r12, 1			;//
	;//	jrne		memset_BYTE			;//
	;//	ld.ub		%r15, %r13			;//
	;//	sll		%r13, 8				;//
	;//	xand		%r9, %r12, 2			;//
	;//	jrne.d		memset_HALF			;//
	;//	or		%r13, %r15			;//							*delay*
	;//	ld.uh		%r13, %r13			;//
	;//	swap		%r15, %r13			;//
	;//	or		%r13, %r15			;//
	;//↓2016/06/16変更:memcpyの先頭に、(dest==src)ならば何もせずに帰る判定を追加しました。
		and		%r10, 1				;//%r10 := src & 1
		jrne.d		memset_BYTE			;//if(src & 1) { goto BYTE }
		ld.w		%r10, %r12			;//%r10 := src						*delay*
		ld.w		%r15, %r14			;//%r15 := tmp = count	────────────┐
		ld.ub		%r9, %r13			;//%r9  := 00000000 00000000 00000000 cccccccc	│
		sll		%r13, 8				;//%r13 := ???????? ???????? cccccccc 00000000	│
		or		%r13, %r9			;//%r13 := ???????? ???????? cccccccc cccccccc	│
		and		%r10, 2				;//%r10 := src & 2				│
		jrne.d		memset_HALF			;//if(src & 2) { goto HALF }			│
		ld.w		%r10, %r12			;//%r10 := src					│	*delay*
		ld.uh		%r13, %r13			;//%r13 := 00000000 00000000 cccccccc cccccccc	│
		swap		%r9, %r13			;//%r9  := cccccccc cccccccc 00000000 00000000	│
		or		%r13, %r9			;//%r13 := cccccccc cccccccc cccccccc cccccccc	│
	;//}}2016/06/16変更:memcpyの先頭に、(dest==src)ならば何もせずに帰る判定を追加しました。			│
memset_WORD:							;//						│
	;//{{2016/06/16変更:memcpyの先頭に、(dest==src)ならば何もせずに帰る判定を追加しました。			│
	;//	xsub		%r15, %r14, 7			;//						│
	;//↓2016/06/16変更:memcpyの先頭に、(dest==src)ならば何もせずに帰る判定を追加しました。			│
		sub		%r15, 7				;// ←─────────────────────┤
	;//}}2016/06/16変更:memcpyの先頭に、(dest==src)ならば何もせずに帰る判定を追加しました。			│
		ld.w		[%r12]+, %r13			;//						│
		jrugt.d		-1				;//						│
		sub		%r15, 4				;//						│	*delay*
		jp.d		memset_BYTE			;//						│
		and		%r14, 3				;//						│	*delay*
		;//---------------------------------------------;//						│
memset_HALF:							;//						│
	;//{{2016/06/16変更:memcpyの先頭に、(dest==src)ならば何もせずに帰る判定を追加しました。			│
	;//	xsub		%r15, %r14, 3			;//						│
	;//↓2016/06/16変更:memcpyの先頭に、(dest==src)ならば何もせずに帰る判定を追加しました。			│
		sub		%r15, 3				;// ←─────────────────────┘
	;//}}2016/06/16変更:memcpyの先頭に、(dest==src)ならば何もせずに帰る判定を追加しました。
		ld.h		[%r12]+, %r13			;//
		jrugt.d		-1				;//
		sub		%r15, 2				;//							*delay*
		and		%r14, 1				;//
memset_BYTE:							;//
		sub		%r14, 1				;//
		jrult		memset_RET			;//
		ld.b		[%r12]+, %r13			;//
		jrugt.d		-1				;//
		sub		%r14, 1				;//							*delay*
memset_RET:							;//
		ret						;//
;//=============================================================;//
__divsi3:							;//
		ld.w		%alr, %r12			;//
		div0s		%r13				;//
		jp.d		div_subr			;//
		ld.w		%r9, %psr			;//%psr(DS,N)保存					*delay*
		;//---------------------------------------------;//
__modsi3:							;//
		call		__divsi3			;//
		ret.d						;//
		ld.w		%r10, %ahr			;//③はダミー処理となる。				*delay*
		;//---------------------------------------------;//
__udivsi3:							;//
		ld.w		%alr, %r12			;//
		div0u		%r13				;//①②はダミー処理となる。
		jp.d		div_subr			;//
		ld.w		%r9, %psr			;//%psr(DS,N)保存					*delay*
		;//---------------------------------------------;//
__umodsi3:							;//
		call		__udivsi3			;//
		ret.d						;//
		ld.w		%r10, %ahr			;//③はダミー処理となる。				*delay*
		;//---------------------------------------------;//
div_subr:							;//
		ld.w		%r10, 4				;//
div_loop:							;//
		div1		%r13				;// 1
		div1		%r13				;// 2
		div1		%r13				;// 3
		div1		%r13				;// 4
		div1		%r13				;// 5	┐
		div1		%r13				;// 6	│変更前のclipidiv.sでは4x8ループでしたが、変更後のksvec200.sでは8x4ループにしました。
		div1		%r13				;// 7	│転送先領域の変更に伴い8バイト余ったので、ループ展開に使用して高速化するのが良いと思ったからです。
		div1		%r13				;// 8	┘
		sub		%r10, 1				;//
		jrne.d		div_loop			;//
		ld.w		%psr, %r9			;//%psr(DS,N)復元					*delay*
		div2s		%r13				;//①div0uで開始した場合はDS=0なので何もしない。
		div3s						;//②div0uで開始した場合はDS=Nなので何もしない。
		ret.d						;//
		ld.w		%r10, %alr			;//③							*delay*
;//=============================================================;//
