;	
;	framsp2a.s
;
;	P/ECE SPC Driver V2
;
;	CLiP - Common Library for P/ECE
;	Copyright (C) 2001-2004 Naoyuki Sawa
;
;	* Mon Oct 11 12:53:00 JST 2004 Naoyuki Sawa
;	- 作成開始。
;
#include "clipsp2a.h"
#include "clipsp2b.h"
#ifdef SPC2_ASM

; * 頻繁にアクセスされるSPC2CPU構造体を高速RAMに配置して、高速化を図ります。
;   SPC2CPU構造体は書き換え対象なので、本当は.codeセクションに配置するのは良くないのですが、
;   clip.mkにて.codeセクションだけを高速RAMへ転送するように設定してあるので、仕方ないです。
;   P/ECEは.code,.data,.bss全部RAM上に展開して実行するので、動作上は問題ありません。
; * メモリ領域を.codeセクションに配置するために、.commではなく.spaceを使っています。
;   .commを使うと強制的に.bssセクションに配置されてしまうので、ダメです。
	.code
	.align 2
	.global spc2cpu
spc2cpu:
	.space SPC2CPU_SIZE

	.code
	.align 1

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

;
; 重要!!
; %r3=countであることを、spc2cpu_runから呼ばれる他のルーチンが利用しています。
; 無駄ループを検出すると%r3の値を変更し、残りタイムスライスを放棄します。
; %r3=countのレジスタ割り当てを変更しないでください。
; 詳しくは、spc2cpu_READとspc2drv_read_asmの実装を参照してください。
;
	.global spc2cpu_run
spc2cpu_run:
	pushn %r3

	xld.w %r0, spc2cpu		; cpu = &spc2cpu
	xld.w %r1, [%r0+PC]		; PC = cpu->pc
	xld.w %r2, spc2cpu_TABLE	; spc2cpu_TABLE
	ld.w %r3, %r12			; count ★このレジスタ割り当て変更不可!!★
	; %r0 = cpu
	; %r1 = PC
	; %r2 = spc2cpu_TABLE
	; %r3 = count ★このレジスタ割り当て変更不可!!★

spc2cpu_run_L10:			; do {

;;{{SPC2_TRACE
;;	pushn %r15
;;	xld.w %r0, [spc2cpu+PC]
;;	xld.w [spc2cpu+PC], %r1
;;	xcall spc2cpu_dump
;;	xld.w [spc2cpu+PC], %r0
;;	popn %r15
;;}}SPC2_TRACE

	ld.ub %r4, [%r1]+		; switch(*PC++)
	xsll %r4, 2
	add %r4, %r2
	ld.w %r4, [%r4]
	call %r4

	xsub %r3, %r3, 1		; } while(--count > 0)
	xjrgt spc2cpu_run_L10

	xld.w [%r0+PC], %r1		; cpu->pc = PC

	popn %r3
	ret

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

;
; 符号無し8bit値を読み出します。
; [in]
;	%r12		読み出すアドレス。
; [out]
;	%r10		読み出したデータ。
; [mod]
;	%r0-3		保存
;	%r4-7		破壊
;	%r8-9		予約
;	%r10		戻り値
;	%r11		破壊
;	%r12-15		保存
;
	.global spc2cpu_READ
spc2cpu_READ:
	xsub %r10, %r12, 0xf0		; if((unsigned)(addr - 0xf0) > 0xf) {
	xcmp %r10, 0xf
	xjrule spc2cpu_READ_L10
	ext spc2ram@ah			;   return spc2ram[addr]
	ext spc2ram@al
	ld.ub %r10, [%r12]
	ret
spc2cpu_READ_L10:			; } else {
	xsub %sp, %sp, 16
	xld.w [%sp+ 0], %r12
	xld.w [%sp+ 4], %r13
	xld.w [%sp+ 8], %r14
	xld.w [%sp+12], %r15
	;;xcall spc2drv_read		;   return spc2drv_read(addr)
	;;↓高速版。
	;;↓無駄ループを検出すると、%r3(spc2cpu_runの命令実行回数)をゼロにして、残りタイムスライスを放棄します。
	;;↓clipsp2.cのspc2drv_read_asmを参照してください。
	xcall spc2drv_read_asm		;   return spc2drv_read_asm(addr)
	xld.w %r12, [%sp+ 0]
	xld.w %r13, [%sp+ 4]
	xld.w %r14, [%sp+ 8]
	xld.w %r15, [%sp+12]
	xadd %sp, %sp, 16
	ret				; }

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

;
; 8bit値を書き込みます。
; [in]
;	%r12		書き込むアドレス。
;	%r13		書き込むデータ。([31:8]は不定でも構いません)
; [mod]
;	%r0-3		保存
;	%r4-7		破壊
;	%r8-9		予約
;	%r10-11		破壊
;	%r12-15		保存
;
	.global spc2cpu_WRITE
spc2cpu_WRITE:
;;{{SPC2_TRACE
;;	pushn %r15
;;	xcall spc2cpu_write_trace
;;	popn %r15
;;}}SPC2_TRACE
	xsub %r10, %r12, 0xf0		; if((unsigned)(addr - 0xf0) > 0xf) {
	xcmp %r10, 0xf
	xjrule spc2cpu_WRITE_L10
	ext spc2ram@ah			;   spc2ram[addr] = data
	ext spc2ram@al
	ld.b [%r12], %r13
	ret
spc2cpu_WRITE_L10:			; } else {
	xsub %sp, %sp, 16
	xld.w [%sp+ 0], %r12
	xld.w [%sp+ 4], %r13
	xld.w [%sp+ 8], %r14
	xld.w [%sp+12], %r15
	ld.ub %r13, %r13		;   spc2drv_writeへ渡すdata[32:8]はゼロ必須!
	xcall spc2drv_write		;   spc2drv_write(addr, (unsigned char)data)
	xld.w %r12, [%sp+ 0]
	xld.w %r13, [%sp+ 4]
	xld.w %r14, [%sp+ 8]
	xld.w %r15, [%sp+12]
	xadd %sp, %sp, 16
	ret				; }

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

;
; 符号無し16bit値を読み出します。
; [in]
;	%r12		読み出すアドレス。
; [out]
;	%r10		読み出したデータ。
; [mod]
;	%r0-3		保存
;	%r4-7		破壊
;	%r8-9		予約
;	%r10		戻り値
;	%r11		破壊
;	%r12-15		保存
;
	.global spc2cpu_READW
spc2cpu_READW:
	xsub %sp, %sp, 4

	xcall spc2cpu_READ
	xld.w [%sp+0], %r10

	xadd %r12, %r12, 1
	xcall spc2cpu_READ
	xsub %r12, %r12, 1

	xsll %r10, 8
	xld.w %r11, [%sp+0]
	or %r10, %r11

	xadd %sp, %sp, 4
	ret

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

;
; 16bit値を書き込みます。
; [in]
;	%r12		書き込むアドレス。
;	%r13		書き込むデータ。([31:16]は不定でも構いません)
; [mod]
;	%r0-3		保存
;	%r4-7		破壊
;	%r8-9		予約
;	%r10-11		破壊
;	%r12-15		保存
;
	.global spc2cpu_WRITEW
