;	
;	clipsp2b.h
;
;	P/ECE SPC Driver V2
;
;	CLiP - Common Library for P/ECE
;	Copyright (C) 2001-2004 Naoyuki Sawa
;
;	* Thu Oct 14 19:00:00 JST 2004 Naoyuki Sawa
;	- 作成開始。
;

;★★★★★★★★★★★★★★★★★★★★★★★★★★
;★ clipsp2a.sとframsp2a.sからインクルードします。 ★
;★ Ｃ言語ソースからインクルードしてはいけません。 ★
;★★★★★★★★★★★★★★★★★★★★★★★★★★

;****************************************************************************
;	SPC2CPU
;****************************************************************************

;
;	SPC2CPU構造体
;
#define PSW_P		 0
#define PSW_NZ		 2
#define PSW_C		 3
#define PSW_CNZ		 2
#define PSW_V		 4
#define X		 5
#define A		 6
#define Y		 7
#define YA		 6
#define SP		 8
#define PC		12
#define SPC2CPU_SIZE	16

;
;	関数呼び出しの簡略表記
;
#macro READ
	xcall spc2cpu_READ
#endm
#macro WRITE
	xcall spc2cpu_WRITE
#endm
#macro READW
	xcall spc2cpu_READW
#endm
#macro WRITEW
	xcall spc2cpu_WRITEW
#endm
#macro ADC
	xcall spc2cpu_ADC
#endm
#macro SBC
	xcall spc2cpu_SBC
#endm
#macro ADDW
	xcall spc2cpu_ADDW
#endm
#macro SUBW
	xcall spc2cpu_SUBW
#endm
#macro BEQ
	xcall spc2cpu_BEQ
#endm
#macro BNE
	xcall spc2cpu_BNE
#endm
#macro DIV
	xcall spc2cpu_DIV
#endm
#macro PACK_PSW
	xcall spc2cpu_PACK_PSW
#endm
#macro UNPACK_PSW
	xcall spc2cpu_UNPACK_PSW
#endm
#macro DIE $1
	xld.w %r12, $1
	xcall spc2cpu_DIE
#endm

;
;	アドレッシングモード
;
;	*** RELATIVE以外に関する説明 ***
;
;	[out]
;		%r12		ひとつめのアドレス。
;		%r13		ふたつめのアドレス。(あれば)
;	[mod]
;		%r12-15		%r12-15のうち、戻り値として使用しないレジスタは、
;				アドレッシングモードマクロの内部計算で破壊されると考えてください。
;				- %r12-15のうち、現在の実装で破壊されていないレジスタも、
;				  今後の変更によって、破壊されるようになる可能性があります。
;				- 実際には、アドレッシングモードマクロはインストラクション処理の最初に
;				  呼ばれることがほとんどなので、レジスタ破壊を気にする必要はないはずです。
;
;	[note]
;		* ふたつのアドレスを返すアドレッシングモードの場合、
;		  ひとつめのアドレスが転送元、ふたつめのアドレスが転送先となることに注意してください。
;		  これは、インストラクション表記の引数順序とは異なります。
;
;		  <例> "dp(d),dp(s)"の場合、%r12=dp(s),%r13=dp(d)
;
;		  このようにした理由は以下のとおりです。
;
;		  - 機械語の後続バイト並びが、転送元,転送先の順です。
;		    前出の例ですと、命令コードの後にはdp(s)のアドレス、その後にdp(d)のアドレスがあります。
;		    感覚的に、機械語の並び順と同じ方がわかりやすいと判断しました。
;		  - spc2cpu_READ,spc2cpu_WRITEは、%r12にアドレスを入れて呼び出します。
;		    アドレッシングモード計算後、最初に転送元アドレスからのREADを行うことが多いので、
;		    %r12に転送元アドレスが入っていた方が使いやすいです。
;
;	
;	*** RELATIVEだけに関する説明 ***
;
;	[out]
;		%r1		更新されたPC。
;	[mod]
;		%r9		RELATIVEだけはインストラクション処理の途中で呼ばれることがあるので、
;				%r12-15や、その他の一般レジスタもなるべく破壊したくありません。
;				そこで、ext33のワークレジスタ%r9を使いました。
;				通常のプログラムは%r9を使わないので、RELATIVEは破壊レジスタ無しと考えて構いません。
;
/* 1. #inm */
#macro INMEDIATE_DATA
	ld.ub %r12, [%r1]+		; inm = *PC++
