1 /*
2  * Copyright (c) 2012
3  *      MIPS Technologies, Inc., California.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the MIPS Technologies, Inc., nor the names of its
14  *    contributors may be used to endorse or promote products derived from
15  *    this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE MIPS TECHNOLOGIES, INC. ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE MIPS TECHNOLOGIES, INC. BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * Author:  Bojan Zivkovic (bojan@mips.com)
30  *
31  * IIR filter optimized for MIPS floating-point architecture
32  *
33  * This file is part of FFmpeg.
34  *
35  * FFmpeg is free software; you can redistribute it and/or
36  * modify it under the terms of the GNU Lesser General Public
37  * License as published by the Free Software Foundation; either
38  * version 2.1 of the License, or (at your option) any later version.
39  *
40  * FFmpeg is distributed in the hope that it will be useful,
41  * but WITHOUT ANY WARRANTY; without even the implied warranty of
42  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
43  * Lesser General Public License for more details.
44  *
45  * You should have received a copy of the GNU Lesser General Public
46  * License along with FFmpeg; if not, write to the Free Software
47  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
48  */
49 
50  /**
51  * @file
52  * Reference: libavcodec/iirfilter.c
53  */
54 
55 #include "config.h"
56 #include "libavcodec/iirfilter.h"
57 
58 #if HAVE_INLINE_ASM
59 #if !HAVE_MIPS32R6 && !HAVE_MIPS64R6
60 typedef struct FFIIRFilterCoeffs {
61     int   order;
62     float gain;
63     int   *cx;
64     float *cy;
65 } FFIIRFilterCoeffs;
66 
67 typedef struct FFIIRFilterState {
68     float x[1];
69 } FFIIRFilterState;
70 
iir_filter_flt_mips(const struct FFIIRFilterCoeffs * c,struct FFIIRFilterState * s,int size,const float * src,ptrdiff_t sstep,float * dst,ptrdiff_t dstep)71 static void iir_filter_flt_mips(const struct FFIIRFilterCoeffs *c,
72                                 struct FFIIRFilterState *s, int size,
73                                 const float *src, ptrdiff_t sstep, float *dst, ptrdiff_t dstep)
74 {
75     if (c->order == 2) {
76         int i;
77         const float *src0 = src;
78         float       *dst0 = dst;
79         for (i = 0; i < size; i++) {
80             float in = *src0 * c->gain  + s->x[0] * c->cy[0] + s->x[1] * c->cy[1];
81             *dst0 = s->x[0] + in + s->x[1] * c->cx[1];
82             s->x[0] = s->x[1];
83             s->x[1] = in;
84             src0 += sstep;
85             dst0 += dstep;
86         }
87     } else if (c->order == 4) {
88         int i;
89         const float *src0 = src;
90         float       *dst0 = dst;
91         float four = 4.0;
92         float six  = 6.0;
93         for (i = 0; i < size; i += 4) {
94             float in1, in2, in3, in4;
95             float res1, res2, res3, res4;
96             float *x  = s->x;
97             float *cy = c->cy;
98             float gain = c->gain;
99             float src0_0 = src0[0      ];
100             float src0_1 = src0[sstep  ];
101             float src0_2 = src0[2*sstep];
102             float src0_3 = src0[3*sstep];
103 
104             __asm__ volatile (
105                 "lwc1   $f0,        0(%[cy])                    \n\t"
106                 "lwc1   $f4,        0(%[x])                     \n\t"
107                 "lwc1   $f5,        4(%[x])                     \n\t"
108                 "lwc1   $f6,        8(%[x])                     \n\t"
109                 "lwc1   $f7,        12(%[x])                    \n\t"
110                 "mul.s  %[in1],     %[src0_0],  %[gain]         \n\t"
111                 "mul.s  %[in2],     %[src0_1],  %[gain]         \n\t"
112                 "mul.s  %[in3],     %[src0_2],  %[gain]         \n\t"
113                 "mul.s  %[in4],     %[src0_3],  %[gain]         \n\t"
114                 "lwc1   $f1,        4(%[cy])                    \n\t"
115                 "madd.s %[in1],     %[in1],     $f0,    $f4     \n\t"
116                 "madd.s %[in2],     %[in2],     $f0,    $f5     \n\t"
117                 "madd.s %[in3],     %[in3],     $f0,    $f6     \n\t"
118                 "madd.s %[in4],     %[in4],     $f0,    $f7     \n\t"
119                 "lwc1   $f2,        8(%[cy])                    \n\t"
120                 "madd.s %[in1],     %[in1],     $f1,    $f5     \n\t"
121                 "madd.s %[in2],     %[in2],     $f1,    $f6     \n\t"
122                 "madd.s %[in3],     %[in3],     $f1,    $f7     \n\t"
123                 "lwc1   $f3,        12(%[cy])                   \n\t"
124                 "add.s  $f8,        $f5,        $f7             \n\t"
125                 "madd.s %[in1],     %[in1],     $f2,    $f6     \n\t"
126                 "madd.s %[in2],     %[in2],     $f2,    $f7     \n\t"
127                 "mul.s  $f9,        $f6,        %[six]          \n\t"
128                 "mul.s  $f10,       $f7,        %[six]          \n\t"
129                 "madd.s %[in1],     %[in1],     $f3,    $f7     \n\t"
130                 "madd.s %[in2],     %[in2],     $f3,    %[in1]  \n\t"
131                 "madd.s %[in3],     %[in3],     $f2,    %[in1]  \n\t"
132                 "madd.s %[in4],     %[in4],     $f1,    %[in1]  \n\t"
133                 "add.s  %[res1],    $f4,        %[in1]          \n\t"
134                 "swc1   %[in1],     0(%[x])                     \n\t"
135                 "add.s  $f0,        $f6,        %[in1]          \n\t"
136                 "madd.s %[in3],     %[in3],     $f3,    %[in2]  \n\t"
137                 "madd.s %[in4],     %[in4],     $f2,    %[in2]  \n\t"
138                 "add.s  %[res2],    $f5,        %[in2]          \n\t"
139                 "madd.s %[res1],    %[res1],    $f8,    %[four] \n\t"
140                 "add.s  $f8,        $f7,        %[in2]          \n\t"
141                 "swc1   %[in2],     4(%[x])                     \n\t"
142                 "madd.s %[in4],     %[in4],     $f3,    %[in3]  \n\t"
143                 "add.s  %[res3],    $f6,        %[in3]          \n\t"
144                 "add.s  %[res1],    %[res1],    $f9             \n\t"
145                 "madd.s %[res2],    %[res2],    $f0,    %[four] \n\t"
146                 "swc1   %[in3],     8(%[x])                     \n\t"
147                 "add.s  %[res4],    $f7,        %[in4]          \n\t"
148                 "madd.s %[res3],    %[res3],    $f8,    %[four] \n\t"
149                 "swc1   %[in4],     12(%[x])                    \n\t"
150                 "add.s  %[res2],    %[res2],    $f10            \n\t"
151                 "add.s  $f8,        %[in1],     %[in3]          \n\t"
152                 "madd.s %[res3],    %[res3],    %[in1], %[six]  \n\t"
153                 "madd.s %[res4],    %[res4],    $f8,    %[four] \n\t"
154                 "madd.s %[res4],    %[res4],    %[in2], %[six]  \n\t"
155 
156                 : [in1]"=&f"(in1), [in2]"=&f"(in2),
157                   [in3]"=&f"(in3), [in4]"=&f"(in4),
158                   [res1]"=&f"(res1), [res2]"=&f"(res2),
159                   [res3]"=&f"(res3), [res4]"=&f"(res4)
160                 : [src0_0]"f"(src0_0), [src0_1]"f"(src0_1),
161                   [src0_2]"f"(src0_2), [src0_3]"f"(src0_3),
162                   [gain]"f"(gain), [x]"r"(x), [cy]"r"(cy),
163                   [four]"f"(four), [six]"f"(six)
164                 : "$f0", "$f1", "$f2", "$f3",
165                   "$f4", "$f5", "$f6", "$f7",
166                   "$f8", "$f9", "$f10",
167                   "memory"
168             );
169 
170             dst0[0      ] = res1;
171             dst0[sstep  ] = res2;
172             dst0[2*sstep] = res3;
173             dst0[3*sstep] = res4;
174 
175             src0 += 4*sstep;
176             dst0 += 4*dstep;
177         }
178     } else {
179         int i;
180         const float *src0 = src;
181         float       *dst0 = dst;
182         for (i = 0; i < size; i++) {
183             int j;
184             float in, res;
185             in = *src0 * c->gain;
186             for(j = 0; j < c->order; j++)
187                 in += c->cy[j] * s->x[j];
188             res = s->x[0] + in + s->x[c->order >> 1] * c->cx[c->order >> 1];
189             for(j = 1; j < c->order >> 1; j++)
190                 res += (s->x[j] + s->x[c->order - j]) * c->cx[j];
191             for(j = 0; j < c->order - 1; j++)
192                 s->x[j] = s->x[j + 1];
193             *dst0 = res;
194             s->x[c->order - 1] = in;
195             src0 += sstep;
196             dst0 += dstep;
197         }
198     }
199 }
200 #endif /* !HAVE_MIPS32R6 && !HAVE_MIPS64R6 */
201 #endif /* HAVE_INLINE_ASM */
202 
ff_iir_filter_init_mips(FFIIRFilterContext * f)203 void ff_iir_filter_init_mips(FFIIRFilterContext *f) {
204 #if HAVE_INLINE_ASM
205 #if !HAVE_MIPS32R6 && !HAVE_MIPS64R6
206     f->filter_flt = iir_filter_flt_mips;
207 #endif /* !HAVE_MIPS32R6 && !HAVE_MIPS64R6 */
208 #endif /* HAVE_INLINE_ASM */
209 }
210