diff --git a/examples/wifi_phy_hier.grc b/examples/wifi_phy_hier.grc
index 26d0447..3aac1e9 100644
--- a/examples/wifi_phy_hier.grc
+++ b/examples/wifi_phy_hier.grc
@@ -1339,7 +1339,7 @@
log
- True
+ False
maxoutbuf
diff --git a/include/ieee802-11/ofdm_decode_mac.h b/include/ieee802-11/ofdm_decode_mac.h
index 8cb193c..91fd353 100644
--- a/include/ieee802-11/ofdm_decode_mac.h
+++ b/include/ieee802-11/ofdm_decode_mac.h
@@ -30,6 +30,13 @@ public:
typedef boost::shared_ptr sptr;
static sptr make(bool log = false, bool debug = false);
+private:
+
+ // Puncturing vectors
+ static const unsigned char d_puncture_1_2[];
+ static const unsigned char d_puncture_2_3[];
+ static const unsigned char d_puncture_3_4[];
+
};
} // namespace ieee802_11
diff --git a/lib/ofdm_decode_mac.cc b/lib/ofdm_decode_mac.cc
index 23d419a..8c7f987 100644
--- a/lib/ofdm_decode_mac.cc
+++ b/lib/ofdm_decode_mac.cc
@@ -23,6 +23,17 @@
#include
#include
+
+static __m128i metric0[4] __attribute__ ((aligned(16)));
+static __m128i metric1[4] __attribute__ ((aligned(16)));
+static __m128i path0[4] __attribute__ ((aligned(16)));
+static __m128i path1[4] __attribute__ ((aligned(16)));
+struct viterbi_state state0[64];
+struct viterbi_state state1[64];
+static int d_init = 0;
+
+int decoded_count;
+
using namespace gr::ieee802_11;
using namespace itpp;
@@ -237,9 +248,6 @@ void demodulate() {
bits = to_vec(demodulate_64qam(symbols));
break;
}
-
- // I hate the guy who wrote itpp
- bits = bits * (-2) + 1;
}
void deinterleave() {
@@ -257,70 +265,173 @@ void deinterleave() {
second[i] = 16 * i - (n_cbps - 1) * int(floor(16.0 * i / n_cbps));
}
+ int count = 0;
for(int i = 0; i < d_tx.n_sym; i++) {
for(int k = 0; k < n_cbps; k++) {
- deinter[i * n_cbps + second[first[k]]] = bits[i * n_cbps + k];
+ if (bits[i * n_cbps + k] > 0)
+ {
+ d_tmp_inbits[i * n_cbps + second[first[k]]] = 0x01;
+ }
+ else
+ {
+ d_tmp_inbits[i * n_cbps + second[first[k]]] = 0x00;
+ }
}
}
+
+ // Set the appropiate coding rate for
+ // the convolutional decoder.
+ set_coding_rate();
+
+ if (d_ntraceback == 5)
+ {
+ count = d_tx.n_sym * n_cbps;
+ d_inbits = d_tmp_inbits;
+ }
+ else
+ {
+ d_inbits = d_inbits_punctured;
+ count = 0;
+ for(int i = 0; i < d_tx.n_sym; i++) {
+ for(int k = 0; k < n_cbps; k++) {
+ while (d_puncture[count % (2 * d_k)] == 0)
+ {
+ d_inbits[count] = 2;
+ count++;
+ }
+
+ // Insert received bits
+ d_inbits[count] = d_tmp_inbits[i * n_cbps + k];
+ count++;
+
+ while (d_puncture[count % (2 * d_k)] == 0)
+ {
+ d_inbits[count] = 2;
+ count++;
+ }
+ }
+ }
+ }
+
+ for (int i = count; i < NeededBits(); i++)
+ d_inbits[i] = 0x00;
}
-void decode_conv() {
- Punctured_Convolutional_Code code;
- ivec generator(2);
- generator(0)=0133;
- generator(1)=0171;
- code.set_generator_polynomials(generator, 7);
+int NeededBits()
+{
+ int return_value;
+ if (d_ntraceback == 5)
+ return_value = d_tx.n_encoded_bits / 2;
+ else if (d_ntraceback == 9)
+ {
+ return_value = (d_tx.n_encoded_bits / 3) * 2;
+ }
+ else // si d_ntraceback == 10
+ {
+ return_value = (d_tx.n_encoded_bits / 4) * 3;
+ }
+ return return_value;
+}
- bmat puncture_matrix;
+void decode_conv_viterbi() {
+
+ d_viterbi_chunks_init(state0);
+ d_viterbi_chunks_init_sse2(metric0, path0);
+
+ int out_count = 0;
+ decoded_count = 0;
+
+ int in_count = 0;
+ int neededBits = NeededBits();
+ while(decoded_count < neededBits)
+ {
+ if ((in_count % 4) == 0) //0 or 3
+ {
+ d_viterbi_butterfly2_sse2(&d_inbits[in_count & 0xfffffffc], metric0, metric1, path0, path1);
+
+ if ((in_count > 0) && (in_count % 16) == 8) // 8 or 11
+ {
+ unsigned char c;
+
+ d_viterbi_get_output_sse2(metric0, path0, d_ntraceback, &c);
+
+ if (d_init == 0)
+ {
+ if (out_count >= d_ntraceback)
+ {
+ for (int i= 0; i < 8; i++)
+ {
+ out_bytes_viterbi[(out_count - d_ntraceback) * 8 + i] = (c >> (7 - i)) & 0x1;
+ decoded_count++;
+ }
+ }
+ }
+ else
+ {
+ out_bytes_viterbi[out_count] = c;
+ for (int i= 0; i < 8; i++)
+ {
+ out_bytes_viterbi[out_count * 8 + i] = (c >> (7 - i)) & 0x1;
+ decoded_count++;
+ }
+ }
+ out_count++;
+ }
+ }
+ in_count++;
+ }
+}
+
+void set_coding_rate()
+{
switch(d_ofdm.encoding) {
case BPSK_1_2:
case QPSK_1_2:
case QAM16_1_2:
- puncture_matrix = "1 1; 1 1";
+ // Code rate 1/2
+ d_ntraceback = 5;
+ d_puncture = d_puncture_1_2;
+ d_k = 1;
+ break;
+ case QAM64_2_3:
+ // Code rate 2/3
+ d_ntraceback = 9;
+ d_puncture = d_puncture_2_3;
+ d_k = 2;
break;
case BPSK_3_4:
case QPSK_3_4:
case QAM16_3_4:
case QAM64_3_4:
- puncture_matrix = "1 1 0; 1 0 1;";
- break;
- case QAM64_2_3:
- puncture_matrix = "1 1 1 1 1 1; 1 0 1 0 1 0;";
+ // Code rate 3/4
+ d_ntraceback = 10;
+ d_puncture = d_puncture_3_4;
+ d_k = 3;
break;
}
- code.set_puncture_matrix(puncture_matrix);
- code.set_truncation_length(30);
+}
- dout << "coding rate " << code.get_rate() << std::endl;
- dout << d_tx.n_encoded_bits << std::endl;
-
- vec rx_signal(deinter, d_tx.n_encoded_bits);
-
- code.reset();
- decoded_bits.set_length(d_tx.n_encoded_bits);
- code.decode_tail(rx_signal, decoded_bits);
-
- //dout << "length decoded " << decoded_bits.size() << std::endl;
- //std::cout << decoded_bits << std::endl;
+void decode_conv() {
+ decode_conv_viterbi();
}
void descramble () {
int state = 0;
for(int i = 0; i < 7; i++) {
- if(decoded_bits(i)) {
+ if(out_bytes_viterbi[i]) {
state |= 1 << (6 - i);
}
}
int feedback;
- for(int i = 7; i < decoded_bits.size(); i++) {
+ for(int i = 7; i < decoded_count; i++) {
feedback = ((!!(state & 64))) ^ (!!(state & 8));
- out_bits[i] = feedback ^ (int)decoded_bits(i);
+ out_bits[i] = feedback ^ (out_bytes_viterbi[i] & 0x1);
state = ((state << 1) & 0x7e) | feedback;
}
- for(int i = 0; i < decoded_bits.size(); i++) {
+ for(int i = 0; i < decoded_count; i++) {
int bit = i % 8;
int byte = i / 8;
if(bit == 0) {
@@ -356,11 +467,24 @@ void print_output() {
private:
gr_complex sym[1000 * 48 * 100];
vec bits;
- double deinter[1000 * 48];
+ unsigned char* d_inbits;
+ unsigned char d_inbits_punctured[1000 * 48];
+ unsigned char d_tmp_inbits[1000 * 48];
char out_bits[40000];
char out_bytes[40000];
+ char out_bytes_viterbi[40000 * 8];
bvec decoded_bits;
+ int d_ntraceback;
+
+ // number of input bits in the convolutional encoder.
+ int d_k;
+
+ const unsigned char * d_puncture;
+ const unsigned char d_puncture_1_2[2] = {1, 1};
+ const unsigned char d_puncture_2_3[4] = {1, 1, 1, 0};
+ const unsigned char d_puncture_3_4[6] = {1, 1, 1, 0, 0, 1};
+
bool d_debug;
bool d_log;
tx_param d_tx;
diff --git a/lib/ofdm_mac.cc b/lib/ofdm_mac.cc
index 6f5ec7a..dec2262 100644
--- a/lib/ofdm_mac.cc
+++ b/lib/ofdm_mac.cc
@@ -73,7 +73,7 @@ void phy_in (pmt::pmt_t msg) {
// TODO: check for frame type to determine header size
pmt::pmt_t blob(pmt::cdr(msg));
const char *mpdu = reinterpret_cast(pmt::blob_data(blob));
- std::cout << "pdu len " << pmt::blob_length(blob) << std::endl;
+ //std::cout << "pdu len " << pmt::blob_length(blob) << std::endl;
pmt::pmt_t msdu = pmt::make_blob(mpdu + 24, pmt::blob_length(blob) - 24);
message_port_pub(pmt::mp("app out"), pmt::cons(pmt::car(msg), msdu));
diff --git a/lib/utils.cc b/lib/utils.cc
index f476af8..9c84ba0 100644
--- a/lib/utils.cc
+++ b/lib/utils.cc
@@ -340,3 +340,697 @@ void generate_bits(const char *psdu, char *data_bits, tx_param &tx) {
}
}
}
+/* Here starts the SSE2 Viterbi convolutional decoder implementation */
+/*
+ * 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
+
+/* The two generator polynomials for the NASA Standard K=7 code.
+ * Since these polynomials are known to be optimal for this constraint
+ * length there is not much point in changing them. But if you do, you
+ * will have to regenerate the BUTTERFLY macro calls in viterbi()
+ */
+#define POLYA 0x6d
+#define POLYB 0x4f
+
+/* 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.
+ */
+
+
+static union branchtab27 { unsigned char c[32]; __m128i v[2];} Branchtab27_sse2[2];
+
+// Maximum number of traceback bytes
+#define TRACEBACK_MAX 24
+// Metrics for each state
+static unsigned char mmresult[64] __attribute__((aligned(16))) = {0};
+// Paths for each state
+static unsigned char ppresult[TRACEBACK_MAX][64] __attribute__((aligned(16))) = {{0,0}};
+// Position in circular buffer where the current decoded byte is stored
+static int store_pos = 0;
+
+#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;\
+ }\
+}
+
+unsigned char d_Partab[] = {
+ 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,
+};/* Parity lookup table */
+
+/* Convolutionally encode data into binary symbols */
+unsigned char
+d_encode(unsigned char *symbols,
+ unsigned char *data,
+ unsigned int nbytes,
+ unsigned char encstate)
+{
+ int i;
+
+ while(nbytes-- != 0){
+ for(i=7;i>=0;i--){
+ encstate = (encstate << 1) | ((*data >> i) & 1);
+ *symbols++ = d_Partab[encstate & POLYA];
+ *symbols++ = d_Partab[encstate & POLYB];
+ }
+ data++;
+ }
+
+ return encstate;
+}
+
+/* Viterbi decoder */
+int
+d_viterbi(unsigned long *metric, /* Final path metric (returned value) */
+ unsigned char *data, /* Decoded output data */
+ unsigned char *symbols, /* Raw deinterleaved input symbols */
+ unsigned int nbits, /* Number of output bits */
+ int mettab[2][256] /* Metric table, [sent sym][rx symbol] */
+ ){
+ unsigned int bitcnt = 0;
+ int mets[4];
+ long bestmetric;
+ int beststate,i;
+ struct viterbi_state state0[64],state1[64],*state,*next;
+
+ state = state0;
+ next = state1;
+
+ /* Initialize starting metrics to prefer 0 state */
+ state[0].metric = 0;
+ for(i=1;i<64;i++)
+ state[i].metric = -999999;
+ state[0].path = 0;
+
+ for(bitcnt = 0;bitcnt < nbits;bitcnt++){
+ /* Read input symbol pair and compute all possible branch
+ * metrics
+ */
+ mets[0] = mettab[0][symbols[0]] + mettab[0][symbols[1]];
+ mets[1] = mettab[0][symbols[0]] + mettab[1][symbols[1]];
+ mets[2] = mettab[1][symbols[0]] + mettab[0][symbols[1]];
+ mets[3] = mettab[1][symbols[0]] + mettab[1][symbols[1]];
+ symbols += 2;
+
+BUTTERFLY(0,0); BUTTERFLY(1,1); BUTTERFLY(2,3); BUTTERFLY(3,2);
+BUTTERFLY(4,3); BUTTERFLY(5,2); BUTTERFLY(6,0); BUTTERFLY(7,1);
+BUTTERFLY(8,0); BUTTERFLY(9,1); BUTTERFLY(10,3); BUTTERFLY(11,2);
+BUTTERFLY(12,3); BUTTERFLY(13,2); BUTTERFLY(14,0); BUTTERFLY(15,1);
+BUTTERFLY(16,2); BUTTERFLY(17,3); BUTTERFLY(18,1); BUTTERFLY(19,0);
+BUTTERFLY(20,1); BUTTERFLY(21,0); BUTTERFLY(22,2); BUTTERFLY(23,3);
+BUTTERFLY(24,2); BUTTERFLY(25,3); BUTTERFLY(26,1); BUTTERFLY(27,0);
+BUTTERFLY(28,1); BUTTERFLY(29,0); BUTTERFLY(30,2); BUTTERFLY(31,3);
+
+ /* Swap current and next states */
+ if(bitcnt & 1){
+ state = state0;
+ next = state1;
+ } else {
+ state = state1;
+ next = state0;
+ }
+ // ETTUS
+ //if(bitcnt > nbits-7){
+ /* In tail, poison non-zero nodes */
+ //for(i=1;i<64;i += 2)
+ // state[i].metric = -9999999;
+ //}
+ /* Produce output every 8 bits once path memory is full */
+ if((bitcnt % 8) == 5 && bitcnt > 32){
+ /* Find current best path */
+ bestmetric = state[0].metric;
+ beststate = 0;
+ for(i=1;i<64;i++){
+ if(state[i].metric > bestmetric){
+ bestmetric = state[i].metric;
+ beststate = i;
+ }
+ }
+#ifdef notdef
+ printf("metrics[%d] = %d state = %lx\n",beststate,
+ state[beststate].metric,state[beststate].path);
+#endif
+ *data++ = state[beststate].path >> 24;
+ }
+
+ }
+ /* Output remaining bits from 0 state */
+ // ETTUS Find best state instead
+ bestmetric = state[0].metric;
+ beststate = 0;
+ for(i=1;i<64;i++){
+ if(state[i].metric > bestmetric){
+ bestmetric = state[i].metric;
+ beststate = i;
+ }
+ }
+ if((i = bitcnt % 8) != 6)
+ state[beststate].path <<= 6-i;
+
+ *data++ = state[beststate].path >> 24;
+ *data++ = state[beststate].path >> 16;
+ *data++ = state[beststate].path >> 8;
+ *data = state[beststate].path;
+ //printf ("BS = %d\tBSM = %d\tM0 = %d\n",beststate,state[beststate].metric,state[0].metric);
+ *metric = state[beststate].metric;
+ return 0;
+}
+
+void
+d_viterbi_chunks_init(struct viterbi_state* state) {
+ // Initialize starting metrics to prefer 0 state
+ int i;
+ state[0].metric = 0;
+ state[0].path = 0;
+ for(i=1;i<64;i++)
+ {
+ state[i].metric = 0;//-999999;
+ state[i].path = 0;
+ }
+}
+
+void
+d_viterbi_chunks_init_sse2(__m128i *mm0, __m128i *pp0) {
+ // Initialize starting metrics to prefer 0 state
+ int i, j;
+
+ for (i = 0; i < 4; i++)
+ {
+ mm0[i] = _mm_setzero_si128();
+ pp0[i] = _mm_setzero_si128();
+ }
+
+ int polys[2] = { POLYA, POLYB };
+ for(i=0; i < 32; i++)
+ {
+ Branchtab27_sse2[0].c[i] = (polys[0] < 0) ^ d_Partab[(2*i) & abs(polys[0])] ? 1 : 0;
+ Branchtab27_sse2[1].c[i] = (polys[1] < 0) ^ d_Partab[(2*i) & abs(polys[1])] ? 1 : 0;
+ }
+
+ for (i = 0; i < 64; i++)
+ {
+ mmresult[i] = 0;
+ for (j = 0; j < TRACEBACK_MAX; j++)
+ ppresult[j][i] = 0;
+ }
+}
+
+
+void
+d_viterbi_butterfly8(unsigned char *symbols, int mettab[2][256], struct viterbi_state *state0, struct viterbi_state *state1)
+{
+ unsigned int bitcnt;
+ int mets[4];
+
+ struct viterbi_state *state, *next;
+ state = state0;
+ next = state1;
+ // Operate on 16 symbols (8 bits) at a time
+ for(bitcnt = 0;bitcnt < 8;bitcnt++){
+ // Read input symbol pair and compute all possible branch metrics
+ mets[0] = mettab[0][symbols[0]] + mettab[0][symbols[1]];
+ mets[1] = mettab[0][symbols[0]] + mettab[1][symbols[1]];
+ mets[2] = mettab[1][symbols[0]] + mettab[0][symbols[1]];
+ mets[3] = mettab[1][symbols[0]] + mettab[1][symbols[1]];
+ symbols += 2;
+
+ // These macro calls were generated by genbut.c
+ BUTTERFLY(0,0); BUTTERFLY(1,1); BUTTERFLY(2,3); BUTTERFLY(3,2);
+BUTTERFLY(4,3); BUTTERFLY(5,2); BUTTERFLY(6,0); BUTTERFLY(7,1);
+BUTTERFLY(8,0); BUTTERFLY(9,1); BUTTERFLY(10,3); BUTTERFLY(11,2);
+BUTTERFLY(12,3); BUTTERFLY(13,2); BUTTERFLY(14,0); BUTTERFLY(15,1);
+BUTTERFLY(16,2); BUTTERFLY(17,3); BUTTERFLY(18,1); BUTTERFLY(19,0);
+BUTTERFLY(20,1); BUTTERFLY(21,0); BUTTERFLY(22,2); BUTTERFLY(23,3);
+BUTTERFLY(24,2); BUTTERFLY(25,3); BUTTERFLY(26,1); BUTTERFLY(27,0);
+BUTTERFLY(28,1); BUTTERFLY(29,0); BUTTERFLY(30,2); BUTTERFLY(31,3);
+
+ // Swap current and next states
+ if(bitcnt & 1){
+ state = state0;
+ next = state1;
+ } else {
+ state = state1;
+ next = state0;
+ }
+ }
+}
+
+void
+d_viterbi_butterfly2(unsigned char *symbols, int mettab[2][256], struct viterbi_state *state0, struct viterbi_state *state1)
+{
+ int mets[4];
+
+ struct viterbi_state *state, *next;
+ state = state0;
+ next = state1;
+
+ // Operate on 4 symbols (2 bits) at a time
+
+ // Read input symbol pair and compute all possible branch metrics
+#if 0
+ if (symbols[0] == 2)
+ {
+ mets[0] = mettab[0][symbols[1]];
+ mets[1] = mettab[1][symbols[1]];
+ mets[2] = mettab[0][symbols[1]];
+ mets[3] = mettab[1][symbols[1]];
+ }
+ else if (symbols[1] == 2)
+ {
+ mets[0] = mettab[0][symbols[0]];
+ mets[1] = mettab[1][symbols[0]];
+ mets[2] = mettab[0][symbols[0]];
+ mets[3] = mettab[1][symbols[0]];
+ }
+ else
+#endif
+ {
+ mets[0] = mettab[0][symbols[0]] + mettab[0][symbols[1]];
+ mets[1] = mettab[0][symbols[0]] + mettab[1][symbols[1]];
+ mets[2] = mettab[1][symbols[0]] + mettab[0][symbols[1]];
+ mets[3] = mettab[1][symbols[0]] + mettab[1][symbols[1]];
+ }
+
+ // These macro calls were generated by genbut.c
+BUTTERFLY(0,0); BUTTERFLY(1,1); BUTTERFLY(2,3); BUTTERFLY(3,2);
+BUTTERFLY(4,3); BUTTERFLY(5,2); BUTTERFLY(6,0); BUTTERFLY(7,1);
+BUTTERFLY(8,0); BUTTERFLY(9,1); BUTTERFLY(10,3); BUTTERFLY(11,2);
+BUTTERFLY(12,3); BUTTERFLY(13,2); BUTTERFLY(14,0); BUTTERFLY(15,1);
+BUTTERFLY(16,2); BUTTERFLY(17,3); BUTTERFLY(18,1); BUTTERFLY(19,0);
+BUTTERFLY(20,1); BUTTERFLY(21,0); BUTTERFLY(22,2); BUTTERFLY(23,3);
+BUTTERFLY(24,2); BUTTERFLY(25,3); BUTTERFLY(26,1); BUTTERFLY(27,0);
+BUTTERFLY(28,1); BUTTERFLY(29,0); BUTTERFLY(30,2); BUTTERFLY(31,3);
+
+ state = state1;
+ next = state0;
+
+ // Read input symbol pair and compute all possible branch metrics
+
+#if 0
+ if (symbols[2] == 2)
+ {
+ mets[0] = mettab[0][symbols[3]];
+ mets[1] = mettab[1][symbols[3]];
+ mets[2] = mettab[0][symbols[3]];
+ mets[3] = mettab[1][symbols[3]];
+ }
+ else if (symbols[3] == 2)
+ {
+ mets[0] = mettab[0][symbols[2]];
+ mets[1] = mettab[1][symbols[2]];
+ mets[2] = mettab[0][symbols[2]];
+ mets[3] = mettab[1][symbols[2]];
+ }
+ else
+#endif
+ {
+ mets[0] = mettab[0][symbols[2]] + mettab[0][symbols[3]];
+ mets[1] = mettab[0][symbols[2]] + mettab[1][symbols[3]];
+ mets[2] = mettab[1][symbols[2]] + mettab[0][symbols[3]];
+ mets[3] = mettab[1][symbols[2]] + mettab[1][symbols[3]];
+ }
+
+ // These macro calls were generated by genbut.c
+ BUTTERFLY(0,0); BUTTERFLY(1,1); BUTTERFLY(2,3); BUTTERFLY(3,2);
+BUTTERFLY(4,3); BUTTERFLY(5,2); BUTTERFLY(6,0); BUTTERFLY(7,1);
+BUTTERFLY(8,0); BUTTERFLY(9,1); BUTTERFLY(10,3); BUTTERFLY(11,2);
+BUTTERFLY(12,3); BUTTERFLY(13,2); BUTTERFLY(14,0); BUTTERFLY(15,1);
+BUTTERFLY(16,2); BUTTERFLY(17,3); BUTTERFLY(18,1); BUTTERFLY(19,0);
+BUTTERFLY(20,1); BUTTERFLY(21,0); BUTTERFLY(22,2); BUTTERFLY(23,3);
+BUTTERFLY(24,2); BUTTERFLY(25,3); BUTTERFLY(26,1); BUTTERFLY(27,0);
+BUTTERFLY(28,1); BUTTERFLY(29,0); BUTTERFLY(30,2); BUTTERFLY(31,3);
+}
+
+void
+d_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(Branchtab27_sse2[1].v[i],sym1v);
+ metsv = _mm_sub_epi8(_mm_set1_epi8(1),metsvm);
+ }
+ else if (symbols[1] == 2)
+ {
+ metsvm = _mm_xor_si128(Branchtab27_sse2[0].v[i],sym0v);
+ metsv = _mm_sub_epi8(_mm_set1_epi8(1),metsvm);
+ }
+ else
+ {
+ metsvm = _mm_add_epi8(_mm_xor_si128(Branchtab27_sse2[0].v[i],sym0v),_mm_xor_si128(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(Branchtab27_sse2[1].v[i],sym1v);
+ metsv = _mm_sub_epi8(_mm_set1_epi8(1),metsvm);
+ }
+ else if (symbols[3] == 2)
+ {
+ metsvm = _mm_xor_si128(Branchtab27_sse2[0].v[i],sym0v);
+ metsv = _mm_sub_epi8(_mm_set1_epi8(1),metsvm);
+ }
+ else
+ {
+ metsvm = _mm_add_epi8(_mm_xor_si128(Branchtab27_sse2[0].v[i],sym0v),_mm_xor_si128(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);
+ }
+}
+
+void
+d_viterbi_butterfly_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;
+
+ for (i = 0; i < 2; i++)
+ printf("symbols[%i]: %i\n", i, symbols[i]);
+
+
+ // 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 1
+ if (symbols[0] == 2)
+ {
+ metsvm = _mm_xor_si128(Branchtab27_sse2[1].v[i],sym1v);
+ }
+ else if (symbols[1] == 0)
+ {
+ metsvm = _mm_xor_si128(Branchtab27_sse2[0].v[i],sym0v);
+ }
+ else
+#endif
+ metsvm = _mm_add_epi8(_mm_xor_si128(Branchtab27_sse2[0].v[i],sym0v),_mm_xor_si128(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);
+ }
+
+ for (i = 0; i < 4; i++)
+ {
+ mm0[i] = metric1[i];
+ pp0[i] = path1[i];
+ }
+
+}
+
+
+unsigned char
+d_viterbi_get_output(struct viterbi_state *state, unsigned char *outbuf) {
+ // Produce output every 8 bits once path memory is full
+ // if((bitcnt % 8) == 5 && bitcnt > 32) {
+
+ // Find current best path
+ unsigned int i, beststate = 0;
+ int bestmetric;
+
+ bestmetric = state[0].metric;
+ beststate = 0;
+ for(i=1;i<64;i++)
+ {
+ if(state[i].metric > bestmetric) {
+ bestmetric = state[i].metric;
+ beststate = i;
+ }
+ }
+
+ *outbuf = state[beststate].path >> 24;
+
+ return bestmetric;
+}
+
+unsigned char
+d_viterbi_get_output_sse2(__m128i *mm0, __m128i *pp0, int ntraceback, unsigned char *outbuf) {
+ // Find current best path
+ int i;
+ int bestmetric, minmetric;
+ int beststate = 0;
+ int pos = 0;
+
+ // Implement a circular buffer with the last ntraceback paths
+ store_pos = (store_pos + 1) % ntraceback;
+
+ // TODO - find another way to extract the value
+ for (i = 0; i < 4; i++)
+ {
+ _mm_store_si128((__m128i *) &mmresult[i*16], mm0[i]);
+ _mm_store_si128((__m128i *) &ppresult[store_pos][i*16], pp0[i]);
+ }
+
+ // Find out the best final state
+ bestmetric = mmresult[beststate];
+ minmetric = mmresult[beststate];
+
+ for (i = 1; i < 64; i++)
+ {
+ if (mmresult[i] > bestmetric)
+ {
+ bestmetric = mmresult[i];
+ beststate = i;
+ }
+ if (mmresult[i] < minmetric)
+ minmetric = mmresult[i];
+ }
+
+ // Trace back
+ for (i = 0, pos = 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 = ppresult[pos][beststate] >> 2;
+ pos = (pos - 1 + ntraceback) % ntraceback;
+ }
+
+ // Store output byte
+ *outbuf = 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;
+}
+/* end of new functions */
diff --git a/lib/utils.h b/lib/utils.h
index ac3400d..c04c7ea 100644
--- a/lib/utils.h
+++ b/lib/utils.h
@@ -23,6 +23,9 @@
#include
#include
+// Needed for the SSE2 Viterbi decoder
+#include
+
const int MAX_SYM = 520; // enough for 1500 byte BPSK 1/2
const int MAX_BITS = 1550 * 8 * 2;
@@ -120,4 +123,66 @@ void split_symbols(const char *input, char *out, tx_param &tx, ofdm_param &ofdm)
void generate_bits(const char *psdu, char *data_bits, tx_param &tx);
+/* New functions for the SSE2 Convolutional Decoder */
+
+/* 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
+ */
+
+
+struct viterbi_state {
+ unsigned long path; /* Decoded path to this state */
+ long metric; /* Cumulative metric to this state */
+
+ /* vector implementation */
+ __m128i pp; /* Decoded path to this state */
+ __m128i mm; /* Cumulative metric to this state */
+};
+
+int d_gen_met(int mettab[2][256], /* Metric table */
+ int amp, /* Signal amplitude */
+ double esn0, /* Es/N0 ratio in dB */
+ double bias, /* Metric bias */
+ int scale); /* Scale factor */
+
+unsigned char
+d_encode(unsigned char *symbols, unsigned char *data,
+ unsigned int nbytes,unsigned char encstate);
+
+void
+d_viterbi_chunks_init(struct viterbi_state* state);
+
+void
+d_viterbi_chunks_init_sse2(__m128i *mm0, __m128i *pp0);
+
+void
+d_viterbi_butterfly2(unsigned char *symbols, int mettab[2][256], struct viterbi_state *state0, struct viterbi_state *state1);
+
+void
+d_viterbi_butterfly2_sse2(unsigned char *symbols, __m128i m0[], __m128i m1[], __m128i p0[], __m128i p1[]);
+
+void
+d_viterbi_butterfly_sse2(unsigned char *symbols, __m128i m0[], __m128i m1[], __m128i p0[], __m128i p1[]);
+
+unsigned char
+d_viterbi_get_output(struct viterbi_state *state, unsigned char *outbuf);
+
+unsigned char
+d_viterbi_get_output_sse2(__m128i *mm0, __m128i *pp0, int ntraceback, unsigned char *outbuf);
+
+
+int
+d_viterbi(unsigned long *metric, /* Final path metric (returned value) */
+ unsigned char *data, /* Decoded output data */
+ unsigned char *symbols, /* Raw deinterleaved input symbols */
+ unsigned int nbits, /* Number of output bits */
+ int mettab[2][256] /* Metric table, [sent sym][rx symbol] */
+);
+
+
+/* End of added functions */
+
+
#endif /* INCLUDED_IEEE802_11_OFDM_UTILS_H */