1/*
2 *  Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
3 *
4 *  Use of this source code is governed by a BSD-style license
5 *  that can be found in the LICENSE file in the root of the source
6 *  tree. An additional intellectual property rights grant can be found
7 *  in the file PATENTS.  All contributing project authors may
8 *  be found in the AUTHORS file in the root of the source tree.
9 */
10
11
12#include "webrtc/common_audio/signal_processing/complex_fft_tables.h"
13#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
14
15#define CFFTSFT 14
16#define CFFTRND 1
17#define CFFTRND2 16384
18
19#define CIFFTSFT 14
20#define CIFFTRND 1
21
22int WebRtcSpl_ComplexFFT(int16_t frfi[], int stages, int mode) {
23  int i = 0;
24  int l = 0;
25  int k = 0;
26  int istep = 0;
27  int n = 0;
28  int m = 0;
29  int32_t wr = 0, wi = 0;
30  int32_t tmp1 = 0;
31  int32_t tmp2 = 0;
32  int32_t tmp3 = 0;
33  int32_t tmp4 = 0;
34  int32_t tmp5 = 0;
35  int32_t tmp6 = 0;
36  int32_t tmp = 0;
37  int16_t* ptr_j = NULL;
38  int16_t* ptr_i = NULL;
39
40  n = 1 << stages;
41  if (n > 1024) {
42    return -1;
43  }
44
45  __asm __volatile (
46    ".set push                                                         \n\t"
47    ".set noreorder                                                    \n\t"
48
49    "addiu      %[k],           $zero,            10                   \n\t"
50    "addiu      %[l],           $zero,            1                    \n\t"
51   "3:                                                                 \n\t"
52    "sll        %[istep],       %[l],             1                    \n\t"
53    "move       %[m],           $zero                                  \n\t"
54    "sll        %[tmp],         %[l],             2                    \n\t"
55    "move       %[i],           $zero                                  \n\t"
56   "2:                                                                 \n\t"
57#if defined(MIPS_DSP_R1_LE)
58    "sllv       %[tmp3],        %[m],             %[k]                 \n\t"
59    "addiu      %[tmp2],        %[tmp3],          512                  \n\t"
60    "addiu      %[m],           %[m],             1                    \n\t"
61    "lhx        %[wi],          %[tmp3](%[kSinTable1024])              \n\t"
62    "lhx        %[wr],          %[tmp2](%[kSinTable1024])              \n\t"
63#else  // #if defined(MIPS_DSP_R1_LE)
64    "sllv       %[tmp3],        %[m],             %[k]                 \n\t"
65    "addu       %[ptr_j],       %[tmp3],          %[kSinTable1024]     \n\t"
66    "addiu      %[ptr_i],       %[ptr_j],         512                  \n\t"
67    "addiu      %[m],           %[m],             1                    \n\t"
68    "lh         %[wi],          0(%[ptr_j])                            \n\t"
69    "lh         %[wr],          0(%[ptr_i])                            \n\t"
70#endif  // #if defined(MIPS_DSP_R1_LE)
71   "1:                                                                 \n\t"
72    "sll        %[tmp1],        %[i],             2                    \n\t"
73    "addu       %[ptr_i],       %[frfi],          %[tmp1]              \n\t"
74    "addu       %[ptr_j],       %[ptr_i],         %[tmp]               \n\t"
75    "lh         %[tmp6],        0(%[ptr_i])                            \n\t"
76    "lh         %[tmp5],        2(%[ptr_i])                            \n\t"
77    "lh         %[tmp3],        0(%[ptr_j])                            \n\t"
78    "lh         %[tmp4],        2(%[ptr_j])                            \n\t"
79    "addu       %[i],           %[i],             %[istep]             \n\t"
80#if defined(MIPS_DSP_R2_LE)
81    "mult       %[wr],          %[tmp3]                                \n\t"
82    "madd       %[wi],          %[tmp4]                                \n\t"
83    "mult       $ac1,           %[wr],            %[tmp4]              \n\t"
84    "msub       $ac1,           %[wi],            %[tmp3]              \n\t"
85    "mflo       %[tmp1]                                                \n\t"
86    "mflo       %[tmp2],        $ac1                                   \n\t"
87    "sll        %[tmp6],        %[tmp6],          14                   \n\t"
88    "sll        %[tmp5],        %[tmp5],          14                   \n\t"
89    "shra_r.w   %[tmp1],        %[tmp1],          1                    \n\t"
90    "shra_r.w   %[tmp2],        %[tmp2],          1                    \n\t"
91    "subu       %[tmp4],        %[tmp6],          %[tmp1]              \n\t"
92    "addu       %[tmp1],        %[tmp6],          %[tmp1]              \n\t"
93    "addu       %[tmp6],        %[tmp5],          %[tmp2]              \n\t"
94    "subu       %[tmp5],        %[tmp5],          %[tmp2]              \n\t"
95    "shra_r.w   %[tmp1],        %[tmp1],          15                   \n\t"
96    "shra_r.w   %[tmp6],        %[tmp6],          15                   \n\t"
97    "shra_r.w   %[tmp4],        %[tmp4],          15                   \n\t"
98    "shra_r.w   %[tmp5],        %[tmp5],          15                   \n\t"
99#else  // #if defined(MIPS_DSP_R2_LE)
100    "mul        %[tmp2],        %[wr],            %[tmp4]              \n\t"
101    "mul        %[tmp1],        %[wr],            %[tmp3]              \n\t"
102    "mul        %[tmp4],        %[wi],            %[tmp4]              \n\t"
103    "mul        %[tmp3],        %[wi],            %[tmp3]              \n\t"
104    "sll        %[tmp6],        %[tmp6],          14                   \n\t"
105    "sll        %[tmp5],        %[tmp5],          14                   \n\t"
106    "addiu      %[tmp6],        %[tmp6],          16384                \n\t"
107    "addiu      %[tmp5],        %[tmp5],          16384                \n\t"
108    "addu       %[tmp1],        %[tmp1],          %[tmp4]              \n\t"
109    "subu       %[tmp2],        %[tmp2],          %[tmp3]              \n\t"
110    "addiu      %[tmp1],        %[tmp1],          1                    \n\t"
111    "addiu      %[tmp2],        %[tmp2],          1                    \n\t"
112    "sra        %[tmp1],        %[tmp1],          1                    \n\t"
113    "sra        %[tmp2],        %[tmp2],          1                    \n\t"
114    "subu       %[tmp4],        %[tmp6],          %[tmp1]              \n\t"
115    "addu       %[tmp1],        %[tmp6],          %[tmp1]              \n\t"
116    "addu       %[tmp6],        %[tmp5],          %[tmp2]              \n\t"
117    "subu       %[tmp5],        %[tmp5],          %[tmp2]              \n\t"
118    "sra        %[tmp4],        %[tmp4],          15                   \n\t"
119    "sra        %[tmp1],        %[tmp1],          15                   \n\t"
120    "sra        %[tmp6],        %[tmp6],          15                   \n\t"
121    "sra        %[tmp5],        %[tmp5],          15                   \n\t"
122#endif  // #if defined(MIPS_DSP_R2_LE)
123    "sh         %[tmp1],        0(%[ptr_i])                            \n\t"
124    "sh         %[tmp6],        2(%[ptr_i])                            \n\t"
125    "sh         %[tmp4],        0(%[ptr_j])                            \n\t"
126    "blt        %[i],           %[n],             1b                   \n\t"
127    " sh        %[tmp5],        2(%[ptr_j])                            \n\t"
128    "blt        %[m],           %[l],             2b                   \n\t"
129    " addu      %[i],           $zero,            %[m]                 \n\t"
130    "move       %[l],           %[istep]                               \n\t"
131    "blt        %[l],           %[n],             3b                   \n\t"
132    " addiu     %[k],           %[k],             -1                   \n\t"
133
134    ".set pop                                                          \n\t"
135
136    : [tmp1] "=&r" (tmp1), [tmp2] "=&r" (tmp2), [tmp3] "=&r" (tmp3),
137      [tmp4] "=&r" (tmp4), [tmp5] "=&r" (tmp5), [tmp6] "=&r" (tmp6),
138      [ptr_i] "=&r" (ptr_i), [i] "=&r" (i), [wi] "=&r" (wi), [wr] "=&r" (wr),
139      [m] "=&r" (m), [istep] "=&r" (istep), [l] "=&r" (l), [k] "=&r" (k),
140      [ptr_j] "=&r" (ptr_j), [tmp] "=&r" (tmp)
141    : [n] "r" (n), [frfi] "r" (frfi), [kSinTable1024] "r" (kSinTable1024)
142    : "hi", "lo", "$ac1hi", "$ac1lo", "memory"
143  );
144
145  return 0;
146}
147
148int WebRtcSpl_ComplexIFFT(int16_t frfi[], int stages, int mode) {
149  int i = 0, l = 0, k = 0;
150  int istep = 0, n = 0, m = 0;
151  int scale = 0, shift = 0;
152  int32_t wr = 0, wi = 0;
153  int32_t tmp1 = 0, tmp2 = 0, tmp3 = 0, tmp4 = 0;
154  int32_t tmp5 = 0, tmp6 = 0, tmp = 0, tempMax = 0, round2 = 0;
155  int16_t* ptr_j = NULL;
156  int16_t* ptr_i = NULL;
157
158  n = 1 << stages;
159  if (n > 1024) {
160    return -1;
161  }
162
163  __asm __volatile (
164    ".set push                                                         \n\t"
165    ".set noreorder                                                    \n\t"
166
167    "addiu      %[k],           $zero,            10                   \n\t"
168    "addiu      %[l],           $zero,            1                    \n\t"
169    "move       %[scale],       $zero                                  \n\t"
170   "3:                                                                 \n\t"
171    "addiu      %[shift],       $zero,            14                   \n\t"
172    "addiu      %[round2],      $zero,            8192                 \n\t"
173    "move       %[ptr_i],       %[frfi]                                \n\t"
174    "move       %[tempMax],     $zero                                  \n\t"
175    "addu       %[i],           %[n],             %[n]                 \n\t"
176   "5:                                                                 \n\t"
177    "lh         %[tmp1],        0(%[ptr_i])                            \n\t"
178    "lh         %[tmp2],        2(%[ptr_i])                            \n\t"
179    "lh         %[tmp3],        4(%[ptr_i])                            \n\t"
180    "lh         %[tmp4],        6(%[ptr_i])                            \n\t"
181#if defined(MIPS_DSP_R1_LE)
182    "absq_s.w   %[tmp1],        %[tmp1]                                \n\t"
183    "absq_s.w   %[tmp2],        %[tmp2]                                \n\t"
184    "absq_s.w   %[tmp3],        %[tmp3]                                \n\t"
185    "absq_s.w   %[tmp4],        %[tmp4]                                \n\t"
186#else  // #if defined(MIPS_DSP_R1_LE)
187    "slt        %[tmp5],        %[tmp1],          $zero                \n\t"
188    "subu       %[tmp6],        $zero,            %[tmp1]              \n\t"
189    "movn       %[tmp1],        %[tmp6],          %[tmp5]              \n\t"
190    "slt        %[tmp5],        %[tmp2],          $zero                \n\t"
191    "subu       %[tmp6],        $zero,            %[tmp2]              \n\t"
192    "movn       %[tmp2],        %[tmp6],          %[tmp5]              \n\t"
193    "slt        %[tmp5],        %[tmp3],          $zero                \n\t"
194    "subu       %[tmp6],        $zero,            %[tmp3]              \n\t"
195    "movn       %[tmp3],        %[tmp6],          %[tmp5]              \n\t"
196    "slt        %[tmp5],        %[tmp4],          $zero                \n\t"
197    "subu       %[tmp6],        $zero,            %[tmp4]              \n\t"
198    "movn       %[tmp4],        %[tmp6],          %[tmp5]              \n\t"
199#endif  // #if defined(MIPS_DSP_R1_LE)
200    "slt        %[tmp5],        %[tempMax],       %[tmp1]              \n\t"
201    "movn       %[tempMax],     %[tmp1],          %[tmp5]              \n\t"
202    "addiu      %[i],           %[i],             -4                   \n\t"
203    "slt        %[tmp5],        %[tempMax],       %[tmp2]              \n\t"
204    "movn       %[tempMax],     %[tmp2],          %[tmp5]              \n\t"
205    "slt        %[tmp5],        %[tempMax],       %[tmp3]              \n\t"
206    "movn       %[tempMax],     %[tmp3],          %[tmp5]              \n\t"
207    "slt        %[tmp5],        %[tempMax],       %[tmp4]              \n\t"
208    "movn       %[tempMax],     %[tmp4],          %[tmp5]              \n\t"
209    "bgtz       %[i],                             5b                   \n\t"
210    " addiu     %[ptr_i],       %[ptr_i],         8                    \n\t"
211    "addiu      %[tmp1],        $zero,            13573                \n\t"
212    "addiu      %[tmp2],        $zero,            27146                \n\t"
213#if !defined(MIPS32_R2_LE)
214    "sll        %[tempMax],     %[tempMax],       16                   \n\t"
215    "sra        %[tempMax],     %[tempMax],       16                   \n\t"
216#else  // #if !defined(MIPS32_R2_LE)
217    "seh        %[tempMax]                                             \n\t"
218#endif  // #if !defined(MIPS32_R2_LE)
219    "slt        %[tmp1],        %[tmp1],          %[tempMax]           \n\t"
220    "slt        %[tmp2],        %[tmp2],          %[tempMax]           \n\t"
221    "addu       %[tmp1],        %[tmp1],          %[tmp2]              \n\t"
222    "addu       %[shift],       %[shift],         %[tmp1]              \n\t"
223    "addu       %[scale],       %[scale],         %[tmp1]              \n\t"
224    "sllv       %[round2],      %[round2],        %[tmp1]              \n\t"
225    "sll        %[istep],       %[l],             1                    \n\t"
226    "move       %[m],           $zero                                  \n\t"
227    "sll        %[tmp],         %[l],             2                    \n\t"
228   "2:                                                                 \n\t"
229#if defined(MIPS_DSP_R1_LE)
230    "sllv       %[tmp3],        %[m],             %[k]                 \n\t"
231    "addiu      %[tmp2],        %[tmp3],          512                  \n\t"
232    "addiu      %[m],           %[m],             1                    \n\t"
233    "lhx        %[wi],          %[tmp3](%[kSinTable1024])              \n\t"
234    "lhx        %[wr],          %[tmp2](%[kSinTable1024])              \n\t"
235#else  // #if defined(MIPS_DSP_R1_LE)
236    "sllv       %[tmp3],        %[m],             %[k]                 \n\t"
237    "addu       %[ptr_j],       %[tmp3],          %[kSinTable1024]     \n\t"
238    "addiu      %[ptr_i],       %[ptr_j],         512                  \n\t"
239    "addiu      %[m],           %[m],             1                    \n\t"
240    "lh         %[wi],          0(%[ptr_j])                            \n\t"
241    "lh         %[wr],          0(%[ptr_i])                            \n\t"
242#endif  // #if defined(MIPS_DSP_R1_LE)
243   "1:                                                                 \n\t"
244    "sll        %[tmp1],        %[i],             2                    \n\t"
245    "addu       %[ptr_i],       %[frfi],          %[tmp1]              \n\t"
246    "addu       %[ptr_j],       %[ptr_i],         %[tmp]               \n\t"
247    "lh         %[tmp3],        0(%[ptr_j])                            \n\t"
248    "lh         %[tmp4],        2(%[ptr_j])                            \n\t"
249    "lh         %[tmp6],        0(%[ptr_i])                            \n\t"
250    "lh         %[tmp5],        2(%[ptr_i])                            \n\t"
251    "addu       %[i],           %[i],             %[istep]             \n\t"
252#if defined(MIPS_DSP_R2_LE)
253    "mult       %[wr],          %[tmp3]                                \n\t"
254    "msub       %[wi],          %[tmp4]                                \n\t"
255    "mult       $ac1,           %[wr],            %[tmp4]              \n\t"
256    "madd       $ac1,           %[wi],            %[tmp3]              \n\t"
257    "mflo       %[tmp1]                                                \n\t"
258    "mflo       %[tmp2],        $ac1                                   \n\t"
259    "sll        %[tmp6],        %[tmp6],          14                   \n\t"
260    "sll        %[tmp5],        %[tmp5],          14                   \n\t"
261    "shra_r.w   %[tmp1],        %[tmp1],          1                    \n\t"
262    "shra_r.w   %[tmp2],        %[tmp2],          1                    \n\t"
263    "addu       %[tmp6],        %[tmp6],          %[round2]            \n\t"
264    "addu       %[tmp5],        %[tmp5],          %[round2]            \n\t"
265    "subu       %[tmp4],        %[tmp6],          %[tmp1]              \n\t"
266    "addu       %[tmp1],        %[tmp6],          %[tmp1]              \n\t"
267    "addu       %[tmp6],        %[tmp5],          %[tmp2]              \n\t"
268    "subu       %[tmp5],        %[tmp5],          %[tmp2]              \n\t"
269    "srav       %[tmp4],        %[tmp4],          %[shift]             \n\t"
270    "srav       %[tmp1],        %[tmp1],          %[shift]             \n\t"
271    "srav       %[tmp6],        %[tmp6],          %[shift]             \n\t"
272    "srav       %[tmp5],        %[tmp5],          %[shift]             \n\t"
273#else  // #if defined(MIPS_DSP_R2_LE)
274    "mul        %[tmp1],        %[wr],            %[tmp3]              \n\t"
275    "mul        %[tmp2],        %[wr],            %[tmp4]              \n\t"
276    "mul        %[tmp4],        %[wi],            %[tmp4]              \n\t"
277    "mul        %[tmp3],        %[wi],            %[tmp3]              \n\t"
278    "sll        %[tmp6],        %[tmp6],          14                   \n\t"
279    "sll        %[tmp5],        %[tmp5],          14                   \n\t"
280    "sub        %[tmp1],        %[tmp1],          %[tmp4]              \n\t"
281    "addu       %[tmp2],        %[tmp2],          %[tmp3]              \n\t"
282    "addiu      %[tmp1],        %[tmp1],          1                    \n\t"
283    "addiu      %[tmp2],        %[tmp2],          1                    \n\t"
284    "sra        %[tmp2],        %[tmp2],          1                    \n\t"
285    "sra        %[tmp1],        %[tmp1],          1                    \n\t"
286    "addu       %[tmp6],        %[tmp6],          %[round2]            \n\t"
287    "addu       %[tmp5],        %[tmp5],          %[round2]            \n\t"
288    "subu       %[tmp4],        %[tmp6],          %[tmp1]              \n\t"
289    "addu       %[tmp1],        %[tmp6],          %[tmp1]              \n\t"
290    "addu       %[tmp6],        %[tmp5],          %[tmp2]              \n\t"
291    "subu       %[tmp5],        %[tmp5],          %[tmp2]              \n\t"
292    "sra        %[tmp4],        %[tmp4],          %[shift]             \n\t"
293    "sra        %[tmp1],        %[tmp1],          %[shift]             \n\t"
294    "sra        %[tmp6],        %[tmp6],          %[shift]             \n\t"
295    "sra        %[tmp5],        %[tmp5],          %[shift]             \n\t"
296#endif  // #if defined(MIPS_DSP_R2_LE)
297    "sh         %[tmp1],         0(%[ptr_i])                           \n\t"
298    "sh         %[tmp6],         2(%[ptr_i])                           \n\t"
299    "sh         %[tmp4],         0(%[ptr_j])                           \n\t"
300    "blt        %[i],            %[n],            1b                   \n\t"
301    " sh        %[tmp5],         2(%[ptr_j])                           \n\t"
302    "blt        %[m],            %[l],            2b                   \n\t"
303    " addu      %[i],            $zero,           %[m]                 \n\t"
304    "move       %[l],            %[istep]                              \n\t"
305    "blt        %[l],            %[n],            3b                   \n\t"
306    " addiu     %[k],            %[k],            -1                   \n\t"
307
308    ".set pop                                                          \n\t"
309
310    : [tmp1] "=&r" (tmp1), [tmp2] "=&r" (tmp2), [tmp3] "=&r" (tmp3),
311      [tmp4] "=&r" (tmp4), [tmp5] "=&r" (tmp5), [tmp6] "=&r" (tmp6),
312      [ptr_i] "=&r" (ptr_i), [i] "=&r" (i), [m] "=&r" (m), [tmp] "=&r" (tmp),
313      [istep] "=&r" (istep), [wi] "=&r" (wi), [wr] "=&r" (wr), [l] "=&r" (l),
314      [k] "=&r" (k), [round2] "=&r" (round2), [ptr_j] "=&r" (ptr_j),
315      [shift] "=&r" (shift), [scale] "=&r" (scale), [tempMax] "=&r" (tempMax)
316    : [n] "r" (n), [frfi] "r" (frfi), [kSinTable1024] "r" (kSinTable1024)
317    : "hi", "lo", "$ac1hi", "$ac1lo", "memory"
318  );
319
320  return scale;
321
322}
323