⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 amf_delayoffchip_262ezkit.c

📁 ADI SHARC DSP 音频算法标准模块库
💻 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 + -