spc2cpu_WRITEW:
	xcall spc2cpu_WRITE

	xadd %r12, %r12, 1
	xrr %r13, 8
	xcall spc2cpu_WRITE
	xsub %r12, %r12, 1
	xrl %r13, 8

	ret

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

;
; キャリー込み8bit加算を行います。
; [in]
;	%r0	SPC2CPU構造体。
;	%r14	足される数。
;	%r15	足す数。
; [out]
;	%r13	結果。([31:8]は不定です)
; [mod]
;	%r0-7	保存
;	%r8-9	予約
;	%r10-11	破壊 (現在の実装では保存ですが、今後のために破壊と考えておく)
;	%r12	保存
;	%r13	戻り値
;	%r14-15	破壊
;
	.global spc2cpu_ADC
spc2cpu_ADC:
	xld.ub %r13, [%r0+PSW_C]	; tmp = a + b + ((PSW_C & 1) ? 1 : 0)
	xand %r13, %r13, 1
	add %r13, %r14
	add %r13, %r15

	xor %r15, %r14			; PSW_V = ~(a ^ b) & (a ^ tmp)
	not %r15, %r15
	xor %r14, %r13
	and %r14, %r15
	xld.b [%r0+PSW_V], %r14

	xld.h [%r0+PSW_CNZ], %r13	; PSW_CNZ = tmp

	ret

;
; キャリー込み8bit減算を行います。
; [in]
;	%r0	SPC2CPU構造体。
;	%r14	引かれる数。
;	%r15	引く数。
; [out]
;	%r13	結果。([31:8]は不定です)
; [mod]
;	%r0-7	保存
;	%r8-9	予約
;	%r10-11	破壊 (現在の実装では保存ですが、今後のために破壊と考えておく)
;	%r12	保存
;	%r13	戻り値
;	%r14-15	破壊
;
	.global spc2cpu_SBC
spc2cpu_SBC:
	xld.ub %r13, [%r0+PSW_C]	; tmp = a - b + ((PSW_C & 1) ? 0 : -1)
	xand %r13, %r13, 1
	xsub %r13, %r13, 1
	add %r13, %r14
	sub %r13, %r15

	xor %r15, %r14			; PSW_V = (a ^ b) & (a ^ tmp)
	xor %r14, %r13
	and %r14, %r15
	xld.b [%r0+PSW_V], %r14

	xxor %r13, %r13, 0x100		; PSW_CNZ = tmp ^ 0x100
	xld.h [%r0+PSW_CNZ], %r13

	ret

;
; キャリー無し16bit加算を行います。
; [in]
;	%r0	SPC2CPU構造体。
;	%r14	足される数。
;	%r15	足す数。
; [out]
;	%r13	結果。([31:16]は不定です)
; [mod]
;	%r0-7	保存
;	%r8-9	予約
;	%r10-11	破壊 (現在の実装では保存ですが、今後のために破壊と考えておく)
;	%r12	保存
;	%r13	戻り値
;	%r14-15	破壊
;
	.global spc2cpu_ADDW
spc2cpu_ADDW:
	ld.w %r13, %r14			; tmp = a + b
	add %r13, %r15

	xor %r15, %r14			; PSW_V = (~(a ^ b) & (a ^ tmp)) >> 8
	not %r15, %r15
	xor %r14, %r13
	and %r14, %r15
	xsrl %r14, 8
	xld.b [%r0+PSW_V], %r14

	ld.w %r14, %r13			; PSW_CNZ = (tmp >> 8) | ((unsigned short)tmp != 0)
	xand %r15, %r13, 0xffff
	jreq.d 3
	srl %r14, 8			; *delay*
	or %r14, 1
	xld.h [%r0+PSW_CNZ], %r14

	ret

;
; キャリー無し16bit減算を行います。
; [in]
;	%r0	SPC2CPU構造体。
;	%r14	引かれる数。
;	%r15	引く数。
; [out]
;	%r13	結果。([31:16]は不定です)
; [mod]
;	%r0-7	保存
;	%r8-9	予約
;	%r10-11	破壊 (現在の実装では保存ですが、今後のために破壊と考えておく)
;	%r12	保存
;	%r13	戻り値
;	%r14-15	破壊
;
	.global spc2cpu_SUBW
spc2cpu_SUBW:
	ld.w %r13, %r14			; tmp = a - b
	sub %r13, %r15

	xor %r15, %r14			; PSW_V = ((a ^ b) & (a ^ tmp)) >> 8
	xor %r14, %r13
	and %r14, %r15
	xsrl %r14, 8
	xld.b [%r0+PSW_V], %r14

	ld.w %r14, %r13			; PSW_CNZ = ((tmp >> 8) | ((unsigned short)tmp != 0)) ^ 0x100
	xand %r15, %r13, 0xffff
	jreq.d 3
	srl %r14, 8			; *delay*
	or %r14, 1
	xxor %r14, %r14, 0x100
	xld.h [%r0+PSW_CNZ], %r14

	ret

;
; ゼロフラグが1ならば分岐します。
; [in]
;	%r0		SPC2CPU構造体。
;	%r1		PC。
;	%psr(Z)		1ならば分岐します。
;			0ならば分岐しません。
; [out]
;	%r1		更新されたPC。
; [mod]
;	%r0-7	保存
;	%r8-9	予約
;	%r10-11	破壊 (現在の実装では保存ですが、今後のために破壊と考えておく)
;	%r12-15	保存
;
	.global spc2cpu_BEQ
spc2cpu_BEQ:
	xjreq spc2cpu_BEQ_L10		; if(!EQ) {
	ret.d				;   PC++
	add %r1, 1			;   *delay*
spc2cpu_BEQ_L10:			; } else {
	RELATIVE			;   RELATIVE
	ret				; }

;
; ゼロフラグが0ならば分岐します。
; [in]
;	%r0		SPC2CPU構造体。
;	%r1		PC。
;	%psr(Z)		0ならば分岐します。
;			1ならば分岐しません。
; [out]
;	%r1		更新されたPC。
; [mod]
;	%r0-7	保存
;	%r8-9	予約
;	%r10-11	破壊 (現在の実装では保存ですが、今後のために破壊と考えておく)
;	%r12-15	保存
;
	.global spc2cpu_BNE
spc2cpu_BNE:
	xjrne spc2cpu_BNE_L10		; if(!NE) {
	ret.d				;   PC++
	add %r1, 1			;   *delay*
spc2cpu_BNE_L10:			; } else {
	RELATIVE			;   RELATIVE
	ret				; }

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

;============================================================================
;	1. 8-BIT DATA TRANSMISSION COMMANDS GROUP 1
;============================================================================

	.global spc2cpu_0xE8
spc2cpu_0xE8: ; MOV A,#inm
	INMEDIATE_DATA
	xld.b [%r0+A], %r12
	xld.b [%r0+PSW_NZ], %r12
	ret

	.global spc2cpu_0xE6
spc2cpu_0xE6: ; MOV A,(X)
	INDIRECT
	READ
	xld.b [%r0+A], %r10
	xld.b [%r0+PSW_NZ], %r10
	ret

	.global spc2cpu_0xBF
spc2cpu_0xBF: ; MOV A,(X)+
	INDIRECT_AUTO_INCREMENT
	READ
	xld.b [%r0+A], %r10
	xld.b [%r0+PSW_NZ], %r10
	ret

	.global spc2cpu_0xE4
