📄 amf_delayntapnoutoffchip_262ezkit.c
字号:
// Copyright(c) 2005 Analog Devices, Inc. All Rights Reserved. ADI Confidential.
#include "AMF_DelayNTapNOutOffChip_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)
#pragma optimize_off
void waitForPPDMA(void)
{
asm("nop; nop;"); // wait 2 cycles before checking PPCTL, due to it's latency
while (RDPORT(PPCTL) & PPDS) {};
}
inline startPPDMA(void)
{
WRPORT(PPCTL) |= (PPDEN|PPEN);
}
//#pragma optimize_for_space
#pragma optimize_off
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_DelayNTapNOutOffChip_262EzKit_Render(AMF_DelayNTapNOutOffChip_262EzKit * restrict instance,float * restrict * buffers,int tickSize);
#if 1
/******************************************
* Algorithm:
*
* Restrictions due to this algorithm:
* - i/o pointer aliasing not allowed. This is because it reads-before-writes
* - 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
#pragma optimize_off
SEG_MOD_FAST_CODE void AMF_DelayNTapNOutOffChip_262EzKit_Render(AMF_DelayNTapNOutOffChip_262EzKit * restrict instance,float * restrict * buffers,int tickSize) {
int delayBufferLength = instance->delayBufferLength; // delay buffer length in samples
int *taps = instance->taps;
float *delayBuffer = EXTERNAL_ADDRESS(instance->delayBuffer); // delay buffer
float *delayWritePtr = instance->delayWritePtr;
float *delayReadPtr;
int i,curTap;
float tmp;
float *in = buffers[0];
float *out;
//float *scr = buffers[2];
float *endPtr;
int firstCount;
int secondCount;
int initializedMemoryCount;
int numTaps = instance->numTaps;
endPtr = delayBuffer + EXT_FLOAT_WORDS * delayBufferLength; // the next word beyond end of buffer
// handle "orphan write pointer"
if (delayWritePtr >= endPtr || delayWritePtr < delayBuffer)
delayWritePtr = delayBuffer;
// wait for any running transfer to finish
// I think this is not needed, if we assume that all PP access at user level disables interrupts.
// This is true for the VA framework platforms.
waitForPPDMA(); // Not needed?? FIXME
///////////////////////////////// transfer from external buffer
initializedMemoryCount = delayBufferLength-instance->counter;
for (curTap = 0; curTap < numTaps; curTap++) {
out = buffers[1+curTap]; // + 1 because first one is input
if (initializedMemoryCount < taps[curTap]) {
// Handle uninitialized external memory.
// write out zeros for first time around
for (i=0; i<tickSize; i++)
out[i] = 0.0;
} else
{
delayReadPtr = delayWritePtr - EXT_FLOAT_WORDS*taps[curTap];
if (delayReadPtr < delayBuffer)
delayReadPtr += delayBufferLength*EXT_FLOAT_WORDS;
// if the "read pointer" will wrap around the buffer this tick, do a split read
if (delayReadPtr + EXT_FLOAT_WORDS*(tickSize - 1) >= endPtr)
{
// split transfer
firstCount = ((int)endPtr - (int)delayReadPtr)/EXT_FLOAT_WORDS; // internal word count
secondCount = tickSize - firstCount;
// first transfer
setupDMATransfer(PPDMA_READING, out, delayReadPtr, firstCount);
startPPDMA();
waitForPPDMA();
// second transfer
setupDMATransfer(PPDMA_READING, out+firstCount, delayBuffer, secondCount);
startPPDMA();
} else
{
// single transfer
setupDMATransfer(PPDMA_READING, out, delayReadPtr, tickSize);
startPPDMA();
}
// wait for the transfer to finish...
waitForPPDMA();
}
}
// if (instance->counter > tickSize)
// instance->counter -= tickSize; // delete if code works
if (instance->counter > 0)
instance->counter -= tickSize;
// 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 (delayWritePtr + EXT_FLOAT_WORDS*(tickSize - 1) >= endPtr)
{ // split transfer
// first transfer
firstCount = ((int)endPtr - (int)delayWritePtr)/EXT_FLOAT_WORDS; // internal word count
secondCount = tickSize - firstCount;
setupDMATransfer(PPDMA_WRITING, in, delayWritePtr, firstCount);
startPPDMA();
waitForPPDMA();
// wait for it to "really" finish
// DAJ - What is this?? FIXME
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 AMFClassDelayNTapNOutOffChip_262EzKit = {
/** Flags. This is not used, and the member should probably be removed. */
AMFModuleClassFlag_VARIABLE_PIN_COUNT,
/** Reference to render function. */
(AMF_RenderFunction)AMF_DelayNTapNOutOffChip_262EzKit_Render, // render function
/* Default bypass */
(void *)0,
};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -