1 /* Copyright (C) 2003 Jean-Marc Valin */
2 /**
3 @file fixed_debug.h
4 @brief Fixed-point operations with debugging
5 */
6 /*
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions
9 are met:
10
11 - Redistributions of source code must retain the above copyright
12 notice, this list of conditions and the following disclaimer.
13
14 - Redistributions in binary form must reproduce the above copyright
15 notice, this list of conditions and the following disclaimer in the
16 documentation and/or other materials provided with the distribution.
17
18 - Neither the name of the Xiph.org Foundation nor the names of its
19 contributors may be used to endorse or promote products derived from
20 this software without specific prior written permission.
21
22 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
26 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
27 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
29 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
30 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
31 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 */
34
35 #ifndef FIXED_DEBUG_H
36 #define FIXED_DEBUG_H
37
38 #include <stdio.h>
39
40 extern long long spx_mips;
41 #define MIPS_INC spx_mips++,
42
43 #define QCONST16(x,bits) ((spx_word16_t)(.5+(x)*(((spx_word32_t)1)<<(bits))))
44 #define QCONST32(x,bits) ((spx_word32_t)(.5+(x)*(((spx_word32_t)1)<<(bits))))
45
46
47 #define VERIFY_SHORT(x) ((x)<=32767&&(x)>=-32768)
48 #define VERIFY_INT(x) ((x)<=2147483647LL&&(x)>=-2147483648LL)
49
NEG16(int x)50 static inline short NEG16(int x)
51 {
52 int res;
53 if (!VERIFY_SHORT(x))
54 {
55 fprintf (stderr, "NEG16: input is not short: %d\n", (int)x);
56 }
57 res = -x;
58 if (!VERIFY_SHORT(res))
59 fprintf (stderr, "NEG16: output is not short: %d\n", (int)res);
60 spx_mips++;
61 return res;
62 }
NEG32(long long x)63 static inline int NEG32(long long x)
64 {
65 long long res;
66 if (!VERIFY_INT(x))
67 {
68 fprintf (stderr, "NEG16: input is not int: %d\n", (int)x);
69 }
70 res = -x;
71 if (!VERIFY_INT(res))
72 fprintf (stderr, "NEG16: output is not int: %d\n", (int)res);
73 spx_mips++;
74 return res;
75 }
76
77 #define EXTRACT16(x) _EXTRACT16(x, __FILE__, __LINE__)
_EXTRACT16(int x,char * file,int line)78 static inline short _EXTRACT16(int x, char *file, int line)
79 {
80 int res;
81 if (!VERIFY_SHORT(x))
82 {
83 fprintf (stderr, "EXTRACT16: input is not short: %d in %s: line %d\n", x, file, line);
84 }
85 res = x;
86 spx_mips++;
87 return res;
88 }
89
90 #define EXTEND32(x) _EXTEND32(x, __FILE__, __LINE__)
_EXTEND32(int x,char * file,int line)91 static inline int _EXTEND32(int x, char *file, int line)
92 {
93 int res;
94 if (!VERIFY_SHORT(x))
95 {
96 fprintf (stderr, "EXTEND32: input is not short: %d in %s: line %d\n", x, file, line);
97 }
98 res = x;
99 spx_mips++;
100 return res;
101 }
102
103 #define SHR16(a, shift) _SHR16(a, shift, __FILE__, __LINE__)
_SHR16(int a,int shift,char * file,int line)104 static inline short _SHR16(int a, int shift, char *file, int line)
105 {
106 int res;
107 if (!VERIFY_SHORT(a) || !VERIFY_SHORT(shift))
108 {
109 fprintf (stderr, "SHR16: inputs are not short: %d >> %d in %s: line %d\n", a, shift, file, line);
110 }
111 res = a>>shift;
112 if (!VERIFY_SHORT(res))
113 fprintf (stderr, "SHR16: output is not short: %d in %s: line %d\n", res, file, line);
114 spx_mips++;
115 return res;
116 }
117 #define SHL16(a, shift) _SHL16(a, shift, __FILE__, __LINE__)
_SHL16(int a,int shift,char * file,int line)118 static inline short _SHL16(int a, int shift, char *file, int line)
119 {
120 int res;
121 if (!VERIFY_SHORT(a) || !VERIFY_SHORT(shift))
122 {
123 fprintf (stderr, "SHL16: inputs are not short: %d %d in %s: line %d\n", a, shift, file, line);
124 }
125 res = a<<shift;
126 if (!VERIFY_SHORT(res))
127 fprintf (stderr, "SHL16: output is not short: %d in %s: line %d\n", res, file, line);
128 spx_mips++;
129 return res;
130 }
131
SHR32(long long a,int shift)132 static inline int SHR32(long long a, int shift)
133 {
134 long long res;
135 if (!VERIFY_INT(a) || !VERIFY_SHORT(shift))
136 {
137 fprintf (stderr, "SHR32: inputs are not int: %d %d\n", (int)a, shift);
138 }
139 res = a>>shift;
140 if (!VERIFY_INT(res))
141 {
142 fprintf (stderr, "SHR32: output is not int: %d\n", (int)res);
143 }
144 spx_mips++;
145 return res;
146 }
SHL32(long long a,int shift)147 static inline int SHL32(long long a, int shift)
148 {
149 long long res;
150 if (!VERIFY_INT(a) || !VERIFY_SHORT(shift))
151 {
152 fprintf (stderr, "SHL32: inputs are not int: %d %d\n", (int)a, shift);
153 }
154 res = a<<shift;
155 if (!VERIFY_INT(res))
156 {
157 fprintf (stderr, "SHL32: output is not int: %d\n", (int)res);
158 }
159 spx_mips++;
160 return res;
161 }
162
163 #define PSHR16(a,shift) (SHR16(ADD16((a),((1<<((shift))>>1))),shift))
164 #define PSHR32(a,shift) (SHR32(ADD32((a),((EXTEND32(1)<<((shift))>>1))),shift))
165 #define VSHR32(a, shift) (((shift)>0) ? SHR32(a, shift) : SHL32(a, -(shift)))
166
167 #define SATURATE16(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x)))
168 #define SATURATE32(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x)))
169
170 //#define SHR(a,shift) ((a) >> (shift))
171 //#define SHL(a,shift) ((a) << (shift))
172
173 #define ADD16(a, b) _ADD16(a, b, __FILE__, __LINE__)
_ADD16(int a,int b,char * file,int line)174 static inline short _ADD16(int a, int b, char *file, int line)
175 {
176 int res;
177 if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
178 {
179 fprintf (stderr, "ADD16: inputs are not short: %d %d in %s: line %d\n", a, b, file, line);
180 }
181 res = a+b;
182 if (!VERIFY_SHORT(res))
183 {
184 fprintf (stderr, "ADD16: output is not short: %d+%d=%d in %s: line %d\n", a,b,res, file, line);
185 }
186 spx_mips++;
187 return res;
188 }
189
190 #define SUB16(a, b) _SUB16(a, b, __FILE__, __LINE__)
_SUB16(int a,int b,char * file,int line)191 static inline short _SUB16(int a, int b, char *file, int line)
192 {
193 int res;
194 if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
195 {
196 fprintf (stderr, "SUB16: inputs are not short: %d %d in %s: line %d\n", a, b, file, line);
197 }
198 res = a-b;
199 if (!VERIFY_SHORT(res))
200 fprintf (stderr, "SUB16: output is not short: %d in %s: line %d\n", res, file, line);
201 spx_mips++;
202 return res;
203 }
204
205 #define ADD32(a, b) _ADD32(a, b, __FILE__, __LINE__)
_ADD32(long long a,long long b,char * file,int line)206 static inline int _ADD32(long long a, long long b, char *file, int line)
207 {
208 long long res;
209 if (!VERIFY_INT(a) || !VERIFY_INT(b))
210 {
211 fprintf (stderr, "ADD32: inputs are not int: %d %d in %s: line %d\n", (int)a, (int)b, file, line);
212 }
213 res = a+b;
214 if (!VERIFY_INT(res))
215 {
216 fprintf (stderr, "ADD32: output is not int: %d in %s: line %d\n", (int)res, file, line);
217 }
218 spx_mips++;
219 return res;
220 }
221
SUB32(long long a,long long b)222 static inline int SUB32(long long a, long long b)
223 {
224 long long res;
225 if (!VERIFY_INT(a) || !VERIFY_INT(b))
226 {
227 fprintf (stderr, "SUB32: inputs are not int: %d %d\n", (int)a, (int)b);
228 }
229 res = a-b;
230 if (!VERIFY_INT(res))
231 fprintf (stderr, "SUB32: output is not int: %d\n", (int)res);
232 spx_mips++;
233 return res;
234 }
235
236 #define ADD64(a,b) (MIPS_INC(a)+(b))
237
238 /* result fits in 16 bits */
MULT16_16_16(int a,int b)239 static inline short MULT16_16_16(int a, int b)
240 {
241 int res;
242 if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
243 {
244 fprintf (stderr, "MULT16_16_16: inputs are not short: %d %d\n", a, b);
245 }
246 res = a*b;
247 if (!VERIFY_SHORT(res))
248 fprintf (stderr, "MULT16_16_16: output is not short: %d\n", res);
249 spx_mips++;
250 return res;
251 }
252
253 #define MULT16_16(a, b) _MULT16_16(a, b, __FILE__, __LINE__)
_MULT16_16(int a,int b,char * file,int line)254 static inline int _MULT16_16(int a, int b, char *file, int line)
255 {
256 long long res;
257 if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
258 {
259 fprintf (stderr, "MULT16_16: inputs are not short: %d %d in %s: line %d\n", a, b, file, line);
260 }
261 res = ((long long)a)*b;
262 if (!VERIFY_INT(res))
263 fprintf (stderr, "MULT16_16: output is not int: %d in %s: line %d\n", (int)res, file, line);
264 spx_mips++;
265 return res;
266 }
267
268 #define MAC16_16(c,a,b) (spx_mips--,ADD32((c),MULT16_16((a),(b))))
269 #define MAC16_16_Q11(c,a,b) (EXTRACT16(ADD16((c),EXTRACT16(SHR32(MULT16_16((a),(b)),11)))))
270 #define MAC16_16_Q13(c,a,b) (EXTRACT16(ADD16((c),EXTRACT16(SHR32(MULT16_16((a),(b)),13)))))
271 #define MAC16_16_P13(c,a,b) (EXTRACT16(ADD32((c),SHR32(ADD32(4096,MULT16_16((a),(b))),13))))
272
273
274 #define MULT16_32_QX(a, b, Q) _MULT16_32_QX(a, b, Q, __FILE__, __LINE__)
_MULT16_32_QX(int a,long long b,int Q,char * file,int line)275 static inline int _MULT16_32_QX(int a, long long b, int Q, char *file, int line)
276 {
277 long long res;
278 if (!VERIFY_SHORT(a) || !VERIFY_INT(b))
279 {
280 fprintf (stderr, "MULT16_32_Q%d: inputs are not short+int: %d %d in %s: line %d\n", Q, (int)a, (int)b, file, line);
281 }
282 if (ABS32(b)>=(EXTEND32(1)<<(15+Q)))
283 fprintf (stderr, "MULT16_32_Q%d: second operand too large: %d %d in %s: line %d\n", Q, (int)a, (int)b, file, line);
284 res = (((long long)a)*(long long)b) >> Q;
285 if (!VERIFY_INT(res))
286 fprintf (stderr, "MULT16_32_Q%d: output is not int: %d*%d=%d in %s: line %d\n", Q, (int)a, (int)b,(int)res, file, line);
287 spx_mips+=5;
288 return res;
289 }
290
MULT16_32_PX(int a,long long b,int Q)291 static inline int MULT16_32_PX(int a, long long b, int Q)
292 {
293 long long res;
294 if (!VERIFY_SHORT(a) || !VERIFY_INT(b))
295 {
296 fprintf (stderr, "MULT16_32_P%d: inputs are not short+int: %d %d\n", Q, (int)a, (int)b);
297 }
298 if (ABS32(b)>=(EXTEND32(1)<<(15+Q)))
299 fprintf (stderr, "MULT16_32_Q%d: second operand too large: %d %d\n", Q, (int)a, (int)b);
300 res = ((((long long)a)*(long long)b) + ((EXTEND32(1)<<Q)>>1))>> Q;
301 if (!VERIFY_INT(res))
302 fprintf (stderr, "MULT16_32_P%d: output is not int: %d*%d=%d\n", Q, (int)a, (int)b,(int)res);
303 spx_mips+=5;
304 return res;
305 }
306
307
308 #define MULT16_32_Q11(a,b) MULT16_32_QX(a,b,11)
309 #define MAC16_32_Q11(c,a,b) ADD32((c),MULT16_32_Q11((a),(b)))
310 #define MULT16_32_Q12(a,b) MULT16_32_QX(a,b,12)
311 #define MULT16_32_Q13(a,b) MULT16_32_QX(a,b,13)
312 #define MULT16_32_Q14(a,b) MULT16_32_QX(a,b,14)
313 #define MULT16_32_Q15(a,b) MULT16_32_QX(a,b,15)
314 #define MULT16_32_P15(a,b) MULT16_32_PX(a,b,15)
315 #define MAC16_32_Q15(c,a,b) ADD32((c),MULT16_32_Q15((a),(b)))
316
SATURATE(int a,int b)317 static inline int SATURATE(int a, int b)
318 {
319 if (a>b)
320 a=b;
321 if (a<-b)
322 a = -b;
323 return a;
324 }
325
MULT16_16_Q11_32(int a,int b)326 static inline int MULT16_16_Q11_32(int a, int b)
327 {
328 long long res;
329 if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
330 {
331 fprintf (stderr, "MULT16_16_Q11: inputs are not short: %d %d\n", a, b);
332 }
333 res = ((long long)a)*b;
334 res >>= 11;
335 if (!VERIFY_INT(res))
336 fprintf (stderr, "MULT16_16_Q11: output is not short: %d*%d=%d\n", (int)a, (int)b, (int)res);
337 spx_mips+=3;
338 return res;
339 }
MULT16_16_Q13(int a,int b)340 static inline short MULT16_16_Q13(int a, int b)
341 {
342 long long res;
343 if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
344 {
345 fprintf (stderr, "MULT16_16_Q13: inputs are not short: %d %d\n", a, b);
346 }
347 res = ((long long)a)*b;
348 res >>= 13;
349 if (!VERIFY_SHORT(res))
350 fprintf (stderr, "MULT16_16_Q13: output is not short: %d*%d=%d\n", a, b, (int)res);
351 spx_mips+=3;
352 return res;
353 }
MULT16_16_Q14(int a,int b)354 static inline short MULT16_16_Q14(int a, int b)
355 {
356 long long res;
357 if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
358 {
359 fprintf (stderr, "MULT16_16_Q14: inputs are not short: %d %d\n", a, b);
360 }
361 res = ((long long)a)*b;
362 res >>= 14;
363 if (!VERIFY_SHORT(res))
364 fprintf (stderr, "MULT16_16_Q14: output is not short: %d\n", (int)res);
365 spx_mips+=3;
366 return res;
367 }
MULT16_16_Q15(int a,int b)368 static inline short MULT16_16_Q15(int a, int b)
369 {
370 long long res;
371 if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
372 {
373 fprintf (stderr, "MULT16_16_Q15: inputs are not short: %d %d\n", a, b);
374 }
375 res = ((long long)a)*b;
376 res >>= 15;
377 if (!VERIFY_SHORT(res))
378 {
379 fprintf (stderr, "MULT16_16_Q15: output is not short: %d\n", (int)res);
380 }
381 spx_mips+=3;
382 return res;
383 }
384
MULT16_16_P13(int a,int b)385 static inline short MULT16_16_P13(int a, int b)
386 {
387 long long res;
388 if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
389 {
390 fprintf (stderr, "MULT16_16_P13: inputs are not short: %d %d\n", a, b);
391 }
392 res = ((long long)a)*b;
393 res += 4096;
394 if (!VERIFY_INT(res))
395 fprintf (stderr, "MULT16_16_P13: overflow: %d*%d=%d\n", a, b, (int)res);
396 res >>= 13;
397 if (!VERIFY_SHORT(res))
398 fprintf (stderr, "MULT16_16_P13: output is not short: %d*%d=%d\n", a, b, (int)res);
399 spx_mips+=4;
400 return res;
401 }
MULT16_16_P14(int a,int b)402 static inline short MULT16_16_P14(int a, int b)
403 {
404 long long res;
405 if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
406 {
407 fprintf (stderr, "MULT16_16_P14: inputs are not short: %d %d\n", a, b);
408 }
409 res = ((long long)a)*b;
410 res += 8192;
411 if (!VERIFY_INT(res))
412 fprintf (stderr, "MULT16_16_P14: overflow: %d*%d=%d\n", a, b, (int)res);
413 res >>= 14;
414 if (!VERIFY_SHORT(res))
415 fprintf (stderr, "MULT16_16_P14: output is not short: %d*%d=%d\n", a, b, (int)res);
416 spx_mips+=4;
417 return res;
418 }
MULT16_16_P15(int a,int b)419 static inline short MULT16_16_P15(int a, int b)
420 {
421 long long res;
422 if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
423 {
424 fprintf (stderr, "MULT16_16_P15: inputs are not short: %d %d\n", a, b);
425 }
426 res = ((long long)a)*b;
427 res += 16384;
428 if (!VERIFY_INT(res))
429 fprintf (stderr, "MULT16_16_P15: overflow: %d*%d=%d\n", a, b, (int)res);
430 res >>= 15;
431 if (!VERIFY_SHORT(res))
432 fprintf (stderr, "MULT16_16_P15: output is not short: %d*%d=%d\n", a, b, (int)res);
433 spx_mips+=4;
434 return res;
435 }
436
437 #define DIV32_16(a, b) _DIV32_16(a, b, __FILE__, __LINE__)
438
_DIV32_16(long long a,long long b,char * file,int line)439 static inline int _DIV32_16(long long a, long long b, char *file, int line)
440 {
441 long long res;
442 if (b==0)
443 {
444 fprintf(stderr, "DIV32_16: divide by zero: %d/%d in %s: line %d\n", (int)a, (int)b, file, line);
445 return 0;
446 }
447 if (!VERIFY_INT(a) || !VERIFY_SHORT(b))
448 {
449 fprintf (stderr, "DIV32_16: inputs are not int/short: %d %d in %s: line %d\n", (int)a, (int)b, file, line);
450 }
451 res = a/b;
452 if (!VERIFY_SHORT(res))
453 {
454 fprintf (stderr, "DIV32_16: output is not short: %d / %d = %d in %s: line %d\n", (int)a,(int)b,(int)res, file, line);
455 if (res>32767)
456 res = 32767;
457 if (res<-32768)
458 res = -32768;
459 }
460 spx_mips+=20;
461 return res;
462 }
463
464 #define DIV32(a, b) _DIV32(a, b, __FILE__, __LINE__)
_DIV32(long long a,long long b,char * file,int line)465 static inline int _DIV32(long long a, long long b, char *file, int line)
466 {
467 long long res;
468 if (b==0)
469 {
470 fprintf(stderr, "DIV32: divide by zero: %d/%d in %s: line %d\n", (int)a, (int)b, file, line);
471 return 0;
472 }
473
474 if (!VERIFY_INT(a) || !VERIFY_INT(b))
475 {
476 fprintf (stderr, "DIV32: inputs are not int/short: %d %d in %s: line %d\n", (int)a, (int)b, file, line);
477 }
478 res = a/b;
479 if (!VERIFY_INT(res))
480 fprintf (stderr, "DIV32: output is not int: %d in %s: line %d\n", (int)res, file, line);
481 spx_mips+=36;
482 return res;
483 }
484 #define PDIV32(a,b) DIV32(ADD32((a),(b)>>1),b)
485 #define PDIV32_16(a,b) DIV32_16(ADD32((a),(b)>>1),b)
486
487 #endif
488