FFTLIB User Guide
FFTLIB_utility.h
Go to the documentation of this file.
1 #ifndef COMMON_FFTLIB_UTILITY_H_
2 #define COMMON_FFTLIB_UTILITY_H_ 1
3 
4 /******************************************************************************/
8 /* Copyright (C) 2015 Texas Instruments Incorporated - https://www.ti.com/
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  *
14  * Redistributions of source code must retain the above copyright
15  * notice, this list of conditions and the following disclaimer.
16  *
17  * Redistributions in binary form must reproduce the above copyright
18  * notice, this list of conditions and the following disclaimer in the
19  * documentation and/or other materials provided with the
20  * distribution.
21  *
22  * Neither the name of Texas Instruments Incorporated nor the names of
23  * its contributors may be used to endorse or promote products derived
24  * from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
29  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
30  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
31  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
32  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
34  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
36  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37  *
38  ******************************************************************************/
39 
40 /*******************************************************************************
41  *
42  * INCLUDES
43  *
44  ******************************************************************************/
45 
46 #include <float.h> // for max float, double values
47 #include <limits.h> // for min, max integer values
48 #include <math.h>
49 
50 #include "FFTLIB_bufParams.h"
51 #include "FFTLIB_types.h"
52 
53 #if defined(__C7100__) || defined(__C7120__) || defined(__C7502__) || defined(__C7504__) || defined(__C7508__) || \
54  defined(__C7524__)
55 #include "c71/FFTLIB_utility.h"
56 #if FFTLIB_DEBUGPRINT >= 1
57 #include "c71/FFTLIB_debug.h"
58 #endif
59 #else
60 #error invalid target
61 #endif
62 
63 #include "c7120/FFTLIB_utility.h"
64 
65 /*******************************************************************************
66  *
67  * EXTERNAL VARIABLES
68  *
69  ******************************************************************************/
70 #ifdef __cplusplus
71 extern "C" {
72 #endif /* __cplusplus */
73 extern uint64_t beg_count; /* Begin cycle count for profiling */
74 extern uint64_t end_count; /* End cycle count for profiling */
75 extern uint64_t overhead; /* Cycle profiling overhead */
76 #ifdef __cplusplus
77 }
78 #endif /* __cplusplus */
79 
80 /*******************************************************************************
81  *
82  * Inline functions
83  *
84  ******************************************************************************/
85 
86 /*******************************************************************************
87  *
88  * Arithmetic with 128-bit signed integers
89  *
90  ******************************************************************************/
91 static inline void FFTLIB_UTIL_mult(int64_t *ph, int64_t *pl, int64_t a, int64_t b);
92 
93 static inline void FFTLIB_UTIL_mult(int64_t *ph, // result
94  int64_t *pl,
95  int64_t a, // left operand
96  int64_t b // right operand
97 )
98 {
99  // sum += A[k + m*K] * B[n + k*N];
100  *pl = a * b;
101 
102  // sign extend the product
103  *ph = ((((uint64_t) *pl) & 0x8000000000000000ULL) != 0ULL) ? (int64_t) 0xffffffffffffffffULL : (int64_t) 0ULL;
104 }
105 
106 #ifdef __cplusplus
107 
108 /*******************************************************************************
109  *
110  * Definition and arithmetic for FFTLIB_int128_t class
111  *
112  ******************************************************************************/
113 
114 // Define a 128-bit integer class to allow natural-c implementations of FFTLIB
115 // 32-bit input/output functions to be templated. The class is implemented in
116 // a header file for easy sharing. All member functions, including constructors
117 // are declared inline for two reasons: (1) performance and (2) necessary for
118 // implementing the class in a multiple-inclusion header file.
119 
120 class FFTLIB_int128_t {
121  public:
122  int64_t hi;
123  int64_t lo;
124  FFTLIB_int128_t(int64_t h, int64_t l); // constructor for both high and low specified
125  FFTLIB_int128_t(int64_t l); // constructor for just low specified (sign extends to high)
126  FFTLIB_int128_t(); // constructor for neither field specified
127  FFTLIB_int128_t operator+(const FFTLIB_int128_t &) const; // operator +
128  FFTLIB_int128_t operator>>(const int8_t &) const; // operator >>
129 };
130 
131 // define constructor
132 inline FFTLIB_int128_t::FFTLIB_int128_t(int64_t h, int64_t l)
133 {
134  hi = h;
135  lo = l;
136 }
137 
138 // define constructor
139 inline FFTLIB_int128_t::FFTLIB_int128_t(int64_t l)
140 {
141  // sign extend l
142  hi = (((uint64_t) l & 0x8000000000000000ULL) != 0LL) ? (int64_t) 0xffffffffffffffffULL
143  : (int64_t) 0x0000000000000000ULL;
144  lo = l;
145 }
146 
147 // define constructor
148 inline FFTLIB_int128_t::FFTLIB_int128_t()
149 {
150  hi = 0x0000000000000000LL;
151  lo = 0x0000000000000000LL;
152 }
153 
154 static inline void FFTLIB_UTIL_shiftRight128(uint64_t *rh, // result
155  uint64_t *rl,
156  uint64_t ah, // operand
157  uint64_t al,
158  int32_t sh, // shift amount
159  int32_t s) // signed
160 {
161  uint64_t h;
162  uint64_t l;
163  int32_t i;
164 
165  h = ah;
166  l = al;
167  for (i = 0; i < sh; i++) {
168  l = __shift_right(l, (uint32_t) 1) | __shift_left(h, (uint32_t) 63);
169  h = __shift_right(h, (uint32_t) 1) | ((s != 0) ? (h & 0x8000000000000000ULL) : 0ULL);
170  }
171 
172  *rh = h;
173  *rl = l;
174 }
175 
176 static inline void FFTLIB_UTIL_Add128(uint64_t *rh, // result
177  uint64_t *rl,
178  uint64_t ah, // left operand
179  uint64_t al,
180  uint64_t bh, // right operand
181  uint64_t bl)
182 {
183  // break up the operands into 4 32b chunks packed into 64b uints
184  uint64_t all;
185  uint64_t alh;
186  uint64_t ahl;
187  uint64_t ahh;
188  uint64_t bll;
189  uint64_t blh;
190  uint64_t bhl;
191  uint64_t bhh;
192  uint64_t s0;
193  uint64_t s1;
194  uint64_t s2;
195  uint64_t s3;
196  uint64_t sh;
197  uint64_t sl;
198 
199  all = __shift_right(al, (uint32_t) 0) & 0x0ffffffffULL;
200  alh = __shift_right(al, (uint32_t) 32) & 0x0ffffffffULL;
201  ahl = __shift_right(ah, (uint32_t) 0) & 0x0ffffffffULL;
202  ahh = __shift_right(ah, (uint32_t) 32) & 0x0ffffffffULL;
203 
204  bll = __shift_right(bl, (uint32_t) 0) & 0x0ffffffffULL;
205  blh = __shift_right(bl, (uint32_t) 32) & 0x0ffffffffULL;
206  bhl = __shift_right(bh, (uint32_t) 0) & 0x0ffffffffULL;
207  bhh = __shift_right(bh, (uint32_t) 32) & 0x0ffffffffULL;
208 
209  // the adds
210  s0 = all + bll;
211  s1 = alh + blh + __shift_right(s0, (uint32_t) 32);
212  s2 = ahl + bhl + __shift_right(s1, (uint32_t) 32);
213  s3 = ahh + bhh + __shift_right(s2, (uint32_t) 32);
214 
215  // pack the results
216  sl = __shift_left(s1, (uint32_t) 32) | (s0 & 0x0ffffffffULL);
217  sh = __shift_left(s3, (uint32_t) 32) | (s2 & 0x0ffffffffULL);
218 
219  *rl = sl;
220  *rh = sh;
221 }
222 
223 // define overloaded + (plus) operator
224 inline FFTLIB_int128_t FFTLIB_int128_t::operator+(const FFTLIB_int128_t &b) const
225 {
226  FFTLIB_int128_t result;
227 
228  FFTLIB_UTIL_Add128((uint64_t *) &(result.hi), (uint64_t *) &(result.lo), this->hi, this->lo, b.hi, b.lo);
229 
230  return result;
231 }
232 
233 // define overloaded >> (bit shift right) operator
234 inline FFTLIB_int128_t FFTLIB_int128_t::operator>>(const int8_t &shift) const
235 {
236  FFTLIB_int128_t result;
237 
238  FFTLIB_UTIL_shiftRight128((uint64_t *) &result.hi, (uint64_t *) &result.lo, this->hi, this->lo, (int32_t) shift, 1);
239  return result;
240 }
241 
242 /*******************************************************************************
243  *
244  * We need special utility to do negation because range of values is from
245  * -2^(bit-width-1) to 2^(bit-width-1)-1. For example, with int16_t, the
246  * range is from -32768 to 32767 - that is, -0x8000 to 0x7FFF. Now, if we want
247  * to evaluate negation of -32768 and we try simply -(-32768) and store the
248  * result in int16_t, we would get -32768 itself. Instead, we want to get 32767.
249  *
250  ******************************************************************************/
251 
252 static inline int16_t FFTLIB_UTIL_negate(int16_t a)
253 {
254  int16_t result;
255 
256  result = (a == -32768) ? 32767 : -a;
257  return result;
258 }
259 
260 static inline int32_t FFTLIB_UTIL_negate(int32_t a)
261 {
262  int32_t result;
263 
264  result = (a == -2147483648) ? 2147483647 : -a;
265  return result;
266 }
267 
268 /*******************************************************************************
269  *
270  * Inline multiply with higher bit-width output type
271  *
272  ******************************************************************************/
273 
274 static inline int32_t FFTLIB_UTIL_mult(int8_t a, int8_t b) { return (int16_t) a * (int16_t) b; }
275 
276 static inline int32_t FFTLIB_UTIL_mult(uint8_t a, int8_t b) { return (int16_t) a * (int16_t) b; }
277 
278 static inline int64_t FFTLIB_UTIL_mult(int16_t a, int16_t b) { return (int32_t) a * (int32_t) b; }
279 
280 static inline int64_t FFTLIB_UTIL_mult(uint16_t a, int16_t b) { return (int32_t) a * (int32_t) b; }
281 
282 static inline FFTLIB_int128_t FFTLIB_UTIL_mult(int32_t a, int32_t b)
283 {
284  FFTLIB_int128_t result(0, 0);
285 
286  result.lo = (int64_t) a * (int64_t) b;
287  // sign extend the product
288  result.hi =
289  (((uint64_t) result.lo & 0x8000000000000000ULL) != 0LL) ? (int64_t) 0xffffffffffffffffULL : (int64_t) 0ULL;
290 
291  return result;
292 }
293 
294 /*******************************************************************************
295  *
296  * Inline saturate with ReLU operation
297  *
298  ******************************************************************************/
299 
300 static inline void FFTLIB_UTIL_saturate_relu(int32_t x, int8_t *y)
301 {
302  if (x > 0x7F) {
303  *y = 0x7F;
304  }
305  else if (x < 0) {
306  *y = 0;
307  }
308  else {
309  *y = (int8_t) x;
310  }
311 
312  return;
313 }
314 
315 static inline void FFTLIB_UTIL_saturate_relu(int32_t x, uint8_t *y)
316 {
317  if (x > 0xFF) {
318  *y = 0xFF;
319  }
320  else if (x < 0) {
321  *y = 0;
322  }
323  else {
324  *y = (uint8_t) x;
325  }
326 
327  return;
328 }
329 
330 static inline void FFTLIB_UTIL_saturate_relu(uint32_t x, uint8_t *y)
331 {
332  if (x > 0xFF) {
333  *y = 0xFF;
334  }
335  else {
336  *y = (uint8_t) x;
337  }
338 
339  return;
340 }
341 
342 static inline void FFTLIB_UTIL_saturate_relu(int64_t x, int16_t *y)
343 {
344  if (x > 0x7FFF) {
345  *y = 0x7FFF;
346  }
347  else if (x < 0x0000) {
348  *y = 0x0000;
349  }
350  else {
351  *y = (int16_t) x;
352  }
353 
354  return;
355 }
356 
357 static inline void FFTLIB_UTIL_saturate_relu(int64_t x, uint16_t *y)
358 {
359  if (x > 0xFFFF) {
360  *y = 0xFFFF;
361  }
362  else if (x < 0x0000) {
363  *y = 0x0000;
364  }
365  else {
366  *y = (uint16_t) x;
367  }
368 
369  return;
370 }
371 
372 static inline void FFTLIB_UTIL_saturate_relu(uint64_t x, uint16_t *y)
373 {
374  if (x > 0xFFFF) {
375  *y = 0xFFFF;
376  }
377  else {
378  *y = (uint16_t) x;
379  }
380 
381  return;
382 }
383 
384 /*******************************************************************************
385  *
386  * Inline shift, round and ReLU operation
387  *
388  ******************************************************************************/
389 
390 template <typename dataType, typename returnType>
391 static inline returnType FFTLIB_UTIL_shiftRoundAndReLU(dataType inVal, uint8_t shift)
392 {
393  returnType result;
394 
395  if (shift == 0) {
396  // remove the rounding, which doesn't make sense with no shift but causes C code problems
397  FFTLIB_UTIL_saturate_relu(inVal, &result);
398  }
399  else {
400  // round and shift
401  // Method requires right shift of signed integers be an arithmetic shift, but right
402  // shift >> on signed integer types is implementation dependent on whether the shift is
403  // arithmetic or logical. There's no simple way in C to specify the shift type as arithmetic.
404  // Instead, we use the __shift_right intrinsic, which is defined to be arithmetic shift.
405  dataType temp;
406  temp = __shift_right(inVal, (shift - 1)) + 1;
407  temp = __shift_right(temp, 1);
408  FFTLIB_UTIL_saturate_relu(temp, &result);
409  }
410 
411  return result;
412 }
413 
414 template int8_t FFTLIB_UTIL_shiftRoundAndReLU<int32_t, int8_t>(int32_t inVal, uint8_t shift);
415 template int16_t FFTLIB_UTIL_shiftRoundAndReLU<int64_t, int16_t>(int64_t inVal, uint8_t shift);
416 // added for unsigned C matrix values inside MMA
417 // template uint8_t FFTLIB_UTIL_shiftRoundAndReLU<uint32_t, uint8_t> (uint32_t inVal, uint8_t shift);
418 // template uint16_t FFTLIB_UTIL_shiftRoundAndReLU<uint64_t, uint16_t> (uint64_t inVal, uint8_t shift);
419 
420 template <> inline uint8_t FFTLIB_UTIL_shiftRoundAndReLU<int32_t, uint8_t>(int32_t inVal, uint8_t shift)
421 {
422  uint8_t result;
423 
424  if (shift == 0) {
425  // remove the rounding, which doesn't make sense with no shift but causes C code problems
426  FFTLIB_UTIL_saturate_relu(inVal, &result);
427  }
428  else {
429  // round and shift
430  // Method requires right shift of signed integers be an arithmetic shift, but right
431  // shift >> on signed integer types is implementation dependent on whether the shift is
432  // arithmetic or logical. There's no simple way in C to specify the shift type as arithmetic.
433  // Instead, we use the __shift_right intrinsic, which is defined to be arithmetic shift.
434  int32_t temp;
435  temp = __shift_right(inVal, (shift - 1)) + 1;
436  temp = __shift_right(temp, 1);
437  FFTLIB_UTIL_saturate_relu(temp, &result);
438  }
439 
440  return result;
441 }
442 
443 template <> inline uint8_t FFTLIB_UTIL_shiftRoundAndReLU<uint32_t, uint8_t>(uint32_t inVal, uint8_t shift)
444 {
445  uint8_t result;
446 
447  if (shift == 0) {
448  // remove the rounding, which doesn't make sense with no shift but causes C code problems
449  FFTLIB_UTIL_saturate_relu(inVal, &result);
450  }
451  else {
452  uint32_t temp;
453  // Subtracting two unsigned values of the same size will result in an unsigned value.
454  // If the first operand is less than the second the result will be arithmetically in correct.
455  // But if the size of the unsigned types is less than that of an unsigned int, C/C++ will promote the types to
456  // signed int before subtracting resulting in an correct result. In either case,
457  // there is no indication of an error.
458  uint32_t shift32_t = (uint32_t) shift;
459  temp = (inVal >> (shift32_t - (uint32_t) 1)) + 1;
460  temp = temp >> 1;
461  FFTLIB_UTIL_saturate_relu(temp, &result);
462  }
463 
464  return result;
465 }
466 
467 template <> inline uint16_t FFTLIB_UTIL_shiftRoundAndReLU<int64_t, uint16_t>(int64_t inVal, uint8_t shift)
468 {
469  uint16_t result;
470 
471  if (shift == 0) {
472  // remove the rounding, which doesn't make sense with no shift but causes C code problems
473  FFTLIB_UTIL_saturate_relu(inVal, &result);
474  }
475  else {
476  // round and shift
477  // Method requires right shift of signed integers be an arithmetic shift, but right
478  // shift >> on signed integer types is implementation dependent on whether the shift is
479  // arithmetic or logical. There's no simple way in C to specify the shift type as arithmetic.
480  // Instead, we use the __shift_right intrinsic, which is defined to be arithmetic shift.
481  int64_t temp;
482  temp = __shift_right(inVal, (shift - 1)) + 1;
483  temp = __shift_right(temp, 1);
484  FFTLIB_UTIL_saturate_relu(temp, &result);
485  }
486 
487  return result;
488 }
489 
490 template <> inline uint16_t FFTLIB_UTIL_shiftRoundAndReLU<uint64_t, uint16_t>(uint64_t inVal, uint8_t shift)
491 {
492  uint16_t result;
493 
494  if (shift == 0) {
495  // remove the rounding, which doesn't make sense with no shift but causes C code problems
496  FFTLIB_UTIL_saturate_relu(inVal, &result);
497  }
498  else {
499  uint64_t temp;
500  uint32_t shift32_t = (uint32_t) shift;
501  temp = (inVal >> (shift32_t - (uint32_t) 1)) + 1;
502  temp = (temp >> 1);
503  FFTLIB_UTIL_saturate_relu(temp, &result);
504  }
505 
506  return result;
507 }
508 
509 /*******************************************************************************
510  *
511  * Inline saturate operation
512  *
513  ******************************************************************************/
514 
515 static inline int8_t FFTLIB_UTIL_saturate(int32_t x)
516 {
517  int8_t retVal;
518  if (x > 0x7F) {
519  retVal = 0x7F;
520  }
521  else if (x < -0x80) {
522  retVal = -0x80;
523  }
524  else {
525  retVal = (int8_t) x;
526  }
527  return retVal;
528 }
529 
530 static inline uint8_t FFTLIB_UTIL_saturate(uint32_t x)
531 {
532  uint8_t retVal;
533  if (x > 0xFF) {
534  retVal = 0xFF;
535  }
536  else {
537  retVal = (uint8_t) x;
538  }
539  return retVal;
540 }
541 
542 static inline int16_t FFTLIB_UTIL_saturate(int64_t x)
543 {
544  int16_t retVal;
545  if (x > 0x7FFF) {
546  retVal = 0x7FFF;
547  }
548  else if (x < -0x8000) {
549  retVal = -0x8000;
550  }
551  else {
552  retVal = (int16_t) x;
553  }
554  return retVal;
555 }
556 
557 static inline uint16_t FFTLIB_UTIL_saturate(uint64_t x)
558 {
559  uint16_t retVal;
560  if (x > 0xFFFF) {
561  retVal = 0xFFFF;
562  }
563  else {
564  retVal = (uint16_t) x;
565  }
566  return retVal;
567 }
568 
569 static inline int32_t FFTLIB_UTIL_saturate(int64_t xh, int64_t xl)
570 {
571  int32_t retVal;
572  // printf("%s: xh = %" PRIx64 ", xl = %" PRIx64 "\n", __FUNCTION__, xh, xl);
573  // if negative
574  if (((uint64_t) xh & 0x8000000000000000ULL) != 0LL) {
575  if (((~(uint64_t) xh & 0xFFFFFFFFFFFFFFFFULL) != 0LL) || ((~(uint64_t) xl & 0xFFFFFFFF80000000ULL) != 0LL)) {
576  retVal = ((int32_t) 0x80000000U);
577  }
578  else {
579  retVal = (int32_t) xl;
580  }
581  }
582  else if (((uint64_t) xl & 0xFFFFFFFF80000000ULL) != 0LL) {
583  //(xl > 0x000000007FFFFFFFLL){ // positive and saturated
584  retVal = ((int32_t) 0x7FFFFFFFU);
585  }
586  else {
587  retVal = (int32_t) xl;
588  }
589  return retVal;
590 }
591 
592 static inline int32_t FFTLIB_UTIL_saturate(FFTLIB_int128_t x) { return FFTLIB_UTIL_saturate(x.hi, x.lo); }
593 
594 /*******************************************************************************
595  *
596  * Inline shift and round operation
597  *
598  ******************************************************************************/
599 
600 template <typename dataType, typename returnType>
601 inline returnType FFTLIB_UTIL_shiftAndRound(dataType inVal, uint8_t shift)
602 {
603  returnType result;
604 
605  if (shift == 0) {
606  // remove the rounding, which doesn't make sense with no shift but causes C code problems
607  result = FFTLIB_UTIL_saturate(inVal);
608  }
609  else {
610  // round and shift
611  dataType temp;
612  temp = (__shift_right(inVal, (shift - 1)) + 1);
613  temp = __shift_right(temp, 1);
614  result = FFTLIB_UTIL_saturate(temp);
615  }
616 
617  return result;
618 }
619 
620 template int8_t FFTLIB_UTIL_shiftAndRound<int32_t, int8_t>(int32_t inVal, uint8_t shift);
621 template int16_t FFTLIB_UTIL_shiftAndRound<int64_t, int16_t>(int64_t inVal, uint8_t shift);
622 
623 template <> inline uint8_t FFTLIB_UTIL_shiftAndRound(uint32_t inVal, uint8_t shift)
624 {
625  uint8_t result;
626 
627  if (shift == 0) {
628  // remove the rounding, which doesn't make sense with no shift but causes C code problems
629  result = FFTLIB_UTIL_saturate(inVal);
630  }
631  else {
632  // round and shift
633  uint32_t temp;
634  uint32_t shift32_t = (uint32_t) shift;
635  temp = (inVal >> (shift32_t - (uint32_t) 1)) + 1;
636  temp = (temp >> 1);
637  result = FFTLIB_UTIL_saturate(temp);
638  }
639 
640  return result;
641 }
642 
643 template <> inline uint16_t FFTLIB_UTIL_shiftAndRound(uint64_t inVal, uint8_t shift)
644 {
645  uint16_t result;
646 
647  if (shift == 0) {
648  // remove the rounding, which doesn't make sense with no shift but causes C code problems
649  result = FFTLIB_UTIL_saturate(inVal);
650  }
651  else {
652  // round and shift
653  uint64_t temp;
654  uint32_t shift32_t = (uint32_t) shift;
655  temp = (inVal >> (shift32_t - (uint32_t) 1)) + 1;
656  temp = (temp >> 1);
657  result = FFTLIB_UTIL_saturate(temp);
658  }
659 
660  return result;
661 }
662 
663 // MISRA-C prohibits using >> on signed integers because it is implementation dependent on whether
664 // that shift is arithmetic or logical. However, for FFTLIB_int128_t, this code implements the shift in software
665 // and ensures that it is arithmetic. To avoid the MISRA-C violation, we use the function version of the shift
666 // rather than the >> operator.
667 template <> inline int32_t FFTLIB_UTIL_shiftAndRound<FFTLIB_int128_t, int32_t>(FFTLIB_int128_t inVal, uint8_t shift)
668 {
669  int32_t result;
670 
671  if (shift == 0) {
672  // remove the rounding, which doesn't make sense with no shift but causes C code problems
673  result = FFTLIB_UTIL_saturate(inVal);
674  }
675  else {
676  // round and shift
677  // result = FFTLIB_UTIL_saturate(((inVal >> ((uint8_t)(shift - 1))) + 1) >> 1);
678  FFTLIB_int128_t temp;
679  // temp = inVal >> (shift - 1)
680  FFTLIB_UTIL_shiftRight128((uint64_t *) &temp.hi, (uint64_t *) &temp.lo, inVal.hi, inVal.lo, (int32_t) (shift - 1),
681  1);
682  temp = temp + 1;
683  // temp = temp >> 1
684  FFTLIB_UTIL_shiftRight128((uint64_t *) &temp.hi, (uint64_t *) &temp.lo, temp.hi, temp.lo, 1, 1);
685  result = FFTLIB_UTIL_saturate(temp);
686  }
687 
688  return result;
689 }
690 
691 /*******************************************************************************
692  *
693  * Convert a double-precision floating point number to 16-bit integer
694  *
695  ******************************************************************************/
696 
697 template <typename returnType> static inline returnType FFTLIB_UTIL_typeConv_i64f_oxX(FFTLIB_D64 x)
698 {
699  int64_t xLocal, maxValue;
700  returnType returnValue;
701 
702  /* Set maxValue to the maximumum possible value for the returnType */
703 
704  // original code
705  // maxValue = (1 << (sizeof(returnType)*8-2)) - 1;
706  // maxValue += (1 << (sizeof(returnType)*8-2));
707  maxValue = ((int64_t) ((uint32_t) 1 << ((uint32_t) (sizeof(returnType) * 8 - 2)))) - 1;
708  maxValue += (int64_t) ((uint32_t) 1 << ((uint32_t) (sizeof(returnType) * 8 - 2)));
709 
710  xLocal = (int64_t) floor(0.5 + x); /* Explicit rounding to integer */
711  if (xLocal >= maxValue) {
712  returnValue = (returnType) maxValue;
713  }
714  else if (xLocal <= -maxValue - 1) {
715  returnValue = (returnType) (-maxValue - 1);
716  }
717  else {
718  returnValue = (returnType) xLocal;
719  }
720  return returnValue;
721 }
722 
723 template int16_t FFTLIB_UTIL_typeConv_i64f_oxX<int16_t>(FFTLIB_D64 x);
724 template int32_t FFTLIB_UTIL_typeConv_i64f_oxX<int32_t>(FFTLIB_D64 x);
725 
726 /*******************************************************************************
727  *
728  * Evaluate cos function, and apply appropriate scale factor
729  *
730  ******************************************************************************/
731 template <typename returnType> static returnType FFTLIB_UTIL_cos_i64f_oxX(FFTLIB_D64 x, FFTLIB_D64 scaleFactor)
732 {
733  return FFTLIB_UTIL_typeConv_i64f_oxX<returnType>(scaleFactor * cos(x));
734 }
735 
736 template int16_t FFTLIB_UTIL_cos_i64f_oxX<int16_t>(FFTLIB_D64 x, FFTLIB_D64 scaleFactor);
737 template int32_t FFTLIB_UTIL_cos_i64f_oxX<int32_t>(FFTLIB_D64 x, FFTLIB_D64 scaleFactor);
738 /*******************************************************************************
739  *
740  * Evaluate sin function, and apply appropriate scale factor
741  *
742  ******************************************************************************/
743 template <typename returnType> static inline returnType FFTLIB_UTIL_sin_i64f_oxX(FFTLIB_D64 x, FFTLIB_D64 scaleFactor)
744 {
745  return FFTLIB_UTIL_typeConv_i64f_oxX<returnType>(scaleFactor * sin(x));
746 }
747 
748 template int16_t FFTLIB_UTIL_sin_i64f_oxX<int16_t>(FFTLIB_D64 x, FFTLIB_D64 scaleFactor);
749 template int32_t FFTLIB_UTIL_sin_i64f_oxX<int32_t>(FFTLIB_D64 x, FFTLIB_D64 scaleFactor);
750 
751 #endif
752 
753 #endif
File to hold buffer parameter related info for FFTLIB.
File to hold common structure, enums, macros and functions for FFTLIB.
double FFTLIB_D64
Double precision floating point.
Definition: FFTLIB_types.h:168
uint64_t end_count
uint64_t overhead
static void FFTLIB_UTIL_mult(int64_t *ph, int64_t *pl, int64_t a, int64_t b)
uint64_t beg_count