spc2cpu_0xE4: ; MOV A,dp
	DIRECT_PAGE
	READ
	xld.b [%r0+A], %r10
	xld.b [%r0+PSW_NZ], %r10
	ret

	.global spc2cpu_0xF4
spc2cpu_0xF4: ; MOV A,dp+X
	X_INDEXED_DIRECT_PAGE
	READ
	xld.b [%r0+A], %r10
	xld.b [%r0+PSW_NZ], %r10
	ret

	.global spc2cpu_0xE5
spc2cpu_0xE5: ; MOV A,labs
	ABSOLUTE
	READ
	xld.b [%r0+A], %r10
	xld.b [%r0+PSW_NZ], %r10
	ret

	.global spc2cpu_0xF5
spc2cpu_0xF5: ; MOV A,labs+X
	X_INDEXED_ABSOLUTE
	READ
	xld.b [%r0+A], %r10
	xld.b [%r0+PSW_NZ], %r10
	ret

	.global spc2cpu_0xF6
spc2cpu_0xF6: ; MOV A,labs+Y
	Y_INDEXED_ABSOLUTE
	READ
	xld.b [%r0+A], %r10
	xld.b [%r0+PSW_NZ], %r10
	ret

	.global spc2cpu_0xE7
spc2cpu_0xE7: ; MOV A,(dp+X)
	X_INDEXED_INDIRECT
	READ
	xld.b [%r0+A], %r10
	xld.b [%r0+PSW_NZ], %r10
	ret

	.global spc2cpu_0xF7
spc2cpu_0xF7: ; MOV A,(dp)+Y
	INDIRECT_Y_INDEXED_INDIRECT
	READ
	xld.b [%r0+A], %r10
	xld.b [%r0+PSW_NZ], %r10
	ret

	.global spc2cpu_0xCD
spc2cpu_0xCD: ; MOV X,#inm
	INMEDIATE_DATA
	xld.b [%r0+X], %r12
	xld.b [%r0+PSW_NZ], %r12
	ret

	.global spc2cpu_0xF8
spc2cpu_0xF8: ; MOV X,dp
	DIRECT_PAGE
	READ
	xld.b [%r0+X], %r10
	xld.b [%r0+PSW_NZ], %r10
	ret

	.global spc2cpu_0xF9
spc2cpu_0xF9: ; MOV X,dp+Y
	Y_INDEXED_DIRECT_PAGE
	READ
	xld.b [%r0+X], %r10
	xld.b [%r0+PSW_NZ], %r10
	ret

	.global spc2cpu_0xE9
spc2cpu_0xE9: ; MOV X,labs
	ABSOLUTE
	READ
	xld.b [%r0+X], %r10
	xld.b [%r0+PSW_NZ], %r10
	ret

	.global spc2cpu_0x8D
spc2cpu_0x8D: ; MOV Y,#inm
	INMEDIATE_DATA
	xld.b [%r0+Y], %r12
	xld.b [%r0+PSW_NZ], %r12
	ret

	.global spc2cpu_0xEB
spc2cpu_0xEB: ; MOV Y,dp
	DIRECT_PAGE
	READ
	xld.b [%r0+Y], %r10
	xld.b [%r0+PSW_NZ], %r10
	ret

	.global spc2cpu_0xFB
spc2cpu_0xFB: ; MOV Y,dp+X
	X_INDEXED_DIRECT_PAGE
	READ
	xld.b [%r0+Y], %r10
	xld.b [%r0+PSW_NZ], %r10
	ret

	.global spc2cpu_0xEC
spc2cpu_0xEC: ; MOV Y,labs
	ABSOLUTE
	READ
	xld.b [%r0+Y], %r10
	xld.b [%r0+PSW_NZ], %r10
	ret

;============================================================================
;	2. 8-BIT DATA TRANSMISSION COMMANDS GROUP 2
;============================================================================

	.global spc2cpu_0xC6
spc2cpu_0xC6: ; MOV (X),A
	INDIRECT
	xld.ub %r13, [%r0+A]
	WRITE
	ret

	.global spc2cpu_0xAF
spc2cpu_0xAF: ; MOV (X)+,A
	INDIRECT_AUTO_INCREMENT
	xld.ub %r13, [%r0+A]
	WRITE
	ret

	.global spc2cpu_0xC4
spc2cpu_0xC4: ; MOV dp,A
	DIRECT_PAGE
	xld.ub %r13, [%r0+A]
	WRITE
	ret

	.global spc2cpu_0xD4
spc2cpu_0xD4: ; MOV dp+X,A
	X_INDEXED_DIRECT_PAGE
	xld.ub %r13, [%r0+A]
	WRITE
	ret

	.global spc2cpu_0xC5
spc2cpu_0xC5: ; MOV labs,A
	ABSOLUTE
	xld.ub %r13, [%r0+A]
	WRITE
	ret

	.global spc2cpu_0xD5
spc2cpu_0xD5: ; MOV labs+X,A
	X_INDEXED_ABSOLUTE
	xld.ub %r13, [%r0+A]
	WRITE
	ret

	.global spc2cpu_0xD6
spc2cpu_0xD6: ; MOV labs+Y,A
	Y_INDEXED_ABSOLUTE
	xld.ub %r13, [%r0+A]
	WRITE
	ret

	.global spc2cpu_0xC7
spc2cpu_0xC7: ; MOV (dp+X),A
	X_INDEXED_INDIRECT
	xld.ub %r13, [%r0+A]
	WRITE
	ret

	.global spc2cpu_0xD7
spc2cpu_0xD7: ; MOV (dp)+Y,A
	INDIRECT_Y_INDEXED_INDIRECT
	xld.ub %r13, [%r0+A]
	WRITE
	ret

	.global spc2cpu_0xD8
spc2cpu_0xD8: ; MOV dp,X
	DIRECT_PAGE
	xld.ub %r13, [%r0+X]
	WRITE
	ret

	.global spc2cpu_0xD9
spc2cpu_0xD9: ; MOV dp+Y,X
	Y_INDEXED_DIRECT_PAGE
	xld.ub %r13, [%r0+X]
	WRITE
	ret

	.global spc2cpu_0xC9
spc2cpu_0xC9: ; MOV labs,X
	ABSOLUTE
	xld.ub %r13, [%r0+X]
	WRITE
	ret

	.global spc2cpu_0xCB
spc2cpu_0xCB: ; MOV dp,Y
	DIRECT_PAGE
	xld.ub %r13, [%r0+Y]
	WRITE
	ret

	.global spc2cpu_0xDB
spc2cpu_0xDB: ; MOV dp+X,Y
	X_INDEXED_DIRECT_PAGE
	xld.ub %r13, [%r0+Y]
	WRITE
	ret

	.global spc2cpu_0xCC
spc2cpu_0xCC: ; MOV labs,Y
	ABSOLUTE
	xld.ub %r13, [%r0+Y]
	WRITE
	ret

;============================================================================
;	3. 8-BIT DATA TRANSMISSIN COMMANDS GROUP 3
;============================================================================

	.global spc2cpu_0x7D
spc2cpu_0x7D: ; MOV A,X
	xld.ub %r10, [%r0+X]
	xld.b [%r0+A], %r10
	xld.b [%r0+PSW_NZ], %r10
	ret

	.global spc2cpu_0xDD
