From c6502ae0223592254b4b037d2922553bed95a9fc Mon Sep 17 00:00:00 2001 From: Stephen Wolfe Date: Thu, 3 Nov 2016 11:04:17 -0400 Subject: [PATCH 1/3] non-x86 support: Only use SSE2 when supported Add generic version of viterbi decoder that does not utilize x86 intrinsics to provide support for other architectures such as ARM. --- CMakeLists.txt | 1 - lib/CMakeLists.txt | 9 ++ lib/viterbi_decoder.cc | 258 ++++++++++++++++++++++++++++++++++++++++- lib/viterbi_decoder.h | 25 ++++ 4 files changed, 290 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1015c4a..98438ad 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,7 +37,6 @@ if(NOT WIN32) #http://gcc.gnu.org/wiki/Visibility add_definitions(-fvisibility=hidden) add_definitions(-std=c++0x) - add_definitions(-msse2) endif() ######################################################################## diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 09fd869..9b1bfc2 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -85,6 +85,15 @@ endmacro(expand_cc_h_impl) ######################################################################## # 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) add_custom_target(ieee802_11_generated_sources DEPENDS ${generated_sources}) add_dependencies(ieee802_11_generated_sources ieee802_11_generated_includes) diff --git a/lib/viterbi_decoder.cc b/lib/viterbi_decoder.cc index 7f54419..a87480d 100644 --- a/lib/viterbi_decoder.cc +++ b/lib/viterbi_decoder.cc @@ -80,7 +80,6 @@ } \ } - using namespace gr::ieee802_11; @@ -91,6 +90,7 @@ viterbi_decoder::viterbi_decoder() : viterbi_decoder::~viterbi_decoder() { } +#ifdef IEEE80211_MSSE2 void viterbi_decoder::viterbi_butterfly2_sse2(unsigned char *symbols, __m128i *mm0, __m128i *mm1, __m128i *pp0, __m128i *pp1) { @@ -197,23 +197,236 @@ viterbi_decoder::viterbi_butterfly2_sse2(unsigned char *symbols, path1[2*i+1] = _mm_unpackhi_epi8(tmp0, tmp1); } } +#else +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]; + } + } +} +#endif // Find current best path +#ifdef IEEE80211_MSSE2 unsigned char viterbi_decoder::viterbi_get_output_sse2(__m128i *mm0, __m128i *pp0, int ntraceback, unsigned char *outbuf) { +#else +unsigned char +viterbi_decoder::viterbi_get_output_generic(unsigned char *mm0, + unsigned char *pp0, int ntraceback, unsigned char *outbuf) { +#endif int i; 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; +#ifdef IEEE80211_MSSE2 for (i = 0; i < 4; i++) { _mm_store_si128((__m128i *) &d_mmresult[i*16], mm0[i]); _mm_store_si128((__m128i *) &d_ppresult[d_store_pos][i*16], pp0[i]); } +#else + 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]; + } + } +#endif // Find out the best final state bestmetric = d_mmresult[beststate]; @@ -241,12 +454,21 @@ viterbi_decoder::viterbi_get_output_sse2(__m128i *mm0, __m128i *pp0, // Store output byte *outbuf = d_ppresult[pos][beststate]; +#ifdef IEEE80211_MSSE2 // Zero out the path variable // and prevent metric overflow for (i = 0; i < 4; i++) { pp0[i] = _mm_setzero_si128(); mm0[i] = _mm_sub_epi8(mm0[i], _mm_set1_epi8(minmetric)); } +#else + 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; + } + } +#endif return bestmetric; } @@ -303,12 +525,21 @@ viterbi_decoder::decode(ofdm_param *ofdm, frame_param *frame, uint8_t *in) { while(n_decoded < d_frame->n_data_bits) { if ((in_count % 4) == 0) { //0 or 3 +#ifdef IEEE80211_MSSE2 viterbi_butterfly2_sse2(&depunctured[in_count & 0xfffffffc], d_metric0, d_metric1, d_path0, d_path1); +#else + viterbi_butterfly2_generic(&depunctured[in_count & 0xfffffffc], d_metric0_generic, d_metric1_generic, + d_path0_generic, d_path1_generic); +#endif if ((in_count > 0) && (in_count % 16) == 8) { // 8 or 11 unsigned char c; +#ifdef IEEE80211_MSSE2 viterbi_get_output_sse2(d_metric0, d_path0, d_ntraceback, &c); +#else + viterbi_get_output_generic(d_metric0_generic, d_path0_generic, d_ntraceback, &c); +#endif if (out_count >= d_ntraceback) { for (int i= 0; i < 8; i++) { @@ -328,7 +559,11 @@ viterbi_decoder::decode(ofdm_param *ofdm, frame_param *frame, uint8_t *in) { void viterbi_decoder::reset() { +#ifdef IEEE80211_MSSE2 viterbi_chunks_init_sse2(); +#else + viterbi_chunks_init_generic(); +#endif switch(d_ofdm->encoding) { case BPSK_1_2: @@ -354,10 +589,17 @@ viterbi_decoder::reset() { } } -void // Initialize starting metrics to prefer 0 state +// Initialize starting metrics to prefer 0 state +#ifdef IEEE80211_MSSE2 +void viterbi_decoder::viterbi_chunks_init_sse2() { +#else +void +viterbi_decoder::viterbi_chunks_init_generic() { +#endif int i, j; +#ifdef IEEE80211_MSSE2 for (i = 0; i < 4; i++) { d_metric0[i] = _mm_setzero_si128(); d_path0[i] = _mm_setzero_si128(); @@ -368,6 +610,18 @@ viterbi_decoder::viterbi_chunks_init_sse2() { d_branchtab27_sse2[0].c[i] = (polys[0] < 0) ^ PARTAB[(2*i) & abs(polys[0])] ? 1 : 0; d_branchtab27_sse2[1].c[i] = (polys[1] < 0) ^ PARTAB[(2*i) & abs(polys[1])] ? 1 : 0; } +#else + 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; + } +#endif for (i = 0; i < 64; i++) { d_mmresult[i] = 0; diff --git a/lib/viterbi_decoder.h b/lib/viterbi_decoder.h index 57cc513..f3df822 100644 --- a/lib/viterbi_decoder.h +++ b/lib/viterbi_decoder.h @@ -17,7 +17,9 @@ #ifndef INCLUDED_IEEE802_11_VITERBI_DECODER_H #define INCLUDED_IEEE802_11_VITERBI_DECODER_H +#ifdef IEEE80211_MSSE2 #include +#endif #include "utils.h" namespace gr { @@ -50,15 +52,28 @@ private: unsigned char d_ppresult[TRACEBACK_MAX][64] __attribute__((aligned(16))); +#ifdef IEEE80211_MSSE2 union branchtab27 { unsigned char c[32]; __m128i v[2]; } d_branchtab27_sse2[2]; +#else + union branchtab27 { + unsigned char c[32]; + } d_branchtab27_generic[2]; +#endif +#ifdef IEEE80211_MSSE2 __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))); +#else + 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))); +#endif int d_ntraceback; int d_k; @@ -76,11 +91,21 @@ private: void reset(); uint8_t* depuncture(uint8_t *in); + +#ifdef IEEE80211_MSSE2 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); +#else + 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); +#endif }; } // namespace ieee802_11 From 9cf628359b6843736678328f9774985b33e2019e Mon Sep 17 00:00:00 2001 From: Stephen Wolfe Date: Thu, 3 Nov 2016 21:35:29 -0400 Subject: [PATCH 2/3] viterbi decoder: separate viterbi implementations reorganizes viterbi decoder source so that each implementation resides in a separate file. --- lib/CMakeLists.txt | 12 +- lib/decode_mac.cc | 2 +- lib/frame_equalizer_impl.h | 2 +- lib/viterbi_decoder/viterbi_decoder.h | 26 ++ .../viterbi_decoder_generic.cc} | 161 ------- .../viterbi_decoder_generic.h} | 31 +- lib/viterbi_decoder/viterbi_decoder_x86.cc | 422 ++++++++++++++++++ lib/viterbi_decoder/viterbi_decoder_x86.h | 90 ++++ 8 files changed, 554 insertions(+), 192 deletions(-) create mode 100644 lib/viterbi_decoder/viterbi_decoder.h rename lib/{viterbi_decoder.cc => viterbi_decoder/viterbi_decoder_generic.cc} (72%) rename lib/{viterbi_decoder.h => viterbi_decoder/viterbi_decoder_generic.h} (75%) create mode 100644 lib/viterbi_decoder/viterbi_decoder_x86.cc create mode 100644 lib/viterbi_decoder/viterbi_decoder_x86.h diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 9b1bfc2..7206bc9 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -120,9 +120,19 @@ list(APPEND gr_ieee802_11_sources sync_long.cc sync_short.cc utils.cc - viterbi_decoder.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 ${Boost_LIBRARIES} ${GNURADIO_ALL_LIBRARIES} diff --git a/lib/decode_mac.cc b/lib/decode_mac.cc index 1a58a83..4b7795e 100644 --- a/lib/decode_mac.cc +++ b/lib/decode_mac.cc @@ -17,7 +17,7 @@ #include #include "utils.h" -#include "viterbi_decoder.h" +#include "viterbi_decoder/viterbi_decoder.h" #include #include diff --git a/lib/frame_equalizer_impl.h b/lib/frame_equalizer_impl.h index 86ea4dc..3670f3f 100644 --- a/lib/frame_equalizer_impl.h +++ b/lib/frame_equalizer_impl.h @@ -21,7 +21,7 @@ #include #include #include "equalizer/base.h" -#include "viterbi_decoder.h" +#include "viterbi_decoder/viterbi_decoder.h" namespace gr { namespace ieee802_11 { diff --git a/lib/viterbi_decoder/viterbi_decoder.h b/lib/viterbi_decoder/viterbi_decoder.h new file mode 100644 index 0000000..7f12431 --- /dev/null +++ b/lib/viterbi_decoder/viterbi_decoder.h @@ -0,0 +1,26 @@ +/* + * 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_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 */ diff --git a/lib/viterbi_decoder.cc b/lib/viterbi_decoder/viterbi_decoder_generic.cc similarity index 72% rename from lib/viterbi_decoder.cc rename to lib/viterbi_decoder/viterbi_decoder_generic.cc index a87480d..a879ef9 100644 --- a/lib/viterbi_decoder.cc +++ b/lib/viterbi_decoder/viterbi_decoder_generic.cc @@ -90,114 +90,6 @@ viterbi_decoder::viterbi_decoder() : viterbi_decoder::~viterbi_decoder() { } -#ifdef IEEE80211_MSSE2 -void -viterbi_decoder::viterbi_butterfly2_sse2(unsigned char *symbols, - __m128i *mm0, __m128i *mm1, __m128i *pp0, __m128i *pp1) { - int i; - - __m128i *metric0, *metric1; - __m128i *path0, *path1; - - metric0 = mm0; - path0 = pp0; - metric1 = mm1; - path1 = pp1; - - // Operate on 4 symbols (2 bits) at a time - - __m128i m0, m1, m2, m3, decision0, decision1, survivor0, survivor1; - __m128i metsv, metsvm; - __m128i shift0, shift1; - __m128i tmp0, tmp1; - __m128i sym0v, sym1v; - - sym0v = _mm_set1_epi8(symbols[0]); - sym1v = _mm_set1_epi8(symbols[1]); - - for (i = 0; i < 2; i++) { - if (symbols[0] == 2) { - metsvm = _mm_xor_si128(d_branchtab27_sse2[1].v[i],sym1v); - metsv = _mm_sub_epi8(_mm_set1_epi8(1),metsvm); - } else if (symbols[1] == 2) { - metsvm = _mm_xor_si128(d_branchtab27_sse2[0].v[i],sym0v); - metsv = _mm_sub_epi8(_mm_set1_epi8(1),metsvm); - } else { - metsvm = _mm_add_epi8(_mm_xor_si128(d_branchtab27_sse2[0].v[i],sym0v),_mm_xor_si128(d_branchtab27_sse2[1].v[i],sym1v)); - metsv = _mm_sub_epi8(_mm_set1_epi8(2),metsvm); - } - - m0 = _mm_add_epi8(metric0[i], metsv); - m1 = _mm_add_epi8(metric0[i+2], metsvm); - m2 = _mm_add_epi8(metric0[i], metsvm); - m3 = _mm_add_epi8(metric0[i+2], metsv); - - decision0 = _mm_cmpgt_epi8(_mm_sub_epi8(m0,m1),_mm_setzero_si128()); - decision1 = _mm_cmpgt_epi8(_mm_sub_epi8(m2,m3),_mm_setzero_si128()); - survivor0 = _mm_or_si128(_mm_and_si128(decision0,m0),_mm_andnot_si128(decision0,m1)); - survivor1 = _mm_or_si128(_mm_and_si128(decision1,m2),_mm_andnot_si128(decision1,m3)); - - shift0 = _mm_slli_epi16(path0[i], 1); - shift1 = _mm_slli_epi16(path0[2+i], 1); - shift1 = _mm_add_epi8(shift1, _mm_set1_epi8(1)); - - metric1[2*i] = _mm_unpacklo_epi8(survivor0,survivor1); - tmp0 = _mm_or_si128(_mm_and_si128(decision0,shift0),_mm_andnot_si128(decision0,shift1)); - - metric1[2*i+1] = _mm_unpackhi_epi8(survivor0,survivor1); - tmp1 = _mm_or_si128(_mm_and_si128(decision1,shift0),_mm_andnot_si128(decision1,shift1)); - - path1[2*i] = _mm_unpacklo_epi8(tmp0, tmp1); - path1[2*i+1] = _mm_unpackhi_epi8(tmp0, tmp1); - } - - metric0 = mm1; - path0 = pp1; - metric1 = mm0; - path1 = pp0; - - sym0v = _mm_set1_epi8(symbols[2]); - sym1v = _mm_set1_epi8(symbols[3]); - - for (i = 0; i < 2; i++) { - if (symbols[2] == 2) { - metsvm = _mm_xor_si128(d_branchtab27_sse2[1].v[i],sym1v); - metsv = _mm_sub_epi8(_mm_set1_epi8(1),metsvm); - - } else if (symbols[3] == 2) { - metsvm = _mm_xor_si128(d_branchtab27_sse2[0].v[i],sym0v); - metsv = _mm_sub_epi8(_mm_set1_epi8(1),metsvm); - - } else { - metsvm = _mm_add_epi8(_mm_xor_si128(d_branchtab27_sse2[0].v[i],sym0v),_mm_xor_si128(d_branchtab27_sse2[1].v[i],sym1v)); - metsv = _mm_sub_epi8(_mm_set1_epi8(2),metsvm); - } - - m0 = _mm_add_epi8(metric0[i], metsv); - m1 = _mm_add_epi8(metric0[i+2], metsvm); - m2 = _mm_add_epi8(metric0[i], metsvm); - m3 = _mm_add_epi8(metric0[i+2], metsv); - - decision0 = _mm_cmpgt_epi8(_mm_sub_epi8(m0,m1),_mm_setzero_si128()); - decision1 = _mm_cmpgt_epi8(_mm_sub_epi8(m2,m3),_mm_setzero_si128()); - survivor0 = _mm_or_si128(_mm_and_si128(decision0,m0),_mm_andnot_si128(decision0,m1)); - survivor1 = _mm_or_si128(_mm_and_si128(decision1,m2),_mm_andnot_si128(decision1,m3)); - - shift0 = _mm_slli_epi16(path0[i], 1); - shift1 = _mm_slli_epi16(path0[2+i], 1); - shift1 = _mm_add_epi8(shift1, _mm_set1_epi8(1)); - - metric1[2*i] = _mm_unpacklo_epi8(survivor0,survivor1); - tmp0 = _mm_or_si128(_mm_and_si128(decision0,shift0),_mm_andnot_si128(decision0,shift1)); - - metric1[2*i+1] = _mm_unpackhi_epi8(survivor0,survivor1); - tmp1 = _mm_or_si128(_mm_and_si128(decision1,shift0),_mm_andnot_si128(decision1,shift1)); - - path1[2*i] = _mm_unpacklo_epi8(tmp0, tmp1); - path1[2*i+1] = _mm_unpackhi_epi8(tmp0, tmp1); - } -} -#else void viterbi_decoder::viterbi_butterfly2_generic(unsigned char *symbols, unsigned char *mm0, unsigned char *mm1, unsigned char *pp0, @@ -391,18 +283,11 @@ viterbi_decoder::viterbi_butterfly2_generic(unsigned char *symbols, } } } -#endif // Find current best path -#ifdef IEEE80211_MSSE2 -unsigned char -viterbi_decoder::viterbi_get_output_sse2(__m128i *mm0, __m128i *pp0, - int ntraceback, unsigned char *outbuf) { -#else unsigned char viterbi_decoder::viterbi_get_output_generic(unsigned char *mm0, unsigned char *pp0, int ntraceback, unsigned char *outbuf) { -#endif int i; int bestmetric, minmetric; int beststate = 0; @@ -414,19 +299,12 @@ viterbi_decoder::viterbi_get_output_generic(unsigned char *mm0, // circular buffer with the last ntraceback paths d_store_pos = (d_store_pos + 1) % ntraceback; -#ifdef IEEE80211_MSSE2 - for (i = 0; i < 4; i++) { - _mm_store_si128((__m128i *) &d_mmresult[i*16], mm0[i]); - _mm_store_si128((__m128i *) &d_ppresult[d_store_pos][i*16], pp0[i]); - } -#else 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]; } } -#endif // Find out the best final state bestmetric = d_mmresult[beststate]; @@ -454,21 +332,12 @@ viterbi_decoder::viterbi_get_output_generic(unsigned char *mm0, // Store output byte *outbuf = d_ppresult[pos][beststate]; -#ifdef IEEE80211_MSSE2 - // Zero out the path variable - // and prevent metric overflow - for (i = 0; i < 4; i++) { - pp0[i] = _mm_setzero_si128(); - mm0[i] = _mm_sub_epi8(mm0[i], _mm_set1_epi8(minmetric)); - } -#else 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; } } -#endif return bestmetric; } @@ -525,21 +394,13 @@ viterbi_decoder::decode(ofdm_param *ofdm, frame_param *frame, uint8_t *in) { while(n_decoded < d_frame->n_data_bits) { if ((in_count % 4) == 0) { //0 or 3 -#ifdef IEEE80211_MSSE2 - viterbi_butterfly2_sse2(&depunctured[in_count & 0xfffffffc], d_metric0, d_metric1, d_path0, d_path1); -#else viterbi_butterfly2_generic(&depunctured[in_count & 0xfffffffc], d_metric0_generic, d_metric1_generic, d_path0_generic, d_path1_generic); -#endif if ((in_count > 0) && (in_count % 16) == 8) { // 8 or 11 unsigned char c; -#ifdef IEEE80211_MSSE2 - viterbi_get_output_sse2(d_metric0, d_path0, d_ntraceback, &c); -#else viterbi_get_output_generic(d_metric0_generic, d_path0_generic, d_ntraceback, &c); -#endif if (out_count >= d_ntraceback) { for (int i= 0; i < 8; i++) { @@ -559,11 +420,7 @@ viterbi_decoder::decode(ofdm_param *ofdm, frame_param *frame, uint8_t *in) { void viterbi_decoder::reset() { -#ifdef IEEE80211_MSSE2 - viterbi_chunks_init_sse2(); -#else viterbi_chunks_init_generic(); -#endif switch(d_ofdm->encoding) { case BPSK_1_2: @@ -590,27 +447,10 @@ viterbi_decoder::reset() { } // Initialize starting metrics to prefer 0 state -#ifdef IEEE80211_MSSE2 -void -viterbi_decoder::viterbi_chunks_init_sse2() { -#else void viterbi_decoder::viterbi_chunks_init_generic() { -#endif int i, j; -#ifdef IEEE80211_MSSE2 - for (i = 0; i < 4; i++) { - d_metric0[i] = _mm_setzero_si128(); - d_path0[i] = _mm_setzero_si128(); - } - - int polys[2] = { 0x6d, 0x4f }; - for(i=0; i < 32; i++) { - d_branchtab27_sse2[0].c[i] = (polys[0] < 0) ^ PARTAB[(2*i) & abs(polys[0])] ? 1 : 0; - d_branchtab27_sse2[1].c[i] = (polys[1] < 0) ^ PARTAB[(2*i) & abs(polys[1])] ? 1 : 0; - } -#else for (i = 0; i < 4; i++) { d_metric0_generic[i] = 0; d_path0_generic[i] = 0; @@ -621,7 +461,6 @@ viterbi_decoder::viterbi_chunks_init_generic() { 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; } -#endif for (i = 0; i < 64; i++) { d_mmresult[i] = 0; diff --git a/lib/viterbi_decoder.h b/lib/viterbi_decoder/viterbi_decoder_generic.h similarity index 75% rename from lib/viterbi_decoder.h rename to lib/viterbi_decoder/viterbi_decoder_generic.h index f3df822..adea66e 100644 --- a/lib/viterbi_decoder.h +++ b/lib/viterbi_decoder/viterbi_decoder_generic.h @@ -14,12 +14,9 @@ * 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_H -#define INCLUDED_IEEE802_11_VITERBI_DECODER_H +#ifndef INCLUDED_IEEE802_11_VITERBI_DECODER_GENERIC_H +#define INCLUDED_IEEE802_11_VITERBI_DECODER_GENERIC_H -#ifdef IEEE80211_MSSE2 -#include -#endif #include "utils.h" namespace gr { @@ -52,28 +49,14 @@ private: unsigned char d_ppresult[TRACEBACK_MAX][64] __attribute__((aligned(16))); -#ifdef IEEE80211_MSSE2 - union branchtab27 { - unsigned char c[32]; - __m128i v[2]; - } d_branchtab27_sse2[2]; -#else union branchtab27 { unsigned char c[32]; } d_branchtab27_generic[2]; -#endif -#ifdef IEEE80211_MSSE2 - __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))); -#else 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))); -#endif int d_ntraceback; int d_k; @@ -92,23 +75,15 @@ private: void reset(); uint8_t* depuncture(uint8_t *in); -#ifdef IEEE80211_MSSE2 - 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); -#else 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); -#endif }; } // namespace ieee802_11 } // namespace gr -#endif /* INCLUDED_IEEE802_11_VITERBI_DECODER_H */ +#endif /* INCLUDED_IEEE802_11_VITERBI_DECODER_GENERIC_H */ diff --git a/lib/viterbi_decoder/viterbi_decoder_x86.cc b/lib/viterbi_decoder/viterbi_decoder_x86.cc new file mode 100644 index 0000000..796f76f --- /dev/null +++ b/lib/viterbi_decoder/viterbi_decoder_x86.cc @@ -0,0 +1,422 @@ +/* + * 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.h" +#include +#include + +/* 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; + + +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) { + int i; + + __m128i *metric0, *metric1; + __m128i *path0, *path1; + + metric0 = mm0; + path0 = pp0; + metric1 = mm1; + path1 = pp1; + + // Operate on 4 symbols (2 bits) at a time + + __m128i m0, m1, m2, m3, decision0, decision1, survivor0, survivor1; + __m128i metsv, metsvm; + __m128i shift0, shift1; + __m128i tmp0, tmp1; + __m128i sym0v, sym1v; + + sym0v = _mm_set1_epi8(symbols[0]); + sym1v = _mm_set1_epi8(symbols[1]); + + for (i = 0; i < 2; i++) { + if (symbols[0] == 2) { + metsvm = _mm_xor_si128(d_branchtab27_sse2[1].v[i],sym1v); + metsv = _mm_sub_epi8(_mm_set1_epi8(1),metsvm); + } else if (symbols[1] == 2) { + metsvm = _mm_xor_si128(d_branchtab27_sse2[0].v[i],sym0v); + metsv = _mm_sub_epi8(_mm_set1_epi8(1),metsvm); + } else { + metsvm = _mm_add_epi8(_mm_xor_si128(d_branchtab27_sse2[0].v[i],sym0v),_mm_xor_si128(d_branchtab27_sse2[1].v[i],sym1v)); + metsv = _mm_sub_epi8(_mm_set1_epi8(2),metsvm); + } + + m0 = _mm_add_epi8(metric0[i], metsv); + m1 = _mm_add_epi8(metric0[i+2], metsvm); + m2 = _mm_add_epi8(metric0[i], metsvm); + m3 = _mm_add_epi8(metric0[i+2], metsv); + + decision0 = _mm_cmpgt_epi8(_mm_sub_epi8(m0,m1),_mm_setzero_si128()); + decision1 = _mm_cmpgt_epi8(_mm_sub_epi8(m2,m3),_mm_setzero_si128()); + survivor0 = _mm_or_si128(_mm_and_si128(decision0,m0),_mm_andnot_si128(decision0,m1)); + survivor1 = _mm_or_si128(_mm_and_si128(decision1,m2),_mm_andnot_si128(decision1,m3)); + + shift0 = _mm_slli_epi16(path0[i], 1); + shift1 = _mm_slli_epi16(path0[2+i], 1); + shift1 = _mm_add_epi8(shift1, _mm_set1_epi8(1)); + + metric1[2*i] = _mm_unpacklo_epi8(survivor0,survivor1); + tmp0 = _mm_or_si128(_mm_and_si128(decision0,shift0),_mm_andnot_si128(decision0,shift1)); + + metric1[2*i+1] = _mm_unpackhi_epi8(survivor0,survivor1); + tmp1 = _mm_or_si128(_mm_and_si128(decision1,shift0),_mm_andnot_si128(decision1,shift1)); + + path1[2*i] = _mm_unpacklo_epi8(tmp0, tmp1); + path1[2*i+1] = _mm_unpackhi_epi8(tmp0, tmp1); + } + + metric0 = mm1; + path0 = pp1; + metric1 = mm0; + path1 = pp0; + + sym0v = _mm_set1_epi8(symbols[2]); + sym1v = _mm_set1_epi8(symbols[3]); + + for (i = 0; i < 2; i++) { + if (symbols[2] == 2) { + metsvm = _mm_xor_si128(d_branchtab27_sse2[1].v[i],sym1v); + metsv = _mm_sub_epi8(_mm_set1_epi8(1),metsvm); + + } else if (symbols[3] == 2) { + metsvm = _mm_xor_si128(d_branchtab27_sse2[0].v[i],sym0v); + metsv = _mm_sub_epi8(_mm_set1_epi8(1),metsvm); + + } else { + metsvm = _mm_add_epi8(_mm_xor_si128(d_branchtab27_sse2[0].v[i],sym0v),_mm_xor_si128(d_branchtab27_sse2[1].v[i],sym1v)); + metsv = _mm_sub_epi8(_mm_set1_epi8(2),metsvm); + } + + m0 = _mm_add_epi8(metric0[i], metsv); + m1 = _mm_add_epi8(metric0[i+2], metsvm); + m2 = _mm_add_epi8(metric0[i], metsvm); + m3 = _mm_add_epi8(metric0[i+2], metsv); + + decision0 = _mm_cmpgt_epi8(_mm_sub_epi8(m0,m1),_mm_setzero_si128()); + decision1 = _mm_cmpgt_epi8(_mm_sub_epi8(m2,m3),_mm_setzero_si128()); + survivor0 = _mm_or_si128(_mm_and_si128(decision0,m0),_mm_andnot_si128(decision0,m1)); + survivor1 = _mm_or_si128(_mm_and_si128(decision1,m2),_mm_andnot_si128(decision1,m3)); + + shift0 = _mm_slli_epi16(path0[i], 1); + shift1 = _mm_slli_epi16(path0[2+i], 1); + shift1 = _mm_add_epi8(shift1, _mm_set1_epi8(1)); + + metric1[2*i] = _mm_unpacklo_epi8(survivor0,survivor1); + tmp0 = _mm_or_si128(_mm_and_si128(decision0,shift0),_mm_andnot_si128(decision0,shift1)); + + metric1[2*i+1] = _mm_unpackhi_epi8(survivor0,survivor1); + tmp1 = _mm_or_si128(_mm_and_si128(decision1,shift0),_mm_andnot_si128(decision1,shift1)); + + path1[2*i] = _mm_unpacklo_epi8(tmp0, tmp1); + path1[2*i+1] = _mm_unpackhi_epi8(tmp0, tmp1); + } +} + +// Find current best path +unsigned char +viterbi_decoder::viterbi_get_output_sse2(__m128i *mm0, __m128i *pp0, + int ntraceback, unsigned char *outbuf) { + int i; + 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; + + for (i = 0; i < 4; i++) { + _mm_store_si128((__m128i *) &d_mmresult[i*16], mm0[i]); + _mm_store_si128((__m128i *) &d_ppresult[d_store_pos][i*16], pp0[i]); + } + + // 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]; + + // Zero out the path variable + // and prevent metric overflow + for (i = 0; i < 4; i++) { + pp0[i] = _mm_setzero_si128(); + mm0[i] = _mm_sub_epi8(mm0[i], _mm_set1_epi8(minmetric)); + } + + 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) { + + 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_sse2(&depunctured[in_count & 0xfffffffc], d_metric0, d_metric1, d_path0, d_path1); + + if ((in_count > 0) && (in_count % 16) == 8) { // 8 or 11 + unsigned char c; + + viterbi_get_output_sse2(d_metric0, d_path0, 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_sse2(); + + 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_sse2() { + int i, j; + + for (i = 0; i < 4; i++) { + d_metric0[i] = _mm_setzero_si128(); + d_path0[i] = _mm_setzero_si128(); + } + + int polys[2] = { 0x6d, 0x4f }; + for(i=0; i < 32; i++) { + d_branchtab27_sse2[0].c[i] = (polys[0] < 0) ^ PARTAB[(2*i) & abs(polys[0])] ? 1 : 0; + d_branchtab27_sse2[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; + } + } +} + + +/* 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 new file mode 100644 index 0000000..3d18fb6 --- /dev/null +++ b/lib/viterbi_decoder/viterbi_decoder_x86.h @@ -0,0 +1,90 @@ +/* + * 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_X86_H +#define INCLUDED_IEEE802_11_VITERBI_DECODER_X86_H + +#include +#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 viterbi_decoder +{ +public: + + viterbi_decoder(); + virtual ~viterbi_decoder(); + + 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]; + } 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_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_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 */ From 528536e3f2ce50bc18f9b3c00015c1b37c2f66a2 Mon Sep 17 00:00:00 2001 From: Stephen Wolfe Date: Mon, 7 Nov 2016 15:00:30 -0500 Subject: [PATCH 3/3] 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,