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
40extern 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
50static 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}
63static 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__)
78static 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__)
91static 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__)
104static 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__)
118static 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
132static 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}
147static 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__)
174static 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__)
191static 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__)
206static 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
222static 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 */
239static 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__)
254static 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__)
275static 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
291static 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
317static 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
326static 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}
340static 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}
354static 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}
368static 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
385static 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}
402static 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}
419static 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
439static 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__)
465static 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