spc2cpu_0xDD: ; MOV A,Y
	xld.ub %r10, [%r0+Y]
	xld.b [%r0+A], %r10
	xld.b [%r0+PSW_NZ], %r10
	ret

	.global spc2cpu_0x5D
spc2cpu_0x5D: ; MOV X,A
	xld.ub %r10, [%r0+A]
	xld.b [%r0+X], %r10
	xld.b [%r0+PSW_NZ], %r10
	ret

	.global spc2cpu_0xFD
spc2cpu_0xFD: ; MOV Y,A
	xld.ub %r10, [%r0+A]
	xld.b [%r0+Y], %r10
	xld.b [%r0+PSW_NZ], %r10
	ret

	.global spc2cpu_0x9D
spc2cpu_0x9D: ; MOV X,SP
	xld.w %r10, [%r0+SP]
	ext spc2ram+0x100@ah
	ext spc2ram+0x100@al
	sub %r10, %r10
	xld.b [%r0+X], %r10
	xld.b [%r0+PSW_NZ], %r10
	ret

	.global spc2cpu_0xBD
spc2cpu_0xBD: ; MOV SP,X
	xld.ub %r10, [%r0+X]
	ext spc2ram+0x100@ah
	ext spc2ram+0x100@al
	add %r10, %r10
	xld.w [%r0+SP], %r10
	ret

	.global spc2cpu_0xFA
spc2cpu_0xFA: ; MOV dp(d),dp(s)
	DIRECT_PAGE_TO_DP
	READ
	ld.w %r12, %r13
	ld.w %r13, %r10
	WRITE
	ret

	.global spc2cpu_0x8F
spc2cpu_0x8F: ; MOV dp,#inm
	INMEDIATE_DATA_TO_DP
	ld.w %r10, %r12
	ld.w %r12, %r13
	ld.w %r13, %r10
	WRITE
	ret

;============================================================================
;	5. 8-BIT LOGIC OPERATION COMMANDS
;============================================================================

	.global spc2cpu_0x28
spc2cpu_0x28: ; AND A,#inm
	INMEDIATE_DATA
	ld.w %r15, %r12
	xld.ub %r14, [%r0+A]
	and %r14, %r15
	xld.b [%r0+A], %r14
	xld.b [%r0+PSW_NZ], %r14
	ret

	.global spc2cpu_0x26
spc2cpu_0x26: ; AND A,(X)
	INDIRECT
	READ
	ld.w %r15, %r10
	xld.ub %r14, [%r0+A]
	and %r14, %r15
	xld.b [%r0+A], %r14
	xld.b [%r0+PSW_NZ], %r14
	ret

	.global spc2cpu_0x24
spc2cpu_0x24: ; AND A,dp
	DIRECT_PAGE
	READ
	ld.w %r15, %r10
	xld.ub %r14, [%r0+A]
	and %r14, %r15
	xld.b [%r0+A], %r14
	xld.b [%r0+PSW_NZ], %r14
	ret

	.global spc2cpu_0x34
spc2cpu_0x34: ; AND A,dp+X
	X_INDEXED_DIRECT_PAGE
	READ
	ld.w %r15, %r10
	xld.ub %r14, [%r0+A]
	and %r14, %r15
	xld.b [%r0+A], %r14
	xld.b [%r0+PSW_NZ], %r14
	ret

	.global spc2cpu_0x25
spc2cpu_0x25: ; AND A,labs
	ABSOLUTE
	READ
	ld.w %r15, %r10
	xld.ub %r14, [%r0+A]
	and %r14, %r15
	xld.b [%r0+A], %r14
	xld.b [%r0+PSW_NZ], %r14
	ret

	.global spc2cpu_0x35
spc2cpu_0x35: ; AND A,labs+X
	X_INDEXED_ABSOLUTE
	READ
	ld.w %r15, %r10
	xld.ub %r14, [%r0+A]
	and %r14, %r15
	xld.b [%r0+A], %r14
	xld.b [%r0+PSW_NZ], %r14
	ret

	.global spc2cpu_0x36
spc2cpu_0x36: ; AND A,labs+Y
	Y_INDEXED_ABSOLUTE
	READ
	ld.w %r15, %r10
	xld.ub %r14, [%r0+A]
	and %r14, %r15
	xld.b [%r0+A], %r14
	xld.b [%r0+PSW_NZ], %r14
	ret

	.global spc2cpu_0x27
spc2cpu_0x27: ; AND A,(dp+X)
	X_INDEXED_INDIRECT
	READ
	ld.w %r15, %r10
	xld.ub %r14, [%r0+A]
	and %r14, %r15
	xld.b [%r0+A], %r14
	xld.b [%r0+PSW_NZ], %r14
	ret

	.global spc2cpu_0x37
spc2cpu_0x37: ; AND A,(dp)+Y
	INDIRECT_Y_INDEXED_INDIRECT
	READ
	ld.w %r15, %r10
	xld.ub %r14, [%r0+A]
	and %r14, %r15
	xld.b [%r0+A], %r14
	xld.b [%r0+PSW_NZ], %r14
	ret

	.global spc2cpu_0x39
spc2cpu_0x39: ; AND (X),(Y)
	INDIRECT_PAGE_TO_IP
	READ
	ld.w %r15, %r10
	READ
	ld.w %r14, %r10
	and %r14, %r15
	xld.b [%r0+A], %r14
	xld.b [%r0+PSW_NZ], %r14
	ret

	.global spc2cpu_0x29
spc2cpu_0x29: ; AND dp(d),dp(s)
	DIRECT_PAGE_TO_DP
	READ
	ld.w %r12, %r13
	ld.w %r13, %r10
	READ
	and %r13, %r10
	WRITE
	xld.b [%r0+PSW_NZ], %r13
	ret

	.global spc2cpu_0x38
spc2cpu_0x38: ; AND dp,#inm
	INMEDIATE_DATA_TO_DP
	ld.w %r10, %r12
	ld.w %r12, %r13
	ld.w %r13, %r10
	READ
	and %r13, %r10
	WRITE
	xld.b [%r0+PSW_NZ], %r13
	ret

;----------------------------------------------------------------------------

	.global spc2cpu_0x08
spc2cpu_0x08: ; OR A,#inm
	INMEDIATE_DATA
	ld.w %r15, %r12
	xld.ub %r14, [%r0+A]
	or %r14, %r15
	xld.b [%r0+A], %r14
	xld.b [%r0+PSW_NZ], %r14
	ret

	.global spc2cpu_0x06
spc2cpu_0x06: ; OR A,(X)
	INDIRECT
	READ
	ld.w %r15, %r10
	xld.ub %r14, [%r0+A]
	or %r14, %r15
	xld.b [%r0+A], %r14
	xld.b [%r0+PSW_NZ], %r14
	ret

	.global spc2cpu_0x04
spc2cpu_0x04: ; OR A,dp
	DIRECT_PAGE
	READ
	ld.w %r15, %r10
	xld.ub %r14, [%r0+A]
	or %r14, %r15
	xld.b [%r0+A], %r14
	xld.b [%r0+PSW_NZ], %r14
	ret

	.global spc2cpu_0x14
