From ea221d0b3f7cec7727f919b323bc2810ce48150f Mon Sep 17 00:00:00 2001 From: Robert Ghilduta Date: Sun, 10 Jan 2021 21:23:16 -0800 Subject: [PATCH] Add C models for FFT/IFFT and Viterbi decoder --- fpga/ip/nuand/fft/model/Makefile | 7 + fpga/ip/nuand/fft/model/dft.c | 173 +++++++++ fpga/ip/nuand/fft/model/idft.c | 166 +++++++++ fpga/ip/nuand/viterbi_decoder/model/encoder.c | 336 ++++++++++++++++++ fpga/ip/nuand/viterbi_decoder/model/out.c | 51 +++ 5 files changed, 733 insertions(+) create mode 100644 fpga/ip/nuand/fft/model/Makefile create mode 100644 fpga/ip/nuand/fft/model/dft.c create mode 100644 fpga/ip/nuand/fft/model/idft.c create mode 100644 fpga/ip/nuand/viterbi_decoder/model/encoder.c create mode 100644 fpga/ip/nuand/viterbi_decoder/model/out.c diff --git a/fpga/ip/nuand/fft/model/Makefile b/fpga/ip/nuand/fft/model/Makefile new file mode 100644 index 0000000..41e18f8 --- /dev/null +++ b/fpga/ip/nuand/fft/model/Makefile @@ -0,0 +1,7 @@ +all: dft idft + +dft: dft.c + gcc -o dft dft.c -g3 -lm + +idft: idft.c + gcc -o idft idft.c -g3 -lm diff --git a/fpga/ip/nuand/fft/model/dft.c b/fpga/ip/nuand/fft/model/dft.c new file mode 100644 index 0000000..0af842b --- /dev/null +++ b/fpga/ip/nuand/fft/model/dft.c @@ -0,0 +1,173 @@ +// This file is part of bladeRF-wiphy. +// +// Copyright (C) 2021 Nuand, LLC. +// +// 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 2 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, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +#include +#include + + +int flip_bits(unsigned in, int bits) { + unsigned ret = 0; + int i; + for (i = 0; i < bits; i++) { + ret |= ( !!(in & (1 << i)) ) << (bits - i - 1); + } + printf("IN %d, OUT %d\n", in, ret); + return ret; +} + +unsigned rotate_left(unsigned in, int width, int num) { + unsigned ret = 0; + unsigned bottom = 0; + unsigned mask = 0; + bottom = in; + //printf("#1 = %d\n", bottom); + bottom >>= (width - num); + //printf("#2 = %d\n", bottom); + mask = ((1 << (num+1)) - 1); + //printf("mask = %d\n", mask); + bottom &= mask; + //printf("BOTTOM = %d\n", bottom); + + ret = in; + ret <<= num; + ret = ret & ((1 << width) - 1); + //printf("TOP = %d\n", ret); + + ret |= bottom; + return(ret); +} + +struct c_sample { + float i, q; +}; + +#define N 64 +#define N_POW 6 +#define FMT "%f" + +struct c_sample rfs_i[] = { + { 402, 750}, { -439, 700}, { 909, -96}, {-7, -496}, {76, -711}, {764, 601}, {-192, 315}, {411, -633}, + {-540, -139}, {-360, -640}, {821, -172}, {160, 291}, {9, -678}, {-679, -241}, {69, -293}, {565, -172}, + {-356, 999}, {515, -19}, {438, -498}, {78, 693}, {-276, 209}, {-865, 131}, {465, 487}, {454, 35}, + {-480, 437}, {-324, -45}, {-86, -991}, {-471, 2}, {-805, -38}, {543, -621}, {170, 397}, {-797, 606}, + {546, 369}, {150, 591}, {-1095, -17}, {109, -684}, {760, -450}, {-573, -478}, {-66, -409}, {682, 484}, + {-862, 201}, {-695, -192}, {16, 819}, {-403, 172}, {-342, -660}, {443, 14}, {544, -389}, {-734, -339}, + {-366, -141}, {381, -626}, {280, 382}, {624, 235}, {-218, 980}, {333, 54}, {333, 506}, {-944, 114}, + {46, 566}, {305, -48}, {457, -20}, {-56, 740}, {-919, 197}, {522, 295}, {-2, 20}, {438, -712} +}; + +void gen_sample(int n, struct c_sample *ptr) { + int r, idx; + for (r = 0; r < n; r++) { + idx = flip_bits(r, N_POW); + ptr[idx] = rfs_i[r]; + printf("Wrote %d to c[%d] = " FMT " + j*" FMT "\n", r, idx, ptr[idx].i, ptr[idx].q); + } +} + +void butter_fly(struct c_sample *A, struct c_sample *B, struct c_sample *TW) +{ + struct c_sample mix, t_A, t_B; + // A = a_i + j * a_q + // B = b_i + j * b_q + + // C = A X B = (a_i * b_i + a_i * j * b_q + j * a_q * b_i + j * a_q * j * b_q) + // C = ( a_i * b_i - a_q * b_q) + j ( a_i * b_q + a_q + b_i ) + // C_i = a_i * b_i - a_q * b_q + // C_q = a_i * b_q + a_q * b_i + + + mix.i = (B->i * TW->i - B->q * TW->q) /(32768);//>> 15; + mix.q = (B->i * TW->q + B->q * TW->i) /(32768);//>> 15; + + //A->i *= 1; + //A->q *= 1; + //B->i *= 1; + //B->q *= 1; + + t_A.i = A->i + mix.i; + t_A.q = A->q + mix.q; + + t_B.i = A->i - mix.i; + t_B.q = A->q - mix.q; + + printf("A: " FMT " + j* " FMT " B: " FMT " + j* " FMT " TW: " FMT " + j* " FMT "\n", A->i, A->q, B->i, B->q, TW->i, TW->q); + printf("mix: " FMT " + j* " FMT "\n", mix.i, mix.q); + + *A = t_A; + *B = t_B; + printf("A: " FMT " + j* " FMT " B: " FMT " + j* " FMT "\n\n", A->i, A->q, B->i, B->q); +} + + +int W_i[N/2]; +int W_q[N/2]; +int main() { + float ti, tq; + int i, j; + struct c_sample s_a[N], s_b[N], s_tw[N]; + gen_sample(N, s_a); + +#if 0 + for (i = 0; i < (N);i++) { + printf("[%d] = " FMT " " FMT "\n", i, s_a[i].i, s_a[i].q); + } +#endif + /* + for (i = 0; i < (N/2);i++) { + printf("%Lf, %Lf\n", sinl((2.0 * M_PI * (float)i) / N), cosl((2.0 * M_PI * (float)i) / N)); + } + */ + + for (i = 0; i < (N/2); i++) { + ti = cosf((2.0 * M_PI * (float)i) / (float)N); + s_tw[i].i = W_i[i] = ti * ((1<<15)-1); + tq = sinf((2.0 * M_PI * (float)i) / (float)N); + s_tw[i].q = W_q[i] = tq * ((1<<15)-1); + + + printf("[%.2d] I= %.15f = 0x%.8x Q= %.15f = 0x%.8x\t\t" FMT ", " FMT "\n", i, ti, W_i[i], tq, W_q[i], s_tw[i].i, s_tw[i].q); + } + + for (i = 0; i < N_POW; i++) { + for (j = 0; j < (N/2); j++) { + int a, b, tw; + a = rotate_left(j * 2, N_POW, i); + b = rotate_left(j * 2 + 1, N_POW, i); + //tw = (j & ((1<< (i)) - 1)) << (N_POW-1-i); DIF + tw = (j ) & ((1 << (N_POW - 1)) - 1) - ((1 << (N_POW - 1 - i)) -1); + + printf("Stage=%d A=%d,%d tw=%d\n", i, a, b, tw); + if ( i == 0) { + printf("\t%d,%d => A is timeidx = %d, B is timeidx = %d\n", a,b, flip_bits(a, N_POW), flip_bits(b, N_POW)); + } + butter_fly(s_a + a, s_a + b, s_tw + tw ); + + } + printf("\n\n"); + } + + for (i = 0; i < N; i++) { + printf("[%.2d] = " FMT " + j * " FMT "\n", i, s_a[i].i, s_a[i].q); + } + printf("\n\n"); + for (i = 0; i < N; i++) { + printf("[%.2d] = %f\n", i, sqrt(s_a[i].i * s_a[i].i + s_a[i].q * s_a[i].q)); + } + return 0; +} diff --git a/fpga/ip/nuand/fft/model/idft.c b/fpga/ip/nuand/fft/model/idft.c new file mode 100644 index 0000000..21a5a01 --- /dev/null +++ b/fpga/ip/nuand/fft/model/idft.c @@ -0,0 +1,166 @@ +// This file is part of bladeRF-wiphy. +// +// Copyright (C) 2021 Nuand, LLC. +// +// 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 2 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, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +#include +#include + + +int flip_bits(unsigned in, int bits) { + unsigned ret = 0; + int i; + for (i = 0; i < bits; i++) { + ret |= ( !!(in & (1 << i)) ) << (bits - i - 1); + } + printf("IN %d, OUT %d\n", in, ret); + return ret; +} + +int f_s[]= { +0, 1, -1, -1, -1, 1, -1, 1, -1, -1, -1, 1, 1, -1, -1, 1, -1, 1, 1, -1, -1, -1, -1, -1, 1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, -1, 1, 1, 1, -1, 1, 1, -1, -1, -1, -1, 1, -1, -1, -1, -1, -1, 1, 1, -1, -1, 1, 1, -1 }; + +unsigned rotate_left(unsigned in, int width, int num) { + unsigned ret = 0; + unsigned bottom = 0; + unsigned mask = 0; + bottom = in; + //printf("#1 = %d\n", bottom); + bottom >>= (width - num); + //printf("#2 = %d\n", bottom); + mask = ((1 << (num+1)) - 1); + //printf("mask = %d\n", mask); + bottom &= mask; + //printf("BOTTOM = %d\n", bottom); + + ret = in; + ret <<= num; + ret = ret & ((1 << width) - 1); + //printf("TOP = %d\n", ret); + + ret |= bottom; + return(ret); +} + +struct c_sample { + long long int i, q; +}; + +#define N 64 +#define N_POW 6 +#define FMT "%lld" + +void gen_sample(int n, struct c_sample *ptr) { + int r, idx; + for (r = 0; r < n; r++) { + idx = flip_bits(r, N_POW); + ptr[idx].i = f_s[r] * 4096; + ptr[idx].q = 0; + printf("Wrote %d to c[%d] = " FMT " + j*" FMT "\n", r, idx, ptr[idx].i, ptr[idx].q); + } +} + +void butter_fly(struct c_sample *A, struct c_sample *B, struct c_sample *TW) +{ + struct c_sample mix, t_A, t_B; + // A = a_i + j * a_q + // B = b_i + j * b_q + + // C = A X B = (a_i * b_i + a_i * j * b_q + j * a_q * b_i + j * a_q * j * b_q) + // C = ( a_i * b_i - a_q * b_q) + j ( a_i * b_q + a_q + b_i ) + // C_i = a_i * b_i - a_q * b_q + // C_q = a_i * b_q + a_q * b_i + + + mix.i = (B->i * TW->i - B->q * TW->q) >> 15; + mix.q = (B->i * TW->q + B->q * TW->i) >> 15; + + //A->i *= 1; + //A->q *= 1; + //B->i *= 1; + //B->q *= 1; + + t_A.i = A->i + mix.i; + t_A.q = A->q + mix.q; + + t_B.i = A->i - mix.i; + t_B.q = A->q - mix.q; + + printf("A: " FMT " + j* " FMT " B: " FMT " + j* " FMT " TW: " FMT " + j* " FMT "\n", A->i, A->q, B->i, B->q, TW->i, TW->q); + printf("mix: " FMT " + j* " FMT "\n", mix.i, mix.q); + + *A = t_A; + *B = t_B; + printf("A: " FMT " + j* " FMT " B: " FMT " + j* " FMT "\n\n", A->i, A->q, B->i, B->q); +} + + +int W_i[N/2]; +int W_q[N/2]; +int main() { + float ti, tq; + int i, j; + struct c_sample s_a[N], s_b[N], s_tw[N]; + gen_sample(N, s_a); + +#if 0 + for (i = 0; i < (N);i++) { + printf("[%d] = " FMT " " FMT "\n", i, s_a[i].i, s_a[i].q); + } +#endif + /* + for (i = 0; i < (N/2);i++) { + printf("%Lf, %Lf\n", sinl((2.0 * M_PI * (float)i) / N), cosl((2.0 * M_PI * (float)i) / N)); + } + */ + + for (i = 0; i < (N/2); i++) { + ti = cosf((2.0 * M_PI * (float)i) / (float)N); + s_tw[i].i = W_i[i] = ti * ((1<<15)-1); + tq = sinf((2.0 * M_PI * (float)i) / (float)N); + s_tw[i].q = W_q[i] = tq * ((1<<15)-1); + + + printf("[%.2d] I= %.15f = 0x%.8x Q= %.15f = 0x%.8x\t\t" FMT ", " FMT "\n", i, ti, W_i[i], tq, W_q[i], s_tw[i].i, s_tw[i].q); + } + + for (i = 0; i < N_POW; i++) { + for (j = 0; j < (N/2); j++) { + int a, b, tw; + a = rotate_left(j * 2, N_POW, i); + b = rotate_left(j * 2 + 1, N_POW, i); + //tw = (j & ((1<< (i)) - 1)) << (N_POW-1-i); DIF + tw = (j) & ((1 << (N_POW - 1)) - 1) - ((1 << (N_POW - 1 - i)) -1); + + printf("Stage=%d A=%d,%d tw=%d\n", i, a, b, tw); + if (i == 0) { + printf("\t%d,%d => A is timeidx = %d, B is timeidx = %d\n", a,b, flip_bits(a, N_POW), flip_bits(b, N_POW)); + } + butter_fly(s_a + a, s_a + b, s_tw + tw ); + + } + printf("\n\n"); + } + + for (i = 0; i < N; i++) { + printf("[%.2d] = " FMT " + j * " FMT "\n", i, s_a[i].i/64, s_a[i].q/64); + } + printf("\n\n"); + for (i = 0; i < N; i++) { + printf("[%.2d] = %f\n", i, sqrt(s_a[i].i * s_a[i].i + s_a[i].q * s_a[i].q)); + } + return 0; +} diff --git a/fpga/ip/nuand/viterbi_decoder/model/encoder.c b/fpga/ip/nuand/viterbi_decoder/model/encoder.c new file mode 100644 index 0000000..261855e --- /dev/null +++ b/fpga/ip/nuand/viterbi_decoder/model/encoder.c @@ -0,0 +1,336 @@ +// This file is part of bladeRF-wiphy. +// +// Copyright (C) 2021 Nuand, LLC. +// +// 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 2 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, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +#include +#include +#include +#include +#include + +#define K 7 +#define C_A 91 +#define C_B 121 + +#define NUM_BT 1000 +#define BIT(y) ( (state >> y) & 1) + +#define T_BIT(y) ( (t_state >> y) & 1) + +uint32_t state; +unsigned int byte_a, byte_b ; + +struct path { + int32_t cost; + uint32_t from_state[NUM_BT]; + uint32_t bits[NUM_BT]; + uint32_t bm[NUM_BT]; + uint32_t set[NUM_BT]; + uint32_t to_state[NUM_BT]; + uint32_t win[NUM_BT]; +}; + +uint32_t win_history[100][64]; + +struct path_metric { + int idx; + struct path paths[ 0x40 ]; +}; + +void branch_metric_loop(struct path_metric *in_path, uint8_t r_a, int erasure_a, uint8_t r_b, int erasure_b) { + // the T_ prefix just means test + unsigned t_state; + uint8_t t_bit_a, t_bit_b; + uint32_t bm; + uint32_t next_state; + + uint32_t bm_tbl_cost[0x40]; // idx: the end state + uint32_t bm_tbl_bit[0x40]; // idx: the end state + memset(bm_tbl_cost, 0xff, sizeof(bm_tbl_cost)); + memset(bm_tbl_bit, 0xff, sizeof(bm_tbl_bit)); + + struct path_metric out_path; + + memcpy(&out_path, in_path, sizeof(out_path)); + out_path.idx = in_path->idx++; + + for (t_state = 0; t_state <= 0x3f; t_state++) { + // calculate the branch metric by: + // assuming the trellis at t_state and is about to head to next_state + // the uncoded data bit determines to which one of two states the trellis goes from t_state + // as it goes to next_state from t_state, two coded bits t_bit_a and t_bit_b are output + // the branch metric is the sum of error between the expected value t_bit_a/t_bit_b and the received value r_a/r_b + // + // each "destination state"'s path metric is calculated by adding the current corresponding branch metric to the two possible "source state"'s path metric, + // and selecting the path with the lowest total path cost + // + // each state can only be entered from 2 previous states, so the hardware only has to calculate the branch metric (and total path metric) from 2 previous "source states". + + // bit is 0? + t_bit_a = T_BIT(5) ^ T_BIT(4) ^ T_BIT(2) ^ T_BIT(1) ^ 0; + t_bit_b = T_BIT(5) ^ T_BIT(2) ^ T_BIT(1) ^ T_BIT(0) ^ 0; + + //bm = (t_bit_a - r_a) + (t_bit_b - r_b); + bm = in_path->paths[t_state].cost; + if (!erasure_a) { + if (t_bit_a > r_a) { + bm += t_bit_a - r_a; + } else { + bm += r_a - t_bit_a; + } + } + + if (!erasure_b) { + if (t_bit_b > r_b) { + bm += t_bit_b - r_b; + } else { + bm += r_b - t_bit_b; + } + } + + next_state = (t_state << 1) & 0x3f; + + if (bm < bm_tbl_cost[next_state]) { + bm_tbl_cost[next_state] = bm; + bm_tbl_bit[next_state] = 0; + + out_path.paths[next_state] = in_path->paths[t_state]; + out_path.paths[next_state].cost = bm; + out_path.paths[next_state].from_state[out_path.idx] = t_state; + out_path.paths[next_state].bits[out_path.idx] = 0; + out_path.paths[next_state].to_state[out_path.idx] = next_state; + out_path.paths[next_state].bm[out_path.idx] = bm; + out_path.paths[next_state].set[out_path.idx] = 1; + win_history[out_path.idx][next_state] = !!(t_state & (1 << 5)); + } + //printf("B=0 COMPUTE S=%.2d TO D=%.2d del=%d\n", t_state, next_state, t_state-next_state); + + + bm = in_path->paths[t_state].cost; + // bit is 1? + t_bit_a = T_BIT(5) ^ T_BIT(4) ^ T_BIT(2) ^ T_BIT(1) ^ 1; + t_bit_b = T_BIT(5) ^ T_BIT(2) ^ T_BIT(1) ^ T_BIT(0) ^ 1; + + if (!erasure_a) { + if (t_bit_a > r_a) { + bm += t_bit_a - r_a; + } else { + bm += r_a - t_bit_a; + } + } + + if (!erasure_b) { + if (t_bit_b > r_b) { + bm += t_bit_b - r_b; + } else { + bm += r_b - t_bit_b; + } + } + next_state = ((t_state << 1) & 0x3f) | 1; + + if (bm < bm_tbl_cost[next_state]) { + bm_tbl_cost[next_state] = bm; + bm_tbl_bit[next_state] = 0; + + out_path.paths[next_state] = in_path->paths[t_state]; + out_path.paths[next_state].cost = bm; + out_path.paths[next_state].from_state[out_path.idx] = t_state; + out_path.paths[next_state].bits[out_path.idx] = 1; + out_path.paths[next_state].to_state[out_path.idx] = next_state; + out_path.paths[next_state].bm[out_path.idx] = bm; + out_path.paths[next_state].set[out_path.idx] = 1; + win_history[out_path.idx][next_state] = !!(t_state & (1 << 5)); + } + //printf("B=1 COMPUTE S=%.2d TO D=%.2d del=%d\n", t_state, next_state, t_state-next_state); + + } + + out_path.idx++; + memcpy(in_path, &out_path, sizeof(out_path)); + +} + +uint16_t encode_bit(unsigned char bit, int shift, uint8_t *out_a, uint8_t *out_b) { + uint8_t bit_a, bit_b; + + //printf("State before = %x\n", (state & 0x3f)); + + bit_a = BIT(5) ^ BIT(4) ^ BIT(2) ^ BIT(1) ^ bit; + bit_b = BIT(5) ^ BIT(2) ^ BIT(1) ^ BIT(0) ^ bit; + + byte_a |= (bit_a << 7); + byte_b |= (bit_b << 7); + + state <<= 1; + state |= bit; + state &= 0x3f; + //printf("State after = %x\n", (state & 0x3f)); + + if (shift) { + byte_a >>= 1; + byte_b >>= 1; + } + + if (out_a) + *out_a = bit_a; + + if (out_b) + *out_b = bit_b; + + return ((bit_a << 8) + bit_b); +} + +void dump_path_metric(struct path_metric *pm_in) { + int j, z; + unsigned min_cost = 0xffff; + unsigned idx = 0; + unsigned c_state; + for (j = 0; j <0x40; j++) { + if (pm_in->paths[j].cost < min_cost) { + min_cost = pm_in->paths[j].cost; + idx = j; + } + printf("[%.2d] = %d\n", j, pm_in->paths[j].cost); + //if (!pm_in->paths[j].cost) { + // printf("%d", pm_in->paths[j].bits[0]); + // break; + //} + } + printf("%d[%d] idx=%d\n", pm_in->paths[idx].bits[0], min_cost, idx); + for (j = 0; j < pm_in->idx; j++) { + for (z = 0; z < 0x40; z++) { + printf("%d", win_history[j][z]); + } + printf("\n"); + } +#if 1 + for (z = 0; z < pm_in->idx; z++) { + printf("%.3d] SET=%d [%.2d]--> bit=%d/w=%d/bm=%d --> [%.2d]", z, + pm_in->paths[idx].set[z], + pm_in->paths[idx].from_state[z], + pm_in->paths[idx].bits[z], + win_history[z][pm_in->paths[idx].to_state[z]], + pm_in->paths[idx].bm[z], + pm_in->paths[idx].to_state[z] + ); + printf(" "); + c_state = pm_in->paths[idx].to_state[z]; + for (j = 5; j >= 0; j--) + printf("%d", !!(c_state & (1 << j))); + + if (win_history[z][c_state]) { + c_state >>= 1; + c_state |= (1<<5); + } else { + c_state >>= 1; + } + printf(" prev_state_hat: "); + for (j = 5; j >= 0; j--) + printf("%d", !!(c_state & (1 << j))); + printf("\n"); + } +#endif + printf("\n"); + +} + +int main(int argc, char *argv[]) { + state = 0; + + uint8_t bit_a, bit_b; + + struct path_metric *pm_in, *pm_out; + + unsigned int tx_bits[] = {1, 1, 1, 0, + 0, 1, 0, 1, + 0, 1, 1, 0, + 0, 1, 1, 1, + 0, 1, 1, 0, + 0, 0, 1, 0, + 0, 0, 0, 0, + 0, 1, 0, 1, + 0, 1, 1, 0, + 0, 1, 1, 1, + 0, 1, 1, 0, + 0, 0, 1, 0, + 0, 0, 0, 0, + 0, 1, 0, 1, + 0, 1, 1, 0, + 0, 1, 1, 1, + 0, 1, 1, 0, + 0, 0, 1, 0, + 0, 0, 0, 0, + 1, 1, 1, 1, + 1, 1, 1, 1, + 1, 1, 1, 1, + 1, 1, 1, 1, + }; + unsigned int tx_len = sizeof(tx_bits)/sizeof(tx_bits[0]); + + pm_in = (struct path_metric *)malloc(sizeof(struct path_metric)); + pm_out = (struct path_metric *)malloc(sizeof(struct path_metric)); + + int i, j, z; + + uint8_t *rx_bits = (uint8_t *)malloc(2 * tx_len * sizeof(uint8_t)); + + for (i = 0; i < tx_len; i++) { + byte_a = byte_b = 0; + + printf("t[%d] = from S[%d] to ", i, state); + encode_bit(tx_bits[i], 1, &bit_a, &bit_b); // 0 -- 1 + printf("= D[%d]\n", state); + rx_bits[i*2 + 0] = bit_a; + rx_bits[i*2 + 1] = bit_b; + //if ((i)==4) + // rx_bits[i*2] ^= 1; + } + memset(pm_in, 0, sizeof(pm_in)); + for (i = 0; i < 0x40; i++) { + pm_in->paths[i].cost = (i == 0) ? 0 : 0xffffff; + for (z = 0; z < 12; z++) { + pm_in->paths[i].set[z] = 0; + pm_in->paths[i].from_state[z] = 0; + pm_in->paths[i].bits[z] = 0; + pm_in->paths[i].bm[z] = 0; + pm_in->paths[i].to_state[z] = 0; + } + } + + int bit; + for (bit = 0; bit < (sizeof(tx_bits)/sizeof(tx_bits[0]))/2 ; bit++) { + bit_a = rx_bits[bit * 2]; + bit_b = rx_bits[bit * 2 + 1]; + branch_metric_loop(pm_in, bit_a, 0, bit_b, 0); + } + printf("LAST = %d\n", bit); + for (j = 0; j <0x40; j++) { + printf("[%d] ", pm_in->paths[j].from_state[0]); + for (i = bit - 20; i < bit; i++) { + printf(" -> [%d]", + pm_in->paths[j].to_state[i] + ); + } + printf("\n"); + } + dump_path_metric(pm_in); + printf("\n"); + free(pm_in); + free(pm_out); + + return 0; +} diff --git a/fpga/ip/nuand/viterbi_decoder/model/out.c b/fpga/ip/nuand/viterbi_decoder/model/out.c new file mode 100644 index 0000000..d03a6c8 --- /dev/null +++ b/fpga/ip/nuand/viterbi_decoder/model/out.c @@ -0,0 +1,51 @@ +// This file is part of bladeRF-wiphy. +// +// Copyright (C) 2021 Nuand, LLC. +// +// 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 2 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, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +#include +#include +#include +#include +#include + +#define K 7 +#define C_A 91 +#define C_B 121 + +#define BIT(y) ( (state >> y) & 1) + +#define T_BIT(y) ( (t_state >> y) & 1) + +int main(int argc, char *argv[]) { + unsigned t_state; + unsigned next_state; + uint8_t t_bit_a, t_bit_b; + for (t_state = 0; t_state <= 0x3f; t_state++) { + // bit is 0? + t_bit_a = T_BIT(5) ^ T_BIT(4) ^ T_BIT(2) ^ T_BIT(1) ^ 0; + t_bit_b = T_BIT(5) ^ T_BIT(2) ^ T_BIT(1) ^ T_BIT(0) ^ 0; + next_state = (t_state << 1) & 0x3f; + printf("S[%d] -- bit=%d coded=%d,%d -- D[%d]\n", t_state, 0, t_bit_a, t_bit_b, next_state); + + // bit is 1? + t_bit_a = T_BIT(5) ^ T_BIT(4) ^ T_BIT(2) ^ T_BIT(1) ^ 1; + t_bit_b = T_BIT(5) ^ T_BIT(2) ^ T_BIT(1) ^ T_BIT(0) ^ 1; + next_state = ((t_state << 1) & 0x3f) | 1; + printf("S[%d] -- bit=%d coded=%d,%d -- D[%d]\n", t_state, 1, t_bit_a, t_bit_b, next_state); + } + return 0; +}