Imported Upstream version 3.0
[debian/gnuradio] / gnuradio-core / src / lib / filter / gr_fir_fsf_simd.cc
1 /* -*- c++ -*- */
2 /*
3  * Copyright 2002 Free Software Foundation, Inc.
4  * 
5  * This file is part of GNU Radio
6  * 
7  * GNU Radio is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2, or (at your option)
10  * any later version.
11  * 
12  * GNU Radio is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with GNU Radio; see the file COPYING.  If not, write to
19  * the Free Software Foundation, Inc., 51 Franklin Street,
20  * Boston, MA 02110-1301, USA.
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26 #include <gr_fir_fsf_simd.h>
27
28 #include <assert.h>
29 #include <malloc16.h>
30 #include <iostream>
31
32 using std::cerr;
33
34 gr_fir_fsf_simd::gr_fir_fsf_simd ()
35   : gr_fir_fsf_generic ()
36 {
37   // cerr << "@@@ gr_fir_fsf_simd\n";
38
39   d_float_dotprod = 0;
40   
41   d_aligned_taps[0] = 0;
42   d_aligned_taps[1] = 0;
43   d_aligned_taps[2] = 0;
44   d_aligned_taps[3] = 0;
45 }
46
47 gr_fir_fsf_simd::gr_fir_fsf_simd (const std::vector<float> &new_taps)
48   : gr_fir_fsf_generic (new_taps)
49 {
50   // cerr << "@@@ gr_fir_fsf_simd\n";
51
52   d_float_dotprod = 0;
53   
54   d_aligned_taps[0] = 0;
55   d_aligned_taps[1] = 0;
56   d_aligned_taps[2] = 0;
57   d_aligned_taps[3] = 0;
58   set_taps (new_taps);
59 }
60
61 gr_fir_fsf_simd::~gr_fir_fsf_simd ()
62 {
63   free16Align (d_aligned_taps[0]);
64   free16Align (d_aligned_taps[1]);
65   free16Align (d_aligned_taps[2]);
66   free16Align (d_aligned_taps[3]);
67 }
68
69 void
70 gr_fir_fsf_simd::set_taps (const std::vector<float> &inew_taps)
71 {
72   gr_fir_fsf::set_taps (inew_taps);     // call superclass
73   const std::vector<float> new_taps = gr_reverse(inew_taps);
74   unsigned len = new_taps.size ();
75
76   // Make 4 copies of the coefficients, one for each data alignment
77   // Note use of special 16-byte-aligned version of calloc()
78   
79   for (unsigned i = 0; i < 4; i++){
80     free16Align (d_aligned_taps[i]);    // free old value
81
82     // this works because the bit representation of a IEEE floating point
83     // +zero is all zeros.  If you're using a different representation,
84     // you'll need to explictly set the result to the appropriate 0.0 value.
85     
86     d_aligned_taps[i] = (float *) calloc16Align (1 + (len + i - 1) / 4,
87                                                4 * sizeof (float));
88     if (d_aligned_taps[i] == 0){
89       // throw something...
90       cerr << "@@@ gr_fir_fsf_simd d_aligned_taps[" << i << "] == 0\n";
91     }
92
93     for (unsigned j = 0; j < len; j++)
94       d_aligned_taps[i][j+i] = new_taps[j];
95   }
96 }
97
98 short 
99 gr_fir_fsf_simd::filter (const float input[])
100 {
101   if (ntaps () == 0)
102     return 0;
103
104
105   // Round input data address down to 16 byte boundary
106   // NB: depending on the alignment of input[], memory
107   // before input[] will be accessed. The contents don't matter since 
108   // they'll be multiplied by zero coefficients. I can't conceive of any
109   // situation where this could cause a segfault since memory protection
110   // in the x86 machines is done on much larger boundaries.
111   
112   const float *ar = (float *)((unsigned long) input & ~15);
113
114   // Choose one of 4 sets of pre-shifted coefficients. al is both the
115   // index into d_aligned_taps[] and the number of 0 words padded onto
116   // that coefficients array for alignment purposes.
117
118   unsigned al = input - ar;
119
120   // call assembler routine to do the work, passing number of 4-float blocks.
121
122   // assert (((unsigned long) ar & 15) == 0);
123   // assert (((unsigned long) d_aligned_taps[al] & 15) == 0);
124
125   // cerr << "ar: " << ar << " d_aligned_taps[ar]: " << d_aligned_taps[al]
126   // << " (ntaps() + al - 1)/4 + 1: " << (ntaps() + al -1) / 4 + 1 << endl;
127   
128   float r = d_float_dotprod (ar, d_aligned_taps[al], (ntaps() + al - 1) / 4 + 1);
129
130   // cerr << "result = " << r << endl;
131
132   return (short) r;     // FIXME? may want to saturate here
133 }