;	
;	framapua.s
;
;	P/ECE APU (RICOH RP2A03) Emulator
;	
;	CLiP - Common Library for P/ECE
;	Copyright (C) 2001-2005 Naoyuki Sawa
;	
;	* Sun Feb 06 18:39:00 JST 2005 Naoyuki Sawa
;	- 作成開始。
;
;#include "clipapua.h"
;/	
;/	framapua.h
;/
;/	P/ECE APU (RICOH RP2A03) Emulator
;/
;/	CLiP - Common Library for P/ECE
;/	Copyright (C) 2001-2005 Naoyuki Sawa
;/
;/	* Sun Feb 06 18:39:00 JST 2005 Naoyuki Sawa
;/	- 作成開始。
;/

;/ このファイルはC/アセンブラソース両方から参照します。
;/ C言語特有の定義を含めてはいけません。

;/ このシンボルを定義すると、アセンブラコードを使用します。
;/ このシンボルを定義しなければ、Ｃ言語コードを使用します。
;#define APU_ASM
;#ifdef APU_ASM

	.code
	.align 1

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

;#define SPEAKER_FREQUENCY	16000	; -> clipmisc.h
;#define	NTSC_COLOR_SUBCARRIER	3579545	; -> clipemu.h
;#define APU_CLOCK		(NTSC_COLOR_SUBCARRIER/2)

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

					; /* レングスカウンタ (60Hz) */
					; typedef struct _APULENGTH {
;#define APULENGTH_FLAGS		 0	; 	unsigned char flags;		/* + 0,1: D0: 0 = レングスカウンタ無効 */
					; 					/*            1 = レングスカウンタ有効 */
;#define APULENGTH_COUNT		 1	; 	unsigned char count;		/* + 1,1: レングスカウンタ (0..127) */
;#define SIZEOF_APULENGTH	 2	; } APULENGTH;				/* = 2 */
 
					; /* リニアカウンタ (240Hz) */
					; typedef struct _APULINEAR {
;#define APULINEAR_FLAGS		 0	; 	unsigned char flags;		/* + 0,1: D0: 0 = リニアカウンタ無効 */
					; 					/*            1 = リニアカウンタ有効 */
;#define APULINEAR_COUNT		 1	; 	unsigned char count;		/* + 1,1: リニアカウンタ (0..127) */
;#define SIZEOF_APULINEAR	 2	; } APULINEAR;				/* = 2 */
 
					; /* エンベロープ (240Hz) */
					; typedef struct _APUENVELOPE {
;#define APUENVELOPE_FLAGS	 0	; 	unsigned char flags;		/* + 0,1: D0: 0 = エンベロープ無効 */
					; 					/*            1 = エンベロープ有効 */
					; 					/*        D1: 0 = ループ無し */
					; 					/*            1 = ループ有り */
;#define APUENVELOPE_PERIOD	 1	; 	unsigned char period;		/* + 1,1: 更新周期 (1..16) */
;#define APUENVELOPE_COUNT	 2	; 	unsigned char count;		/* + 2,1: 進行カウンタ (0..16) */
;#define APUENVELOPE_VOLUME	 3	; 	unsigned char volume;		/* + 3,1: ボリューム (0..15) */
;#define SIZEOF_APUENVELOPE	 4	; } APUENVELOPE;			/* = 4 */
 
					; /* スイープ (120Hz) */
					; typedef struct _APUSWEEP {
;#define APUSWEEP_FLAGS		 0	; 	unsigned char flags;		/* + 0,1: D0: 0 = スイープ無効 */
					; 					/*            1 = スイープ有効 */
					; 					/*        D1: 0 = 周期増加 */
					; 					/*            1 = 周期減少 */
;#define APUSWEEP_SHIFT		 1	; 	unsigned char shift;		/* + 1,1: 波長増減量のシフト数 */
;#define APUSWEEP_PERIOD		 2	; 	unsigned char period;		/* + 2,1: 更新周期 (1..8) */
;#define APUSWEEP_COUNT		 3	; 	unsigned char count;		/* + 3,1: 進行カウンタ (0..8) */
;#define APUSWEEP_WAVELENGTH	 4	; 	short wavelength;		/* + 4,2: 波長 ($000..$800) */
;#define SIZEOF_APUSWEEP		 6	; } APUSWEEP;				/* = 6 */
 
					; /* 矩形波 (Ch0,Ch1) */
					; typedef struct _APUSQUARE {
;#define APUSQUARE_LENGTH	 0	; 	APULENGTH length;		/* + 0,2: レングスカウンタ */
;#define APUSQUARE_ENVELOPE	 2	; 	APUENVELOPE envelope;		/* + 2,4: エンベロープ */
;#define APUSQUARE_SWEEP		 6	; 	APUSWEEP sweep;			/* + 6,6: スイープ */
;#define APUSQUARE_DUTY		12	; 	unsigned char duty;		/* +12,1: デューティサイクル (2,4,8,12) */
;#define APUSQUARE_WAVEINDEX	13	; 	unsigned char waveindex;	/* +13,1: 波形インデクス (0..15) */
					; 					/* +14,2: (パディング) */
;#define APUSQUARE_WAVECOUNT	16	; 	int wavecount;			/* +16,4: 波形進行カウンタ */
;#define SIZEOF_APUSQUARE	20	; } APUSQUARE;				/* =20 */
 
					; /* 三角波 (Ch2) */
					; typedef struct _APUTRIANGLE {
;#define APUTRIANGLE_LENGTH	 0	; 	APULENGTH length;		/* + 0,2: レングスカウンタ */
;#define APUTRIANGLE_LINEAR	 2	; 	APULINEAR linear;		/* + 2,2: リニアカウンタ */
;#define APUTRIANGLE_WAVELENGTH	 4	; 	short wavelength;		/* + 4,2: 波長 ($000..$7ff) */
;#define APUTRIANGLE_WAVEINDEX	 6	; 	unsigned char waveindex;	/* + 6,1: 波形インデクス (0..31) */
					; 					/* + 7,1: (パディング) */
;#define APUTRIANGLE_WAVECOUNT	 8	; 	int wavecount;			/* + 8,4: 波形進行カウンタ */
;#define SIZEOF_APUTRIANGLE	12	; } APUTRIANGLE;			/* =12 */
 
					; /* ノイズ (Ch3) */
					; typedef struct _APUNOISE {
;#define APUNOISE_LENGTH		 0	; 	APULENGTH length;		/* + 0,2: レングスカウンタ */
;#define APUNOISE_ENVELOPE	 2	; 	APUENVELOPE envelope;		/* + 2,4: エンベロープ */
;#define APUNOISE_MODE		 6	; 	unsigned char mode;		/* + 6,1: 0 = long mode, 1 = short mode */
					; 					/* + 7,1: (パディング) */
;#define APUNOISE_LFSR		 8	; 	unsigned short lfsr;		/* + 8,2: LFSR (Linear Feedback Shift Register) */
;#define APUNOISE_WAVELENGTH	10	; 	short wavelength;		/* +10,2: 波長 ($000..$fff) */
;#define APUNOISE_WAVECOUNT	12	; 	int wavecount;			/* +12,4: 波形進行カウンタ */
;#define SIZEOF_APUNOISE		16	; } APUNOISE;				/* =16 */

					; /* デルタPCM (Ch4) */
					; typedef struct _APUDMC {
;#define APUDMC_FLAGS		 0	; 	unsigned char flags;		/* + 0,1: D0: 0 = ループ無し */
					; 					/*            1 = ループ有り */
					; 					/*        D7: 発声開始時に、apu_write()  がセット(1)します。 */
					; 					/*            発声完了時に、apu_dmc_mix()がクリア(0)します。 */
;#define APUDMC_INIT_OUTPUT	 1	; 	char init_output;		/* + 1,1: 出力初期値 (-64..63) */
;#define APUDMC_INIT_ADDRESS	 2	; 	unsigned short init_address;	/* + 2,2: サンプルアドレス初期値 ($C000..$FFC0) */
;#define APUDMC_INIT_LENGTH	 4	; 	short init_length;		/* + 4,2: サンプルデータ長初期値 ($001..$FF1) ★出力初期値も1カウント分と見なす★ */
;#define APUDMC_WAVELENGTH	 6	; 	short wavelength;		/* + 6,2: 波長 ($036..$1ac) */
					; 	//
					; 					/* + 8,1: (パディング) */
;#define APUDMC_OUTPUT		 9	; 	char output;			/* + 9,1: 現在の出力値 (-64..63) */
;#define APUDMC_ADDRESS		10	; 	unsigned short address;		/* +10,2: 次回サンプルアドレス (init_address->$FFFF->$8000->$FFFF) */
;#define APUDMC_LENGTH		12	; 	short length;			/* +12,2: 残りサンプルデータ長 (init_length->$000) */
;#define APUDMC_SAMPLE		14	; 	unsigned short sample;		/* +14,2: サンプルバッファ */
					; 					/*        サンプル取得時に (0x100|data) をセットします。 */
					; 					/*        最下位ビットを消費するたびに、右シフトします。 */
					; 					/*        (sample<=1) ならば、サンプルバッファが空です。 */
;#define APUDMC_WAVECOUNT	16	; 	int wavecount;			/* +16,4: 波形進行カウンタ */
					; 	//
;#define APUDMC_MEMORY		20	; 	const unsigned char* memory;	/* +20,4: サンプルデータメモリの先頭アドレス */
;#define SIZEOF_APUDMC		24	; } APUDMC;				/* =24 */

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

;
;	void apu_square_mix(APUSQUARE* square, short wbuff[/*64*/])
;
	.global	apu_square_mix
apu_square_mix:
	ext	0x1		; 	xld.ub	%r9, [%r12+0x1]
	ld.ub	%r9,[%r12]
	cmp	%r9,0x0		; 	xcmp	%r9, 0							; if(!length->count) goto EXIT
	jreq	apu_square_mix_EXIT	; 	xjreq	apu_square_mix_EXIT
	;
	ext	0x5		; 	xld.ub	%r4, [%r12+0x5]	; %r4 = volume = envelope->volume
	ld.ub	%r4,[%r12]
	cmp	%r4,0x0		; 	xcmp	%r4, 0							; if(!volume) goto EXIT
	jreq	apu_square_mix_EXIT	; 	xjreq	apu_square_mix_EXIT
	;
	ext	0xa		; 	xld.h	%r5, [%r12+0xa]		; %r5 = wavelength = sweep->wavelength
	ld.h	%r5,[%r12]
	cmp	%r5,0x8		; 	xcmp	%r5, 8							; if(wavelength <= 8) goto EXIT
	jrle	apu_square_mix_EXIT	; 	xjrle	apu_square_mix_EXIT
	ext	0x1f		; 	xcmp	%r5, 0x7ff						; if(wavelength >= 0x7ff) goto EXIT
	cmp	%r5,0x3f
	jrge	apu_square_mix_EXIT	; 	xjrge	apu_square_mix_EXIT
	;
	add	%r5,0x1		; 	xadd	%r5, %r5, 1						; wavelength = (wavelength + 1) * SPEAKER_FREQUENCY
	ext	0xfa		; 	xld.w	%r9, 16000
	ld.w	%r9,0x0
	mlt.h	%r5, %r9
	ld.w	%r5, %alr
	;
	ext	0xc		; 	xld.ub	%r6, [%r12+0xc]				; %r6 = duty = square->duty
	ld.ub	%r6,[%r12]
	;
	ext	0xd		; 	xld.ub	%r14, [%r12+0xd]			; %r14 = waveindex = square->waveindex
	ld.ub	%r14,[%r12]
	ext	0x10		; 	xld.w	%r15, [%r12+0x10]			; %r15 = wavecount = square->wavecount
	ld.w	%r15,[%r12]
	;
	cmp	%r14, %r6						; output = (waveindex < duty) ? volume : -volume
	jrge.d	4
	ld.w	%r7, %r4						; *delay*
	not	%r7, %r4						; (skip?)
	add	%r7, 1							; (skip?)
	;
	ext	0x3		; 	xld.w	%r10, 0x1b4f4c						; %r10 = APU_CLOCK
	ext	0xd3d
	ld.w	%r10,0xc
	ext	0x1		; 	xld.w	%r11, 64						; %r11 = i = 64
	ld.w	%r11,0x0
apu_square_mix_DO:
	sub	%r15, %r10						; wavecount -= APU_CLOCK
	jruge	apu_square_mix_NO_ADVANCE	; 	xjruge	apu_square_mix_NO_ADVANCE				; if(NonCarry) goto NO_ADVANCE
	;
apu_square_mix_ADVANCE:
	add	%r15, %r5						; wavecount += wavelength
	jruge.d	apu_square_mix_ADVANCE	; 	xjruge.d	apu_square_mix_ADVANCE				; if(NonCarry) goto ADVANCE
	add	%r14, 1							; waveindex++ *delay*
	;
	and	%r14,0xf	; 	xand	%r14, %r14, 15						; waveindex &= 15
	;
	cmp	%r14, %r6						; output = (waveindex < duty) ? volume : -volume
	jrge.d	4
	ld.w	%r7, %r4						; *delay*
	not	%r7, %r4						; (skip?)
	add	%r7, 1							; (skip?)
	;
apu_square_mix_NO_ADVANCE:
	ld.h	%r9, [%r13]						; *wbuff++ += output
	add	%r9, %r7
	ld.h	[%r13]+, %r9
	;
	sub	%r11,0x1	; 	xsub	%r11, %r11, 1						; if(--i) goto DO
	jrne	apu_square_mix_DO	; 	xjrne	apu_square_mix_DO
	;
	ext	0xd		; 	xld.b	[%r12+0xd], %r14			; square->waveindex = waveindex
	ld.b	[%r12],%r14
	ext	0x10		; 	xld.w	[%r12+0x10], %r15			; square->wavecount = wavecount
	ld.w	[%r12],%r15
	;
apu_square_mix_EXIT:
	ret

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

;
;	void apu_triangle_mix(APUTRIANGLE* triangle, short wbuff[/*64*/])
;
	.global	apu_triangle_mix
apu_triangle_mix:
	ext	0x1		; 	xld.ub	%r9, [%r12+0x1]
	ld.ub	%r9,[%r12]
	cmp	%r9,0x0		; 	xcmp	%r9, 0							; if(!length->count) goto EXIT
	jreq	apu_triangle_mix_EXIT	; 	xjreq	apu_triangle_mix_EXIT
	;
	ext	0x3		; 	xld.ub	%r9, [%r12+0x3]
	ld.ub	%r9,[%r12]
	cmp	%r9,0x0		; 	xcmp	%r9, 0							; if(!linear->count) goto EXIT
	jreq	apu_triangle_mix_EXIT	; 	xjreq	apu_triangle_mix_EXIT
	;
	ext	0x4		; 	xld.h	%r5, [%r12+0x4]			; %r5 = wavelength = triangle->wavelength
	ld.h	%r5,[%r12]
	cmp	%r5,0x8		; 	xcmp	%r5, 8							; if(wavelength <= 8) goto EXIT
	jrle	apu_triangle_mix_EXIT	; 	xjrle	apu_triangle_mix_EXIT
	ext	0x1f		; 	xcmp	%r5, 0x7ff						; if(wavelength >= 0x7ff) goto EXIT
	cmp	%r5,0x3f
	jrge	apu_triangle_mix_EXIT	; 	xjrge	apu_triangle_mix_EXIT
	;
	add	%r5,0x1		; 	xadd	%r5, %r5, 1						; wavelength = (wavelength + 1) * SPEAKER_FREQUENCY
	ext	0xfa		; 	xld.w	%r9, 16000
	ld.w	%r9,0x0
	mlt.h	%r5, %r9
	ld.w	%r5, %alr
	;
	ext	0x6		; 	xld.ub	%r14, [%r12+0x6]			; %r14 = waveindex = triangle->waveindex
	ld.ub	%r14,[%r12]
	ext	0x8		; 	xld.w	%r15, [%r12+0x8]			; %r15 = wavecount = triangle->wavecount
	ld.w	%r15,[%r12]
	;
	ext	apu_triangle_waveform_table@ah				; output = apu_triangle_waveform_table[waveindex]
	ext	apu_triangle_waveform_table@al
	ld.b	%r7, [%r14]
	;
	ext	0x3		; 	xld.w	%r10, 0x1b4f4c						; %r10 = APU_CLOCK
	ext	0xd3d
	ld.w	%r10,0xc
	ext	0x1		; 	xld.w	%r11, 64						; %r11 = i = 64
	ld.w	%r11,0x0
apu_triangle_mix_DO:
	sub	%r15, %r10						; wavecount -= APU_CLOCK
	jruge	apu_triangle_mix_NO_ADVANCE	; 	xjruge	apu_triangle_mix_NO_ADVANCE				; if(NonCarry) goto NO_ADVANCE
	;
apu_triangle_mix_ADVANCE:
	add	%r15, %r5						; wavecount += wavelength
	jruge.d	apu_triangle_mix_ADVANCE	; 	xjruge.d	apu_triangle_mix_ADVANCE			; if(NonCarry) goto ADVANCE
	add	%r14, 1							; waveindex++ *delay*
	;
	and	%r14,0x1f	; 	xand	%r14, %r14, 31						; waveindex &= 31
	;
	ext	apu_triangle_waveform_table@ah				; output = apu_triangle_waveform_table[waveindex]
	ext	apu_triangle_waveform_table@al
	ld.b	%r7, [%r14]
	;
apu_triangle_mix_NO_ADVANCE:
	ld.h	%r9, [%r13]						; *wbuff++ += output
	add	%r9, %r7
	ld.h	[%r13]+, %r9
	;
	sub	%r11,0x1	; 	xsub	%r11, %r11, 1						; if(--i) goto DO
	jrne	apu_triangle_mix_DO	; 	xjrne	apu_triangle_mix_DO
	;
	ext	0x6		; 	xld.b	[%r12+0x6], %r14			; triangle->waveindex = waveindex
	ld.b	[%r12],%r14
	ext	0x8		; 	xld.w	[%r12+0x8], %r15			; triangle->wavecount = wavecount
	ld.w	[%r12],%r15
	;
apu_triangle_mix_EXIT:
	ret

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

;
;	void apu_noise_mix(APUNOISE* noise, short wbuff[/*64*/])
;
	.global	apu_noise_mix
apu_noise_mix:
	ext	0x1		; 	xld.ub	%r9, [%r12+0x1]
	ld.ub	%r9,[%r12]
	cmp	%r9,0x0		; 	xcmp	%r9, 0							; if(!length->count) goto EXIT
	jreq	apu_noise_mix_EXIT	; 	xjreq	apu_noise_mix_EXIT
	;
	ext	0x5		; 	xld.ub	%r4, [%r12+0x5]	; %r4 = volume = envelope->volume
	ld.ub	%r4,[%r12]
	cmp	%r4,0x0		; 	xcmp	%r4, 0							; if(!volume) goto EXIT
	jreq	apu_noise_mix_EXIT	; 	xjreq	apu_noise_mix_EXIT
	;
	ext	0xa		; 	xld.h	%r5, [%r12+0xa]				; %r5 = wavelength = noise->wavelength
	ld.h	%r5,[%r12]
	cmp	%r5,0x0		; 	xcmp	%r5, 0							; if(!wavelength) goto EXIT
	jreq	apu_noise_mix_EXIT	; 	xjreq	apu_noise_mix_EXIT
	;
	ext	0xfa		; 	xld.w	%r9, 16000					; wavelength = wavelength * SPEAKER_FREQUENCY
	ld.w	%r9,0x0
	mlt.h	%r5, %r9
	ld.w	%r5, %alr
	;
	ext	0x6		; 	xld.ub	%r6, [%r12+0x6]				; %r6 = mode = noise->mode
	ld.ub	%r6,[%r12]
	;
	ext	0x8		; 	xld.uh	%r14, [%r12+0x8     ]				; %r14 = lfsr      = noise->lfsr
	ld.uh	%r14,[%r12]
	ext	0xc		; 	xld.w	%r15, [%r12+0xc]				; %r15 = wavecount = noise->wavecount
	ld.w	%r15,[%r12]
	;
	ext	0x1		; 	xand	%r9, %r14, 1						; output = !(lfsr & 1) ? volume : -volume
	and	%r9,%r14
	jreq.d	4
	ld.w	%r7, %r4						; *delay*
	not	%r7, %r4						; (skip?)
	add	%r7, 1							; (skip?)
	;
	ext	0x3		; 	xld.w	%r10, 0x1b4f4c						; %r10 = APU_CLOCK
	ext	0xd3d
	ld.w	%r10,0xc
	ext	0x1		; 	xld.w	%r11, 64						; %r11 = i = 64
	ld.w	%r11,0x0
apu_noise_mix_DO:
	sub	%r15, %r10						; wavecount -= APU_CLOCK
	jruge	apu_noise_mix_NO_ADVANCE	; 	xjruge	apu_noise_mix_NO_ADVANCE				; if(NonCarry) goto NO_ADVANCE
	;
apu_noise_mix_ADVANCE:
	ld.w	%r9, %r14						; %r9 = v = ((lfsr>>0) ^ (lfsr>>mode)) & 1
	srl	%r9, %r6						; ★ "xsrl %r9,%r6"としてはいけません!!
	xor	%r9, %r14						; ★ xsrlが展開され、%r9が破壊されてしまいます。
	and	%r9, 1							; ★ %r6=mode=1or6なので、xsrlは必要ありません。
	;
	srl	%r14,0x1	; 	xsrl	%r14, 1
	sll	%r9,0x8		; 	xsll	%r9, 14							; lfsr = (lfsr >> 1) | (v << 14)
	sll	%r9,0x6
	;or	%r14, %r9						; ◎ -> 4行下へ移動しました。
	;
	add	%r15, %r5						; wavecount += wavelength
	jruge.d	apu_noise_mix_ADVANCE	; 	xjruge.d	apu_noise_mix_ADVANCE				; if(NonCarry) goto ADVANCE
	or	%r14, %r9						; ◎ <- 4行上から移しました。 *delay*
	;
	ext	0x1		; 	xand	%r9, %r14, 1						; output = !(lfsr & 1) ? volume : -volume
	and	%r9,%r14
	jreq.d	4
	ld.w	%r7, %r4						; *delay*
	not	%r7, %r4						; (skip?)
	add	%r7, 1							; (skip?)
	;
apu_noise_mix_NO_ADVANCE:
	ld.h	%r9, [%r13]						; *wbuff++ += output
	add	%r9, %r7
	ld.h	[%r13]+, %r9
	;
	sub	%r11,0x1	; 	xsub	%r11, %r11, 1						; if(--i) goto DO
	jrne	apu_noise_mix_DO	; 	xjrne	apu_noise_mix_DO
	;
	ext	0x8		; 	xld.h	[%r12+0x8     ], %r14				; noise->lfsr      = lfsr
	ld.h	[%r12],%r14
	ext	0xc		; 	xld.w	[%r12+0xc], %r15				; noise->wavecount = wavecount
	ld.w	[%r12],%r15
	;
apu_noise_mix_EXIT:
	ret

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

;
;	void apu_dmc_mix(APUDMC* dmc, short wbuff[/*64*/])
;
	.global	apu_dmc_mix
apu_dmc_mix:
	pushn	%r0
	ext	0x14		; 	xld.w	%r0, [%r12+0x14]				; %r0 = memory = dmc->memory
	ld.w	%r0,[%r12]
	;
	ext	0x6		; 	xld.h	%r5, [%r12+0x6]				; %r5 = wavelength = dmc->wavelength
	ld.h	%r5,[%r12]
	cmp	%r5,0x0		; 	xcmp	%r5, 0							; if(!wavelength) goto STOP
	jreq	apu_dmc_mix_STOP	; 	xjreq	apu_dmc_mix_STOP
	;
	ext	0xfa		; 	xld.w	%r9, 16000					; wavelength = wavelength * SPEAKER_FREQUENCY
	ld.w	%r9,0x0
	mlt.h	%r5, %r9
	ld.w	%r5, %alr
	;
	ext	0x9		; 	xld.b	%r7 , [%r12+0x9   ]				; %r7  = output    = dmc->output
	ld.b	%r7,[%r12]
	ext	0xa		; 	xld.uh	%r4 , [%r12+0xa  ]				; %r4  = address   = dmc->address
	ld.uh	%r4,[%r12]
	ext	0xc		; 	xld.h	%r6 , [%r12+0xc   ]				; %r6  = length    = dmc->length
	ld.h	%r6,[%r12]
	ext	0xe		; 	xld.uh	%r14, [%r12+0xe   ]				; %r14 = sample    = dmc->sample
	ld.uh	%r14,[%r12]
	ext	0x10		; 	xld.w	%r15, [%r12+0x10]				; %r15 = wavecount = dmc->wavecount
	ld.w	%r15,[%r12]
	;
	ext	0x3		; 	xld.w	%r10, 0x1b4f4c						; %r10 = APU_CLOCK
	ext	0xd3d
	ld.w	%r10,0xc
	ext	0x1		; 	xld.w	%r11, 64						; %r11 = i = 64
	ld.w	%r11,0x0
apu_dmc_mix_DO:
	sub	%r15, %r10						; wavecount -= APU_CLOCK
	jruge	apu_dmc_mix_NO_ADVANCE	; 	xjruge	apu_dmc_mix_NO_ADVANCE					; if(NonCarry) goto NO_ADVANCE
	;
apu_dmc_mix_ADVANCE:
	cmp	%r14,0x1	; 	xcmp	%r14, 1							; if(sample <= 1) {
	jrgt	apu_dmc_mix_SAMPLE_NOT_EMPTY	; 	xjrgt	apu_dmc_mix_SAMPLE_NOT_EMPTY				;   
	sub	%r6,0x1		; 	xsub	%r6, %r6, 1						;   length--
	jrne	apu_dmc_mix_LENGTH_NOT_ZERO	; 	xjrne	apu_dmc_mix_LENGTH_NOT_ZERO				;   if(!length) {
	btst	[%r12],0x0	; 	xbtst	[%r12+0x0], 0x0					;     if(!(dmc->flags & (1<<0)))
	jreq	apu_dmc_mix_STOP	; 	xjreq	apu_dmc_mix_STOP					;       goto STOP
	ext	0x1		; 	xld.b	%r7, [%r12+0x1 ]				;     output  = dmc->init_output
	ld.b	%r7,[%r12]
	ext	0x2		; 	xld.uh	%r4, [%r12+0x2]				;     address = dmc->init_address
	ld.uh	%r4,[%r12]
	ext	0x4		; 	xld.h	%r6, [%r12+0x4 ]				;     length  = dmc->init_length
	ld.h	%r6,[%r12]
	jp	apu_dmc_mix_ADVANCE_LOOP	; 	xjp	apu_dmc_mix_ADVANCE_LOOP				;     continue
apu_dmc_mix_LENGTH_NOT_ZERO:						;   }
	add	%r4, %r0						;   sample = memory[address++] | 0x100
	ld.ub	%r14, [%r4]+						;   
	sub	%r4, %r0						;   
	ext	0x4		; 	xoor	%r14, %r14, 0x100					;   
	or	%r14,0x0
	ld.uh	%r4, %r4						;   address = (unsigned short)address | 0x8000
	ext	0x200		; 	xoor	%r4, %r4, 0x8000					;   
	or	%r4,0x0
apu_dmc_mix_SAMPLE_NOT_EMPTY:						; }
	;
	ext	0x1		; 	xand	%r9, %r14, 1						; if(!(sample & 1)) {
	and	%r9,%r14
	jrne.d	apu_dmc_mix_SAMPLE_LSB_1	; 	xjrne.d	apu_dmc_mix_SAMPLE_LSB_1				; 
	srl	%r14, 1							; sample >>= 1 *delay*
	ext	0x1fff		; 	xcmp	%r7, -62						;
	cmp	%r7,0x2
	jrge.d	apu_dmc_mix_SAMPLE_LSB_DONE	; 	xjrge.d	apu_dmc_mix_SAMPLE_LSB_DONE				;   if(output >= -64 + 2) {
	sub	%r7, 2							;     output -= 2 *delay*
	ld.w	%r7, -1							;   } else { output = -64 (=-1<<6) }
	jp.d	apu_dmc_mix_SAMPLE_LSB_DONE	; 	xjp.d	apu_dmc_mix_SAMPLE_LSB_DONE				;   
	sll	%r7, 6							;                 *delay*
apu_dmc_mix_SAMPLE_LSB_1:						; } else {
	ext	0x0		; 	xcmp	%r7, 0x3e						; 
	cmp	%r7,0x3e
	jrle.d	apu_dmc_mix_SAMPLE_LSB_DONE	; 	xjrle.d	apu_dmc_mix_SAMPLE_LSB_DONE				;   if(output <= 64 - 2) {
	add	%r7, 2							;     output += 2 *delay*
	ext	0x0		; 	xld.w	%r7, 63							;   } else { output = 63 }
	ld.w	%r7,0x3f
apu_dmc_mix_SAMPLE_LSB_DONE:						; }
	;
apu_dmc_mix_ADVANCE_LOOP:
	add	%r15, %r5						; wavecount += wavelength
	jruge	apu_dmc_mix_ADVANCE	; 	xjruge	apu_dmc_mix_ADVANCE					; if(NonCarry) goto ADVANCE
	;
apu_dmc_mix_NO_ADVANCE:
	ld.h	%r9, [%r13]						; *wbuff++ += output
	add	%r9, %r7
	ld.h	[%r13]+, %r9
	;
	sub	%r11,0x1	; 	xsub	%r11, %r11, 1						; if(--i) goto DO
	jrne	apu_dmc_mix_DO	; 	xjrne	apu_dmc_mix_DO
	;
	ext	0x9		; 	xld.b	[%r12+0x9   ], %r7				; dmc->output    = output
	ld.b	[%r12],%r7
	ext	0xa		; 	xld.h	[%r12+0xa  ], %r4				; dmc->address   = address
	ld.h	[%r12],%r4
	ext	0xc		; 	xld.h	[%r12+0xc   ], %r6				; dmc->length    = length
	ld.h	[%r12],%r6
	ext	0xe		; 	xld.h	[%r12+0xe   ], %r14				; dmc->sample    = sample
	ld.h	[%r12],%r14
	ext	0x10		; 	xld.w	[%r12+0x10], %r15				; dmc->wavecount = wavecount
	ld.w	[%r12],%r15
	;
apu_dmc_mix_EXIT:
	popn	%r0
	ret
	;
apu_dmc_mix_STOP:
	bclr	[%r12],0x7	; 	xbclr	[%r12+0x0], 0x7					; dmc->flags &= ~(1<<7)
	jp	apu_dmc_mix_EXIT	; 	xjp	apu_dmc_mix_EXIT

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

;#endif /*APU_ASM*/
