Imported Upstream version 3.0
[debian/gnuradio] / gnuradio-core / src / lib / filter / gr_fir_ccc_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_ccc_simd.h>
27
28 #include <assert.h>
29 #include <malloc16.h>
30 #include <iostream>
31
32 using std::cerr;
33 using std::endl;
34
35 gr_fir_ccc_simd::gr_fir_ccc_simd ()
36   : gr_fir_ccc_generic ()
37 {
38   // cerr << "@@@ gr_fir_ccc_simd\n";
39
40   d_ccomplex_dotprod = 0;
41   
42   d_aligned_taps[0] = 0;
43   d_aligned_taps[1] = 0;
44   d_aligned_taps[2] = 0;
45   d_aligned_taps[3] = 0;
46 }
47
48 gr_fir_ccc_simd::gr_fir_ccc_simd (const std::vector<gr_complex> &new_taps)
49   : gr_fir_ccc_generic (new_taps)
50 {
51   // cerr << "@@@ gr_fir_ccc_simd\n";
52
53   d_ccomplex_dotprod = 0;
54   
55   d_aligned_taps[0] = 0;
56   d_aligned_taps[1] = 0;
57   d_aligned_taps[2] = 0;
58   d_aligned_taps[3] = 0;
59   set_taps (new_taps);
60 }
61
62 gr_fir_ccc_simd::~gr_fir_ccc_simd ()
63 {
64   free16Align (d_aligned_taps[0]);
65   free16Align (d_aligned_taps[1]);
66   free16Align (d_aligned_taps[2]);
67   free16Align (d_aligned_taps[3]);
68 }
69
70 void
71 gr_fir_ccc_simd::set_taps (const std::vector<gr_complex> &inew_taps)
72 {
73   gr_fir_ccc::set_taps (inew_taps);     // call superclass
74
75   const std::vector<gr_complex> new_taps = gr_reverse(inew_taps);
76   unsigned len = new_taps.size ();
77
78   // Make 4 copies of the coefficients, one for each data alignment
79   // Note use of special 16-byte-aligned version of calloc()
80   
81   for (unsigned i = 0; i < 4; i++){
82     free16Align (d_aligned_taps[i]);    // free old value
83
84     // this works because the bit representation of a IEEE floating point
85     // +zero is all zeros.  If you're using a different representation,
86     // you'll need to explictly set the result to the appropriate 0.0 value.
87     
88     d_aligned_taps[i] = (float *) calloc16Align (1 + (len + i - 1) / 2,
89                                                2 * 4 * sizeof (float));
90     if (d_aligned_taps[i] == 0){
91       // throw something...
92       cerr << "@@@ gr_fir_ccc_simd d_aligned_taps[" << i << "] == 0\n";
93     }
94
95     for (unsigned j = 0; j < len; j++) {
96       d_aligned_taps[i][2*(j+i)] = new_taps[j].real();
97       d_aligned_taps[i][2*(j+i)+1] = new_taps[j].imag();
98     }
99   }
100 }
101
102 gr_complex 
103 gr_fir_ccc_simd::filter (const gr_complex input[])
104 {
105   if (ntaps () == 0)
106     return 0.0;
107
108
109   // Round input data address down to 16 byte boundary
110   // NB: depending on the alignment of input[], memory
111   // before input[] will be accessed. The contents don't matter since 
112   // they'll be multiplied by zero coefficients. I can't conceive of any
113   // situation where this could cause a segfault since memory protection
114   // in the x86 machines is done on much larger boundaries.
115   
116   const gr_complex *ar = (gr_complex *)((unsigned long) input & ~15);
117
118   // Choose one of 4 sets of pre-shifted coefficients. al is both the
119   // index into d_aligned_taps[] and the number of 0 words padded onto
120   // that coefficients array for alignment purposes.
121
122   unsigned al = input - ar;
123
124   // call assembler routine to do the work, passing number of 2x4-float blocks.
125
126   // assert (((unsigned long) ar & 15) == 0);
127   // assert (((unsigned long) d_aligned_taps[al] & 15) == 0);
128
129   // cerr << "ar: " << ar << " d_aligned_taps[ar]: " << d_aligned_taps[al]
130   //  << " (ntaps() + al - 1)/2 + 1: " << (ntaps() + al -1) / 2 + 1 << endl;
131
132   float result[2];
133
134   d_ccomplex_dotprod ((float*)ar, d_aligned_taps[al], (ntaps() + al - 1) / 2 + 1, result);
135
136   // cerr << "result = " << result[0] << " " << result[1] << endl;
137
138   return gr_complex(result[0], result[1]);
139 }