171 lines
4.4 KiB
Plaintext
171 lines
4.4 KiB
Plaintext
|
//
|
||
|
// Copyright(c) by Benny Sjostrand (benny@hostmobility.com)
|
||
|
//
|
||
|
// 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; either version 2 of the License, or
|
||
|
// (at your option) any later version.
|
||
|
//
|
||
|
// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||
|
//
|
||
|
|
||
|
|
||
|
//
|
||
|
// This code runs inside the DSP (cs4610, cs4612, cs4624, or cs4630),
|
||
|
// to compile it you need a tool named SPASM 3.0 and DSP code owned by
|
||
|
// Cirrus Logic(R). The SPASM program will generate a object file (cwcdma.osp),
|
||
|
// the "ospparser" tool will genereate the cwcdma.h file it's included from
|
||
|
// the cs46xx_lib.c file.
|
||
|
//
|
||
|
//
|
||
|
// The purpose of this code is very simple: make it possible to tranfser
|
||
|
// the samples 'as they are' with no alteration from a PCMreader
|
||
|
// SCB (DMA from host) to any other SCB. This is useful for AC3 through SPDIF.
|
||
|
// SRC (source rate converters) task always alters the samples in somehow,
|
||
|
// however it's from 48khz -> 48khz.
|
||
|
// The alterations are not audible, but AC3 wont work.
|
||
|
//
|
||
|
// ...
|
||
|
// |
|
||
|
// +---------------+
|
||
|
// | AsynchFGTxSCB |
|
||
|
// +---------------+
|
||
|
// |
|
||
|
// subListPtr
|
||
|
// |
|
||
|
// +--------------+
|
||
|
// | DMAReader |
|
||
|
// +--------------+
|
||
|
// |
|
||
|
// subListPtr
|
||
|
// |
|
||
|
// +-------------+
|
||
|
// | PCMReader |
|
||
|
// +-------------+
|
||
|
// (DMA from host)
|
||
|
//
|
||
|
|
||
|
struct dmaSCB
|
||
|
{
|
||
|
long dma_reserved1[3];
|
||
|
|
||
|
short dma_reserved2:dma_outBufPtr;
|
||
|
|
||
|
short dma_unused1:dma_unused2;
|
||
|
|
||
|
long dma_reserved3[4];
|
||
|
|
||
|
short dma_subListPtr:dma_nextSCB;
|
||
|
short dma_SPBptr:dma_entryPoint;
|
||
|
|
||
|
long dma_strmRsConfig;
|
||
|
long dma_strmBufPtr;
|
||
|
|
||
|
long dma_reserved4;
|
||
|
|
||
|
VolumeControl s2m_volume;
|
||
|
};
|
||
|
|
||
|
#export DMAReader
|
||
|
void DMAReader()
|
||
|
{
|
||
|
execChild();
|
||
|
r2 = r0->dma_subListPtr;
|
||
|
r1 = r0->nextSCB;
|
||
|
|
||
|
rsConfig01 = r2->strmRsConfig;
|
||
|
// Load rsConfig for input buffer
|
||
|
|
||
|
rsDMA01 = r2->basicReq.daw, , tb = Z(0 - rf);
|
||
|
// Load rsDMA in case input buffer is a DMA buffer Test to see if there is any data to transfer
|
||
|
|
||
|
if (tb) goto execSibling_2ind1 after {
|
||
|
r5 = rf + (-1);
|
||
|
r6 = r1->dma_entryPoint; // r6 = entry point of sibling task
|
||
|
r1 = r1->dma_SPBptr, // r1 = pointer to sibling task's SPB
|
||
|
, ind = r6; // Load entry point of sibling task
|
||
|
}
|
||
|
|
||
|
rsConfig23 = r0->dma_strmRsConfig;
|
||
|
// Load rsConfig for output buffer (never a DMA buffer)
|
||
|
|
||
|
r4 = r0->dma_outBufPtr;
|
||
|
|
||
|
rsa0 = r2->strmBufPtr;
|
||
|
// rsa0 = input buffer pointer
|
||
|
|
||
|
for (i = r5; i >= 0; --i)
|
||
|
after {
|
||
|
rsa2 = r4;
|
||
|
// rsa2 = output buffer pointer
|
||
|
|
||
|
nop;
|
||
|
nop;
|
||
|
}
|
||
|
//*****************************
|
||
|
// TODO: cycles to this point *
|
||
|
//*****************************
|
||
|
{
|
||
|
acc0 = (rsd0 = *rsa0++1);
|
||
|
// get sample
|
||
|
|
||
|
nop; // Those "nop"'s are really uggly, but there's
|
||
|
nop; // something with DSP's pipelines which I don't
|
||
|
nop; // understand, resulting this code to fail without
|
||
|
// having those "nop"'s (Benny)
|
||
|
|
||
|
rsa0?reqDMA = r2;
|
||
|
// Trigger DMA transfer on input stream,
|
||
|
// if needed to replenish input buffer
|
||
|
|
||
|
nop;
|
||
|
// Yet another magic "nop" to make stuff work
|
||
|
|
||
|
,,r98 = acc0 $+>> 0;
|
||
|
// store sample in ALU
|
||
|
|
||
|
nop;
|
||
|
// latency on load register.
|
||
|
// (this one is understandable)
|
||
|
|
||
|
*rsa2++1 = r98;
|
||
|
// store sample in output buffer
|
||
|
|
||
|
nop; // The same story
|
||
|
nop; // as above again ...
|
||
|
nop;
|
||
|
}
|
||
|
// TODO: cycles per loop iteration
|
||
|
|
||
|
r2->strmBufPtr = rsa0,, ;
|
||
|
// Update the modified buffer pointers
|
||
|
|
||
|
r4 = rsa2;
|
||
|
// Load output pointer position into r4
|
||
|
|
||
|
r2 = r0->nextSCB;
|
||
|
// Sibling task
|
||
|
|
||
|
goto execSibling_2ind1 // takes 6 cycles
|
||
|
after {
|
||
|
r98 = r2->thisSPB:entryPoint;
|
||
|
// Load child routine entry and data address
|
||
|
|
||
|
r1 = r9;
|
||
|
// r9 is r2->thisSPB
|
||
|
|
||
|
r0->dma_outBufPtr = r4,,
|
||
|
// Store updated output buffer pointer
|
||
|
|
||
|
ind = r8;
|
||
|
// r8 is r2->entryPoint
|
||
|
}
|
||
|
}
|