spc2cpu_0x14: ; OR A,dp+X
	X_INDEXED_DIRECT_PAGE
	READ
	ld.w %r15, %r10
	xld.ub %r14, [%r0+A]
	or %r14, %r15
	xld.b [%r0+A], %r14
	xld.b [%r0+PSW_NZ], %r14
	ret

	.global spc2cpu_0x05
spc2cpu_0x05: ; OR A,labs
	ABSOLUTE
	READ
	ld.w %r15, %r10
	xld.ub %r14, [%r0+A]
	or %r14, %r15
	xld.b [%r0+A], %r14
	xld.b [%r0+PSW_NZ], %r14
	ret

	.global spc2cpu_0x15
spc2cpu_0x15: ; OR A,labs+X
	X_INDEXED_ABSOLUTE
	READ
	ld.w %r15, %r10
	xld.ub %r14, [%r0+A]
	or %r14, %r15
	xld.b [%r0+A], %r14
	xld.b [%r0+PSW_NZ], %r14
	ret

	.global spc2cpu_0x16
spc2cpu_0x16: ; OR A,labs+Y
	Y_INDEXED_ABSOLUTE
	READ
	ld.w %r15, %r10
	xld.ub %r14, [%r0+A]
	or %r14, %r15
	xld.b [%r0+A], %r14
	xld.b [%r0+PSW_NZ], %r14
	ret

	.global spc2cpu_0x07
spc2cpu_0x07: ; OR A,(dp+X)
	X_INDEXED_INDIRECT
	READ
	ld.w %r15, %r10
	xld.ub %r14, [%r0+A]
	or %r14, %r15
	xld.b [%r0+A], %r14
	xld.b [%r0+PSW_NZ], %r14
	ret

	.global spc2cpu_0x17
spc2cpu_0x17: ; OR A,(dp)+Y
	INDIRECT_Y_INDEXED_INDIRECT
	READ
	ld.w %r15, %r10
	xld.ub %r14, [%r0+A]
	or %r14, %r15
	xld.b [%r0+A], %r14
	xld.b [%r0+PSW_NZ], %r14
	ret

	.global spc2cpu_0x19
spc2cpu_0x19: ; OR (X),(Y)
	INDIRECT_PAGE_TO_IP
	READ
	ld.w %r15, %r10
	READ
	ld.w %r14, %r10
	or %r14, %r15
	xld.b [%r0+A], %r14
	xld.b [%r0+PSW_NZ], %r14
	ret

	.global spc2cpu_0x09
spc2cpu_0x09: ; OR dp(d),dp(s)
	DIRECT_PAGE_TO_DP
	READ
	ld.w %r12, %r13
	ld.w %r13, %r10
	READ
	or %r13, %r10
	WRITE
	xld.b [%r0+PSW_NZ], %r13
	ret

	.global spc2cpu_0x18
spc2cpu_0x18: ; OR dp,#inm
	INMEDIATE_DATA_TO_DP
	ld.w %r10, %r12
	ld.w %r12, %r13
	ld.w %r13, %r10
	READ
	or %r13, %r10
	WRITE
	xld.b [%r0+PSW_NZ], %r13
	ret

;----------------------------------------------------------------------------

	.global spc2cpu_0x48
spc2cpu_0x48: ; EOR A,#inm
	INMEDIATE_DATA
	ld.w %r15, %r12
	xld.ub %r14, [%r0+A]
	xor %r14, %r15
	xld.b [%r0+A], %r14
	xld.b [%r0+PSW_NZ], %r14
	ret

	.global spc2cpu_0x46
spc2cpu_0x46: ; EOR A,(X)
	INDIRECT
	READ
	ld.w %r15, %r10
	xld.ub %r14, [%r0+A]
	xor %r14, %r15
	xld.b [%r0+A], %r14
	xld.b [%r0+PSW_NZ], %r14
	ret

	.global spc2cpu_0x44
spc2cpu_0x44: ; EOR A,dp
	DIRECT_PAGE
	READ
	ld.w %r15, %r10
	xld.ub %r14, [%r0+A]
	xor %r14, %r15
	xld.b [%r0+A], %r14
	xld.b [%r0+PSW_NZ], %r14
	ret

	.global spc2cpu_0x54
spc2cpu_0x54: ; EOR A,dp+X
	X_INDEXED_DIRECT_PAGE
	READ
	ld.w %r15, %r10
	xld.ub %r14, [%r0+A]
	xor %r14, %r15
	xld.b [%r0+A], %r14
	xld.b [%r0+PSW_NZ], %r14
	ret

	.global spc2cpu_0x45
spc2cpu_0x45: ; EOR A,labs
	ABSOLUTE
	READ
	ld.w %r15, %r10
	xld.ub %r14, [%r0+A]
	xor %r14, %r15
	xld.b [%r0+A], %r14
	xld.b [%r0+PSW_NZ], %r14
	ret

	.global spc2cpu_0x55
spc2cpu_0x55: ; EOR A,labs+X
	X_INDEXED_ABSOLUTE
	READ
	ld.w %r15, %r10
	xld.ub %r14, [%r0+A]
	xor %r14, %r15
	xld.b [%r0+A], %r14
	xld.b [%r0+PSW_NZ], %r14
	ret

	.global spc2cpu_0x56
spc2cpu_0x56: ; EOR A,labs+Y
	Y_INDEXED_ABSOLUTE
	READ
	ld.w %r15, %r10
	xld.ub %r14, [%r0+A]
	xor %r14, %r15
	xld.b [%r0+A], %r14
	xld.b [%r0+PSW_NZ], %r14
	ret

	.global spc2cpu_0x47
spc2cpu_0x47: ; EOR A,(dp+X)
	X_INDEXED_INDIRECT
	READ
	ld.w %r15, %r10
	xld.ub %r14, [%r0+A]
	xor %r14, %r15
	xld.b [%r0+A], %r14
	xld.b [%r0+PSW_NZ], %r14
	ret

	.global spc2cpu_0x57
spc2cpu_0x57: ; EOR A,(dp)+Y
	INDIRECT_Y_INDEXED_INDIRECT
	READ
	ld.w %r15, %r10
	xld.ub %r14, [%r0+A]
	xor %r14, %r15
	xld.b [%r0+A], %r14
	xld.b [%r0+PSW_NZ], %r14
	ret

	.global spc2cpu_0x59
spc2cpu_0x59: ; EOR (X),(Y)
	INDIRECT_PAGE_TO_IP
	READ
	ld.w %r15, %r10
	READ
	ld.w %r14, %r10
	xor %r14, %r15
	xld.b [%r0+A], %r14
	xld.b [%r0+PSW_NZ], %r14
	ret

	.global spc2cpu_0x49
spc2cpu_0x49: ; EOR dp(d),dp(s)
	DIRECT_PAGE_TO_DP
	READ
	ld.w %r12, %r13
	ld.w %r13, %r10
	READ
	xor %r13, %r10
	WRITE
	xld.b [%r0+PSW_NZ], %r13
	ret

	.global spc2cpu_0x58
spc2cpu_0x58: ; EOR dp,#inm
	INMEDIATE_DATA_TO_DP
	ld.w %r10, %r12
	ld.w %r12, %r13
	ld.w %r13, %r10
	READ
	xor %r13, %r10
	WRITE
	xld.b [%r0+PSW_NZ], %r13
	ret

