Name: LATNRM.ASM Type: Assembler Macro Version: 1.0 Last Change: 1-Aug-86 Description: Normalized Lattice IIR Filter Assembler Macro This implements a normalized lattice filter as described by A. Gray and J. Markel in "A Normalized Digital Filter Structure", IEEE ASSP June, 1975. | input V ------q2---->(+)-------->-----q1---->(+)-------->-----q0-->(+)--------- | ^ | ^ | ^ | | | | | | | | k2 -k2 k1 -k1 k0 -k0 V | | | | | | | V | V | V | | -(+)<--q2-------<--1/z---(+)<---q1------<--1/z---(+)<--q0-----<--1/z---- | s2 | s1 | s0 | v3 v2 v1 v0 | \_______ __________/ | \ \ / / ------------------------------(+)-------------------------------- L_________> output output sample is in A. The filter is called by: latnrm order ;call normalized lattice filter where 'latnrm' is the filter macro name and 'order' is the order (number of different k parameters) of the filter (3 in this example). An example of how to use this macro is found in the DSPLIB in the file LATNRMT.ASM. The address registers are set as: r0 r4 | | v v X: q2 k2 q1 k1 q0 k0 v3 v2 v1 v0 Y: sx s2 s1 s0 m0=3*N (=9, mod 10) m4=N (=3, mod 4) The register R0 is initialized to point to the first q coefficient of the leftmost section of the filter. The register R4 is initialized to point to the first location of modulo storage for the filter states. The modulo register M0 is initialized to three times the order of the filter. The modulo register M4 is initialized to the order of the filter (note that this results in a modulus of ORDER+1). The input sample is put in y0 (called w in the comments) and the output sample is in A. The filter is called by: latnrm order ;call normalized lattice filter where 'latnrm' is the filter macro name and 'order' is the order (number of different k parameters) of the filter (3 in this example). FILTER OPERATION The operation of this filter can be described (refer to Figure 7 and the macro 'latnrm'): 1. The input sample is initially in product register Y0. The pointer R0 is initially pointing to the first filter coefficient (Q2) and the state pointer R4 is pointing to the first location of the state variable storage. 2. The first MOVE instruction loads the first Q coefficient into X1 for the leftmost section of the filter. The pointer R0 is then incremented to point to the next coefficient (K). Each section of the filter has four multiplies with an additional multiply after the loop to compute the FIR taps. Each section of this filter has the appearance of a "box". 3. The loop then makes ORDER passes. This loop calculates the state variables. These state variables are later multiplied by the V coefficient taps and summed to form the output. 4. The first multiply in the loop multiplies the input (Y0) by the first coefficient (Q2 in X1) and leaves the result in A. This computes the top of the box. Simultaneously, the k coefficient (k2) for this section of the filter is loaded and the coefficient pointer is incremented. The state variable for this section of the filter is also loaded (Y1) and the pointer to the state variables is not incremented so that later in the loop, the new state variable can be written in its place. 5. The second instruction of the loop (MAC) multiplies the k coefficient (in X0) by the state variable previously loaded (Y1) and subtracts this result from the summing junction at the top right of the box. This value is the top left input to the next section of the filter. The value in B is saved as the new state variable and the pointer R4 is incremented to point to the next state variable. Note that on the first pass of the loop, the value in B is unknown and an unknown value is saved as the first state variable. This value is eventually overwritten after exiting the loop. 6. The next multiply will multiply the input value (Y0) by the k coefficient (X0) to compute the left side of the box (B). At this point, the top right value of the box (A) is moved into a product register (Y0) to be used as the input to the next filter section. 7. The state variable at the bottom left of the box is then computed by summing the value from the left side of the box (B) with the product of the q value (Q2 in X1) and the state variable (Y1). This resulting state variable is saved on the next pass of the loop. The next q value for the next section of the filter is then loaded into X1 and the pointer R0 is incremented. 8. Upon exiting from the loop, the loop has calculated and saved ORDER-1 state variables (the first value saved was an unknown value do to the order of the statements always saving the last state variable and upon entry to the loop the last state variable is a unknown value). Since ORDER+1 state variables are needed to compute the FIR taps, the other two state variables need to be saved yet. 9. The value in the last state is then rounded and the second last state is saved (B). The pointer is incremented to point to the next state position. At this point the pointer is pointing to the unknown value that was first written. 10. The top rightmost value (in A) is then saved as the last state. This value overwrites the unknown value initially saved. The pointer R4 increments to point to the state value to multiply the tap v3. 11. The state variable to multiply V3 by is then loaded into Y0 and the A register is cleared to accumulate the FIR taps. 12. A repeat instruction is used to multiply and accumulate ORDER taps. The last pass of the DO loop had already loaded the first v coefficient (V3) into X1. 13. The last FIR tap is then multiplied, accumulated and the result is rounded. Since R4 was incremented once before the repeat loop and ORDER times during the loop, R4 now is pointing to the same position again (the modulo on R4 is ORDER+1). The register R4 is then incremented to point to the next state which is the first state to be loaded for the next sample time. Benchmarks for this filter are: 13 instructions, 5N+9 instructions cycles, 2 stack locations.