📄 amf_delayoffchip_262ezkit.c
字号:
// Copyright(c) 2005 Analog Devices, Inc. All Rights Reserved.
// This software is proprietary and confidential to Analog Devices, Inc. and its licensors.
// File : $Id: //depot/development/visualaudio/modules/2.5.0/SHARC/Source/AMF_DelayOffChip_262EzKit.c#4 $
// Part of : VisualAudio V2.5.0
// Updated : $Date: 2006/10/12 $ by $Author: Fernando $
#include "AMF_DelayOffChip_262EzKit.h"
/** Read a named integer port. */
#define RDPORT(name) (*(const int*)(name))
/** Write a named integer port. */
#define WRPORT(name) (*(volatile int*)(name))
#define PPDMA_READING 0
#define PPDMA_WRITING 1
#define EXT_MEMORY_WIDTH 8
#define EXT_DECODER_MASK 0xFFE00000
#define EXT_ADDRESS_MASK 0x001FFFFF
/*** external symbol address fixup ***/
#define EXTERNAL_ADDRESS(x) ((void *)(((unsigned int)x & EXT_DECODER_MASK) |\
(((unsigned int)x & EXT_ADDRESS_MASK)*(32/EXT_MEMORY_WIDTH))))
#define EXT_FLOAT_WORDS (32/EXT_MEMORY_WIDTH)
SEG_MOD_FAST_CODE void waitForPPDMA(void)
{
asm("nop; nop;"); // wait 2 cycles before checking PPCTL, due to it's latency
while (RDPORT(PPCTL) & PPDS) {};
}
SEG_MOD_FAST_CODE inline void startPPDMA(void)
{
WRPORT(PPCTL) |= (PPDEN|PPEN);
}
#pragma optimize_for_space
SEG_MOD_FAST_CODE void setupDMATransfer(int direction, float *internalPointer, float *externalPointer, int internalWordCount)
{
// WRPORT(PPCTL) = PPBHC | PPDUR4 | (direction == PPDMA_WRITING ? PPTRAN : 0);
WRPORT(PPCTL) = PPDUR4 | (direction == PPDMA_WRITING ? PPTRAN : 0);
WRPORT(IIPP) = (int)internalPointer; // internal buffer start
WRPORT(IMPP) = 1; // internal address modifier
WRPORT(ICPP) = internalWordCount; // internal word count
WRPORT(EIPP) = (int)externalPointer; // external buffer start
WRPORT(EMPP) = 1; // external address modifier
WRPORT(ECPP) = internalWordCount*EXT_FLOAT_WORDS; // external word count
}
void AMF_DelayOffChip_262EzKit_Render(AMF_DelayOffChip_262EzKit * restrict instance,float * restrict * buffers,int tickSize);
#if 1
/******************************************
* Algorithm:
*
* The algorithm is a variant on the one-pointer delay method, therefore
* the amount of memory used doesn't have to be longer than the delay or
* anything like that. It does mean, however, that both the read
* and write DMAs may need to wrap around in the middle.
*
* - transfer one tick's worth of samples from external memory into
* the output buffer, starting at the writepointer address
* (in external mem), and wrapping around if necessary.
* - transfer the input buffer back to external memory, to the
* same range of address as incoming transfer came from.
*
* Restrictions due to this algorithm:
* - i/o pointer aliasing not allowed
* - this is a read-before-write method which reads/writes a whole tick
* at a time, so the minimum delay of this module is equal to the
* tick size. Of course, delays going all they way down to zero are
* probably valid to do on-chip anyways.
*
* *****************************************/
#pragma optimize_for_space
SEG_MOD_FAST_CODE void AMF_DelayOffChip_262EzKit_Render(AMF_DelayOffChip_262EzKit * restrict instance,float * restrict * buffers,int tickSize) {
int delay = instance->delay; // delay in samples
float *delayBuffer = EXTERNAL_ADDRESS(instance->delayBuffer); // delay buffer
float *delayWritePtr = instance->delayWritePtr;
int i;
float tmp;
float *in = buffers[0];
float *out = buffers[1];
//float *scr = buffers[2];
float *endPtr = delayBuffer + EXT_FLOAT_WORDS*instance->delay; // the next word beyond end of buffer
int split = 0;
int firstCount;
int secondCount;
// handle "orphan write pointer"
if (delayWritePtr >= endPtr || delayWritePtr < delayBuffer) delayWritePtr = delayBuffer;
// wait for any running transfer to finish
waitForPPDMA();
///////////////////////////////// transfer from external buffer
// Handle uninitialized external memory.
// write out zeros for first time around
if (instance->counter > tickSize)
{
#pragma vector_for
for (i=0; i<tickSize; i++)
out[i] = 0.0;
instance->counter -= tickSize;
} else
{
// if the "write pointer" will wrap around the buffer this tick, do a split read
if (delayWritePtr + EXT_FLOAT_WORDS*(tickSize - 1) >= endPtr)
{
// split transfer
split = 1;
firstCount = ((int)endPtr - (int)delayWritePtr)/EXT_FLOAT_WORDS; // internal word count
secondCount = tickSize - firstCount;
// first transfer
setupDMATransfer(PPDMA_READING, out, delayWritePtr, firstCount);
startPPDMA();
waitForPPDMA();
// second transfer
setupDMATransfer(PPDMA_READING, out+firstCount, delayBuffer, secondCount);
startPPDMA();
} else
{
// single transfer
setupDMATransfer(PPDMA_READING, out, delayWritePtr, tickSize);
startPPDMA();
}
// wait for the transfer to finish...
waitForPPDMA();
if (instance->counter > 0)
{
#pragma vector_for
for (i=0; i<instance->counter; i++)
out[i] = 0.0;
instance->counter = 0;
}
}
// NOTE!!!!!!!!!!!!!!! since this delay doesn't interpret the data
// (it just copies it around) there is no need to worry about
// the right endian-ness on the reading and writing (which could be
// an issue since the transfers are only 8 bits at a time).
// HOWEVER, any module based on this code that does use that data
// in any way other than copying it directly to/from a buffer may
// need to do something about the ordering.
// Note that copying to and from a scratch buffer shouldn't need any endian-ness handling
///////////////////////////////// do the delay copies
/*
for (i=0; i<tickSize; i++) {
tmp = scr[i]; // this ordering is so that we don't write out[i] before reading in[i], so that we can allow aliasing
scr[i] = in[i];
out[i] = tmp;
}
*/
///////////////////////////////// transfer back to external buffer
if (split)
{
// first transfer
setupDMATransfer(PPDMA_WRITING, in, delayWritePtr, firstCount);
startPPDMA();
waitForPPDMA();
// wait for it to "really" finish
asm("nop; nop; nop; nop; nop; nop; nop; nop;");
asm("nop; nop; nop; nop; nop; nop;");
// second transfer
setupDMATransfer(PPDMA_WRITING, in+firstCount, delayBuffer, secondCount);
startPPDMA();
instance->delayWritePtr = delayBuffer + EXT_FLOAT_WORDS*secondCount;
} else
{
// single transfer
setupDMATransfer(PPDMA_WRITING, in, delayWritePtr, tickSize);
startPPDMA();
instance->delayWritePtr = delayWritePtr + EXT_FLOAT_WORDS*tickSize;
}
// NOTE: if we can make sure that any other code that wants to use the
// parallel port will wait for any existing transfer to finish, then
// we would not have to wait here, and possibly overlap the transfer
// with whatever processing happens next
// wait for the transfer to finish...
waitForPPDMA();
}
#endif
SEG_MOD_SLOW_CONST const AMF_ModuleClass AMFClassDelayOffChip_262EzKit = {
/* Flags */
0,
/** Reference to render function. */
(AMF_RenderFunction)AMF_DelayOffChip_262EzKit_Render, // render function
/* Default bypass */
(void *)0,
/* Input descriptor - 1 input, and it is mono. */
1, 0,
/* Output descriptor - 1 output, and it is mono. */
1, 0,
};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -