;	
;	framsva.s
;
;	P/ECE SUPERVISION Video/Sound Emulator
;
;	CLiP - Common Library for P/ECE
;	Copyright (C) 2001-2005 Naoyuki Sawa
;
;	* Thu Apr 14 05:55:00 JST 2005 Naoyuki Sawa
;	- 作成開始。
;

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

	.code
	.align	1

;****************************************************************************
;	Video
;****************************************************************************

; [note]
;	* framdmva.sのdmgvideo_reduce()をほとんどそのまま流用しました。
;	  変更点は、iの初期値(1->3)と再設定値(3->6)だけです。
;
	.global	svvideo_reduce
svvideo_reduce:
	xld.w	%r10, 8				; z = 8
svvideo_reduce_DO_Z:				; do {
	;
	xld.w	%r11, 11			; y = 11
	xld.w	%r15, 3				; i = 3
svvideo_reduce_DO_Y:				; do {
	;
	xld.w	%r14, 32			; x = 32
	xsub	%r15, %r15, 1			; if(--i) goto DO_X1
	xjrne	svvideo_reduce_DO_X1
	;
svvideo_reduce_DO_X0:
	ld.ub	%r4, [%r13]+			; %r4    =  src[0]
	ld.ub	%r5, [%r13]+			; %r5    =  src[1]
	ld.ub	%r6, [%r13]+			; %r6    =  src[2]
	ld.b	[%r12]+, %r4			; dst[0] =  src[0]
	ld.b	[%r12]+, %r5			; dst[1] =  src[1]
	ld.b	[%r12]+, %r6			; dst[2] =  src[2]
	ld.ub	%r4, [%r13]+			; %r4    =  src[3]
	ld.ub	%r5, [%r13]+			; %r5    =  src[4]
	xadd	%r4, %r4, 1			; %r4    =  src[3]       +1 *anti-interlock*
	add	%r4, %r5			; %r4    =  src[3]+src[4]+1
	xsrl	%r4, 1				; %r4    = (src[3]+src[4]+1)>>1
	ld.b	[%r12]+, %r4			; dst[3] = (src[3]+src[4]+1)>>1
	;
	xsub	%r14, %r14, 1			; } while(x)
	xjrne	svvideo_reduce_DO_X0
	xjp.d	svvideo_reduce_LOOP_Y
	ld.w	%r15, 6				; i = 6 *delay*
	;
svvideo_reduce_DO_X1:				; do {
	xld.ub	%r4, [%r13+160]			; %r4    =         src[160]
	 ld.ub	%r5, [%r13]+			; %r5    =  src[0]
	xadd	%r4, %r4, 1			; %r4    =         src[160]+1 *anti-interlock*
	add	%r4, %r5			; %r4    =  src[0]+src[160]+1
	xsrl	%r4, 1				; %r4    = (src[0]+src[160]+1)>>1
	ld.b	[%r12]+, %r4			; dst[0] = (src[0]+src[160]+1)>>1
	xld.ub	%r4, [%r13+160]			; %r4    =         src[161]
	 ld.ub	%r5, [%r13]+			; %r5    =  src[1]
	xadd	%r4, %r4, 1			; %r4    =         src[161]+1 *anti-interlock*
	add	%r4, %r5			; %r4    =  src[1]+src[161]+1
	xsrl	%r4, 1				; %r4    = (src[1]+src[161]+1)>>1
	ld.b	[%r12]+, %r4			; dst[1] = (src[1]+src[161]+1)>>1
	xld.ub	%r4, [%r13+160]			; %r4    =         src[162]
	 ld.ub	%r5, [%r13]+			; %r5    =  src[2]
	xadd	%r4, %r4, 1			; %r4    =         src[162]+1 *anti-interlock*
	add	%r4, %r5			; %r4    =  src[2]+src[162]+1
	xsrl	%r4, 1				; %r4    = (src[2]+src[162]+1)>>1
	ld.b	[%r12]+, %r4			; dst[2] = (src[2]+src[162]+1)>>1
	xld.ub	%r4, [%r13+160]			; %r4    =                src[163]
	 ld.ub	%r5, [%r13]+			; %r5    =  src[3]
	xld.ub	%r6, [%r13+160]			; %r6    =                         src[164]
	 ld.ub	%r7, [%r13]+			; %r7    =         src[4]
	xadd	%r4, %r4, 2			; %r4    =                src[163]         +2
	add	%r4, %r5			; %r4    =  src[3]       +src[163]         +2
	add	%r4, %r6			; %r4    =  src[3]       +src[163]+src[164]+2
	add	%r4, %r7			; %r4    =  src[3]+src[4]+src[163]+src[164]+2
	xsrl	%r4, 2				; %r4    = (src[3]+src[4]+src[163]+src[164]+2)>>2
	ld.b	[%r12]+, %r4			; dst[3] = (src[3]+src[4]+src[163]+src[164]+2)>>2
	;
	xsub	%r14, %r14, 1			; } while(x)
	xjrne	svvideo_reduce_DO_X1
	xadd	%r13, %r13, 160			; src += 160
	;
svvideo_reduce_LOOP_Y:
	xsub	%r11, %r11, 1			; } while(y)
	xjrne	svvideo_reduce_DO_Y
	;
	xsub	%r10, %r10, 1			; } while(z)
	xjrne	svvideo_reduce_DO_Z
	ret

