summaryrefslogtreecommitdiff
path: root/sim/testsuite/bfin/iir.s
blob: b1cb420e3b65261cdccf92434fb6f51d6a4793a5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
# mach: bfin

// GENERIC BIQUAD:
// ---------------
//  x ---------+---------|---------+-------y
//             |         |t1       |
//             |         D         |
//             |   a1    |    b1   |
//             +---<-----|---->----+
//             |         |         |
//             |         D         |   D's are delays
//             |   a2    |    b2   |   ">" represent multiplications
//             +---<-----|---->----+
// To test this routine, use a biquad with a pole pair at z = (0.7 +- 0.1j),
// and a double zero at z = -1.0, which is a low-pass. The transfer function is:
//        1 + 2z^-1 + z^-2
// H(z) = ----------------------
//        1 - 1.4z^-1 + 0.5z^-2
// a1 = 1.4
// a2 = -0.5
// b1 = 2
// b2 = 1
// This filter conforms to the biquad test in BDT, since it has coefficients
// larger than 1.0 in magnitude, and b0=1. (Note that the a's have a negative
// sign.)
// This filter can be simulated in matlab. To simulate one biquad, use
// A = [1.0, -1.4, 0.5]
// B = [1, 2, 1]
// Y=filter(B,A,X)
// To simulate two cascaded biquads, use
// Y=filter(B,A,filter(B,A,X))
// SCALED COEFFICIENTS:
// --------------------
// In order to conform to 1.15 representation, must scale coeffs by 0.5.
// This requires an additional internal re-scale. The equations for the Type II
// filter are:
// t1 = x +     a1*t1*z^-1 + a2*t1*z^-2
// y  = b0*t1 + b1*t1*z^-1 + b2*t1*z^-2
// (Note inclusion of term b0, which in the example is b0 = 1.)
// If all coeffs are replaced by
// ai --> ai' = 0.5*a1
// then the two equations become
// t1    = x +     2*a1'*t1*z^-1 + 2*a2'*t1*z^-2
// 0.5*y = b0'*t1  + b1'*t1*z^-1 + b2'*t1*z^-2
// which can be implemented as:
//                2.0        b0'=0.5
//  x ---------+--->-----|---->----+-------y
//             |         |t1       |
//             |         D         |
//             |   a1'   |    b1'  |
//             +---<-----|---->----+
//             |         |         |
//             |         D         |
//             |   a2'   |    b2'  |
//             +---<-----|---->----+
// But, b0' can be eliminated by:
//  x ---------+---------|---------+-------y
//             |         |         |
//             |         V 2.0     |
//             |         |         |
//             |         |t1       |
//             |         D         |
//             |   a1'   |    b1'  |
//             +---<-----|---->----+
//             |         |         |
//             |         D         |
//             |   a2'   |    b2'  |
//             +---<-----|---->----+
// Function biquadf() computes this implementation on float data.
// CASCADED BIQUADS
// ----------------
// Cascaded biquads are simulated by simply cascading copies of the
// filter defined above. However, one must be careful with the resulting
// filter, as it is not very stable numerically (double poles in the
// vecinity of +1). It would of course be better to cascade different
// filters, as that would result in more stable structures.
// The functions biquadf() and biquadR() have been tested with up to 3
// stages using this technique, with inputs having small signal amplitude
// (less than 0.001) and under 300 samples.
//
// In order to pipeline, need to maintain two pointers into the state
// array: one to load (I0) and one to store (I2). This is required since
// the load of iteration i+1 is hoisted above the store of iteration i.

.include "testutils.inc"
	start


	// I3 points to input buffer
	loadsym I3, input;

	// P1 points to output buffer
	loadsym P1, output;

	R0 = 0;	R7 = 0;

	P2 = 10;
	LSETUP ( L$0 , L$0end ) LC0 = P2;
L$0:

	// I0 and I2 are pointers to state
	loadsym I0, state;
	I2 = I0;

	// pointer to coeffs
	loadsym I1, Coeff;

	R0.H = W [ I3 ++ ];	// load input value into RH0
	A0.w = R0;		// A0 holds x

	P2 = 2;
	LSETUP ( L$1 , L$1end ) LC1 = P2;

	// load 2 coeffs into R1 and R2
	// load state into R3
	R1 = [ I1 ++ ];
	MNOP || R2 = [ I1 ++ ] || R3 = [ I0 ++ ];

L$1:

	// A1=b1*s0   A0=a1*s0+x
	A1 = R1.L * R3.L, A0 += R1.H * R3.L || R1 = [ I1 ++ ] || NOP;

	// A1+=b2*s1  A0+=a2*s1
	// and move scaled value in A0 (t1) into RL4
	A1 += R2.L * R3.H, R4.L = ( A0 += R2.H * R3.H ) (S2RND) || R2 = [ I1 ++ ] || NOP;

	// Advance state. before:
	//  R4 =   uuuu   t1
	//  R3 = stat[1] stat[0]
	// after PACKLL:
	//  R3 = stat[0] t1
	R5 = PACK( R3.L , R4.L ) || R3 = [ I0 ++ ] || NOP;

	// collect output into A0, and move to RL0.
	// Keep output value in A0, since it is also
	// the accumulator used to store the input to
	// the next stage. Also, store updated state
L$1end:
	R0.L = ( A0 += A1 ) || [ I2 ++ ] = R5 || NOP;

	// store output
L$0end:
	W [ P1 ++ ] = R0;

	// Check results
	loadsym I2, output;
	R0.L = W [ I2 ++ ];	DBGA ( R0.L , 0x0028 );
	R0.L = W [ I2 ++ ];	DBGA ( R0.L , 0x0110 );
	R0.L = W [ I2 ++ ];	DBGA ( R0.L , 0x0373 );
	R0.L = W [ I2 ++ ];	DBGA ( R0.L , 0x075b );
	R0.L = W [ I2 ++ ];	DBGA ( R0.L , 0x0c00 );
	R0.L = W [ I2 ++ ];	DBGA ( R0.L , 0x1064 );
	R0.L = W [ I2 ++ ];	DBGA ( R0.L , 0x13d3 );
	R0.L = W [ I2 ++ ];	DBGA ( R0.L , 0x15f2 );
	R0.L = W [ I2 ++ ];	DBGA ( R0.L , 0x16b9 );
	R0.L = W [ I2 ++ ];	DBGA ( R0.L , 0x1650 );

	pass

	.data
state:
	.dw 0x0000
	.dw 0x0000
	.dw 0x0000
	.dw 0x0000
	.dw 0x0000
	.dw 0x0000
	.dw 0x0000
	.dw 0x0000

	.data
Coeff:
	.dw 0x7fff
	.dw 0x5999
	.dw 0x4000
	.dw 0xe000
	.dw 0x7fff
	.dw 0x5999
	.dw 0x4000
	.dw 0xe000
input:
	.dw 0x0028
	.dw 0x0000
	.dw 0x0000
	.dw 0x0000
	.dw 0x0000
	.dw 0x0000
	.dw 0x0000
	.dw 0x0000
	.dw 0x0000
	.dw 0x0000
	.dw 0x0000
output:
	.dw 0x0000
	.dw 0x0000
	.dw 0x0000
	.dw 0x0000
	.dw 0x0000
	.dw 0x0000
	.dw 0x0000
	.dw 0x0000
	.dw 0x0000
	.dw 0x0000
	.dw 0x0000
	.dw 0x0000
	.dw 0x0000