#endm
/* 2. dp */
#macro DIRECT_PAGE
	xld.uh %r15, [%r0+PSW_P]	; mem = PSW_P | *PC++
	ld.ub %r12, [%r1]+
	or %r12, %r15
#endm
/* 3. dp+X */
#macro X_INDEXED_DIRECT_PAGE
	xld.uh %r15, [%r0+PSW_P]	; mem = PSW_P | (unsigned char)(*PC++ + X)
	ld.ub %r12, [%r1]+
	xld.ub %r13, [%r0+X]
	add %r12, %r13
	ld.ub %r12, %r12
	or %r12, %r15
#endm
/* 4. dp+Y */
#macro Y_INDEXED_DIRECT_PAGE
	xld.uh %r15, [%r0+PSW_P]	; mem = PSW_P | (unsigned char)(*PC++ + Y)
	ld.ub %r12, [%r1]+
	xld.ub %r13, [%r0+Y]
	add %r12, %r13
	ld.ub %r12, %r12
	or %r12, %r15
#endm
/* 5. (X) */
#macro INDIRECT
	xld.uh %r15, [%r0+PSW_P]	; mem = PSW_P | X
	xld.ub %r12, [%r0+X]
	or %r12, %r15
#endm
/* 6. (X)+ */
#macro INDIRECT_AUTO_INCREMENT
	xld.uh %r15, [%r0+PSW_P]	; mem = PSW_P | X++
	xld.ub %r12, [%r0+X]
	xadd %r13, %r12, 1
	xld.b [%r0+X], %r13
	or %r12, %r15
#endm
/* 7. (X),(Y) */
#macro INDIRECT_PAGE_TO_IP
	xld.uh %r15, [%r0+PSW_P]
	xld.ub %r12, [%r0+Y]		; src = PSW_P | Y
	xld.ub %r13, [%r0+X]		; dst = PSW_P | X
	or %r12, %r15
	or %r13, %r15
#endm
/* 8. dp(d),dp(s) */
#macro DIRECT_PAGE_TO_DP
	xld.uh %r15, [%r0+PSW_P]
	ld.ub %r12, [%r1]+		; src = PSW_P | *PC++
	ld.ub %r13, [%r1]+		; dst = PSW_P | *PC++
	or %r12, %r15
	or %r13, %r15
#endm
/* 9. dp,#inm */
#macro INMEDIATE_DATA_TO_DP
	xld.uh %r15, [%r0+PSW_P]
	ld.ub %r12, [%r1]+		; inm = *PC++
	ld.ub %r13, [%r1]+		; mem = PSW_P | *PC++
	or %r13, %r15
#endm
/* 10. labs */
#macro ABSOLUTE
	ld.ub %r12, [%r1]+		; mem  = *PC++
	ld.ub %r13, [%r1]+		; mem |= *PC++ << 8
	xsll %r13, 8
	or %r12, %r13
#endm
/* 11. labs+X */
#macro X_INDEXED_ABSOLUTE
	ld.ub %r12, [%r1]+		; mem  = *PC++
	ld.ub %r13, [%r1]+		; mem |= *PC++ << 8
	xld.ub %r14, [%r0+X]		; mem  = (unsigned short)(mem + X)
	xsll %r13, 8
	or %r12, %r13
	add %r12, %r14
	ld.uh %r12, %r12
#endm
/* 12. labs+Y */
#macro Y_INDEXED_ABSOLUTE
	ld.ub %r12, [%r1]+		; mem  = *PC++
	ld.ub %r13, [%r1]+		; mem |= *PC++ << 8
	xld.ub %r14, [%r0+Y]		; mem  = (unsigned short)(mem + Y)
	xsll %r13, 8
	or %r12, %r13
	add %r12, %r14
	ld.uh %r12, %r12
