Merge pull request #49 from swolfe0105/non-x86-support

non-x86 support: Only use SSE2 when supported
This commit is contained in:
Bastian Bloessl
2016-11-11 13:55:34 +01:00
committed by GitHub
11 changed files with 713 additions and 119 deletions
-1
View File
@@ -37,7 +37,6 @@ if(NOT WIN32)
#http://gcc.gnu.org/wiki/Visibility #http://gcc.gnu.org/wiki/Visibility
add_definitions(-fvisibility=hidden) add_definitions(-fvisibility=hidden)
add_definitions(-std=c++0x) add_definitions(-std=c++0x)
add_definitions(-msse2)
endif() endif()
######################################################################## ########################################################################
+21 -1
View File
@@ -85,6 +85,15 @@ endmacro(expand_cc_h_impl)
######################################################################## ########################################################################
# Invoke macro to generate various sources # Invoke macro to generate various sources
######################################################################## ########################################################################
include (CheckCCompilerFlag)
CHECK_C_COMPILER_FLAG ("-msse2" SSE2_SUPPORTED)
if(SSE2_SUPPORTED)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -msse2")
add_definitions(-DIEEE80211_MSSE2)
endif(SSE2_SUPPORTED)
expand_cc_h_impl(moving_average_XX cc ff) expand_cc_h_impl(moving_average_XX cc ff)
add_custom_target(ieee802_11_generated_sources DEPENDS ${generated_sources}) add_custom_target(ieee802_11_generated_sources DEPENDS ${generated_sources})
add_dependencies(ieee802_11_generated_sources ieee802_11_generated_includes) add_dependencies(ieee802_11_generated_sources ieee802_11_generated_includes)
@@ -111,9 +120,20 @@ list(APPEND gr_ieee802_11_sources
sync_long.cc sync_long.cc
sync_short.cc sync_short.cc
utils.cc utils.cc
viterbi_decoder.cc viterbi_decoder/base.cc
) )
# use SSE2 optimized viterbi implementation if SSE2 is enabled
if(SSE2_SUPPORTED)
list(APPEND gr_ieee802_11_sources
viterbi_decoder/viterbi_decoder_x86.cc
)
else()
list(APPEND gr_ieee802_11_sources
viterbi_decoder/viterbi_decoder_generic.cc
)
endif(SSE2_SUPPORTED)
list(APPEND gr_ieee802_11_libs list(APPEND gr_ieee802_11_libs
${Boost_LIBRARIES} ${Boost_LIBRARIES}
${GNURADIO_ALL_LIBRARIES} ${GNURADIO_ALL_LIBRARIES}
+1 -1
View File
@@ -17,7 +17,7 @@
#include <ieee802-11/decode_mac.h> #include <ieee802-11/decode_mac.h>
#include "utils.h" #include "utils.h"
#include "viterbi_decoder.h" #include "viterbi_decoder/viterbi_decoder.h"
#include <boost/crc.hpp> #include <boost/crc.hpp>
#include <gnuradio/io_signature.h> #include <gnuradio/io_signature.h>
+1 -1
View File
@@ -21,7 +21,7 @@
#include <ieee802-11/frame_equalizer.h> #include <ieee802-11/frame_equalizer.h>
#include <ieee802-11/constellations.h> #include <ieee802-11/constellations.h>
#include "equalizer/base.h" #include "equalizer/base.h"
#include "viterbi_decoder.h" #include "viterbi_decoder/viterbi_decoder.h"
namespace gr { namespace gr {
namespace ieee802_11 { namespace ieee802_11 {
+105
View File
@@ -0,0 +1,105 @@
/*
* Copyright (C) 2016 Bastian Bloessl <bloessl@ccs-labs.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "base.h"
#include <cstring>
#include <iostream>
using namespace gr::ieee802_11;
base::base() :
d_store_pos(0) {
}
base::~base() {
}
uint8_t*
base::depuncture(uint8_t *in) {
int count;
int n_cbps = d_ofdm->n_cbps;
uint8_t *depunctured;
if (d_ntraceback == 5) {
count = d_frame->n_sym * n_cbps;
depunctured = in;
} else {
depunctured = d_depunctured;
count = 0;
for(int i = 0; i < d_frame->n_sym; i++) {
for(int k = 0; k < n_cbps; k++) {
while (d_depuncture_pattern[count % (2 * d_k)] == 0) {
depunctured[count] = 2;
count++;
}
// Insert received bits
depunctured[count] = in[i * n_cbps + k];
count++;
while (d_depuncture_pattern[count % (2 * d_k)] == 0) {
depunctured[count] = 2;
count++;
}
}
}
}
return depunctured;
}
/* Parity lookup table */
const unsigned char base::PARTAB[256] = {
0, 1, 1, 0, 1, 0, 0, 1,
1, 0, 0, 1, 0, 1, 1, 0,
1, 0, 0, 1, 0, 1, 1, 0,
0, 1, 1, 0, 1, 0, 0, 1,
1, 0, 0, 1, 0, 1, 1, 0,
0, 1, 1, 0, 1, 0, 0, 1,
0, 1, 1, 0, 1, 0, 0, 1,
1, 0, 0, 1, 0, 1, 1, 0,
1, 0, 0, 1, 0, 1, 1, 0,
0, 1, 1, 0, 1, 0, 0, 1,
0, 1, 1, 0, 1, 0, 0, 1,
1, 0, 0, 1, 0, 1, 1, 0,
0, 1, 1, 0, 1, 0, 0, 1,
1, 0, 0, 1, 0, 1, 1, 0,
1, 0, 0, 1, 0, 1, 1, 0,
0, 1, 1, 0, 1, 0, 0, 1,
1, 0, 0, 1, 0, 1, 1, 0,
0, 1, 1, 0, 1, 0, 0, 1,
0, 1, 1, 0, 1, 0, 0, 1,
1, 0, 0, 1, 0, 1, 1, 0,
0, 1, 1, 0, 1, 0, 0, 1,
1, 0, 0, 1, 0, 1, 1, 0,
1, 0, 0, 1, 0, 1, 1, 0,
0, 1, 1, 0, 1, 0, 0, 1,
0, 1, 1, 0, 1, 0, 0, 1,
1, 0, 0, 1, 0, 1, 1, 0,
1, 0, 0, 1, 0, 1, 1, 0,
0, 1, 1, 0, 1, 0, 0, 1,
1, 0, 0, 1, 0, 1, 1, 0,
0, 1, 1, 0, 1, 0, 0, 1,
0, 1, 1, 0, 1, 0, 0, 1,
1, 0, 0, 1, 0, 1, 1, 0,
};
const unsigned char base::PUNCTURE_1_2[2] = {1, 1};
const unsigned char base::PUNCTURE_2_3[4] = {1, 1, 1, 0};
const unsigned char base::PUNCTURE_3_4[6] = {1, 1, 1, 0, 0, 1};
@@ -14,10 +14,9 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef INCLUDED_IEEE802_11_VITERBI_DECODER_H #ifndef INCLUDED_IEEE802_11_VITERBI_DECODER_BASE_H
#define INCLUDED_IEEE802_11_VITERBI_DECODER_H #define INCLUDED_IEEE802_11_VITERBI_DECODER_BASE_H
#include <xmmintrin.h>
#include "utils.h" #include "utils.h"
namespace gr { namespace gr {
@@ -31,17 +30,15 @@ namespace ieee802_11 {
* created by Phil Karn. The SSE2 version was made by Bogdan * created by Phil Karn. The SSE2 version was made by Bogdan
* Diaconescu. For more info see: gr-dvbt/lib/d_viterbi.h * Diaconescu. For more info see: gr-dvbt/lib/d_viterbi.h
*/ */
class viterbi_decoder class base
{ {
public: public:
viterbi_decoder(); base();
virtual ~viterbi_decoder(); ~base();
virtual uint8_t* decode(ofdm_param *ofdm, frame_param *frame, uint8_t *in) = 0;
uint8_t* decode(ofdm_param *ofdm, frame_param *frame, uint8_t *in);
private:
protected:
// Position in circular buffer where the current decoded byte is stored // Position in circular buffer where the current decoded byte is stored
int d_store_pos; int d_store_pos;
// Metrics for each state // Metrics for each state
@@ -49,17 +46,6 @@ private:
// Paths for each state // Paths for each state
unsigned char d_ppresult[TRACEBACK_MAX][64] __attribute__((aligned(16))); unsigned char d_ppresult[TRACEBACK_MAX][64] __attribute__((aligned(16)));
union branchtab27 {
unsigned char c[32];
__m128i v[2];
} d_branchtab27_sse2[2];
__m128i d_metric0[4] __attribute__ ((aligned(16)));
__m128i d_metric1[4] __attribute__ ((aligned(16)));
__m128i d_path0[4] __attribute__ ((aligned(16)));
__m128i d_path1[4] __attribute__ ((aligned(16)));
int d_ntraceback; int d_ntraceback;
int d_k; int d_k;
ofdm_param *d_ofdm; ofdm_param *d_ofdm;
@@ -74,16 +60,11 @@ private:
static const unsigned char PUNCTURE_2_3[4]; static const unsigned char PUNCTURE_2_3[4];
static const unsigned char PUNCTURE_3_4[6]; static const unsigned char PUNCTURE_3_4[6];
void reset(); virtual void reset() = 0;
uint8_t* depuncture(uint8_t *in); uint8_t* depuncture(uint8_t *in);
void viterbi_chunks_init_sse2();
void viterbi_butterfly2_sse2(unsigned char *symbols,
__m128i m0[], __m128i m1[], __m128i p0[], __m128i p1[]);
unsigned char viterbi_get_output_sse2(__m128i *mm0,
__m128i *pp0, int ntraceback, unsigned char *outbuf);
}; };
} // namespace ieee802_11 } // namespace ieee802_11
} // namespace gr } // namespace gr
#endif /* INCLUDED_IEEE802_11_VITERBI_DECODER_H */ #endif /* INCLUDED_IEEE802_11_VITERBI_DECODER_BASE_H */
+26
View File
@@ -0,0 +1,26 @@
/*
* Copyright (C) 2016 Bastian Bloessl <bloessl@ccs-labs.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef INCLUDED_IEEE802_11_VITERBI_DECODER_H
#define INCLUDED_IEEE802_11_VITERBI_DECODER_H
#ifdef IEEE80211_MSSE2
#include "viterbi_decoder_x86.h"
#else
#include "viterbi_decoder_generic.h"
#endif
#endif /* INCLUDED_IEEE802_11_VITERBI_DECODER_H */
@@ -0,0 +1,426 @@
/*
* Copyright 1995 Phil Karn, KA9Q
* Copyright 2008 Free Software Foundation, Inc.
* 2014 Added SSE2 implementation Bogdan Diaconescu
*
* This file is part of GNU Radio
*
* GNU Radio is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* GNU Radio is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Radio; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
/*
* Viterbi decoder for K=7 rate=1/2 convolutional code
* Some modifications from original Karn code by Matt Ettus
* Major modifications by adding SSE2 code by Bogdan Diaconescu
*/
#include "viterbi_decoder_generic.h"
#include <cstring>
#include <iostream>
/* The basic Viterbi decoder operation, called a "butterfly"
* operation because of the way it looks on a trellis diagram. Each
* butterfly involves an Add-Compare-Select (ACS) operation on the two nodes
* where the 0 and 1 paths from the current node merge at the next step of
* the trellis.
*
* The code polynomials are assumed to have 1's on both ends. Given a
* function encode_state() that returns the two symbols for a given
* encoder state in the low two bits, such a code will have the following
* identities for even 'n' < 64:
*
* encode_state(n) = encode_state(n+65)
* encode_state(n+1) = encode_state(n+64) = (3 ^ encode_state(n))
*
* Any convolutional code you would actually want to use will have
* these properties, so these assumptions aren't too limiting.
*
* Doing this as a macro lets the compiler evaluate at compile time the
* many expressions that depend on the loop index and encoder state and
* emit them as immediate arguments.
* This makes an enormous difference on register-starved machines such
* as the Intel x86 family where evaluating these expressions at runtime
* would spill over into memory.
*/
#define BUTTERFLY(i,sym) { \
int m0,m1,m2,m3; \
/* ACS for 0 branch */ \
m0 = state[i].metric + mets[sym]; /* 2*i */ \
m1 = state[i+32].metric + mets[3 ^ sym]; /* 2*i + 64 */ \
if(m0 > m1){ \
next[2*i].metric = m0; \
next[2*i].path = state[i].path << 1; \
} else { \
next[2*i].metric = m1; \
next[2*i].path = (state[i+32].path << 1)|1; \
} \
/* ACS for 1 branch */ \
m2 = state[i].metric + mets[3 ^ sym]; /* 2*i + 1 */ \
m3 = state[i+32].metric + mets[sym]; /* 2*i + 65 */ \
if(m2 > m3){ \
next[2*i+1].metric = m2; \
next[2*i+1].path = state[i].path << 1; \
} else { \
next[2*i+1].metric = m3; \
next[2*i+1].path = (state[i+32].path << 1)|1; \
} \
}
using namespace gr::ieee802_11;
void
viterbi_decoder::viterbi_butterfly2_generic(unsigned char *symbols,
unsigned char *mm0, unsigned char *mm1, unsigned char *pp0,
unsigned char *pp1)
{
int i, j, k;
unsigned char *metric0, *metric1;
unsigned char *path0, *path1;
metric0 = mm0;
path0 = pp0;
metric1 = mm1;
path1 = pp1;
// Operate on 4 symbols (2 bits) at a time
unsigned char m0[16], m1[16], m2[16], m3[16], decision0[16], decision1[16], survivor0[16], survivor1[16];
unsigned char metsv[16], metsvm[16];
unsigned char shift0[16], shift1[16];
unsigned char tmp0[16], tmp1[16];
unsigned char sym0v[16], sym1v[16];
unsigned short simd_epi16;
for (j = 0; j < 16; j++) {
sym0v[j] = symbols[0];
sym1v[j] = symbols[1];
}
for (i = 0; i < 2; i++) {
if (symbols[0] == 2) {
for (j = 0; j < 16; j++) {
metsvm[j] = d_branchtab27_generic[1].c[(i*16) + j] ^ sym1v[j];
metsv[j] = 1 - metsvm[j];
}
}
else if (symbols[1] == 2) {
for (j = 0; j < 16; j++) {
metsvm[j] = d_branchtab27_generic[0].c[(i*16) + j] ^ sym0v[j];
metsv[j] = 1 - metsvm[j];
}
}
else {
for (j = 0; j < 16; j++) {
metsvm[j] = (d_branchtab27_generic[0].c[(i*16) + j] ^ sym0v[j]) + (d_branchtab27_generic[1].c[(i*16) + j] ^ sym1v[j]);
metsv[j] = 2 - metsvm[j];
}
}
for (j = 0; j < 16; j++) {
m0[j] = metric0[(i*16) + j] + metsv[j];
m1[j] = metric0[((i+2)*16) + j] + metsvm[j];
m2[j] = metric0[(i*16) + j] + metsvm[j];
m3[j] = metric0[((i+2)*16) + j] + metsv[j];
}
for (j = 0; j < 16; j++) {
decision0[j] = ((m0[j] - m1[j]) > 0) ? 0xff : 0x0;
decision1[j] = ((m2[j] - m3[j]) > 0) ? 0xff : 0x0;
survivor0[j] = (decision0[j] & m0[j]) | ((~decision0[j]) & m1[j]);
survivor1[j] = (decision1[j] & m2[j]) | ((~decision1[j]) & m3[j]);
}
for (j = 0; j < 16; j += 2) {
simd_epi16 = path0[(i*16) + j];
simd_epi16 |= path0[(i*16) + (j+1)] << 8;
simd_epi16 <<= 1;
shift0[j] = simd_epi16;
shift0[j+1] = simd_epi16 >> 8;
simd_epi16 = path0[((i+2)*16) + j];
simd_epi16 |= path0[((i+2)*16) + (j+1)] << 8;
simd_epi16 <<= 1;
shift1[j] = simd_epi16;
shift1[j+1] = simd_epi16 >> 8;
}
for (j = 0; j < 16; j++) {
shift1[j] = shift1[j] + 1;
}
for (j = 0, k = 0; j < 16; j += 2, k++) {
metric1[(2*i*16) + j] = survivor0[k];
metric1[(2*i*16) + (j+1)] = survivor1[k];
}
for (j = 0; j < 16; j++) {
tmp0[j] = (decision0[j] & shift0[j]) | ((~decision0[j]) & shift1[j]);
}
for (j = 0, k = 8; j < 16; j += 2, k++) {
metric1[((2*i+1)*16) + j] = survivor0[k];
metric1[((2*i+1)*16) + (j+1)] = survivor1[k];
}
for (j = 0; j < 16; j++) {
tmp1[j] = (decision1[j] & shift0[j]) | ((~decision1[j]) & shift1[j]);
}
for (j = 0, k = 0; j < 16; j += 2, k++) {
path1[(2*i*16) + j] = tmp0[k];
path1[(2*i*16) + (j+1)] = tmp1[k];
}
for (j = 0, k = 8; j < 16; j += 2, k++) {
path1[((2*i+1)*16) + j] = tmp0[k];
path1[((2*i+1)*16) + (j+1)] = tmp1[k];
}
}
metric0 = mm1;
path0 = pp1;
metric1 = mm0;
path1 = pp0;
for (j = 0; j < 16; j++) {
sym0v[j] = symbols[2];
sym1v[j] = symbols[3];
}
for (i = 0; i < 2; i++) {
if (symbols[2] == 2) {
for (j = 0; j < 16; j++) {
metsvm[j] = d_branchtab27_generic[1].c[(i*16) + j] ^ sym1v[j];
metsv[j] = 1 - metsvm[j];
}
}
else if (symbols[3] == 2) {
for (j = 0; j < 16; j++) {
metsvm[j] = d_branchtab27_generic[0].c[(i*16) + j] ^ sym0v[j];
metsv[j] = 1 - metsvm[j];
}
}
else {
for (j = 0; j < 16; j++) {
metsvm[j] = (d_branchtab27_generic[0].c[(i*16) + j] ^ sym0v[j]) + (d_branchtab27_generic[1].c[(i*16) + j] ^ sym1v[j]);
metsv[j] = 2 - metsvm[j];
}
}
for (j = 0; j < 16; j++) {
m0[j] = metric0[(i*16) + j] + metsv[j];
m1[j] = metric0[((i+2)*16) + j] + metsvm[j];
m2[j] = metric0[(i*16) + j] + metsvm[j];
m3[j] = metric0[((i+2)*16) + j] + metsv[j];
}
for (j = 0; j < 16; j++) {
decision0[j] = ((m0[j] - m1[j]) > 0) ? 0xff : 0x0;
decision1[j] = ((m2[j] - m3[j]) > 0) ? 0xff : 0x0;
survivor0[j] = (decision0[j] & m0[j]) | ((~decision0[j]) & m1[j]);
survivor1[j] = (decision1[j] & m2[j]) | ((~decision1[j]) & m3[j]);
}
for (j = 0; j < 16; j += 2) {
simd_epi16 = path0[(i*16) + j];
simd_epi16 |= path0[(i*16) + (j+1)] << 8;
simd_epi16 <<= 1;
shift0[j] = simd_epi16;
shift0[j+1] = simd_epi16 >> 8;
simd_epi16 = path0[((i+2)*16) + j];
simd_epi16 |= path0[((i+2)*16) + (j+1)] << 8;
simd_epi16 <<= 1;
shift1[j] = simd_epi16;
shift1[j+1] = simd_epi16 >> 8;
}
for (j = 0; j < 16; j++) {
shift1[j] = shift1[j] + 1;
}
for (j = 0, k = 0; j < 16; j += 2, k++) {
metric1[(2*i*16) + j] = survivor0[k];
metric1[(2*i*16) + (j+1)] = survivor1[k];
}
for (j = 0; j < 16; j++) {
tmp0[j] = (decision0[j] & shift0[j]) | ((~decision0[j]) & shift1[j]);
}
for (j = 0, k = 8; j < 16; j += 2, k++) {
metric1[((2*i+1)*16) + j] = survivor0[k];
metric1[((2*i+1)*16) + (j+1)] = survivor1[k];
}
for (j = 0; j < 16; j++) {
tmp1[j] = (decision1[j] & shift0[j]) | ((~decision1[j]) & shift1[j]);
}
for (j = 0, k = 0; j < 16; j += 2, k++) {
path1[(2*i*16) + j] = tmp0[k];
path1[(2*i*16) + (j+1)] = tmp1[k];
}
for (j = 0, k = 8; j < 16; j += 2, k++) {
path1[((2*i+1)*16) + j] = tmp0[k];
path1[((2*i+1)*16) + (j+1)] = tmp1[k];
}
}
}
// Find current best path
unsigned char
viterbi_decoder::viterbi_get_output_generic(unsigned char *mm0,
unsigned char *pp0, int ntraceback, unsigned char *outbuf) {
int i;
int bestmetric, minmetric;
int beststate = 0;
int pos = 0;
int j;
// circular buffer with the last ntraceback paths
d_store_pos = (d_store_pos + 1) % ntraceback;
for (i = 0; i < 4; i++) {
for (j = 0; j < 16; j++) {
d_mmresult[(i*16) + j] = mm0[(i*16) + j];
d_ppresult[d_store_pos][(i*16) + j] = pp0[(i*16) + j];
}
}
// Find out the best final state
bestmetric = d_mmresult[beststate];
minmetric = d_mmresult[beststate];
for (i = 1; i < 64; i++) {
if (d_mmresult[i] > bestmetric) {
bestmetric = d_mmresult[i];
beststate = i;
}
if (d_mmresult[i] < minmetric) {
minmetric = d_mmresult[i];
}
}
// Trace back
for (i = 0, pos = d_store_pos; i < (ntraceback - 1); i++) {
// Obtain the state from the output bits
// by clocking in the output bits in reverse order.
// The state has only 6 bits
beststate = d_ppresult[pos][beststate] >> 2;
pos = (pos - 1 + ntraceback) % ntraceback;
}
// Store output byte
*outbuf = d_ppresult[pos][beststate];
for (i = 0; i < 4; i++) {
for (j = 0; j < 16; j++) {
pp0[(i*16) + j] = 0;
mm0[(i*16) + j] = mm0[(i*16) + j] - minmetric;
}
}
return bestmetric;
}
uint8_t*
viterbi_decoder::decode(ofdm_param *ofdm, frame_param *frame, uint8_t *in) {
d_ofdm = ofdm;
d_frame = frame;
reset();
uint8_t *depunctured = depuncture(in);
int in_count = 0;
int out_count = 0;
int n_decoded = 0;
while(n_decoded < d_frame->n_data_bits) {
if ((in_count % 4) == 0) { //0 or 3
viterbi_butterfly2_generic(&depunctured[in_count & 0xfffffffc], d_metric0_generic, d_metric1_generic,
d_path0_generic, d_path1_generic);
if ((in_count > 0) && (in_count % 16) == 8) { // 8 or 11
unsigned char c;
viterbi_get_output_generic(d_metric0_generic, d_path0_generic, d_ntraceback, &c);
if (out_count >= d_ntraceback) {
for (int i= 0; i < 8; i++) {
d_decoded[(out_count - d_ntraceback) * 8 + i] = (c >> (7 - i)) & 0x1;
n_decoded++;
}
}
out_count++;
}
}
in_count++;
}
return d_decoded;
}
void
viterbi_decoder::reset() {
viterbi_chunks_init_generic();
switch(d_ofdm->encoding) {
case BPSK_1_2:
case QPSK_1_2:
case QAM16_1_2:
d_ntraceback = 5;
d_depuncture_pattern = PUNCTURE_1_2;
d_k = 1;
break;
case QAM64_2_3:
d_ntraceback = 9;
d_depuncture_pattern = PUNCTURE_2_3;
d_k = 2;
break;
case BPSK_3_4:
case QPSK_3_4:
case QAM16_3_4:
case QAM64_3_4:
d_ntraceback = 10;
d_depuncture_pattern = PUNCTURE_3_4;
d_k = 3;
break;
}
}
// Initialize starting metrics to prefer 0 state
void
viterbi_decoder::viterbi_chunks_init_generic() {
int i, j;
for (i = 0; i < 4; i++) {
d_metric0_generic[i] = 0;
d_path0_generic[i] = 0;
}
int polys[2] = { 0x6d, 0x4f };
for(i=0; i < 32; i++) {
d_branchtab27_generic[0].c[i] = (polys[0] < 0) ^ PARTAB[(2*i) & abs(polys[0])] ? 1 : 0;
d_branchtab27_generic[1].c[i] = (polys[1] < 0) ^ PARTAB[(2*i) & abs(polys[1])] ? 1 : 0;
}
for (i = 0; i < 64; i++) {
d_mmresult[i] = 0;
for (j = 0; j < TRACEBACK_MAX; j++) {
d_ppresult[j][i] = 0;
}
}
}
@@ -0,0 +1,60 @@
/*
* Copyright (C) 2016 Bastian Bloessl <bloessl@ccs-labs.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef INCLUDED_IEEE802_11_VITERBI_DECODER_GENERIC_H
#define INCLUDED_IEEE802_11_VITERBI_DECODER_GENERIC_H
#include "base.h"
namespace gr {
namespace ieee802_11 {
/* This Viterbi decoder was taken from the gr-dvbt module of
* GNU Radio. It is an SSE2 version of the Viterbi Decoder
* created by Phil Karn. The SSE2 version was made by Bogdan
* Diaconescu. For more info see: gr-dvbt/lib/d_viterbi.h
*/
class viterbi_decoder : public base
{
public:
virtual uint8_t* decode(ofdm_param *ofdm, frame_param *frame, uint8_t *in);
private:
union branchtab27 {
unsigned char c[32];
} d_branchtab27_generic[2];
unsigned char d_metric0_generic[64] __attribute__ ((aligned(16)));
unsigned char d_metric1_generic[64] __attribute__ ((aligned(16)));
unsigned char d_path0_generic[64] __attribute__ ((aligned(16)));
unsigned char d_path1_generic[64] __attribute__ ((aligned(16)));
void reset();
void viterbi_chunks_init_generic();
void viterbi_butterfly2_generic(unsigned char *symbols,
unsigned char m0[], unsigned char m1[], unsigned char p0[],
unsigned char p1[]);
unsigned char viterbi_get_output_generic(unsigned char *mm0,
unsigned char *pp0, int ntraceback, unsigned char *outbuf);
};
} // namespace ieee802_11
} // namespace gr
#endif /* INCLUDED_IEEE802_11_VITERBI_DECODER_GENERIC_H */
@@ -27,7 +27,7 @@
* Some modifications from original Karn code by Matt Ettus * Some modifications from original Karn code by Matt Ettus
* Major modifications by adding SSE2 code by Bogdan Diaconescu * Major modifications by adding SSE2 code by Bogdan Diaconescu
*/ */
#include "viterbi_decoder.h" #include "viterbi_decoder_x86.h"
#include <cstring> #include <cstring>
#include <iostream> #include <iostream>
@@ -80,17 +80,8 @@
} \ } \
} }
using namespace gr::ieee802_11; using namespace gr::ieee802_11;
viterbi_decoder::viterbi_decoder() :
d_store_pos(0) {
}
viterbi_decoder::~viterbi_decoder() {
}
void void
viterbi_decoder::viterbi_butterfly2_sse2(unsigned char *symbols, viterbi_decoder::viterbi_butterfly2_sse2(unsigned char *symbols,
__m128i *mm0, __m128i *mm1, __m128i *pp0, __m128i *pp1) { __m128i *mm0, __m128i *mm1, __m128i *pp0, __m128i *pp1) {
@@ -251,41 +242,6 @@ viterbi_decoder::viterbi_get_output_sse2(__m128i *mm0, __m128i *pp0,
return bestmetric; return bestmetric;
} }
uint8_t*
viterbi_decoder::depuncture(uint8_t *in) {
int count;
int n_cbps = d_ofdm->n_cbps;
uint8_t *depunctured;
if (d_ntraceback == 5) {
count = d_frame->n_sym * n_cbps;
depunctured = in;
} else {
depunctured = d_depunctured;
count = 0;
for(int i = 0; i < d_frame->n_sym; i++) {
for(int k = 0; k < n_cbps; k++) {
while (d_depuncture_pattern[count % (2 * d_k)] == 0) {
depunctured[count] = 2;
count++;
}
// Insert received bits
depunctured[count] = in[i * n_cbps + k];
count++;
while (d_depuncture_pattern[count % (2 * d_k)] == 0) {
depunctured[count] = 2;
count++;
}
}
}
}
return depunctured;
}
uint8_t* uint8_t*
viterbi_decoder::decode(ofdm_param *ofdm, frame_param *frame, uint8_t *in) { viterbi_decoder::decode(ofdm_param *ofdm, frame_param *frame, uint8_t *in) {
@@ -354,7 +310,8 @@ viterbi_decoder::reset() {
} }
} }
void // Initialize starting metrics to prefer 0 state // Initialize starting metrics to prefer 0 state
void
viterbi_decoder::viterbi_chunks_init_sse2() { viterbi_decoder::viterbi_chunks_init_sse2() {
int i, j; int i, j;
@@ -376,44 +333,3 @@ viterbi_decoder::viterbi_chunks_init_sse2() {
} }
} }
} }
/* Parity lookup table */
const unsigned char viterbi_decoder::PARTAB[256] = {
0, 1, 1, 0, 1, 0, 0, 1,
1, 0, 0, 1, 0, 1, 1, 0,
1, 0, 0, 1, 0, 1, 1, 0,
0, 1, 1, 0, 1, 0, 0, 1,
1, 0, 0, 1, 0, 1, 1, 0,
0, 1, 1, 0, 1, 0, 0, 1,
0, 1, 1, 0, 1, 0, 0, 1,
1, 0, 0, 1, 0, 1, 1, 0,
1, 0, 0, 1, 0, 1, 1, 0,
0, 1, 1, 0, 1, 0, 0, 1,
0, 1, 1, 0, 1, 0, 0, 1,
1, 0, 0, 1, 0, 1, 1, 0,
0, 1, 1, 0, 1, 0, 0, 1,
1, 0, 0, 1, 0, 1, 1, 0,
1, 0, 0, 1, 0, 1, 1, 0,
0, 1, 1, 0, 1, 0, 0, 1,
1, 0, 0, 1, 0, 1, 1, 0,
0, 1, 1, 0, 1, 0, 0, 1,
0, 1, 1, 0, 1, 0, 0, 1,
1, 0, 0, 1, 0, 1, 1, 0,
0, 1, 1, 0, 1, 0, 0, 1,
1, 0, 0, 1, 0, 1, 1, 0,
1, 0, 0, 1, 0, 1, 1, 0,
0, 1, 1, 0, 1, 0, 0, 1,
0, 1, 1, 0, 1, 0, 0, 1,
1, 0, 0, 1, 0, 1, 1, 0,
1, 0, 0, 1, 0, 1, 1, 0,
0, 1, 1, 0, 1, 0, 0, 1,
1, 0, 0, 1, 0, 1, 1, 0,
0, 1, 1, 0, 1, 0, 0, 1,
0, 1, 1, 0, 1, 0, 0, 1,
1, 0, 0, 1, 0, 1, 1, 0,
};
const unsigned char viterbi_decoder::PUNCTURE_1_2[2] = {1, 1};
const unsigned char viterbi_decoder::PUNCTURE_2_3[4] = {1, 1, 1, 0};
const unsigned char viterbi_decoder::PUNCTURE_3_4[6] = {1, 1, 1, 0, 0, 1};
+61
View File
@@ -0,0 +1,61 @@
/*
* Copyright (C) 2016 Bastian Bloessl <bloessl@ccs-labs.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef INCLUDED_IEEE802_11_VITERBI_DECODER_X86_H
#define INCLUDED_IEEE802_11_VITERBI_DECODER_X86_H
#include <xmmintrin.h>
#include "base.h"
namespace gr {
namespace ieee802_11 {
/* This Viterbi decoder was taken from the gr-dvbt module of
* GNU Radio. It is an SSE2 version of the Viterbi Decoder
* created by Phil Karn. The SSE2 version was made by Bogdan
* Diaconescu. For more info see: gr-dvbt/lib/d_viterbi.h
*/
class viterbi_decoder : public base
{
public:
virtual uint8_t* decode(ofdm_param *ofdm, frame_param *frame, uint8_t *in);
private:
union branchtab27 {
unsigned char c[32];
__m128i v[2];
} d_branchtab27_sse2[2];
__m128i d_metric0[4] __attribute__ ((aligned(16)));
__m128i d_metric1[4] __attribute__ ((aligned(16)));
__m128i d_path0[4] __attribute__ ((aligned(16)));
__m128i d_path1[4] __attribute__ ((aligned(16)));
virtual void reset();
void viterbi_chunks_init_sse2();
void viterbi_butterfly2_sse2(unsigned char *symbols,
__m128i m0[], __m128i m1[], __m128i p0[], __m128i p1[]);
unsigned char viterbi_get_output_sse2(__m128i *mm0,
__m128i *pp0, int ntraceback, unsigned char *outbuf);
};
} // namespace ieee802_11
} // namespace gr
#endif /* INCLUDED_IEEE802_11_VITERBI_DECODER_X86_H */