;============================================================================
;	7. SHIFT, ROTATION COMMANDS
;============================================================================

	.global spc2cpu_0x1C
spc2cpu_0x1C: ; ASL A
	xld.ub %r13, [%r0+A]
	xsll %r13, 1
	xld.b [%r0+A], %r13
	xld.h [%r0+PSW_CNZ], %r13
	ret

	.global spc2cpu_0x0B
spc2cpu_0x0B: ; ASL dp
	DIRECT_PAGE
	READ
	ld.w %r13, %r10
	xsll %r13, 1
	WRITE
	xld.h [%r0+PSW_CNZ], %r13
	ret

	.global spc2cpu_0x1B
spc2cpu_0x1B: ; ASL dp+X
	X_INDEXED_DIRECT_PAGE
	READ
	ld.w %r13, %r10
	xsll %r13, 1
	WRITE
	xld.h [%r0+PSW_CNZ], %r13
	ret

	.global spc2cpu_0x0C
spc2cpu_0x0C: ; ASL labs
	ABSOLUTE
	READ
	ld.w %r13, %r10
	xsll %r13, 1
	WRITE
	xld.h [%r0+PSW_CNZ], %r13
	ret

;----------------------------------------------------------------------------

	.global spc2cpu_0x5C
spc2cpu_0x5C: ; LSR A
	xld.ub %r13, [%r0+A]
	xld.b [%r0+PSW_C], %r13
	xsrl %r13, 1
	xld.b [%r0+A], %r13
	xld.b [%r0+PSW_NZ], %r13
	ret

	.global spc2cpu_0x4B
spc2cpu_0x4B: ; LSR dp
	DIRECT_PAGE
	READ
	ld.w %r13, %r10
	xld.b [%r0+PSW_C], %r13
	xsrl %r13, 1
	WRITE
	xld.b [%r0+PSW_NZ], %r13
	ret

	.global spc2cpu_0x5B
spc2cpu_0x5B: ; LSR dp+X
	X_INDEXED_DIRECT_PAGE
	READ
	ld.w %r13, %r10
	xld.b [%r0+PSW_C], %r13
	xsrl %r13, 1
	WRITE
	xld.b [%r0+PSW_NZ], %r13
	ret

	.global spc2cpu_0x4C
spc2cpu_0x4C: ; LSR labs
	ABSOLUTE
	READ
	ld.w %r13, %r10
	xld.b [%r0+PSW_C], %r13
	xsrl %r13, 1
	WRITE
	xld.b [%r0+PSW_NZ], %r13
	ret

;----------------------------------------------------------------------------

	.global spc2cpu_0x3C
spc2cpu_0x3C: ; ROL A
	xld.ub %r13, [%r0+A]
	xsll %r13, 1
	xld.ub %r10, [%r0+PSW_C]
	xand %r10, %r10, 1
	or %r13, %r10
	xld.b [%r0+A], %r13
	xld.h [%r0+PSW_CNZ], %r13
	ret

	.global spc2cpu_0x2B
spc2cpu_0x2B: ; ROL dp
	DIRECT_PAGE
	READ
	ld.w %r13, %r10
	xsll %r13, 1
	xld.ub %r10, [%r0+PSW_C]
	xand %r10, %r10, 1
	or %r13, %r10
	WRITE
	xld.h [%r0+PSW_CNZ], %r13
	ret

	.global spc2cpu_0x3B
spc2cpu_0x3B: ; ROL dp+X
	X_INDEXED_DIRECT_PAGE
	READ
	ld.w %r13, %r10
	xsll %r13, 1
	xld.ub %r10, [%r0+PSW_C]
	xand %r10, %r10, 1
	or %r13, %r10
	WRITE
	xld.h [%r0+PSW_CNZ], %r13
	ret

	.global spc2cpu_0x2C
spc2cpu_0x2C: ; ROL labs
	ABSOLUTE
	READ
	ld.w %r13, %r10
	xsll %r13, 1
	xld.ub %r10, [%r0+PSW_C]
	xand %r10, %r10, 1
	or %r13, %r10
	WRITE
	xld.h [%r0+PSW_CNZ], %r13
	ret

;----------------------------------------------------------------------------

	.global spc2cpu_0x7C
spc2cpu_0x7C: ; ROR A
	xld.ub %r10, [%r0+A]
	xld.ub %r13, [%r0+PSW_C]
	xld.b [%r0+PSW_C], %r10
	xsrl %r10, 1
	xsll %r13, 7
	or %r13, %r10
	xld.b [%r0+A], %r13
	xld.b [%r0+PSW_NZ], %r13
	ret

	.global spc2cpu_0x6B
spc2cpu_0x6B: ; ROR dp
	DIRECT_PAGE
	READ
	xld.ub %r13, [%r0+PSW_C]
	xld.b [%r0+PSW_C], %r10
	xsrl %r10, 1
	xsll %r13, 7
	or %r13, %r10
	WRITE
	xld.b [%r0+PSW_NZ], %r13
	ret

	.global spc2cpu_0x7B
spc2cpu_0x7B: ; ROR dp+X
	X_INDEXED_DIRECT_PAGE
	READ
	xld.ub %r13, [%r0+PSW_C]
	xld.b [%r0+PSW_C], %r10
	xsrl %r10, 1
	xsll %r13, 7
	or %r13, %r10
	WRITE
	xld.b [%r0+PSW_NZ], %r13
	ret

	.global spc2cpu_0x6C
spc2cpu_0x6C: ; ROR labs
	ABSOLUTE
	READ
	xld.ub %r13, [%r0+PSW_C]
	xld.b [%r0+PSW_C], %r10
	xsrl %r10, 1
	xsll %r13, 7
	or %r13, %r10
	WRITE
	xld.b [%r0+PSW_NZ], %r13
	ret

;----------------------------------------------------------------------------

	.global spc2cpu_0x9F
spc2cpu_0x9F: ; XCN A
	xld.ub %r10, [%r0+A]
	ld.w %r11, %r10
	xsrl %r10, 4
	xsll %r11, 4
	or %r10, %r11
	xld.b [%r0+A], %r10
	xld.b [%r0+PSW_NZ], %r10
	ret

;============================================================================
;	12. BRANCHING COMMANDS
;============================================================================

	.global spc2cpu_0x2F
spc2cpu_0x2F: ; BRA rel
	RELATIVE
	ret

	.global spc2cpu_0xF0
spc2cpu_0xF0: ; BEQ rel
	xld.ub %r10, [%r0+PSW_NZ]
	xcmp %r10, 0
	BEQ
	ret

	.global spc2cpu_0xD0
spc2cpu_0xD0: ; BNE rel
	xld.ub %r10, [%r0+PSW_NZ]
	xcmp %r10, 0
	BNE
	ret

	.global spc2cpu_0xB0
spc2cpu_0xB0: ; BCS rel
	xbtst [%r0+PSW_C], 0
	BNE
	ret

	.global spc2cpu_0x90
spc2cpu_0x90: ; BCC rel
	xbtst [%r0+PSW_C], 0
	BEQ
	ret

	.global spc2cpu_0x70
spc2cpu_0x70: ; BVS rel
	xbtst [%r0+PSW_V], 7
	BNE
	ret

	.global spc2cpu_0x50
