📄 amf_delay_render.asm
字号:
// 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_Delay_Render.asm#3 $
// Part of : VisualAudio V2.5.0
// Updated : $Date: 2006/10/12 $ by $Author: Fernando $
// Module Name : AMF_Delay_Render.asm
// DSP Processor : ADSP21161
// Description : Delay audio module ASM file.
// Owner : Analog Devices
// Original Author : Tim Stilson
// Date : 7/17/03
//====================================================================================
// Processor resources used:
// 86 words pmem INTERNAL
// 362 max cycles (TickSize=128) (106 + 4*tickSize/2)
// (SIMD used)
//====================================================================================
#if 1
////////////////////////////////////////////////////////////////////////////////
//
// History:
//
// 7/17/03 Tim Stilson: created
//
////////////////////////////////////////////////////////////////////////////////
//
// Mono Delay with SIMD access to delay memory (for on-chip delay storage on 21161)
//
// Special Requirements:
// - DelaySize must be even, greater than or equal to TickSize, and greater than or equal to DelayLength
// - DelayBuffer must be allocated to size DelaySize+1, and that last word is used specially
//
////////////////////////////////////////////////////////////////////////////////
#include "processor.h"
#include "AMF_Delay.h"
#include "asm_macros.h"
#include "asm_sprt.h"
// global routines
.global _AMF_Delay_Render; ;
.segment /pm SEG_MOD_FAST_CODE;
////////////////////////////////////////////////////////////////////////////////
// Delay filter
//
_AMF_Delay_Render:
// push context on stack
puts=mode1;
r0=i3; puts=r0;
r0=i2; puts=r0;
r0=i1; puts=r0;
r0=i0; puts=r0;
r0=b1; puts=r0;
r0=b0; puts=r0;
i4=r8; // i4->*buffers
// initialize input and output samples pointers
i3=dm(0,i4); // i1->buffers[0], input
i2=dm(1,i4); // i2->buffers[1], output
i4=r4; //i4->testModuleInstance[0]
// initialize coefficient pointer
b1=dm(AMF_Delay_DelayBuffer,i4); // buffer base
l1=dm(AMF_Delay_DelaySize,i4); // length of circular buffer (must be even, >= tickSize and also be >= delay length)
r0=dm(AMF_Delay_Delay,i4); // actual delay in samples
i1=dm(AMF_Delay_DelayWritePtr,i4); // current delay write pointer
// setup read pointer
b0=b1; // same circular buffer for read ptr
l0=l1; // same circular buffer for read ptr
r1=i1; // writeptr
r2=b1; // buffer base
r8=l1; // buffer length
r0=r1-r0; // readPtr = writePtr-delay
AMF_Delay_While_Loop:
comp(r0,r2); // check against base of buffer
if ge jump AMF_Delay_AfterWhile;
r0=r0+r8; // readPtr += bufferLength
jump AMF_Delay_While_Loop;
AMF_Delay_AfterWhile:
s0=r0; // s0=readPtr;
/////////// Fixup to handle interaction between SIMD reads and circular buffers ///////
// if the end of the circular buffer is the first word of a SIMD read (i.e. the SIMD
// read crosses the circular buffer boundary between the PEx and PEy sides of the read)
// then the read will actually return the value beyond the end of the ciruclar buffer in the
// PEy side of the read, rather than the first value in the circular buffer. This is
// because the read is commited before the circular-buffer pointer calculations are done
// (and probably because SIMD reads are only possible to contiguous pairs of words anyways).
// Thus, if we have an odd delay length, we may find that the buffer reads may have this problem.
// Therefore, we do a "fixup" to place the first value in the buffer also into the first word
// after the buffer, so that the SIMD read will return the right value. The peculiarities of
// this fixup will place various restrictions on the setup:
// - The delay will use a "readPtr-follows-writePtr" (i.e. two-pointer) algorithm rather than
// the single-pointer method that all the other single-tap delay modules use.
// - The allocated length for the delay buffer must be one word longer than the circular
// buffer length.
// - To avoid worrying about the write pointer wrapping around more than once per tick,
// the circular buffer length must be >= tickSize (this is the reason for using the
// two-pointer delay algorithm, by the way). This allows us to do the fixup outside
// the inner loop and therefore not add much to the cost of the module.
// - to avoid worrying about the same interaction between the circular buffer and the
// SIMD writes, the circular buffer is required to be an even length.
//////////////////////////////////////////////////////////////////////////////////////
// if delay is even, then skip all this
// if neither pointer will wrap this tick, then skip the rest of this
// if (writeptr < readptr) copy first word to one past the end of buffer (i.e. to buffer[bufferLength])
// if (writePtr >= readptr) then it will write to first word in buffer during this
// tick, and it will do it before the read ptr gets to it, so we will copy that value to
// the word past the end of the buffer.
//////////////////////// pseudo code /////////////////////////////////////////////////
// if (delay&1 && (writePtr+tickSize >= bufferBase+bufferLength || readPtr+tickSize >= bufferBase+bufferLength))
// {
// if (writePtr == buffer)
// buffer[bufferLength]=in[0];
// else if (writePtr < readPtr)
// buffer[bufferLength]=buffer[0];
// else
// buffer[bufferLength]=in[bufferBase+bufferLength-writePtr];
// }
//////////////////////////////////////////////////////////////////////////////////////
r4=dm(AMF_Delay_Delay,i4); // delay in samples
r2=1;
r2=r4 AND r2; // check to see if odd
if eq jump AMF_Delay_AfterFixup; // even, don't need to do anything special
//r0=readptr
//r1=i1; //writePtr
r2=b1; //bufferBase
comp(r1,r2);
if ne jump AMF_Delay_NotEqual;
i0=b0; // i0=buffer base
m4=r8;
r1=dm(m5,i3); // in[0];
dm(m4,i0)=r1; // copied to the word after the end of the buffer
jump AMF_Delay_AfterFixup;
AMF_Delay_NotEqual:
r4=r1+r12; // writePtr-ticksize
r2=r2+r8; // bufferBase+bufferLength;
comp(r4,r2);
if ge jump AMF_Delay_DoFixup;
r4=r0+r12; // readPtr-ticksize
comp(r4,r2);
if ge jump AMF_Delay_DoFixup;
jump AMF_Delay_AfterFixup;
AMF_Delay_DoFixup:
i0=b0; // i0=buffer base
comp(r1,r0); // compare writePtr and readPtr
if ge jump AMF_Delay_GreaterEqual;
m4=r8;
r1=dm(m5,i0); // buffer[0];
dm(m4,i0)=r1; // copied to the word after the end of the buffer
jump AMF_Delay_AfterFixup;
AMF_Delay_GreaterEqual:
r2=r2-r1; // bufferBase+bufferLength-writePtr
m4=r2;
r1=dm(m4,i3); // r1=in[1+bufferBase+bufferLength-writePtr]
m4=r8;
dm(m4,i0)=r1; // copied to the word after the end of the buffer
AMF_Delay_AfterFixup:
i0=s0; // restore readPtr;
bit set MODE1 PEYEN;
m4=2;
r12=lshift r12 by -1;
lcntr=r12, do AMF_Delay_Loop until lce;
r1=dm(i3,m4); // r1 = in[i/i+1];
r0=dm(i0,m4); // r0 = delay[readPtr/readPtr+1];
dm(i2,m4)=r0; // out=delayout
AMF_Delay_Loop:
dm(i1,m4)=r1; // delay[writePtr/writePtr+1]=in, incr and wrap index
bit clr MODE1 PEYEN;
l1 = 0;
l0 = 0;
r0=i1;
dm(AMF_Delay_DelayWritePtr,i4)=r0; // store away current delay pointer
// pop context off stack
b0=gets(1);
b1=gets(2);
i0=gets(3);
i1=gets(4);
i2=gets(5);
i3=gets(6);
mode1=gets(7);
alter(7);
//------------------------------------------------------------------------------------
_AMF_Delay_Render.END:
leaf_exit; // C-rth requires this instead of rts
//------------------------------------------------------------------------------------
.endseg;
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -