amain.s 7.08 KB

/*************************************************************************
 *								         *
 *               Copyright (C) 1994, Silicon Graphics, Inc.       	 *
 *								         *
 *  These coded instructions, statements, and computer programs  contain *
 *  unpublished  proprietary  information of Silicon Graphics, Inc., and *
 *  are protected by Federal copyright  law.  They  may not be disclosed *
 *  to  third  parties  or copied or duplicated in any form, in whole or *
 *  in part, without the prior written consent of Silicon Graphics, Inc. *
 *								         *
 ************************************************************************/

/*
 * File:		amain.s
 *
 * This is the 'audio task' for the RSP. It takes blocks of commands
 * and interprets them.
 *
 * The approach is modelled on the graphics task display list processing
 * and the command list interpreter is taken from that code.
 *
 */


#include <rsp.h>
#include <rcp.h>
#include <mbi.h>
#include <os.h>
#include <sptask.h>
#include "aud_dmem.h"	
	
		.text	TASKBASE	# this is coordinated with rspboot.s
		.data	(DCACHEBASE + RSP_PDATA_OFFSET)
	
#include "aud_dmem_init.h"
#include "aud_regs.h"

	
 ######################################################################
 #
 #  Begin task initialization
 #
 #  Register $1 holds the task header address
 # format for the task header is defined in os.h

		.ent	astart

.name tskhd,	$1

	# Base of parameter area:
	#
		addi	parbase, zero, RSP_PARAMETER_OFFSET

	# Base of scatch area:
	#
		addi	scrbase, zero, RSP_SCRATCH_OFFSET
	#
	# get the command list out of the header:	
	#		
		lw	inp, OS_TASK_OFF_DATA(tskhd)
		lw	gcount, OS_TASK_OFF_DATA_SZ(tskhd)
.unname	tskhd
		.end	astart
	#
	# save graphics' RDP buffer & freeze DP if neccessary
	#
#define STARTUP_YIELD
#include "ayield.s"
#undef STARTUP_YIELD

	#
	# start the DMA of the display list into DMEM.
	#
		.ent	amain

		jal	LoadDL
		nop
	
	#
	# while DMA is going on, do some initializations:
	#
	
	# clear memory segment entries

.name seg_ptr, 	$1
.name i, 	$2
		addi	i, zero, 15
		addi	seg_ptr, zero, RSP_SEG_OFFSET
SegInitLp:	sw	zero, 0(seg_ptr)
		bgtz	i, SegInitLp
		addi	i, i, -1
.unname seg_ptr
.unname i
 #
 # end of initialization section
 #
 #########################################################################

	
 #########################################################################
 #
 # Note about display list command processing:	
 #
 #	- 'inp' always points to the "next" DL command in DRAM. This
 # 	  is the pointer used to retrieve the next block of DL commands.
 #
 #	- 'gcount' parallels inp, counting down the remaining DL commands.
 #
 #	- 'dinp' is the local pointer in DMEM to the part of the command
 #	  list in DMEM.
 #
 #	- 'dlcount' parallels dinp, counting down the remaining DL commands
 #	  in DMEM.
 #
 # So when (dlcount == 0) we need to fetch more display list, when
 # (gcount == 0), we are done (audio doesn't implement DL call/branch).
 #
 #########################################################################
DMAWaitDL:	mfc0	$2, DMA_BUSY
		bne	$2, zero, DMAWaitDL
		# Delay slot
		
 	# process aud list:	
.name	dlcmd,	$1
		addi	dinp, zero, RSP_DLINPUT_OFFSET

	# Clear the semaphore
		mtc0	$0, SP_RESERVED

DecodeDL:	lw	aud0, 0(dinp)
		lw	aud1, 4(dinp)
		srl	dlcmd, aud0, 23
		andi	dlcmd, dlcmd, 0xfe

	# advance these pointers after consuming aud0/1
		addi	inp, inp, 8
		addi	gcount, gcount, -8
		addi	dinp, dinp, 8
		addi	dlcount, dlcount, -8
	
.name op_addr, $2
ContDecode:		
		add	op_addr, zero, dlcmd	# compute jump address
		lh	op_addr, OPTYPE_JMP_OFFSET(op_addr)
		jr	op_addr
		nop
		break		# if we got here, it's an error...
.unname op_addr
.unname dlcmd