spc2cpu_0x50: ; BVC rel
	xbtst [%r0+PSW_V], 7
	BEQ
	ret

	.global spc2cpu_0x30
spc2cpu_0x30: ; BMI rel
	xbtst [%r0+PSW_NZ], 7
	BNE
	ret

	.global spc2cpu_0x10
spc2cpu_0x10: ; BPL rel
	xbtst [%r0+PSW_NZ], 7
	BEQ
	ret

	.global spc2cpu_0x03
spc2cpu_0x03: ; BBS0 dp,rel
	DIRECT_PAGE
	READ
	xand %r10, %r10, 1<<0
	BNE
	ret

	.global spc2cpu_0x23
spc2cpu_0x23: ; BBS1 dp,rel
	DIRECT_PAGE
	READ
	xand %r10, %r10, 1<<1
	BNE
	ret

	.global spc2cpu_0x43
spc2cpu_0x43: ; BBS2 dp,rel
	DIRECT_PAGE
	READ
	xand %r10, %r10, 1<<2
	BNE
	ret

	.global spc2cpu_0x63
spc2cpu_0x63: ; BBS3 dp,rel
	DIRECT_PAGE
	READ
	xand %r10, %r10, 1<<3
	BNE
	ret

	.global spc2cpu_0x83
spc2cpu_0x83: ; BBS4 dp,rel
	DIRECT_PAGE
	READ
	xand %r10, %r10, 1<<4
	BNE
	ret

	.global spc2cpu_0xA3
spc2cpu_0xA3: ; BBS5 dp,rel
	DIRECT_PAGE
	READ
	xand %r10, %r10, 1<<5
	BNE
	ret

	.global spc2cpu_0xC3
spc2cpu_0xC3: ; BBS6 dp,rel
	DIRECT_PAGE
	READ
	xand %r10, %r10, 1<<6
	BNE
	ret

	.global spc2cpu_0xE3
spc2cpu_0xE3: ; BBS7 dp,rel
	DIRECT_PAGE
	READ
	xand %r10, %r10, 1<<7
	BNE
	ret

	.global spc2cpu_0x13
spc2cpu_0x13: ; BBC0 dp,rel
	DIRECT_PAGE
	READ
	xand %r10, %r10, 1<<0
	BEQ
	ret

	.global spc2cpu_0x33
spc2cpu_0x33: ; BBC1 dp,rel
	DIRECT_PAGE
	READ
	xand %r10, %r10, 1<<1
	BEQ
	ret

	.global spc2cpu_0x53
spc2cpu_0x53: ; BBC2 dp,rel
	DIRECT_PAGE
	READ
	xand %r10, %r10, 1<<2
	BEQ
	ret

	.global spc2cpu_0x73
spc2cpu_0x73: ; BBC3 dp,rel
	DIRECT_PAGE
	READ
	xand %r10, %r10, 1<<3
	BEQ
	ret

	.global spc2cpu_0x93
spc2cpu_0x93: ; BBC4 dp,rel
	DIRECT_PAGE
	READ
	xand %r10, %r10, 1<<4
	BEQ
	ret

	.global spc2cpu_0xB3
spc2cpu_0xB3: ; BBC5 dp,rel
	DIRECT_PAGE
	READ
	xand %r10, %r10, 1<<5
	BEQ
	ret

	.global spc2cpu_0xD3
spc2cpu_0xD3: ; BBC6 dp,rel
	DIRECT_PAGE
	READ
	xand %r10, %r10, 1<<6
	BEQ
	ret

	.global spc2cpu_0xF3
spc2cpu_0xF3: ; BBC7 dp,rel
	DIRECT_PAGE
	READ
	xand %r10, %r10, 1<<7
	BEQ
	ret

	.global spc2cpu_0x2E
spc2cpu_0x2E: ; CBNE dp,rel
	DIRECT_PAGE
	READ
	xld.ub %r11, [%r0+A]
	cmp %r11, %r10
	BNE
	ret

	.global spc2cpu_0xDE
spc2cpu_0xDE: ; CBNE dp+X,rel
	X_INDEXED_DIRECT_PAGE
	READ
	xld.ub %r11, [%r0+A]
	cmp %r11, %r10
	BNE
	ret

	.global spc2cpu_0x6E
spc2cpu_0x6E: ; DBNZ dp,rel
	DIRECT_PAGE
	READ
	xsub %r13, %r10, 1
	BNE
	WRITE
	ret

	.global spc2cpu_0xFE
spc2cpu_0xFE: ; DBNZ Y,rel
	xld.ub %r10, [%r0+Y]
	xsub %r10, %r10, 1
	xld.b [%r0+Y], %r10
	BNE
	ret

	.global spc2cpu_0x5F
spc2cpu_0x5F: ; JMP labs
	ABSOLUTE
	ext spc2ram@ah
	ext spc2ram@al
	add %r1, %r12
	ret

	.global spc2cpu_0x1F
spc2cpu_0x1F: ; JMP (labs+X)
	X_INDEXED_ABSOLUTE_INDIRECT
	ext spc2ram@ah
	ext spc2ram@al
	add %r1, %r12
	ret

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

	.global spc2vce_mix
