From 86caa06ce8af752054789db4624efedda036adee Mon Sep 17 00:00:00 2001 From: Aang23 Date: Wed, 21 Jul 2021 15:36:44 +0200 Subject: [PATCH] Get around the viterbi kernel issue in Volk --- README.md | 11 -- .../codings/viterbi/cc_decoder_impl.cpp | 32 +++- .../viterbi/volk_k7_r2_generic_fixed.h | 176 ++++++++++++++++++ 3 files changed, 207 insertions(+), 12 deletions(-) create mode 100644 src-core/common/codings/viterbi/volk_k7_r2_generic_fixed.h diff --git a/README.md b/README.md index 0bdc48a3a..e04f05d83 100644 --- a/README.md +++ b/README.md @@ -4,17 +4,6 @@ A generic satellite data processing software. **Still WIP** -# Important - Possible issues with VOLK Viterbi decoding (Windows users can probably ignore this) - -/!\ Some decoders utilize VOLK's Viterbi decoder. But as of writing this, only the "spiral" (SSE) implementation performs as intended. Please ensure you have it set as such in your volk_config or things may not work as expected! /!\ - -On Windows, this should not be necessary as it this will (should!) be the default already. - -On Linux, Mac OS and similar platforms, please edit your ~/.volk/volk_config file. -Find the line referring to `volk_8u_x4_conv_k7_r2_8u`, and make sure it contains the following : `volk_8u_x4_conv_k7_r2_8u spiral spiral`. - -If you are using an ARM-based machine (Raspbery Pi, most Android devices), there is unfortunately no way around poorer decoding performances of the "generic" kernel... Until this gets fixed in VOLK itself. - # Usage First of all, as with any program using volk, running volk_profile once is highly recommended for better performances. diff --git a/src-core/common/codings/viterbi/cc_decoder_impl.cpp b/src-core/common/codings/viterbi/cc_decoder_impl.cpp index 6539ded1e..d4e258061 100644 --- a/src-core/common/codings/viterbi/cc_decoder_impl.cpp +++ b/src-core/common/codings/viterbi/cc_decoder_impl.cpp @@ -15,6 +15,8 @@ #include #include #include +#include "logger.h" +#include "volk_k7_r2_generic_fixed.h" namespace fec { @@ -122,7 +124,35 @@ namespace fec d_SUBSHIFT = 0; } - std::map yp_kernel = {{"k=7r=2", volk_8u_x4_conv_k7_r2_8u}}; + conv_kernel k7_r2_kernel = volk_fixed::volk_8u_x4_conv_k7_r2_8u_generic; // Default to our fixed generic kernel + + // We need to get around Volk's broken generic and AVX kernel.... + { + volk_func_desc k7_r2_desc = volk_8u_x4_conv_k7_r2_8u_get_func_desc(); // Check what kernels are available + + bool has_spiral = false; + + for (int i = 0; i < (int)k7_r2_desc.n_impls; i++) + { + if (std::string(k7_r2_desc.impl_names[i]) == "spiral") // Try to find spiral + { + has_spiral = true; + break; + } + } + + if (has_spiral) + { // If spiral is available, use it + logger->trace("Volk has the spiral kernel using it!"); + k7_r2_kernel = volk_fixed::volk_8u_x4_conv_k7_r2_8u_spiral; + } + else + { // Stick to our fixed kernel + logger->trace("Volk does not have the spiral kernel, will default to bundled generic."); + } + } + + std::map yp_kernel = {{"k=7r=2", k7_r2_kernel}}; std::string k_ = "k="; std::string r_ = "r="; diff --git a/src-core/common/codings/viterbi/volk_k7_r2_generic_fixed.h b/src-core/common/codings/viterbi/volk_k7_r2_generic_fixed.h new file mode 100644 index 000000000..7d265fa72 --- /dev/null +++ b/src-core/common/codings/viterbi/volk_k7_r2_generic_fixed.h @@ -0,0 +1,176 @@ +/* -*- c++ -*- */ +/* + * Copyright 2014 Free Software Foundation, Inc. + * + * 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. + */ + +/*! + * \page volk_8u_x4_conv_k7_r2_8u + * + * \b Overview + * + * Performs convolutional decoding for a K=7, rate 1/2 convolutional + * code. The polynomials user defined. + * + * Dispatcher Prototype + * \code + * void volk_8u_x4_conv_k7_r2_8u(unsigned char* Y, unsigned char* X, unsigned char* syms, + * unsigned char* dec, unsigned int framebits, unsigned int excess, unsigned char* + * Branchtab) \endcode + * + * \b Inputs + * \li X: + * \li syms: + * \li dec: + * \li framebits: size of the frame to decode in bits. + * \li excess: + * \li Branchtab: + * + * \b Outputs + * \li Y: The decoded output bits. + * + * \b Example + * \code + * int N = 10000; + * + * volk_8u_x4_conv_k7_r2_8u(); + * + * volk_free(x); + * \endcode + */ + +// The default version in Volk is broken right now, so I am including this fix +// SatDump will default to unless volk_config returned a working implemenation + +#ifndef INCLUDED_volk_8u_x4_conv_k7_r2_8u_H +#define INCLUDED_volk_8u_x4_conv_k7_r2_8u_H + +#include + +namespace volk_fixed +{ + typedef union + { + unsigned char /*DECISIONTYPE*/ t[64 /*NUMSTATES*/ / 8 /*DECISIONTYPE_BITSIZE*/]; + unsigned int w[64 /*NUMSTATES*/ / 32]; + unsigned short s[64 /*NUMSTATES*/ / 16]; + unsigned char c[64 /*NUMSTATES*/ / 8]; +#ifdef _MSC_VER + } decision_t; +#else + } decision_t __attribute__((aligned(16))); +#endif + + static inline void renormalize(unsigned char *X, unsigned char /*threshold*/) + { + int NUMSTATES = 64; + int i; + + unsigned char min = X[0]; + // if(min > threshold) { + for (i = 0; i < NUMSTATES; i++) + if (min > X[i]) + min = X[i]; + for (i = 0; i < NUMSTATES; i++) + X[i] -= min; + //} + } + + // helper BFLY for GENERIC version + static inline void BFLY(int i, + int s, + unsigned char *syms, + unsigned char *Y, + unsigned char *X, + decision_t *d, + unsigned char *Branchtab) + { + int j, decision0, decision1; + unsigned char metric, m0, m1, m2, m3; + + int NUMSTATES = 64; + int RATE = 2; + int METRICSHIFT = 2; + int PRECISIONSHIFT = 2; + + metric = 0; + for (j = 0; j < RATE; j++) + metric += (Branchtab[i + j * NUMSTATES / 2] ^ syms[s * RATE + j]) >> METRICSHIFT; + metric = metric >> PRECISIONSHIFT; + + unsigned char max = ((RATE * ((256 - 1) >> METRICSHIFT)) >> PRECISIONSHIFT); + + m0 = X[i] + metric; + m1 = X[i + NUMSTATES / 2] + (max - metric); + m2 = X[i] + (max - metric); + m3 = X[i + NUMSTATES / 2] + metric; + + decision0 = (signed int)(m0 - m1) > 0; + decision1 = (signed int)(m2 - m3) > 0; + + Y[2 * i] = decision0 ? m1 : m0; + Y[2 * i + 1] = decision1 ? m3 : m2; + + d->w[i / (sizeof(unsigned int) * 8 / 2) + + s * (sizeof(decision_t) / sizeof(unsigned int))] |= + (decision0 | decision1 << 1) << ((2 * i) & (sizeof(unsigned int) * 8 - 1)); + } + + static inline void volk_8u_x4_conv_k7_r2_8u_generic(unsigned char *Y, + unsigned char *X, + unsigned char *syms, + unsigned char *dec, + unsigned int framebits, + unsigned int excess, + unsigned char *Branchtab) + { + int nbits = framebits + excess; + int NUMSTATES = 64; + int RENORMALIZE_THRESHOLD = 210; + + int s, i; + for (s = 0; s < nbits; s++) + { + void *tmp; + for (i = 0; i < NUMSTATES / 2; i++) + { + BFLY(i, s, syms, Y, X, (decision_t *)dec, Branchtab); + } + + renormalize(Y, RENORMALIZE_THRESHOLD); + + /// Swap pointers to old and new metrics + tmp = (void *)X; + X = Y; + Y = (unsigned char *)tmp; + } + } + + static inline void volk_8u_x4_conv_k7_r2_8u_spiral(unsigned char *Y, + unsigned char *X, + unsigned char *syms, + unsigned char *dec, + unsigned int framebits, + unsigned int excess, + unsigned char *Branchtab) + { + volk_8u_x4_conv_k7_r2_8u_manual(Y, X, syms, dec, framebits, excess, Branchtab, "spiral"); + } +}; +#endif /*INCLUDED_volk_8u_x4_conv_k7_r2_8u_H*/ \ No newline at end of file