viterbi decoder: add viterbi decoder base class

Add a viterbi decoder base class that viterbi decoder
implementations can inherit from.
This commit is contained in:
Stephen Wolfe
2016-11-07 15:00:30 -05:00
parent 9cf628359b
commit 528536e3f2
7 changed files with 185 additions and 240 deletions
+1
View File
@@ -120,6 +120,7 @@ list(APPEND gr_ieee802_11_sources
sync_long.cc sync_long.cc
sync_short.cc sync_short.cc
utils.cc utils.cc
viterbi_decoder/base.cc
) )
# use SSE2 optimized viterbi implementation if SSE2 is enabled # use SSE2 optimized viterbi implementation if SSE2 is enabled
+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};
+70
View File
@@ -0,0 +1,70 @@
/*
* 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_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 */
+1 -87
View File
@@ -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_generic.h"
#include <cstring> #include <cstring>
#include <iostream> #include <iostream>
@@ -83,13 +83,6 @@
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_generic(unsigned char *symbols, viterbi_decoder::viterbi_butterfly2_generic(unsigned char *symbols,
unsigned char *mm0, unsigned char *mm1, unsigned char *pp0, 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 bestmetric, minmetric;
int beststate = 0; int beststate = 0;
int pos = 0; int pos = 0;
#ifndef IEEE80211_MSSE2
int j; int j;
#endif
// circular buffer with the last ntraceback paths // circular buffer with the last ntraceback paths
d_store_pos = (d_store_pos + 1) % ntraceback; d_store_pos = (d_store_pos + 1) % ntraceback;
@@ -342,42 +333,6 @@ viterbi_decoder::viterbi_get_output_generic(unsigned char *mm0,
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) {
@@ -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};
+3 -32
View File
@@ -17,38 +17,24 @@
#ifndef INCLUDED_IEEE802_11_VITERBI_DECODER_GENERIC_H #ifndef INCLUDED_IEEE802_11_VITERBI_DECODER_GENERIC_H
#define INCLUDED_IEEE802_11_VITERBI_DECODER_GENERIC_H #define INCLUDED_IEEE802_11_VITERBI_DECODER_GENERIC_H
#include "utils.h" #include "base.h"
namespace gr { namespace gr {
namespace ieee802_11 { namespace ieee802_11 {
// Maximum number of traceback bytes
#define TRACEBACK_MAX 24
/* This Viterbi decoder was taken from the gr-dvbt module of /* This Viterbi decoder was taken from the gr-dvbt module of
* GNU Radio. It is an SSE2 version of the Viterbi Decoder * GNU Radio. It is an SSE2 version of the Viterbi Decoder
* 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 viterbi_decoder : public base
{ {
public: public:
viterbi_decoder(); virtual uint8_t* decode(ofdm_param *ofdm, frame_param *frame, uint8_t *in);
virtual ~viterbi_decoder();
uint8_t* decode(ofdm_param *ofdm, frame_param *frame, uint8_t *in);
private: 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 { union branchtab27 {
unsigned char c[32]; unsigned char c[32];
} d_branchtab27_generic[2]; } d_branchtab27_generic[2];
@@ -58,22 +44,7 @@ private:
unsigned char d_path0_generic[64] __attribute__ ((aligned(16))); unsigned char d_path0_generic[64] __attribute__ ((aligned(16)));
unsigned char d_path1_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(); void reset();
uint8_t* depuncture(uint8_t *in);
void viterbi_chunks_init_generic(); void viterbi_chunks_init_generic();
void viterbi_butterfly2_generic(unsigned char *symbols, void viterbi_butterfly2_generic(unsigned char *symbols,
+1 -88
View File
@@ -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>
@@ -82,14 +82,6 @@
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) {
@@ -205,9 +197,6 @@ viterbi_decoder::viterbi_get_output_sse2(__m128i *mm0, __m128i *pp0,
int bestmetric, minmetric; int bestmetric, minmetric;
int beststate = 0; int beststate = 0;
int pos = 0; int pos = 0;
#ifndef IEEE80211_MSSE2
int j;
#endif
// circular buffer with the last ntraceback paths // circular buffer with the last ntraceback paths
d_store_pos = (d_store_pos + 1) % ntraceback; d_store_pos = (d_store_pos + 1) % ntraceback;
@@ -253,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) {
@@ -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};
+4 -33
View File
@@ -18,38 +18,24 @@
#define INCLUDED_IEEE802_11_VITERBI_DECODER_X86_H #define INCLUDED_IEEE802_11_VITERBI_DECODER_X86_H
#include <xmmintrin.h> #include <xmmintrin.h>
#include "utils.h" #include "base.h"
namespace gr { namespace gr {
namespace ieee802_11 { namespace ieee802_11 {
// Maximum number of traceback bytes
#define TRACEBACK_MAX 24
/* This Viterbi decoder was taken from the gr-dvbt module of /* This Viterbi decoder was taken from the gr-dvbt module of
* GNU Radio. It is an SSE2 version of the Viterbi Decoder * GNU Radio. It is an SSE2 version of the Viterbi Decoder
* 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 viterbi_decoder : public base
{ {
public: public:
viterbi_decoder(); virtual uint8_t* decode(ofdm_param *ofdm, frame_param *frame, uint8_t *in);
virtual ~viterbi_decoder();
uint8_t* decode(ofdm_param *ofdm, frame_param *frame, uint8_t *in);
private: 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 { union branchtab27 {
unsigned char c[32]; unsigned char c[32];
__m128i v[2]; __m128i v[2];
@@ -60,22 +46,7 @@ private:
__m128i d_path0[4] __attribute__ ((aligned(16))); __m128i d_path0[4] __attribute__ ((aligned(16)));
__m128i d_path1[4] __attribute__ ((aligned(16))); __m128i d_path1[4] __attribute__ ((aligned(16)));
int d_ntraceback; virtual void reset();
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_sse2(); void viterbi_chunks_init_sse2();
void viterbi_butterfly2_sse2(unsigned char *symbols, void viterbi_butterfly2_sse2(unsigned char *symbols,