spc2vce_mix:
	pushn %r3
	xsub %sp, %sp, 8
	; %r12 = vce
	; %r13 = mixbuf

	; メインボリューム×チャネルボリューム×エンベロープを求めます。
	xld.w %r0, [spc2dsp+MVOL]	; vol = (dsp->mvol * vce->vol * (vce->envx >> 16)) >> 13
	xld.w %r10, [%r12+VOL]
	xld.w %r11, [%r12+ENVX]
	mlt.h %r0, %r10
	ld.w %r0, %alr
	xsrl %r11, 16
	mlt.h %r0, %r11
	ld.w %r0, %alr
	xsrl %r0, 13
	xjreq spc2vce_mix_EXIT		; ボリュームが0か、ほとんどゼロ
	; %r0 = vol

	; 高速化のため、頻繁に使うフィールドを取り出しておきます。
	xld.w %r1, [%r12+PROGRESS]	; vce->progress
	xld.w %r2, [%r12+P]		; vce->p
	; %r1 = progress
	; %r2 = p

	; vce->sampleのベースアドレスも計算しておいた方が速いです。
	; この値はvceから簡単に復元できるので、spc2vce_decode_brr呼び出し時にスタックに保存する必要はありません。
	; vce->pも簡単に復元できるのですが、メモリ読み出しを伴わない分vce->sampleの方が復元コストが安いと考え、
	; vce->pは保存されるレジスタ%r2に、vce->sampleは保存されないレジスタ%r4に置くことにしました。
	xadd %r4, %r12, SAMPLE
	; %r4 = sample

	; 同様に、16<<11も頻繁に使うので、レジスタに保持することにします。
	; %r4=sampleと同様、spc2vce_decode_brr呼び出し時はスタックに保存せず、明示的に16<<11を代入して復元します。
	xld.w %r5, 16<<11
	; %r5 = 16<<11

	xld.w %r3, 64			; for(i = 0; i < 64; i++) {
	; %r3 = i
spc2vce_mix_L10:
	add %r1, %r2			; progress += p

spc2vce_mix_L20:
	cmp %r1, %r5			; while(progress >= 16 << 11) {
	xjrlt spc2vce_mix_L30
	sub %r1, %r5			; progress -= 16 << 11

	xbtst [%r12+LAST_LOOP], 0	; if(vce->last_loop & 1) { /* 最終ブロック */
	xjreq spc2vce_mix_L40
	xbtst [%r12+LAST_LOOP], 1	; if(!(vce->last_loop & 2)) { /* ループしない音色 */
	xjrne spc2vce_mix_L50

	xld.w [%r12+STATE], %r8		; vce->state = 0
	xjp spc2vce_mix_EXIT		; return

spc2vce_mix_L50:			; } else { /* ループ音色 */
	xld.w %r10, [%r12+LSA]		; vce->brr_addr = vce->lsa
	xld.w [%r12+BRR_ADDR], %r10
	; FALLTHRU

spc2vce_mix_L40:			; } /* if */
	xld.w [%sp+ 0], %r12
	xld.w [%sp+ 4], %r13
	xcall spc2vce_decode_brr	; spc2vce_decode_brr(vce)
	xld.w %r12, [%sp+ 0]
	xld.w %r13, [%sp+ 4]
	xadd %r4, %r12, SAMPLE		; %r4 = sample 復元
	xld.w %r5, 16<<11		; %r5 = 16<<11 復元
	xjp spc2vce_mix_L20

spc2vce_mix_L30:			; } /* while */
	ld.w %r10, [%r13]		; *mixbuf
	ld.w %r11, %r1			; sample[progress >> 11]
	xsrl %r11, 11-1
	xand %r11, %r11, ~1
	add %r11, %r4
	ld.h %r11, [%r11]
	mlt.h %r11, %r0			; sample[progress >> 11] * vol
	ld.w %r11, %alr
	add %r10, %r11			; *mixbuf++ += (sample[progress >> 11] * vol)
	ld.w [%r13]+, %r10

	xsub %r3, %r3, 1		; } /* for */
	xjrne spc2vce_mix_L10

	; 進行カウンタ書き戻し。忘れないで!!
	xld.w [%r12+PROGRESS], %r1	; vce->progress

spc2vce_mix_EXIT:
	xadd %sp, %sp, 8
	popn %r3
	ret

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

	.global spc2vce_decode_brr
spc2vce_decode_brr:
	pushn %r1
	; %r12 = vce

	; 圧縮データ、展開バッファポインタを取得。
	xadd %r13, %r12, SAMPLE		; dst = vce->sample
	xld.w %r14, [%r12+BRR_ADDR]	; 先にBRRブロックアドレスを進めておきます。
	xadd %r10, %r14, 9
	xld.w [%r12+BRR_ADDR], %r10
	ext spc2ram@ah			; src = &spc2ram[vce->brr_addr]
	ext spc2ram@al			; (ext33は"xadd %rd,%rs,addr"を展開できない)
	add %r14, %r14
	; %r13 = dst
	; %r14 = src

	; ヘッダ読み出し、格納。
	ld.ub %r15, [%r14]+		; header = *src++
	xld.w [%r12+LAST_LOOP], %r15	; vce->last_loop = header
	; %r15 = header

	; フィルタ係数取得。
	xand %r10, %r15, 3<<2		; f = spc2dsp_filter_table[(header >> 2) & 3]
	ext spc2dsp_filter_table@ah	; (ext33は"xadd %rd,%rs,addr"を展開できない)
	ext spc2dsp_filter_table@al
	add %r10, %r10
	ld.h %r4, [%r10]+		; f1 = f[0]
	ld.h %r5, [%r10]		; f2 = f[1]
	; %r4 = f1
	; %r5 = f1

	; スケーリング係数取得。
	xsrl %r15, 4			; range = header >> 4
	; %r15 = range

	xld.h %r6, [%r13+(16-1)*2]	; prev1 = vce->sample[16 - 1] /* 1つ前のサンプル */
	xld.h %r7, [%r13+(16-2)*2]	; prev2 = vce->sample[16 - 2] /* 2つ前のサンプル */
	; %r6 = prev1
	; %r7 = prev2

	xld.w %r12, 8			; for(i = 0; i < 8; i++) {
	; %r12 = i
spc2vce_decode_brr_L10:

	ld.b %r0, [%r14]+		; ..._ssssssss_hhhhllll,s=h[MSB]
	xsll %r0, 4			; ..._sssshhhh_llll0000
	ld.b %r1, %r0			; ..._tttttttt_llll0000,t=l[MSB]
	xsra %r0, 8			; ..._ssssssss_sssshhhh => data1 /* 上位ニブルが先 */
	xsra %r1, 4			; ..._tttttttt_ttttllll => data2 /* 下位ニブルが後 */
	; %r0 = data1
	; %r1 = data2

	; 先行サンプルを復号。
	mlt.h %r6, %r4			; prev1 * f1
	ld.w %r10, %alr
	mlt.h %r7, %r5			; prev2 * f2
	ld.w %r11, %alr
	sub %r10, %r11			; (prev1 * f1) - (prev2 * f2)
	xsra %r10, 8			; ((prev1 * f1) - (prev2 * f2)) >> 8
	xsll %r0, %r15			; data1 << range
	add %r0, %r10			; (data1 << range) + (((prev1 * f1) - (prev2 * f2)) >> 8)
	xcmp %r0, -0x7fff		; if(data1 < -0x7fff) data1 = -0x7fff
	xjrge spc2vce_decode_brr_L20
	xld.w %r0, -0x7fff
spc2vce_decode_brr_L20:
	xcmp %r0, 0x7fff		; if(data1 >  0x7fff) data1 =  0x7fff
	xjrle spc2vce_decode_brr_L30
	xld.w %r0, 0x7fff
spc2vce_decode_brr_L30:
	ld.h [%r13]+, %r0		; *dst++ = data1
	ld.w %r7, %r6			; prev2 = prev1
	ld.w %r6, %r0			; prev1 = data1

	; 後続サンプルを復号。
	mlt.h %r6, %r4			; prev1 * f1
	ld.w %r10, %alr
	mlt.h %r7, %r5			; prev2 * f2
	ld.w %r11, %alr
	sub %r10, %r11			; (prev1 * f1) - (prev2 * f2)
	xsra %r10, 8			; ((prev1 * f1) - (prev2 * f2)) >> 8
	xsll %r1, %r15			; data2 << range
	add %r1, %r10			; (data2 << range) + (((prev1 * f1) - (prev2 * f2)) >> 8)
	xcmp %r1, -0x7fff		; if(data2 < -0x7fff) data2 = -0x7fff
	xjrge spc2vce_decode_brr_L40
	xld.w %r1, -0x7fff
spc2vce_decode_brr_L40:
	xcmp %r1, 0x7fff		; if(data2 >  0x7fff) data2 =  0x7fff
	xjrle spc2vce_decode_brr_L50
	xld.w %r1, 0x7fff
spc2vce_decode_brr_L50:
	ld.h [%r13]+, %r1		; *dst++ = data2
	ld.w %r7, %r6			; prev2 = prev1
	ld.w %r6, %r1			; prev1 = data2

	xsub %r12, %r12, 1		; } /* for */
	xjrne spc2vce_decode_brr_L10

	popn %r1
	ret

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

#endif ;/*SPC2_ASM*/