;****************************************************************************
;	Sound
;****************************************************************************

				; typedef struct _SVSOUNDTONE {
#define TONE_VOLUME	 0	; 	int volume;	/* + 0,4: ボリューム (silent:0..15:max) */
#define TONE_PERIOD	 4	; 	int period;	/* + 4,4: 音程(周期) */
#define TONE_POLAR	 8	; 	int polar;	/* + 8,4: 出力極性 0:-/1:+ */
#define TONE_COUNT	12	; 	int count;	/* +12,4: 周期カウンタ */
				; } SVSOUNDTONE;	/* =16 */

				; typedef struct _SVSOUNDNOISE {
#define NOISE_ON	 0	; 	int on;		/* + 0,4: 0:Off/1:On */
#define NOISE_VOLUME	 4	; 	int volume;	/* + 4,4: ボリューム (silent:0..15:max) */
#define NOISE_PERIOD	 8	; 	int period;	/* + 8,4: 音程(周期) */
#define NOISE_LFSR	12	; 	int lfsr;	/* +12,4: ノイズLFSR */
#define NOISE_COUNT	16	; 	int count;	/* +16,4: 周期カウンタ */
				; } SVSOUNDNOISE;	/* =20 */

#define SVSOUND_VOLUME_SHIFT	((16-7)+1)	; -> framsv.c

;
;	void svsound_tone_mix(SVSOUNDTONE* tone, short wbuff[/*SVSOUNDBUFLEN*/])
;
	.global	svsound_tone_mix
svsound_tone_mix:
	xld.w	%r4, [%r12+TONE_VOLUME]		; %r4 = volume = tone->volume
	xcmp	%r4, 0				; if(!volume) goto EXIT
	xjreq	svsound_tone_mix_EXIT
	;
	xld.w	%r5, [%r12+TONE_PERIOD]		; %r5 = period = tone->period
	xcmp	%r5, 0				; if(!period) goto EXIT
	xjreq	svsound_tone_mix_EXIT
	;
	xld.w	%r6, [%r12+TONE_POLAR]		; %r6 = polar = tone->polar /* 取り出し */
	xld.w	%r7, [%r12+TONE_COUNT]		; %r7 = count = tone->count /* 取り出し */
	;
	not	%r10, %r4			; %r10 = -volume
	xadd	%r10, %r10, 1
	;
	xcmp	%r6, 0				; %r11 = output = polar ? volume : -volume
	jrne.d	3
	ld.w	%r11, %r4			; *delay*
	ld.w	%r11, %r10			; (skip?)
	;
	xld.w	%r14, (4000000/16000)*2		; %r14 = (4000000/SPEAKER_FREQUENCY)*2
	xld.w	%r15, 320			; %r15 = i = SVSOUNDBUFLEN
svsound_tone_mix_DO:
	sub	%r7, %r14			; count -= (4000000/SPEAKER_FREQUENCY)*2
	xjruge	svsound_tone_mix_NO_ADVANCE	; if(NonCarry) goto NO_ADVANCE
	;
svsound_tone_mix_ADVANCE:
	add	%r7, %r5			; count += period
	xjruge.d svsound_tone_mix_ADVANCE	; if(NonCarry) goto ADVANCE
	xor	%r6, 1				; polar ^= 1 *delay*
	;
	xcmp	%r6, 0				; output = polar ? volume : -volume
	jrne.d	3
	ld.w	%r11, %r4			; *delay*
	ld.w	%r11, %r10			; (skip?)
	;
