goutfifo.s 5.82 KB


 ############################################################################
 #
 # Output coordination routines:
 #
 # We support three cases:
 #
 #      1.) output directly to RDP using DMEM as buffer. Requires
 #          producer/consumer synchronization.
 #
 #      2.) output routed to DRAM. In this case, we use DMEM as
 #          a temporary buffer, then DMA out to DRAM.
 #
 #	3.) output routed to DRAM, but DRAM is utilized as a circular 
 #	    buffer
 #
 # Goals:
 #
 #      - small code size.
 #      - efficient and non-obtrusive
 #      - flexible, can easily route to DRAM or RDP.
 #
 # In order to do this, and make it transparent to the parts of the
 # code which do the writing, we implement an open/close interface.
 #
 # FUNCTION:        OUTPUT TO RDP:                  OUTPUT TO DRAM:
 #-------------------------------------------------------------------------
 # open(size)   - wait for size avail in        - does nothing
 #                ring buffer.
 #              - possibly handle wrap
 #              - wait for 'current' to get
 #                out of the way
 #
 # close()      - advance CP0 pointer           - do DMA of cmd to DRAM
 #                                              - increment pointers
 #                                              - reset DMEM buffer
 #
 # In between the open() and close(), the ucode writes the data to DMEM.
 # (to either the RDP ring buffer or a temp buffer to be DMA'd)
 #
 ############################################################################

 # DMEM is utilized as follows for this output routine:
 # RSP_STATE_FIFO_OUTP:		pointer in dram to next empty ring buffer entry
 # RSP_STATE_FIFO_BUF_TOP:	pointer in dram to beginning of ring buffer
 # RSP_STATE_FIFO_BUF_END:	pointer in dram to end of ring buffer
 #                                 (ie the byte following the ring buffer)

        #
        # These registers used by both routines.
        #
.name   dmemp,          $20
.name   dramp,          $19
.name   outsz,          $18 # set by caller to max size to write
.name	tmp,		$6

 ############################################################################
 #
 # 
 #
#if !(defined(OUTPUT_DRAM)||defined(OUTPUT_FIFO))
                .ent    OutputOpen

OutputOpen:
                jr      return
                nop

                .end    OutputOpen
#endif /* !(OUTPUT_DRAM || OUTPUT_FIFO) */
 #
 #
 #
 ############################################################################

 ############################################################################
 #
 #
 #
                .ent    OutputClose
#ifdef	DMANOWAIT2
OutputCloseEnd:	
		jr	return
#endif
OutputClose:
#ifdef	DMANOWAIT2
		addi	tmp, outp, 176-RSP_OUTPUT_END
		blez	tmp, OutputCloseEnd
OutputCloseFlush:

#endif	
 # check if the packet will fit in the buffer
#ifdef	DMA2BUF		
		lh	dmemp, RSP_STATE_FIFO_DMA2BUF(rsp_state)
checkFIFO:	mfc0	tmp, DMA_BUSY	# ロード遅延の間に処理する
		lw	dramp, RSP_STATE_FIFO_OUTP(rsp_state)		
		add	$21, zero, return
		bne	tmp, zero, checkFIFO
		sub	outsz, outp, dmemp
		mtc0	dramp, CMD_END
#else
		add	$21, zero, return
		lw	dramp, RSP_STATE_FIFO_OUTP(rsp_state)
		addi	outsz, outp, (-1*RSP_OUTPUT_OFFSET)
#endif
		lw	outp,  RSP_STATE_FIFO_BUF_END(rsp_state)
		blez	outsz, CloseDone
#if	(defined(DMA2BUF)||defined(DMANOWAIT))
		add	tmp, dramp, outsz		# end data in dram
		sub	tmp, outp, tmp
                bgez    tmp, CurrentFit
#else
		add	dmemp, dramp, outsz		# end data in dram
		sub	dmemp, outp, dmemp		# bigger than buffer?
                bgez    dmemp, CurrentFit
#endif
WrapBuffer:
 # packet will not fit, wait for current to wrap
#if	(defined(DMA2BUF)||defined(DMANOWAIT))
                mfc0    tmp, CMD_STATUS
                andi    tmp, tmp, 0x0400
                bne     tmp, zero, WrapBuffer
#else
                mfc0    dmemp, CMD_STATUS
                andi    dmemp, dmemp, 0x0400
                bne     dmemp, zero, WrapBuffer
#endif
                # note delay slot

 # wait for current to advance
AdvanceCurrent:
                mfc0    outp, CMD_CURRENT		# outp = current
		lw	dramp, RSP_STATE_FIFO_BUF_TOP(rsp_state) # buffer start
                beq     outp, dramp, AdvanceCurrent
                nop
                mtc0    dramp, CMD_START         # reset START
CurrentFit:
                # done if current_address <= dramp
                mfc0    outp, CMD_CURRENT		# outp = current
#if	(defined(DMA2BUF)||defined(DMANOWAIT))
                sub     tmp, dramp, outp
                bgez    tmp, CloseDMA
#else
                sub     dmemp, dramp, outp
                bgez    dmemp, CloseDMA
#endif
                # note delay slot

                # loop if current_address <= (outp + outsz)
#if	(defined(DMA2BUF)||defined(DMANOWAIT))
                add     tmp, dramp, outsz
                sub     tmp, tmp, outp
                bgez    tmp, CurrentFit
#else
                add     dmemp, dramp, outsz
                sub     dmemp, dmemp, outp
                bgez    dmemp, CurrentFit
#endif
                nop
CloseDMA:
		add	outp, dramp, outsz
		addi	outsz, outsz, -1
#ifndef	DMA2BUF
		addi	dmemp, zero, RSP_OUTPUT_OFFSET
#endif
		jal	DMAproc
		addi	$17, zero, 1	# set 'iswrite'
#ifdef	DMANOWAIT
		sw	outp, RSP_STATE_FIFO_OUTP(rsp_state)
CloseDone:	jr      $21
                addi	outp, zero, RSP_OUTPUT_OFFSET		
#else
#ifdef	DMA2BUF	
		sw	outp, RSP_STATE_FIFO_OUTP(rsp_state)
		xori	dmemp,dmemp,(RSP_OUTPUT_OFFSET)^(RSP_OUTPUT_OFFSET+176*2)
		sh	dmemp,RSP_STATE_FIFO_DMA2BUF(rsp_state) 
CloseDone:	jr      $21
                addi	outp, dmemp, 0
#else
		jal	DMAwait
		sw	outp, RSP_STATE_FIFO_OUTP(rsp_state)
		mtc0	outp, CMD_END
CloseDone:
                jr      $21
                addi	outp, zero, RSP_OUTPUT_OFFSET
#endif
#endif
                .end    OutputClose
 #
 #
 #
 ############################################################################

.unname outsz
.unname dramp
.unname dmemp
.unname tmp