From 528536e3f2ce50bc18f9b3c00015c1b37c2f66a2 Mon Sep 17 00:00:00 2001 From: Stephen Wolfe Date: Mon, 7 Nov 2016 15:00:30 -0500 Subject: [PATCH] viterbi decoder: add viterbi decoder base class Add a viterbi decoder base class that viterbi decoder implementations can inherit from. --- lib/CMakeLists.txt | 1 + lib/viterbi_decoder/base.cc | 105 ++++++++++++++++++ lib/viterbi_decoder/base.h | 70 ++++++++++++ .../viterbi_decoder_generic.cc | 88 +-------------- lib/viterbi_decoder/viterbi_decoder_generic.h | 35 +----- lib/viterbi_decoder/viterbi_decoder_x86.cc | 89 +-------------- lib/viterbi_decoder/viterbi_decoder_x86.h | 37 +----- 7 files changed, 185 insertions(+), 240 deletions(-) create mode 100644 lib/viterbi_decoder/base.cc create mode 100644 lib/viterbi_decoder/base.h diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 7206bc9..2de5c53 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -120,6 +120,7 @@ list(APPEND gr_ieee802_11_sources sync_long.cc sync_short.cc utils.cc + viterbi_decoder/base.cc ) # use SSE2 optimized viterbi implementation if SSE2 is enabled diff --git a/lib/viterbi_decoder/base.cc b/lib/viterbi_decoder/base.cc new file mode 100644 index 0000000..86564b8 --- /dev/null +++ b/lib/viterbi_decoder/base.cc @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2016 Bastian Bloessl + * + * 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 . + */ + +#include "base.h" +#include +#include + +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}; diff --git a/lib/viterbi_decoder/base.h b/lib/viterbi_decoder/base.h new file mode 100644 index 0000000..4a98ef0 --- /dev/null +++ b/lib/viterbi_decoder/base.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2016 Bastian Bloessl + * + * 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 . + */ +#ifndef INCLUDED_IEEE802_11_VITERBI_DECODER_BASE_H +#define INCLUDED_IEEE802_11_VITERBI_DECODER_BASE_H + +#include "utils.h" + +namespace gr { +namespace ieee802_11 { + +// Maximum number of traceback bytes +#define TRACEBACK_MAX 24 + +/* 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 base +{ +public: + + base(); + ~base(); + virtual uint8_t* decode(ofdm_param *ofdm, frame_param *frame, uint8_t *in) = 0; + +protected: + // Position in circular buffer where the current decoded byte is stored + int d_store_pos; + // Metrics for each state + unsigned char d_mmresult[64] __attribute__((aligned(16))); + // Paths for each state + unsigned char d_ppresult[TRACEBACK_MAX][64] __attribute__((aligned(16))); + + int d_ntraceback; + int d_k; + ofdm_param *d_ofdm; + frame_param *d_frame; + const unsigned char *d_depuncture_pattern; + + uint8_t d_depunctured[MAX_ENCODED_BITS]; + uint8_t d_decoded[MAX_ENCODED_BITS * 3 / 4]; + + static const unsigned char PARTAB[256]; + static const unsigned char PUNCTURE_1_2[2]; + static const unsigned char PUNCTURE_2_3[4]; + static const unsigned char PUNCTURE_3_4[6]; + + virtual void reset() = 0; + uint8_t* depuncture(uint8_t *in); +}; + +} // namespace ieee802_11 +} // namespace gr + +#endif /* INCLUDED_IEEE802_11_VITERBI_DECODER_BASE_H */ diff --git a/lib/viterbi_decoder/viterbi_decoder_generic.cc b/lib/viterbi_decoder/viterbi_decoder_generic.cc index a879ef9..15fa252 100644 --- a/lib/viterbi_decoder/viterbi_decoder_generic.cc +++ b/lib/viterbi_decoder/viterbi_decoder_generic.cc @@ -27,7 +27,7 @@ * Some modifications from original Karn code by Matt Ettus * Major modifications by adding SSE2 code by Bogdan Diaconescu */ -#include "viterbi_decoder.h" +#include "viterbi_decoder_generic.h" #include #include @@ -83,13 +83,6 @@ using namespace gr::ieee802_11; -viterbi_decoder::viterbi_decoder() : - d_store_pos(0) { -} - -viterbi_decoder::~viterbi_decoder() { -} - void viterbi_decoder::viterbi_butterfly2_generic(unsigned char *symbols, unsigned char *mm0, unsigned char *mm1, unsigned char *pp0, @@ -292,9 +285,7 @@ viterbi_decoder::viterbi_get_output_generic(unsigned char *mm0, int bestmetric, minmetric; int beststate = 0; int pos = 0; -#ifndef IEEE80211_MSSE2 int j; -#endif // circular buffer with the last ntraceback paths d_store_pos = (d_store_pos + 1) % ntraceback; @@ -342,42 +333,6 @@ viterbi_decoder::viterbi_get_output_generic(unsigned char *mm0, 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* viterbi_decoder::decode(ofdm_param *ofdm, frame_param *frame, uint8_t *in) { @@ -469,44 +424,3 @@ viterbi_decoder::viterbi_chunks_init_generic() { } } } - - -/* 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}; diff --git a/lib/viterbi_decoder/viterbi_decoder_generic.h b/lib/viterbi_decoder/viterbi_decoder_generic.h index adea66e..b1fb5ce 100644 --- a/lib/viterbi_decoder/viterbi_decoder_generic.h +++ b/lib/viterbi_decoder/viterbi_decoder_generic.h @@ -17,38 +17,24 @@ #ifndef INCLUDED_IEEE802_11_VITERBI_DECODER_GENERIC_H #define INCLUDED_IEEE802_11_VITERBI_DECODER_GENERIC_H -#include "utils.h" +#include "base.h" namespace gr { namespace ieee802_11 { -// Maximum number of traceback bytes -#define TRACEBACK_MAX 24 - /* 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 +class viterbi_decoder : public base { public: - viterbi_decoder(); - virtual ~viterbi_decoder(); - - uint8_t* decode(ofdm_param *ofdm, frame_param *frame, uint8_t *in); + virtual uint8_t* decode(ofdm_param *ofdm, frame_param *frame, uint8_t *in); private: - // Position in circular buffer where the current decoded byte is stored - int d_store_pos; - // Metrics for each state - unsigned char d_mmresult[64] __attribute__((aligned(16))); - // Paths for each state - unsigned char d_ppresult[TRACEBACK_MAX][64] __attribute__((aligned(16))); - - union branchtab27 { unsigned char c[32]; } d_branchtab27_generic[2]; @@ -58,22 +44,7 @@ private: unsigned char d_path0_generic[64] __attribute__ ((aligned(16))); unsigned char d_path1_generic[64] __attribute__ ((aligned(16))); - int d_ntraceback; - int d_k; - ofdm_param *d_ofdm; - frame_param *d_frame; - const unsigned char *d_depuncture_pattern; - - uint8_t d_depunctured[MAX_ENCODED_BITS]; - uint8_t d_decoded[MAX_ENCODED_BITS * 3 / 4]; - - static const unsigned char PARTAB[256]; - static const unsigned char PUNCTURE_1_2[2]; - static const unsigned char PUNCTURE_2_3[4]; - static const unsigned char PUNCTURE_3_4[6]; - void reset(); - uint8_t* depuncture(uint8_t *in); void viterbi_chunks_init_generic(); void viterbi_butterfly2_generic(unsigned char *symbols, diff --git a/lib/viterbi_decoder/viterbi_decoder_x86.cc b/lib/viterbi_decoder/viterbi_decoder_x86.cc index 796f76f..2e2a689 100644 --- a/lib/viterbi_decoder/viterbi_decoder_x86.cc +++ b/lib/viterbi_decoder/viterbi_decoder_x86.cc @@ -27,7 +27,7 @@ * Some modifications from original Karn code by Matt Ettus * Major modifications by adding SSE2 code by Bogdan Diaconescu */ -#include "viterbi_decoder.h" +#include "viterbi_decoder_x86.h" #include #include @@ -82,14 +82,6 @@ using namespace gr::ieee802_11; - -viterbi_decoder::viterbi_decoder() : - d_store_pos(0) { -} - -viterbi_decoder::~viterbi_decoder() { -} - void viterbi_decoder::viterbi_butterfly2_sse2(unsigned char *symbols, __m128i *mm0, __m128i *mm1, __m128i *pp0, __m128i *pp1) { @@ -205,9 +197,6 @@ viterbi_decoder::viterbi_get_output_sse2(__m128i *mm0, __m128i *pp0, int bestmetric, minmetric; int beststate = 0; int pos = 0; -#ifndef IEEE80211_MSSE2 - int j; -#endif // circular buffer with the last ntraceback paths d_store_pos = (d_store_pos + 1) % ntraceback; @@ -253,41 +242,6 @@ viterbi_decoder::viterbi_get_output_sse2(__m128i *mm0, __m128i *pp0, 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* viterbi_decoder::decode(ofdm_param *ofdm, frame_param *frame, uint8_t *in) { @@ -379,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}; diff --git a/lib/viterbi_decoder/viterbi_decoder_x86.h b/lib/viterbi_decoder/viterbi_decoder_x86.h index 3d18fb6..721b2a4 100644 --- a/lib/viterbi_decoder/viterbi_decoder_x86.h +++ b/lib/viterbi_decoder/viterbi_decoder_x86.h @@ -18,38 +18,24 @@ #define INCLUDED_IEEE802_11_VITERBI_DECODER_X86_H #include -#include "utils.h" +#include "base.h" namespace gr { namespace ieee802_11 { -// Maximum number of traceback bytes -#define TRACEBACK_MAX 24 - /* 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 +class viterbi_decoder : public base { public: - viterbi_decoder(); - virtual ~viterbi_decoder(); - - uint8_t* decode(ofdm_param *ofdm, frame_param *frame, uint8_t *in); + virtual uint8_t* decode(ofdm_param *ofdm, frame_param *frame, uint8_t *in); private: - // Position in circular buffer where the current decoded byte is stored - int d_store_pos; - // Metrics for each state - unsigned char d_mmresult[64] __attribute__((aligned(16))); - // Paths for each state - unsigned char d_ppresult[TRACEBACK_MAX][64] __attribute__((aligned(16))); - - union branchtab27 { unsigned char c[32]; __m128i v[2]; @@ -60,22 +46,7 @@ private: __m128i d_path0[4] __attribute__ ((aligned(16))); __m128i d_path1[4] __attribute__ ((aligned(16))); - int d_ntraceback; - int d_k; - ofdm_param *d_ofdm; - frame_param *d_frame; - const unsigned char *d_depuncture_pattern; - - uint8_t d_depunctured[MAX_ENCODED_BITS]; - uint8_t d_decoded[MAX_ENCODED_BITS * 3 / 4]; - - static const unsigned char PARTAB[256]; - static const unsigned char PUNCTURE_1_2[2]; - static const unsigned char PUNCTURE_2_3[4]; - static const unsigned char PUNCTURE_3_4[6]; - - void reset(); - uint8_t* depuncture(uint8_t *in); + virtual void reset(); void viterbi_chunks_init_sse2(); void viterbi_butterfly2_sse2(unsigned char *symbols,