#endm
/* 13. (dp+X) */
#macro X_INDEXED_INDIRECT
	xld.uh %r15, [%r0+PSW_P]	; mem = PSW_P | (unsigned char)(*PC++ + X)
	ld.ub %r13, [%r1]+
	xld.ub %r14, [%r0+X]
	add %r13, %r14
	ld.ub %r13, %r13
	or %r13, %r15
	ext spc2ram@ah			; mem = spc2ram[mem] | spc2ram[mem + 1] << 8
	ext spc2ram@al
	add %r13, %r13
	ld.ub %r12, [%r13]+
	ld.ub %r13, [%r13]
	xsll %r13, 8
	or %r12, %r13
#endm
/* 14. (dp)+Y */
#macro INDIRECT_Y_INDEXED_INDIRECT
	xld.uh %r15, [%r0+PSW_P]	; mem = PSW_P | *PC++
	ld.ub %r13, [%r1]+
	or %r13, %r15
	ext spc2ram@ah			; mem = spc2ram[mem] | spc2ram[mem + 1] << 8
	ext spc2ram@al			; mem = (unsigned short)(mem + Y)
	add %r13, %r13
	ld.ub %r12, [%r13]+
	ld.ub %r13, [%r13]
	xld.ub %r14, [%r0+Y]
	xsll %r13, 8
	or %r12, %r13
	add %r12, %r14
	ld.uh %r12, %r12
#endm
/* 15. rel */
#macro RELATIVE
	; 他のアドレッシングモードがインストラクション処理の先頭だけで呼ばれるのに対し、
	; RELATIVEだけはインストラクション処理の途中で呼ばれることがあるので、
	; %r12-15や、その他の一般レジスタもなるべく破壊したくありません。
	; そこで、ext33のワークレジスタ%r9を使います。
	; RELATIVEの実装に、ext33の拡張命令(xldとか)を使わないよう、気をつけてください。
	ld.b %r9, [%r1]+		; tmp = (char)*PC++
	ext spc2ram@ah			; PC = &spc2ram[(unsigned short)(PC - spc2ram + tmp)]
	ext spc2ram@al
	sub %r1, %r1
	add %r1, %r9
	ld.uh %r1, %r1
	ext spc2ram@ah
	ext spc2ram@al
	add %r1, %r1
#endm
/* 16. (labs+X) */
#macro X_INDEXED_ABSOLUTE_INDIRECT
	ld.ub %r13, [%r1]+		; mem  = *PC++
	ld.ub %r14, [%r1]+		; mem |= *PC++ << 8
	xld.ub %r15, [%r0+X]		; mem  = (unsigned short)(mem + X)
	xsll %r14, 8
	or %r13, %r14
	add %r13, %r15
	ld.uh %r13, %r13
	ext spc2ram@ah			; mem  = spc2ram[mem] | spc2ram[mem + 1] << 8
	ext spc2ram@al
	add %r13, %r13
	ld.ub %r12, [%r13]+
	ld.ub %r13, [%r13]
	xsll %r13, 8
	or %r12, %r13
#endm
/* 17. mem.bit */
#macro ABSOLUTE_BOOLEAN_BIT
	ld.ub %r13, [%r1]+		; bit   = *PC++
	ld.ub %r14, [%r1]+		; bit  |= *PC++ << 8
	xsll %r14, 8
	or %r13, %r14
	xand %r12, %r13, 0x1fff		; mem   = bit & 0x1fff
	xsrl %r13, 13			; bit >>= 13
#endm

;****************************************************************************
;	SPC2DSP
;****************************************************************************

;
;	SPC2VCE構造体
;
#define STATE		 0
#define VOL		 4
#define P		 8
#define AR		12
#define DR		16
#define SR		20
#define SL		24
#define GAIN		28
#define ENVX		32
#define LSA		36
#define BRR_ADDR	40
#define LAST_LOOP	44
#define PROGRESS	48
#define SAMPLE		52

;
;	SPC2DSP構造体
;
#define MVOL		  0
#define VCE		  4
#define REG		676

;****************************************************************************

