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