svsound_tone_mix_NO_ADVANCE:
	ld.h	%r9, [%r13]			; *wbuff++ += output
	add	%r9, %r11
	ld.h	[%r13]+, %r9
	;
	xsub	%r15, %r15, 1			; if(--i) goto DO
	xjrne	svsound_tone_mix_DO
	;
	xld.w	[%r12+TONE_POLAR], %r6		; tone->polar = polar /* 書き戻し */
	xld.w	[%r12+TONE_COUNT], %r7		; tone->count = count /* 書き戻し */
	;
svsound_tone_mix_EXIT:
	ret

;
;	void svsound_noise_mix(SVSOUNDNOISE* noise, short wbuff[/*SVSOUNDBUFLEN*/])
;
	.global	svsound_noise_mix
svsound_noise_mix:
	xbtst	[%r12+NOISE_ON], 0		; if(!noise->on) goto EXIT
	xjreq	svsound_noise_mix_EXIT
	;
	xld.w	%r4, [%r12+NOISE_VOLUME]	; %r4 = volume = noise->volume
	xcmp	%r4, 0				; if(!volume) goto EXIT
	xjreq	svsound_noise_mix_EXIT
	;
	xld.w	%r5, [%r12+NOISE_PERIOD]	; %r5 = period = noise->period
	xcmp	%r5, 0				; if(!period) goto EXIT
	xjreq	svsound_noise_mix_EXIT
	;
	xld.w	%r6, [%r12+NOISE_LFSR ]		; %r6 = lfsr  = noise->lfsr  /* 取り出し */
	xld.w	%r7, [%r12+NOISE_COUNT]		; %r7 = count = noise->count /* 取り出し */
	;
	not	%r10, %r4			; %r10 = -volume
	xadd	%r10, %r10, 1
	;
	xand	%r9, %r6, 1			; %r11 = output = (lfsr & 1) ? volume : -volume
	jrne.d	3
	ld.w	%r11, %r4			; *delay*
	ld.w	%r11, %r10			; (skip?)
	;
	xld.w	%r15, 320			; %r15 = i = SVSOUNDBUFLEN
svsound_noise_mix_DO:
	xsub	%r7, %r7, 1			; count--
	xjruge	svsound_noise_mix_NO_ADVANCE	; if(NonCarry) goto NO_ADVANCE
	;
svsound_noise_mix_ADVANCE:
	ld.w	%r9, %r6			; %r9 = x = (lfsr ^ (lfsr >> 5)) & 1
	xsrl	%r9, 5
	xor	%r9, %r6
	xand	%r9, %r9, 1
	xsrl	%r6, 1				; lfsr = (lfsr >> 1) | (x << 8)
	xsll	%r9, 8
	;or	%r6, %r9			; ---------------------------+
	;					;                            |
	add	%r7, %r5			; count += period            |
	xjruge.d svsound_noise_mix_ADVANCE	; if(NonCarry) goto ADVANCE  |
	 or	%r6, %r9			; *delay* <------------------+
	;
	xand	%r9, %r6, 1			; %r11 = output = (lfsr & 1) ? volume : -volume
	jrne.d	3
	ld.w	%r11, %r4			; *delay*
	ld.w	%r11, %r10			; (skip?)
	;
svsound_noise_mix_NO_ADVANCE:
	ld.h	%r9, [%r13]			; *wbuff++ += output
	add	%r9, %r11
	ld.h	[%r13]+, %r9
	;
	xsub	%r15, %r15, 1			; if(--i) goto DO
	xjrne	svsound_noise_mix_DO
	;
	xld.w	[%r12+NOISE_LFSR ], %r6		; noise->lfsr  = lfsr  /* 書き戻し */
	xld.w	[%r12+NOISE_COUNT], %r7		; noise->count = count /* 書き戻し */
	;
svsound_noise_mix_EXIT:
	ret

;
;	void svsound_volume_shift(short wbuff[/*SVSOUNDBUFLEN*/])
;
	.global svsound_volume_shift
svsound_volume_shift:
	; %r12 = wbuff
	xld.w %r13, 320			; SVSOUNDBUFLEN = 320
	xld.w %r4, 32767
	not %r5, %r4			; -32768
svsound_volume_shift_DO:
	ld.h %r6, [%r12]
	xsll %r6, SVSOUND_VOLUME_SHIFT
	cmp %r6, %r4
	jrle.d 3
	cmp %r6, %r5			; *delay*
	ld.w %r6, %r4			; (skip?)
	jrge.d 3
	sub %r13, 1			; *delay*
	ld.w %r6, %r5			; (skip?)
	ld.h [%r12]+, %r6
	xjrne svsound_volume_shift_DO
	ret

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