/************************************************************** File Name: fir_blk.asm Date Modified: 2/16/99 RFG 7/17/00 PPG Purpose: Subroutine that implements a Block FIR Filter given coefficients and samples. Equation: y(n) = Summation from k=0 to M of h(k)*x(n-k) Calling Parameters: b0,i0 = address of delay line buffer l0 = length of delay line buffer b1,i1 = address of input samples buffer b8,i8 = address of coefficients buffer l8 = length of coefficients buffer b9,i9 = address of output buffer r1 = number of taps in the filter divided by 2 r2 = number of samples r3 = (number of taps in filter - 6) / 2 s0,m0,l1,l9 = 0 m1,m10 = 1 m2=-1 m3,m9 = 2 Assumptions: All arrays must start on even address boundaries. All arrays must have an even number length (zero pad if necessary) Return Values: i9=OUTPUT Registers Affected: f0,s0,f4,s4,f8,s8,f12,s12 i0,i8,i9 Cycle Count: 9 + taps/2 + samples(6 + taps/2) + 9 cache misses Number of PM Locations: 21 instruction words 2 * Number of taps locations for coefficients Number of samples + 1 locations for the output buffer Number of DM Locations: Number of taps locations for the delay line buffer Number of samples locations for the input buffer Circular buffer notes: Because SIMD or Long word access transfer two 32-bit words, programs must be careful when using these accesses in circular buffering. It is important that SIMD or Long word accesses do not cross a circular buffer boundary. If a SIMD mode access occurs using a circular buffer index register that points to the last location in the circular buffer (end of buffer), the resulting access transfers the last location in the circular buffer and the first location outside the buffer (end of buffer + 1). **************************************************************/ #include "def21161.h" .global fir; /* program memory code */ .section/pm seg_pmco; fir: /* Circular Buffer Enable, SIMD Mode Enable */ bit set MODE1 CBUFEN | PEYEN; r0 = dm(i1,m1); /* read one sample from INPUT[i] */ /* SIMD not in effect until next cycle */ /* clear delay line */ f8=0.0; lcntr = r1, do clear_fir until lce; clear_fir: dm(i0,m3) = f8; f4 = pm(i8,m9); /* read 2 coeffs */ lcntr = r2, do main_fir until lce; /* outer loop - sample loop */ dm(i0,m3)=f0, pm(i9,m10)=f8; /* transfer sample to delayline, write result to OUTPUT[i] */ f8=f0*f4, f0=dm(i0,m3), f4=pm(i8,m9); /* samples * coeffs, read 2 samples, read 2 coeffs */ f12=f0*f4, f0=dm(i0,m3), f4=pm(i8,m9); /* samples * coeffs, read 2 samples, read 2 coeffs */ lcntr=r3, do macs until lce; /* FIR loop */ macs: f12=f0*f4, f8=f8+f12, f0=dm(i0,m3), f4=pm(i8,m9); /* samples * coeffs, accum, read 2 samples, read 2 coeffs */ f12=f0*f4, f8=f8+f12, s0=dm(i0,m2); /* samples * coeffs, accum, dummy read to move pointer to oldest sample */ f8=f8+f12, s10=dm(i1,m1); /* final SIMD accum, read new sample */ r12=s8; /* move PEy total into PEx register file */ f8=f8+f12, f0=dm(i0,m0), f4=pm(i8,m9); /* last accum, read sample into s0 for first MAC of next sample, read 2 coeffs */ main_fir: f0 <-> s10; /* place new sample in s0 */ rts (db); /* Circular Buffer Disable, SIMD Mode Disable */ bit clr MODE1 CBUFEN | PEYEN; pm(i9,m10)=f8; fir.end: