/*
__DSPHandler.S for Nintendont (Kernel)

Copyright (C) 2014 FIX94

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation version 2.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/
#include <asm.h>
.include "constants.inc"

#note:r3 and r12 will get overwritten, safe to use

__DSPHandler:
	lis		r12,	STREAMING@h
	lwz		r3,	STREAMING@l(r12)
	lis		r12,	AI_CR@h
	lwz		r12,	AI_CR@l(r12)
	and.	r3,	r3,	r12
	bne		startcp
	cmpwi	r0,	0
	blr

startcp:
	stwu	r1,	-0x20(r1)
	stw		r4,	0x0(r1)
	stw		r5,	0x4(r1)
	stw		r6,	0x8(r1)
	stw		r7,	0xC(r1)
	stw		r8,	0x10(r1)
	stw		r9,	0x14(r1)
	stw		r0,	0x18(r1)
	mflr	r0
	stw		r0,	0x1C(r1)

#extract from AI directly
	lis		r12,	AI_DMA_ADDR@h
	lwz		r9,	AI_DMA_ADDR@l(r12)
	rlwinm	r9,	r9,	0,		7,		26 # 0x01ffffe0
	oris	r9,	r9,	0x8000
	lhz		r8,	AI_DMA_SIZE@l(r12)
	rlwinm	r8,	r8,	5,		12,		31 # 0x000fffe0

	lis		r12,	AI_ADP_LOC@h
	lwz		r4,	AI_ADP_LOC@l(r12)
	li		r3,	0xC40
	slwi	r3,	r3,	4		#BUFSIZE=0xC400
	cmplw	r4,	r3
	blt		buf1
buf2:
	slwi	r3,	r3,	1		#MAXBUF=0x18800
buf1:
	lis		r6,	AI_ADP_BUF@h

	srwi	r7,	r8,	5
	mtctr	r7
	mr		r5,	r6
	add		r5,	r5,	r4
DCInvalidateRange1:
	dcbi	0,	r5
	addi	r5,	r5,	0x20
	bdnz	DCInvalidateRange1

	li		r5,	0
startcopy:
	lis		r12,	AI_VR@h
#left audiostream
	lhax	r0,	r6,	r4
#calc volume
	lwz		r7,	AI_VR@l(r12)
	clrlwi	r7,	r7,	24
	mullw	r0,	r7,	r0
	srawi	r0,	r0,	8
#left original
	lhax	r7,	r9,	r5
#combine streams
	bl		combinebuffer
#save new stream
	sthx	r7,	r9,	r5

	addi	r4,	r4,	2
	addi	r5,	r5,	2

#right audiostream
	lhax	r0,	r6,	r4
#calc volume
	lwz		r7,	AI_VR@l(r12)
	extrwi	r7,	r7,	8,		16
	mullw	r0,	r7,	r0
	srawi	r0,	r0,	8
#right original
	lhax	r7,	r9,	r5
#combine streams
	bl		combinebuffer
#save new stream
	sthx	r7,	r9,	r5

	addi	r4,	r4,	2
	addi	r5,	r5,	2

	cmplw	r4,	r3
	beq		changebuffer
copy2:
	cmplw	r5,	r8
	blt		startcopy

	srwi	r7,	r8,	5
	mtctr	r7
	mr		r5,	r9
DCFlushRange:
	dcbf	0,	r5
	addi	r5,	r5,	0x20
	bdnz	DCFlushRange

exit:
	lis		r12,	AI_ADP_LOC@h
	stw		r4,	AI_ADP_LOC@l(r12)

	lwz		r0,	0x1C(r1)
	mtlr	r0
	lwz		r4,	0x0(r1)
	lwz		r5,	0x4(r1)
	lwz		r6,	0x8(r1)
	lwz		r7,	0xC(r1)
	lwz		r8,	0x10(r1)
	lwz		r9,	0x14(r1)
	lwz		r0,	0x18(r1)
	cmpwi	r0,	0
	addi	r1,	r1,	0x20
	blr

changebuffer:
	li		r0,	1
	lis		r12,	UPDATE_STREAM@h
	stw		r0,	UPDATE_STREAM@l(r12)
	li		r0,	0xC40
	slwi	r0,	r0,	4		#BUFSIZE=0xC400
	cmplw	r4,	r0
	beq		copy2
	cmplw	r5,	r8
	beq		resetbuffer				#no need to invalidate if we are done anyways
#invalidate buffer one
	sub		r7,	r8,	r5
	srwi	r7,	r7,	5
	mtctr	r7
	mr		r7,	r6
DCInvalidateRange3:
	dcbi	0,	r7
	addi	r7,	r7,	0x20
	bdnz	DCInvalidateRange3
resetbuffer:
	li		r4,	0
	b		copy2

#the most simple linear compressor I could come up with
combinebuffer:
	add		r7,	r7,	r0
	cmpwi	r7,	0x4CCC
	bgt		compressPos
	cmpwi	r7,	-0x4CCC
	blt		compressNeg
	blr
compressPos:
	subi	r7,	r7,	0x4CCC
	srawi	r7,	r7,	2
	addi	r7,	r7,	0x4CCC
	blr
compressNeg:
	addi	r7,	r7,	0x4CCC
	srawi	r7,	r7,	2
	subi	r7,	r7,	0x4CCC
	blr