AudDone: 	# we're done with this one, do the next one (if available)...

 		bgtz	dlcount, DecodeDL
		nop
	
	# if there's more command list to process, load it, otherwise done
DoneTest:	blez	gcount, TaskDone
		nop
		jal	LoadDL
		nop

		j	DMAWaitDL	# continue processing
		nop

		.end	amain

TaskDone: 	# Done, interrupt the CPU
	#
	# restore graphics' RDP buffer & unfreeze DP if neccessary
	#
#define DONE_UNYIELD
#include "ayield.s"
#undef DONE_UNYIELD


	# Set signal to indicate task done and break

 		ori	$1, zero, SP_SET_TASKDONE
		mtc0	$1, SP_STATUS
		break
		nop
	# Spin
MainWait:	beq	zero, zero, MainWait
		nop	
	

 #########################################################################
 #
 # start the DMA of the display list into DMEM.
 #
 # Registers upon call:
 #		inp	pointer to read from
 #		gcount	max size to read (bytes)
 #		return	where to go when we're done
 #
 # Registers upon return:
 #		dlcount	size actually read (bytes)
 #		dinp	pointer to data we read in
 #
 # Registers used:
 #		$1, $2, $3, $4, $5, return, gcount, inp, dlcount, dinp
 #

		.ent	LoadCL

.name dmaddr,	$1
.name draddr, 	$2
.name dma_size, $3
.name tmp,	$4
.name save_ret, $5

LoadDL:		addi	save_ret, return, 0
		add	draddr, zero, inp
		addi	dma_size, gcount, 0
		addi	tmp, dma_size, (-1 * RSP_DLINPUT_SIZE8)
		blez	tmp, WillFit
		addi	dmaddr, zero, RSP_DLINPUT_OFFSET
		addi	dma_size, zero, (RSP_DLINPUT_SIZE8)
WillFit:	addi	dlcount, dma_size, 0
		jal	DMAread
		addi	dma_size, dma_size, -1
		addi	dinp, zero, RSP_DLINPUT_OFFSET
		jr	save_ret
		nop
.unname dmaddr
.unname draddr
.unname dma_size
.unname tmp
.unname save_ret

		.end	LoadCL
 #
 #
 #
 #########################################################################

 #########################################################################
 #
 # DMA read and write routines. These routines initiate a DMA read or
 # write and then return. It is the responsibility of the calling routine
 # to wait on the read finished and to release the semaphore
 #
 # Passed parameters:  	$1 DMEM address
 #			$2 DRAM address
 #			$3 Read/Write length
 #
 #########################################################################

.name	tmp,	$4

 ###################
 # DMA read
 ###################
		.ent	DMAread
 # Get a semaphore
DMAread:	mfc0	tmp, SP_RESERVED
		bne	tmp, $0, DMAread
		nop

 # Wait till DMA not full
DRFull1:	mfc0	tmp, DMA_FULL
		bne	tmp, $0, DRFull1
		nop

 # Initiate the read
		mtc0	$1, DMA_CACHE
		mtc0	$2, DMA_DRAM
		mtc0	$3, DMA_READ_LENGTH

		jr	return
		nop

		.end	DMAread

 ###################
 # DMA write
 ###################

		.ent	DMAwrite
 # Get a semaphore
DMAwrite:	mfc0	tmp, SP_RESERVED
		bne	tmp, $0, DMAwrite
		nop

 # Wait till DMA not full
DRFull2:	mfc0	tmp, DMA_FULL
		bne	tmp, $0, DRFull2
		nop

 # Initiate the read
		mtc0	$1, DMA_CACHE
		mtc0	$2, DMA_DRAM
		mtc0	$3, DMA_WRITE_LENGTH

		jr	return
		nop

		.end	DMAwrite

.unname	tmp
 
 #########################################################################
 #
 # Modules are separated logically and appended by #include.
 #
 #########################################################################

#include "asetup.s"
 # Includes the commands A_CLEARBUFF, A_LOADBUFF, A_SAVEBUFF, A_SEGMENT, 
 # A_SETBUFF, A_SETVOL, A_DMMOVE, A_LOADADPCM

#include "adpcm.s"
 # Includes the adpcm decoder

#include "afilter.s"
 # Includes the 2 pole filter
	
#include "aresample.s"
 # Includes the commands A_RESAMPLE

#include "aenv.s"
 # Includes the exponential enveloper

#include "amixer.s"
 # Includes the mixer