├── LICENSE ├── README.md ├── fpga ├── common │ └── wlan_files.tcl ├── ip │ ├── altera │ │ ├── fft64 │ │ │ ├── fft64.qsys │ │ │ └── generate.sh │ │ ├── viterbi_decoder │ │ │ ├── generate.sh │ │ │ └── viterbi_decoder.qsys │ │ └── wlan_pll │ │ │ └── generate.sh │ ├── generate.sh │ └── nuand │ │ ├── cordic.vhd │ │ ├── fft │ │ ├── model │ │ │ ├── Makefile │ │ │ ├── dft.c │ │ │ └── idft.c │ │ └── vhdl │ │ │ ├── dual_port_ram.vhd │ │ │ ├── fft.vhd │ │ │ ├── fft_top.vhd │ │ │ └── tb │ │ │ ├── compile.do │ │ │ └── fft_tb.vhd │ │ ├── nco.vhd │ │ └── viterbi_decoder │ │ ├── model │ │ ├── encoder.c │ │ └── out.c │ │ └── vhdl │ │ ├── branch_compare.vhd │ │ ├── comp2.vhd │ │ ├── r2_comparator.vhd │ │ ├── tb │ │ ├── compile.do │ │ ├── r2_comparator_tb.vhd │ │ ├── viterbi_decoder_tb.vhd │ │ └── wave.do │ │ ├── traceback.vhd │ │ ├── tracer.vhd │ │ ├── viterbi_decoder.vhd │ │ └── viterbi_p.vhd ├── modelsim │ └── wlan.do ├── quartus │ └── wlan.qip └── vhdl │ ├── clock_sync_logic.vhd │ ├── clock_sync_logic_vector.vhd │ ├── clock_sync_params.vhd │ ├── tb │ ├── wlan_ack_generator_tb.vhd │ ├── wlan_acquisition_tb.vhd │ ├── wlan_bsd_tb.vhd │ ├── wlan_channel_inverter_tb.vhd │ ├── wlan_clock_tb.vhd │ ├── wlan_dsss_plcp_crc_tb.vhd │ ├── wlan_interleaver_tb.vhd │ ├── wlan_lfsr_tb.vhd │ ├── wlan_modulator_tb.vhd │ ├── wlan_peak_finder_tb.vhd │ ├── wlan_rx_tb.vhd │ ├── wlan_sample_loader.vhd │ ├── wlan_sample_saver.vhd │ ├── wlan_symbol_shaper_tb.vhd │ ├── wlan_tables_p.vhd │ ├── wlan_tb.vhd │ ├── wlan_top_tb.vhd │ ├── wlan_tx_long_tb.vhd │ ├── wlan_tx_short_tb.vhd │ ├── wlan_tx_tb.vhd │ ├── wlan_viterbi_encoder_tb.vhd │ └── wlan_viterbi_tb.vhd │ ├── wlan_ack_generator.vhd │ ├── wlan_acquisition.vhd │ ├── wlan_agc.vhd │ ├── wlan_agc_drv.vhd │ ├── wlan_bsd.vhd │ ├── wlan_cfo_correction.vhd │ ├── wlan_cfo_estimate.vhd │ ├── wlan_channel_inverter.vhd │ ├── wlan_clamper.vhd │ ├── wlan_correlator.vhd │ ├── wlan_crc.vhd │ ├── wlan_csma.vhd │ ├── wlan_dcf.vhd │ ├── wlan_deinterleaver.vhd │ ├── wlan_delay_correlator.vhd │ ├── wlan_demodulator.vhd │ ├── wlan_depuncturer.vhd │ ├── wlan_descrambler.vhd │ ├── wlan_divide.vhd │ ├── wlan_dsss_demodulator.vhd │ ├── wlan_dsss_despreader.vhd │ ├── wlan_dsss_p_norm.vhd │ ├── wlan_dsss_peak_finder.vhd │ ├── wlan_dsss_plcp_crc.vhd │ ├── wlan_dsss_rx.vhd │ ├── wlan_dsss_rx_controller.vhd │ ├── wlan_dsss_rx_framer.vhd │ ├── wlan_encoder.vhd │ ├── wlan_equalizer.vhd │ ├── wlan_fft64.vhd │ ├── wlan_framer.vhd │ ├── wlan_ifft64.vhd │ ├── wlan_interleaver.vhd │ ├── wlan_interleaver_p.vhd │ ├── wlan_lfsr.vhd │ ├── wlan_modulator.vhd │ ├── wlan_p.vhd │ ├── wlan_p_norm.vhd │ ├── wlan_peak_finder.vhd │ ├── wlan_phase_correction.vhd │ ├── wlan_rx.vhd │ ├── wlan_rx_controller.vhd │ ├── wlan_rx_framer.vhd │ ├── wlan_rx_p.vhd │ ├── wlan_rx_packet_buffer.vhd │ ├── wlan_sample_buffer.vhd │ ├── wlan_scrambler.vhd │ ├── wlan_symbol_shaper.vhd │ ├── wlan_top.vhd │ ├── wlan_tx.vhd │ ├── wlan_tx_controller.vhd │ ├── wlan_tx_long.vhd │ ├── wlan_tx_p.vhd │ ├── wlan_tx_short.vhd │ ├── wlan_viterbi_decoder.vhd │ └── wlan_viterbi_encoder.vhd └── matlab ├── util.m └── wlan_rx.m /README.md: -------------------------------------------------------------------------------- 1 | # bladeRF-wiphy 2 | 3 | bladeRF-wiphy is an open-source IEEE 802.11 compatible software defined radio VHDL modem 4 | 5 | 6 | 7 | ## What is the bladeRF-wiphy project? 8 | The bladeRF-wiphy project is an open-source IEEE 802.11 compatible software defined radio VHDL modem. The modem is able to modulate and demodulate 802.11 packets (the protocol WiFi is based on), and run directly on the bladeRF 2.0 micro xA9’s FPGA. 9 | 10 | The bladeRF-wiphy coupled with Linux mac80211 allows the [bladeRF 2.0 micro xA9](https://www.nuand.com/product/bladerf-xA9/) to become a software defined radio 802.11 access point! 802.11 packets (PDUs) are modulated and demodulated directly on the FPGA, so only 802.11 packets are transferred between the FPGA and libbladeRF. 11 | 12 | ## Documentation 13 | A technical deep dive of bladeRF-wiphy https://www.nuand.com/bladeRF-wiphy/ 14 | 15 | Instructions to compile, install, and run bladeRF-wiphy and tools https://www.nuand.com/bladeRF-wiphy-instructions/ 16 | 17 | Instructions to simulate bladeRF-wiphy: https://www.nuand.com/bladeRF-wiphy-simulation/ 18 | 19 |

20 | 21 |

22 | 23 | ## Features 24 | - IEEE 802.11 compatible FPGA based PHY receiver and transmitter 25 | - Compatible with [bladeRF 2.0 micro xA9](https://www.nuand.com/product/bladerf-xA9/) 26 | - Linux mac80211 MAC integration 27 | - RX and TX monitor mode support 28 | - Hardware Distributed Coordination Function (DCF) allows quick turn-around time ACKs 29 | - High-performance equalizer – implements Zero Forcing (ZF) and optionally Decision Feedback Equalizer (DFE) 30 | 31 | ## Modulation schemes 32 | - DSSS - CCK 33 | - OFDM - 20MHz (6Mbps, 9Mbps, 12Mbps, 18Mbps, 24Mbps, 36Mbps, 48Mbps, 54Mbps) 34 | 35 | ## Modulation constellations 36 | - DSSS-CCK DBPSK 37 | - OFDM-BPSK 38 | - OFDM-QPSK 39 | - OFDM-16-QAM 40 | - OFDM-64-QAM 41 | 42 | ## Contact information 43 | Email: bladeRF@nuand.com 44 | 45 | Slack: See Slack section on this [page](https://www.nuand.com/support/) 46 | -------------------------------------------------------------------------------- /fpga/ip/altera/fft64/fft64.qsys: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /fpga/ip/altera/fft64/generate.sh: -------------------------------------------------------------------------------- 1 | qsys-generate --sim --synthesis=VHDL ./fft64.qsys 2 | -------------------------------------------------------------------------------- /fpga/ip/altera/viterbi_decoder/generate.sh: -------------------------------------------------------------------------------- 1 | qsys-generate --sim --synthesis=VHDL viterbi_decoder.qsys 2 | -------------------------------------------------------------------------------- /fpga/ip/altera/viterbi_decoder/viterbi_decoder.qsys: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /fpga/ip/altera/wlan_pll/generate.sh: -------------------------------------------------------------------------------- 1 | ip-generate --file-set=QUARTUS_SYNTH --component-name=altera_pll --output-name=wlan_pll \ 2 | --component-param=gui_reference_clock_frequency="40MHz" \ 3 | --component-param=gui_output_clock_frequency0="80MHz" \ 4 | --component-param=gui_phase_shift0="0ps" \ 5 | --component-param=gui_duty_cycle0="50%" 6 | -------------------------------------------------------------------------------- /fpga/ip/generate.sh: -------------------------------------------------------------------------------- 1 | for i in */*/generate.sh; do echo "Running $i"; (cd `dirname $i`; sh generate.sh); done 2 | -------------------------------------------------------------------------------- /fpga/ip/nuand/fft/model/Makefile: -------------------------------------------------------------------------------- 1 | all: dft idft 2 | 3 | dft: dft.c 4 | gcc -o dft dft.c -g3 -lm 5 | 6 | idft: idft.c 7 | gcc -o idft idft.c -g3 -lm 8 | -------------------------------------------------------------------------------- /fpga/ip/nuand/fft/model/dft.c: -------------------------------------------------------------------------------- 1 | // This file is part of bladeRF-wiphy. 2 | // 3 | // Copyright (C) 2021 Nuand, LLC. 4 | // 5 | // This program is free software; you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation; either version 2 of the License, or 8 | // (at your option) any later version. 9 | // 10 | // This program is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License along 16 | // with this program; if not, write to the Free Software Foundation, Inc., 17 | // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | 19 | #include 20 | #include 21 | 22 | 23 | int flip_bits(unsigned in, int bits) { 24 | unsigned ret = 0; 25 | int i; 26 | for (i = 0; i < bits; i++) { 27 | ret |= ( !!(in & (1 << i)) ) << (bits - i - 1); 28 | } 29 | printf("IN %d, OUT %d\n", in, ret); 30 | return ret; 31 | } 32 | 33 | unsigned rotate_left(unsigned in, int width, int num) { 34 | unsigned ret = 0; 35 | unsigned bottom = 0; 36 | unsigned mask = 0; 37 | bottom = in; 38 | //printf("#1 = %d\n", bottom); 39 | bottom >>= (width - num); 40 | //printf("#2 = %d\n", bottom); 41 | mask = ((1 << (num+1)) - 1); 42 | //printf("mask = %d\n", mask); 43 | bottom &= mask; 44 | //printf("BOTTOM = %d\n", bottom); 45 | 46 | ret = in; 47 | ret <<= num; 48 | ret = ret & ((1 << width) - 1); 49 | //printf("TOP = %d\n", ret); 50 | 51 | ret |= bottom; 52 | return(ret); 53 | } 54 | 55 | struct c_sample { 56 | float i, q; 57 | }; 58 | 59 | #define N 64 60 | #define N_POW 6 61 | #define FMT "%f" 62 | 63 | struct c_sample rfs_i[] = { 64 | { 402, 750}, { -439, 700}, { 909, -96}, {-7, -496}, {76, -711}, {764, 601}, {-192, 315}, {411, -633}, 65 | {-540, -139}, {-360, -640}, {821, -172}, {160, 291}, {9, -678}, {-679, -241}, {69, -293}, {565, -172}, 66 | {-356, 999}, {515, -19}, {438, -498}, {78, 693}, {-276, 209}, {-865, 131}, {465, 487}, {454, 35}, 67 | {-480, 437}, {-324, -45}, {-86, -991}, {-471, 2}, {-805, -38}, {543, -621}, {170, 397}, {-797, 606}, 68 | {546, 369}, {150, 591}, {-1095, -17}, {109, -684}, {760, -450}, {-573, -478}, {-66, -409}, {682, 484}, 69 | {-862, 201}, {-695, -192}, {16, 819}, {-403, 172}, {-342, -660}, {443, 14}, {544, -389}, {-734, -339}, 70 | {-366, -141}, {381, -626}, {280, 382}, {624, 235}, {-218, 980}, {333, 54}, {333, 506}, {-944, 114}, 71 | {46, 566}, {305, -48}, {457, -20}, {-56, 740}, {-919, 197}, {522, 295}, {-2, 20}, {438, -712} 72 | }; 73 | 74 | void gen_sample(int n, struct c_sample *ptr) { 75 | int r, idx; 76 | for (r = 0; r < n; r++) { 77 | idx = flip_bits(r, N_POW); 78 | ptr[idx] = rfs_i[r]; 79 | printf("Wrote %d to c[%d] = " FMT " + j*" FMT "\n", r, idx, ptr[idx].i, ptr[idx].q); 80 | } 81 | } 82 | 83 | void butter_fly(struct c_sample *A, struct c_sample *B, struct c_sample *TW) 84 | { 85 | struct c_sample mix, t_A, t_B; 86 | // A = a_i + j * a_q 87 | // B = b_i + j * b_q 88 | 89 | // C = A X B = (a_i * b_i + a_i * j * b_q + j * a_q * b_i + j * a_q * j * b_q) 90 | // C = ( a_i * b_i - a_q * b_q) + j ( a_i * b_q + a_q + b_i ) 91 | // C_i = a_i * b_i - a_q * b_q 92 | // C_q = a_i * b_q + a_q * b_i 93 | 94 | 95 | mix.i = (B->i * TW->i - B->q * TW->q) /(32768);//>> 15; 96 | mix.q = (B->i * TW->q + B->q * TW->i) /(32768);//>> 15; 97 | 98 | //A->i *= 1; 99 | //A->q *= 1; 100 | //B->i *= 1; 101 | //B->q *= 1; 102 | 103 | t_A.i = A->i + mix.i; 104 | t_A.q = A->q + mix.q; 105 | 106 | t_B.i = A->i - mix.i; 107 | t_B.q = A->q - mix.q; 108 | 109 | 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); 110 | printf("mix: " FMT " + j* " FMT "\n", mix.i, mix.q); 111 | 112 | *A = t_A; 113 | *B = t_B; 114 | printf("A: " FMT " + j* " FMT " B: " FMT " + j* " FMT "\n\n", A->i, A->q, B->i, B->q); 115 | } 116 | 117 | 118 | int W_i[N/2]; 119 | int W_q[N/2]; 120 | int main() { 121 | float ti, tq; 122 | int i, j; 123 | struct c_sample s_a[N], s_b[N], s_tw[N]; 124 | gen_sample(N, s_a); 125 | 126 | #if 0 127 | for (i = 0; i < (N);i++) { 128 | printf("[%d] = " FMT " " FMT "\n", i, s_a[i].i, s_a[i].q); 129 | } 130 | #endif 131 | /* 132 | for (i = 0; i < (N/2);i++) { 133 | printf("%Lf, %Lf\n", sinl((2.0 * M_PI * (float)i) / N), cosl((2.0 * M_PI * (float)i) / N)); 134 | } 135 | */ 136 | 137 | for (i = 0; i < (N/2); i++) { 138 | ti = cosf((2.0 * M_PI * (float)i) / (float)N); 139 | s_tw[i].i = W_i[i] = ti * ((1<<15)-1); 140 | tq = sinf((2.0 * M_PI * (float)i) / (float)N); 141 | s_tw[i].q = W_q[i] = tq * ((1<<15)-1); 142 | 143 | 144 | 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); 145 | } 146 | 147 | for (i = 0; i < N_POW; i++) { 148 | for (j = 0; j < (N/2); j++) { 149 | int a, b, tw; 150 | a = rotate_left(j * 2, N_POW, i); 151 | b = rotate_left(j * 2 + 1, N_POW, i); 152 | //tw = (j & ((1<< (i)) - 1)) << (N_POW-1-i); DIF 153 | tw = (j ) & ((1 << (N_POW - 1)) - 1) - ((1 << (N_POW - 1 - i)) -1); 154 | 155 | printf("Stage=%d A=%d,%d tw=%d\n", i, a, b, tw); 156 | if ( i == 0) { 157 | 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)); 158 | } 159 | butter_fly(s_a + a, s_a + b, s_tw + tw ); 160 | 161 | } 162 | printf("\n\n"); 163 | } 164 | 165 | for (i = 0; i < N; i++) { 166 | printf("[%.2d] = " FMT " + j * " FMT "\n", i, s_a[i].i, s_a[i].q); 167 | } 168 | printf("\n\n"); 169 | for (i = 0; i < N; i++) { 170 | printf("[%.2d] = %f\n", i, sqrt(s_a[i].i * s_a[i].i + s_a[i].q * s_a[i].q)); 171 | } 172 | return 0; 173 | } 174 | -------------------------------------------------------------------------------- /fpga/ip/nuand/fft/model/idft.c: -------------------------------------------------------------------------------- 1 | // This file is part of bladeRF-wiphy. 2 | // 3 | // Copyright (C) 2021 Nuand, LLC. 4 | // 5 | // This program is free software; you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation; either version 2 of the License, or 8 | // (at your option) any later version. 9 | // 10 | // This program is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License along 16 | // with this program; if not, write to the Free Software Foundation, Inc., 17 | // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | 19 | #include 20 | #include 21 | 22 | 23 | int flip_bits(unsigned in, int bits) { 24 | unsigned ret = 0; 25 | int i; 26 | for (i = 0; i < bits; i++) { 27 | ret |= ( !!(in & (1 << i)) ) << (bits - i - 1); 28 | } 29 | printf("IN %d, OUT %d\n", in, ret); 30 | return ret; 31 | } 32 | 33 | int f_s[]= { 34 | 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 }; 35 | 36 | unsigned rotate_left(unsigned in, int width, int num) { 37 | unsigned ret = 0; 38 | unsigned bottom = 0; 39 | unsigned mask = 0; 40 | bottom = in; 41 | //printf("#1 = %d\n", bottom); 42 | bottom >>= (width - num); 43 | //printf("#2 = %d\n", bottom); 44 | mask = ((1 << (num+1)) - 1); 45 | //printf("mask = %d\n", mask); 46 | bottom &= mask; 47 | //printf("BOTTOM = %d\n", bottom); 48 | 49 | ret = in; 50 | ret <<= num; 51 | ret = ret & ((1 << width) - 1); 52 | //printf("TOP = %d\n", ret); 53 | 54 | ret |= bottom; 55 | return(ret); 56 | } 57 | 58 | struct c_sample { 59 | long long int i, q; 60 | }; 61 | 62 | #define N 64 63 | #define N_POW 6 64 | #define FMT "%lld" 65 | 66 | void gen_sample(int n, struct c_sample *ptr) { 67 | int r, idx; 68 | for (r = 0; r < n; r++) { 69 | idx = flip_bits(r, N_POW); 70 | ptr[idx].i = f_s[r] * 4096; 71 | ptr[idx].q = 0; 72 | printf("Wrote %d to c[%d] = " FMT " + j*" FMT "\n", r, idx, ptr[idx].i, ptr[idx].q); 73 | } 74 | } 75 | 76 | void butter_fly(struct c_sample *A, struct c_sample *B, struct c_sample *TW) 77 | { 78 | struct c_sample mix, t_A, t_B; 79 | // A = a_i + j * a_q 80 | // B = b_i + j * b_q 81 | 82 | // C = A X B = (a_i * b_i + a_i * j * b_q + j * a_q * b_i + j * a_q * j * b_q) 83 | // C = ( a_i * b_i - a_q * b_q) + j ( a_i * b_q + a_q + b_i ) 84 | // C_i = a_i * b_i - a_q * b_q 85 | // C_q = a_i * b_q + a_q * b_i 86 | 87 | 88 | mix.i = (B->i * TW->i - B->q * TW->q) >> 15; 89 | mix.q = (B->i * TW->q + B->q * TW->i) >> 15; 90 | 91 | //A->i *= 1; 92 | //A->q *= 1; 93 | //B->i *= 1; 94 | //B->q *= 1; 95 | 96 | t_A.i = A->i + mix.i; 97 | t_A.q = A->q + mix.q; 98 | 99 | t_B.i = A->i - mix.i; 100 | t_B.q = A->q - mix.q; 101 | 102 | 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); 103 | printf("mix: " FMT " + j* " FMT "\n", mix.i, mix.q); 104 | 105 | *A = t_A; 106 | *B = t_B; 107 | printf("A: " FMT " + j* " FMT " B: " FMT " + j* " FMT "\n\n", A->i, A->q, B->i, B->q); 108 | } 109 | 110 | 111 | int W_i[N/2]; 112 | int W_q[N/2]; 113 | int main() { 114 | float ti, tq; 115 | int i, j; 116 | struct c_sample s_a[N], s_b[N], s_tw[N]; 117 | gen_sample(N, s_a); 118 | 119 | #if 0 120 | for (i = 0; i < (N);i++) { 121 | printf("[%d] = " FMT " " FMT "\n", i, s_a[i].i, s_a[i].q); 122 | } 123 | #endif 124 | /* 125 | for (i = 0; i < (N/2);i++) { 126 | printf("%Lf, %Lf\n", sinl((2.0 * M_PI * (float)i) / N), cosl((2.0 * M_PI * (float)i) / N)); 127 | } 128 | */ 129 | 130 | for (i = 0; i < (N/2); i++) { 131 | ti = cosf((2.0 * M_PI * (float)i) / (float)N); 132 | s_tw[i].i = W_i[i] = ti * ((1<<15)-1); 133 | tq = sinf((2.0 * M_PI * (float)i) / (float)N); 134 | s_tw[i].q = W_q[i] = tq * ((1<<15)-1); 135 | 136 | 137 | 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); 138 | } 139 | 140 | for (i = 0; i < N_POW; i++) { 141 | for (j = 0; j < (N/2); j++) { 142 | int a, b, tw; 143 | a = rotate_left(j * 2, N_POW, i); 144 | b = rotate_left(j * 2 + 1, N_POW, i); 145 | //tw = (j & ((1<< (i)) - 1)) << (N_POW-1-i); DIF 146 | tw = (j) & ((1 << (N_POW - 1)) - 1) - ((1 << (N_POW - 1 - i)) -1); 147 | 148 | printf("Stage=%d A=%d,%d tw=%d\n", i, a, b, tw); 149 | if (i == 0) { 150 | 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)); 151 | } 152 | butter_fly(s_a + a, s_a + b, s_tw + tw ); 153 | 154 | } 155 | printf("\n\n"); 156 | } 157 | 158 | for (i = 0; i < N; i++) { 159 | printf("[%.2d] = " FMT " + j * " FMT "\n", i, s_a[i].i/64, s_a[i].q/64); 160 | } 161 | printf("\n\n"); 162 | for (i = 0; i < N; i++) { 163 | printf("[%.2d] = %f\n", i, sqrt(s_a[i].i * s_a[i].i + s_a[i].q * s_a[i].q)); 164 | } 165 | return 0; 166 | } 167 | -------------------------------------------------------------------------------- /fpga/ip/nuand/fft/vhdl/dual_port_ram.vhd: -------------------------------------------------------------------------------- 1 | -- This file is part of bladeRF-wiphy. 2 | -- 3 | -- Copyright (C) 2021 Nuand, LLC. 4 | -- 5 | -- This program is free software; you can redistribute it and/or modify 6 | -- it under the terms of the GNU General Public License as published by 7 | -- the Free Software Foundation; either version 2 of the License, or 8 | -- (at your option) any later version. 9 | -- 10 | -- This program is distributed in the hope that it will be useful, 11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | -- GNU General Public License for more details. 14 | -- 15 | -- You should have received a copy of the GNU General Public License along 16 | -- with this program; if not, write to the Free Software Foundation, Inc., 17 | -- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | 19 | library ieee; 20 | use ieee.std_logic_1164.all; 21 | use ieee.numeric_std.all; 22 | 23 | entity dual_port_ram is 24 | generic( 25 | ADDR_BITS : in natural := 6; 26 | DATA_BITS : in natural := 32 27 | ); 28 | port( 29 | clock : in std_logic; 30 | reset : in std_logic; 31 | 32 | acc : in std_logic; 33 | solo : in std_logic; 34 | write : in std_logic; 35 | 36 | addr_a : in std_logic_vector(ADDR_BITS-1 downto 0); 37 | in_a : in std_logic_vector(DATA_BITS-1 downto 0); 38 | data_a : out std_logic_vector(DATA_BITS-1 downto 0); 39 | 40 | addr_b : in std_logic_vector(ADDR_BITS-1 downto 0); 41 | in_b : in std_logic_vector(DATA_BITS-1 downto 0); 42 | data_b : out std_logic_vector(DATA_BITS-1 downto 0) 43 | ); 44 | end entity; 45 | 46 | architecture arch of dual_port_ram is 47 | type ram_t is array(natural range <>) of std_logic_vector(DATA_BITS-1 downto 0); 48 | 49 | signal ram : ram_t((2**ADDR_BITS-1) downto 0); 50 | begin 51 | sync : process(clock, reset) 52 | variable add_a, add_b : integer; 53 | begin 54 | if (reset = '1') then 55 | for i in ram'range loop 56 | ram(i) <= ( others => '0' ); 57 | end loop; 58 | elsif (rising_edge(clock)) then 59 | if (acc = '1') then 60 | add_a := to_integer(unsigned(addr_a)); 61 | add_b := to_integer(unsigned(addr_b)); 62 | 63 | if (write = '1') then 64 | ram(add_a) <= in_a; 65 | data_a <= in_a; 66 | if (solo = '0') then 67 | ram(add_b) <= in_b; 68 | data_b <= in_b; 69 | else 70 | data_b <= ( others => '0' ); 71 | end if; 72 | else 73 | data_a <= ram(add_a); 74 | if (solo = '0') then 75 | data_b <= ram(add_b); 76 | else 77 | data_b <= ( others => '0' ); 78 | end if; 79 | end if; 80 | end if; 81 | 82 | end if; 83 | end process; 84 | end architecture; 85 | 86 | architecture synth of dual_port_ram is 87 | type ram_t is array(natural range <>) of std_logic_vector(DATA_BITS-1 downto 0); 88 | 89 | shared variable ram : ram_t((2**ADDR_BITS-1) downto 0); 90 | begin 91 | synca : process(clock, reset) 92 | variable addra : integer; 93 | begin 94 | if (rising_edge(clock)) then 95 | addra := to_integer(unsigned(addr_a)); 96 | if (write = '1') then 97 | ram(addra) := in_a; 98 | end if; 99 | data_a <= ram(addra); 100 | end if; 101 | end process; 102 | 103 | syncb : process(clock, reset) 104 | variable addrb : integer; 105 | begin 106 | if (rising_edge(clock)) then 107 | addrb := to_integer(unsigned(addr_b)); 108 | if (write = '1') then 109 | ram(addrb) := in_b; 110 | end if; 111 | data_b <= ram(addrb); 112 | end if; 113 | end process; 114 | end architecture synth; 115 | -------------------------------------------------------------------------------- /fpga/ip/nuand/fft/vhdl/fft_top.vhd: -------------------------------------------------------------------------------- 1 | -- This file is part of bladeRF-wiphy. 2 | -- 3 | -- Copyright (C) 2021 Nuand, LLC. 4 | -- 5 | -- This program is free software; you can redistribute it and/or modify 6 | -- it under the terms of the GNU General Public License as published by 7 | -- the Free Software Foundation; either version 2 of the License, or 8 | -- (at your option) any later version. 9 | -- 10 | -- This program is distributed in the hope that it will be useful, 11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | -- GNU General Public License for more details. 14 | -- 15 | -- You should have received a copy of the GNU General Public License along 16 | -- with this program; if not, write to the Free Software Foundation, Inc., 17 | -- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | 19 | library ieee; 20 | use ieee.std_logic_1164.all; 21 | use ieee.numeric_std.all; 22 | use ieee.math_real.all; 23 | library pll; 24 | use pll.all; 25 | entity fft_top is 26 | generic( 27 | BITS : in natural := 16 28 | ); 29 | port( 30 | clk : in std_logic; 31 | reset : in std_logic; 32 | 33 | inverse : in std_logic; 34 | in_real : in std_logic_vector(BITS-1 downto 0); 35 | in_imag : in std_logic_vector(BITS-1 downto 0); 36 | in_valid : in std_logic; 37 | in_sop : in std_logic; 38 | in_eop : in std_logic; 39 | 40 | out_real : out std_logic_vector(BITS-1 downto 0); 41 | out_imag : out std_logic_vector(BITS-1 downto 0); 42 | out_error : out std_logic; 43 | out_valid : out std_logic; 44 | out_sop : out std_logic; 45 | out_eop : out std_logic 46 | ); 47 | end entity; 48 | 49 | architecture arch of fft_top is 50 | signal clock : std_logic; 51 | begin 52 | 53 | U_pll : entity pll.pll 54 | port map( 55 | refclk => clk, 56 | rst => '0', 57 | outclk_0 => clock, 58 | locked => open 59 | ); 60 | 61 | U_fft : entity work.fft(mult) 62 | generic map( 63 | N => 64, 64 | BITS => 16 65 | ) 66 | port map( 67 | clock => clock, 68 | reset => reset, 69 | 70 | inverse => inverse, 71 | in_real => in_real, 72 | in_imag => in_imag, 73 | in_valid => in_valid, 74 | in_sop => in_sop, 75 | in_eop => in_eop, 76 | 77 | out_real => out_real, 78 | out_imag => out_imag, 79 | out_error => out_error, 80 | out_valid => out_valid, 81 | out_sop => out_sop, 82 | out_eop => out_eop 83 | ); 84 | 85 | 86 | 87 | end architecture; 88 | -------------------------------------------------------------------------------- /fpga/ip/nuand/fft/vhdl/tb/compile.do: -------------------------------------------------------------------------------- 1 | vcom -work work -2008 ../dual_port_ram.vhd 2 | vcom -work work -2008 ../fft.vhd 3 | vcom -work work -2008 fft_tb.vhd 4 | -------------------------------------------------------------------------------- /fpga/ip/nuand/fft/vhdl/tb/fft_tb.vhd: -------------------------------------------------------------------------------- 1 | -- This file is part of bladeRF-wiphy. 2 | -- 3 | -- Copyright (C) 2021 Nuand, LLC. 4 | -- 5 | -- This program is free software; you can redistribute it and/or modify 6 | -- it under the terms of the GNU General Public License as published by 7 | -- the Free Software Foundation; either version 2 of the License, or 8 | -- (at your option) any later version. 9 | -- 10 | -- This program is distributed in the hope that it will be useful, 11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | -- GNU General Public License for more details. 14 | -- 15 | -- You should have received a copy of the GNU General Public License along 16 | -- with this program; if not, write to the Free Software Foundation, Inc., 17 | -- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | 19 | library ieee; 20 | use ieee.std_logic_1164.all; 21 | use ieee.numeric_std.all; 22 | 23 | entity fft_tb is 24 | end entity; 25 | 26 | architecture arch of fft_tb is 27 | signal clock : std_logic := '0'; 28 | signal reset : std_logic; 29 | 30 | signal in_real : std_logic_vector(15 downto 0); 31 | signal in_imag : std_logic_vector(15 downto 0); 32 | signal in_valid : std_logic; 33 | signal in_sop : std_logic; 34 | signal in_eop : std_logic; 35 | 36 | type lut_t is array(natural range <>) of integer; 37 | 38 | signal lut : lut_t(0 to 127) := ( 39 | 750, 402, 700, -439, -96, 909, -496, -7, -711, 76, 601, 764, 315, -192, -633, 411, 40 | -139, -540, -640, -360, -172, 821, 291, 160, -678, 9, -241, -679, -293, 69, -172, 565, 41 | 999, -356, -19, 515, -498, 438, 693, 78, 209, -276, 131, -865, 487, 465, 35, 454, 42 | 437, -480, -45, -324, -991, -86, 2, -471, -38, -805, -621, 543, 397, 170, 606, -797, 43 | 369, 546, 591, 150, -17, -1095, -684, 109, -450, 760, -478, -573, -409, -66, 484, 682, 44 | 201, -826, -192, -695, 819, 16, 172, -403, -660, -342, 14, 443, -389, 544, -339, -734, 45 | -141, -366, -626, 381, 382, 280, 235, 624, -980, -218, 54, 333, 506, 333, 114, -944, 46 | 566, 46, -48, 305, -20, 457, 740, -56, 197, -919, 295, 522, 20, -2, -712, 438 47 | ); 48 | 49 | signal ilut : lut_t(0 to 63) := ( 50 | 0, 1, -1, -1, -1, 1, -1, 1, -1, -1, -1, 1, 1, -1, -1, 1, -1, 1, 1, -1, -1, -1, -1, 51 | -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, 52 | -1, -1, -1, 1, -1, -1, -1, -1, -1, 1, 1, -1, -1, 1, 1, -1 ); 53 | 54 | 55 | 56 | 57 | constant N : integer := 64; 58 | begin 59 | clock <= not clock after 6.25 ns; 60 | reset <= '1', '0' after 50 ns; 61 | 62 | process 63 | begin 64 | in_real <= ( others => '0' ); 65 | in_imag <= ( others => '0' ); 66 | in_valid <= '0'; 67 | in_sop <= '0'; 68 | in_eop <= '0'; 69 | wait for 100 ns; 70 | for iz in 0 to 80 loop 71 | for i in 0 to N-1 loop 72 | wait until rising_edge(clock); 73 | in_real <= std_logic_vector(to_signed(4096*ilut(i), in_real'high + 1)); 74 | in_imag <= ( others => '0' ); --std_logic_vector(to_signed(lut(i*2+1), in_real'high + 1)); 75 | in_valid <= '1'; 76 | if (i = 0) then 77 | in_sop <= '1'; 78 | else 79 | in_sop <= '0'; 80 | end if; 81 | 82 | if (i = N-1) then 83 | in_eop <= '1'; 84 | else 85 | in_eop <= '0'; 86 | end if; 87 | end loop; 88 | 89 | wait until rising_edge(clock); 90 | in_valid <= '0'; 91 | in_sop <= '0'; 92 | in_eop <= '0'; 93 | wait for 500 ns; 94 | end loop; 95 | wait for 5 ms; 96 | end process; 97 | 98 | U_uut: entity work.fft(mult) 99 | generic map( 100 | N => N 101 | ) 102 | port map( 103 | clock => clock, 104 | reset => reset, 105 | 106 | inverse => '1', 107 | in_real => in_real, 108 | in_imag => in_imag, 109 | in_valid => in_valid, 110 | in_sop => in_sop, 111 | in_eop => in_eop, 112 | 113 | out_real => open, 114 | out_imag => open, 115 | out_error => open, 116 | out_valid => open 117 | ); 118 | 119 | end architecture; 120 | 121 | -------------------------------------------------------------------------------- /fpga/ip/nuand/nco.vhd: -------------------------------------------------------------------------------- 1 | -- This file is part of bladeRF-wiphy. 2 | -- 3 | -- Copyright (C) 2020 Nuand, LLC. 4 | -- 5 | -- This program is free software; you can redistribute it and/or modify 6 | -- it under the terms of the GNU General Public License as published by 7 | -- the Free Software Foundation; either version 2 of the License, or 8 | -- (at your option) any later version. 9 | -- 10 | -- This program is distributed in the hope that it will be useful, 11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | -- GNU General Public License for more details. 14 | -- 15 | -- You should have received a copy of the GNU General Public License along 16 | -- with this program; if not, write to the Free Software Foundation, Inc., 17 | -- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | 19 | library ieee ; 20 | use ieee.std_logic_1164.all ; 21 | use ieee.numeric_std.all ; 22 | 23 | package nco_p is 24 | 25 | type nco_input_t is record 26 | dphase : signed(15 downto 0) ; 27 | valid : std_logic ; 28 | end record ; 29 | 30 | type nco_output_t is record 31 | re : signed(15 downto 0) ; 32 | im : signed(15 downto 0) ; 33 | valid : std_logic ; 34 | end record ; 35 | 36 | end package ; -- nco_p 37 | 38 | library ieee ; 39 | use ieee.std_logic_1164.all ; 40 | use ieee.numeric_std.all ; 41 | 42 | library work ; 43 | use work.cordic_p.all ; 44 | use work.nco_p.all ; 45 | 46 | entity nco is 47 | port ( 48 | clock : in std_logic ; 49 | reset : in std_logic ; 50 | inputs : in nco_input_t ; 51 | outputs : out nco_output_t 52 | ) ; 53 | end entity ; -- nco 54 | 55 | architecture arch of nco is 56 | 57 | signal phase : signed(15 downto 0) ; 58 | 59 | signal cordic_inputs : cordic_xyz_t ; 60 | signal cordic_outputs : cordic_xyz_t ; 61 | 62 | begin 63 | 64 | accumulate_phase : process(clock, reset) 65 | variable temp : signed(15 downto 0) ; 66 | begin 67 | if( reset = '1' ) then 68 | phase <= (others =>'0') ; 69 | elsif( rising_edge( clock ) ) then 70 | if( inputs.valid = '1' ) then 71 | temp := phase + inputs.dphase ; 72 | if( temp > 16384 ) then 73 | temp := temp - 32768 ; 74 | elsif( temp < -16384 ) then 75 | temp := temp + 32768 ; 76 | end if ; 77 | phase <= temp ; 78 | end if ; 79 | end if ; 80 | end process ; 81 | 82 | cordic_inputs <= ( x => to_signed(1234,16), y => to_signed(0,16), z => phase, valid => inputs.valid ) ; 83 | 84 | U_cordic : entity work.cordic 85 | port map ( 86 | clock => clock, 87 | reset => reset, 88 | mode => CORDIC_ROTATION, 89 | inputs => cordic_inputs, 90 | outputs => cordic_outputs 91 | ) ; 92 | 93 | outputs.re <= cordic_outputs.x ; 94 | outputs.im <= cordic_outputs.y ; 95 | outputs.valid <= cordic_outputs.valid ; 96 | 97 | end architecture ; -- arch 98 | -------------------------------------------------------------------------------- /fpga/ip/nuand/viterbi_decoder/model/out.c: -------------------------------------------------------------------------------- 1 | // This file is part of bladeRF-wiphy. 2 | // 3 | // Copyright (C) 2021 Nuand, LLC. 4 | // 5 | // This program is free software; you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation; either version 2 of the License, or 8 | // (at your option) any later version. 9 | // 10 | // This program is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License along 16 | // with this program; if not, write to the Free Software Foundation, Inc., 17 | // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #define K 7 26 | #define C_A 91 27 | #define C_B 121 28 | 29 | #define BIT(y) ( (state >> y) & 1) 30 | 31 | #define T_BIT(y) ( (t_state >> y) & 1) 32 | 33 | int main(int argc, char *argv[]) { 34 | unsigned t_state; 35 | unsigned next_state; 36 | uint8_t t_bit_a, t_bit_b; 37 | for (t_state = 0; t_state <= 0x3f; t_state++) { 38 | // bit is 0? 39 | t_bit_a = T_BIT(5) ^ T_BIT(4) ^ T_BIT(2) ^ T_BIT(1) ^ 0; 40 | t_bit_b = T_BIT(5) ^ T_BIT(2) ^ T_BIT(1) ^ T_BIT(0) ^ 0; 41 | next_state = (t_state << 1) & 0x3f; 42 | printf("S[%d] -- bit=%d coded=%d,%d -- D[%d]\n", t_state, 0, t_bit_a, t_bit_b, next_state); 43 | 44 | // bit is 1? 45 | t_bit_a = T_BIT(5) ^ T_BIT(4) ^ T_BIT(2) ^ T_BIT(1) ^ 1; 46 | t_bit_b = T_BIT(5) ^ T_BIT(2) ^ T_BIT(1) ^ T_BIT(0) ^ 1; 47 | next_state = ((t_state << 1) & 0x3f) | 1; 48 | printf("S[%d] -- bit=%d coded=%d,%d -- D[%d]\n", t_state, 1, t_bit_a, t_bit_b, next_state); 49 | } 50 | return 0; 51 | } 52 | -------------------------------------------------------------------------------- /fpga/ip/nuand/viterbi_decoder/vhdl/branch_compare.vhd: -------------------------------------------------------------------------------- 1 | -- This file is part of bladeRF-wiphy. 2 | -- 3 | -- Copyright (C) 2021 Nuand, LLC. 4 | -- 5 | -- This program is free software; you can redistribute it and/or modify 6 | -- it under the terms of the GNU General Public License as published by 7 | -- the Free Software Foundation; either version 2 of the License, or 8 | -- (at your option) any later version. 9 | -- 10 | -- This program is distributed in the hope that it will be useful, 11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | -- GNU General Public License for more details. 14 | -- 15 | -- You should have received a copy of the GNU General Public License along 16 | -- with this program; if not, write to the Free Software Foundation, Inc., 17 | -- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | 19 | library ieee; 20 | use ieee.std_logic_1164.all; 21 | use ieee.numeric_std.all; 22 | 23 | library work; 24 | use work.viterbi_p.all; 25 | 26 | entity branch_compare is 27 | generic( 28 | RESET_ACTIVE : boolean := false; 29 | REG_UNCODED : boolean := false 30 | ); 31 | port( 32 | clock : in std_logic; 33 | reset : in std_logic; 34 | 35 | bm_a : in unsigned(15 downto 0); 36 | bm_b : in unsigned(15 downto 0); 37 | bm_valid : in std_logic; 38 | 39 | path_in_a : in path_t; 40 | path_in_b : in path_t; 41 | 42 | branch : in branch_inputs_t; 43 | path_out : out path_t; 44 | 45 | win : out std_logic 46 | ); 47 | end entity; 48 | 49 | architecture arch of branch_compare is 50 | begin 51 | 52 | process(reset, clock) 53 | variable cost_a, cost_b : unsigned(path_in_a.cost'range); 54 | begin 55 | if (reset = '1') then 56 | path_out <= NULL_PATH_RST(RESET_ACTIVE); 57 | win <= '0'; 58 | elsif (rising_edge(clock)) then 59 | if (bm_valid = '1') then 60 | cost_a := path_in_a.cost + bm_a; 61 | cost_b := path_in_b.cost + bm_b; 62 | 63 | if ((path_in_a.cost = (path_in_a.cost'range => '1')) and 64 | (path_in_b.cost = (path_in_b.cost'range => '1'))) then 65 | win <= '0'; 66 | path_out.cost <= ( others => '1' ); 67 | elsif (path_in_a.cost = (path_in_a.cost'range => '1')) then 68 | win <= '1'; 69 | path_out.cost <= cost_b; 70 | elsif (path_in_b.cost = (path_in_b.cost'range => '1')) then 71 | win <= '0'; 72 | path_out.cost <= cost_a; 73 | else 74 | if (cost_b < cost_a) then 75 | win <= '1'; 76 | path_out.cost <= cost_b; 77 | else 78 | win <= '0'; 79 | path_out.cost <= cost_a; 80 | end if; 81 | end if; 82 | end if; 83 | end if; 84 | end process; 85 | end architecture; 86 | -------------------------------------------------------------------------------- /fpga/ip/nuand/viterbi_decoder/vhdl/comp2.vhd: -------------------------------------------------------------------------------- 1 | -- This file is part of bladeRF-wiphy. 2 | -- 3 | -- Copyright (C) 2021 Nuand, LLC. 4 | -- 5 | -- This program is free software; you can redistribute it and/or modify 6 | -- it under the terms of the GNU General Public License as published by 7 | -- the Free Software Foundation; either version 2 of the License, or 8 | -- (at your option) any later version. 9 | -- 10 | -- This program is distributed in the hope that it will be useful, 11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | -- GNU General Public License for more details. 14 | -- 15 | -- You should have received a copy of the GNU General Public License along 16 | -- with this program; if not, write to the Free Software Foundation, Inc., 17 | -- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | 19 | library ieee; 20 | use ieee.std_logic_1164.all; 21 | use ieee.numeric_std.all; 22 | 23 | library work; 24 | use work.viterbi_p.all; 25 | 26 | entity comp2 is 27 | port( 28 | clock : in std_logic; 29 | reset : in std_logic; 30 | 31 | path_name_a : in path_name_t; 32 | path_name_b : in path_name_t; 33 | path_valid : in std_logic; 34 | 35 | path_name_out : out path_name_t 36 | ); 37 | end entity; 38 | 39 | architecture arch of comp2 is 40 | begin 41 | process(clock, reset) 42 | begin 43 | if (reset = '1') then 44 | path_name_out.name <= (others => '0'); 45 | path_name_out.path <= NULL_PATH_T; 46 | elsif (rising_edge(clock)) then 47 | if (path_valid = '1') then 48 | if (path_name_b.path.cost < path_name_a.path.cost) then 49 | path_name_out <= path_name_b; 50 | else 51 | path_name_out <= path_name_a; 52 | end if; 53 | end if; 54 | end if; 55 | end process; 56 | end architecture; 57 | -------------------------------------------------------------------------------- /fpga/ip/nuand/viterbi_decoder/vhdl/r2_comparator.vhd: -------------------------------------------------------------------------------- 1 | -- This file is part of bladeRF-wiphy. 2 | -- 3 | -- Copyright (C) 2021 Nuand, LLC. 4 | -- 5 | -- This program is free software; you can redistribute it and/or modify 6 | -- it under the terms of the GNU General Public License as published by 7 | -- the Free Software Foundation; either version 2 of the License, or 8 | -- (at your option) any later version. 9 | -- 10 | -- This program is distributed in the hope that it will be useful, 11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | -- GNU General Public License for more details. 14 | -- 15 | -- You should have received a copy of the GNU General Public License along 16 | -- with this program; if not, write to the Free Software Foundation, Inc., 17 | -- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | 19 | library ieee; 20 | use ieee.std_logic_1164.all; 21 | use ieee.numeric_std.all; 22 | 23 | library work; 24 | use work.viterbi_p.all; 25 | 26 | entity r2_comparator is 27 | generic( 28 | NUM_PATHS : in natural := 64; 29 | STATE_BITS : in natural := 6 30 | ); 31 | port( 32 | clock : in std_logic; 33 | reset : in std_logic; 34 | 35 | paths : in path_arr_t(NUM_PATHS-1 downto 0); 36 | path_valid : in std_logic; 37 | 38 | label_out : out unsigned(STATE_BITS-1 downto 0); 39 | valid_out : out std_logic 40 | ); 41 | end entity; 42 | 43 | architecture arch of r2_comparator is 44 | type path_name_arr_arr_t is array(natural range <>) of path_name_arr_t(NUM_PATHS-1 downto 0); 45 | 46 | signal r2_matrix : path_name_arr_arr_t(STATE_BITS downto 0); 47 | 48 | signal valid_out_r : std_logic_vector(STATE_BITS - 1 downto 1); 49 | begin 50 | gen_init_path: for i in paths'range generate 51 | r2_matrix(0)(i).path <= paths(i); 52 | r2_matrix(0)(i).name <= to_unsigned(i, 6); 53 | end generate; 54 | 55 | process(clock, reset) 56 | begin 57 | if (reset = '1') then 58 | valid_out_r <= ( others => '0' ); 59 | valid_out <= '0'; 60 | elsif (rising_edge(clock)) then 61 | if (path_valid = '1') then 62 | valid_out_r <= path_valid & valid_out_r(valid_out_r'high downto 2); 63 | valid_out <= valid_out_r(1); 64 | else 65 | valid_out <= '0'; 66 | end if; 67 | end if; 68 | end process; 69 | 70 | gen_cs: for cs_i in 1 to STATE_BITS generate 71 | gen_rs: for rs_i in 0 to NUM_PATHS/(2**cs_i)-1 generate 72 | U_comp2 : entity work.comp2 73 | port map( 74 | clock => clock, 75 | reset => reset, 76 | 77 | path_name_a => r2_matrix(cs_i-1)(rs_i * 2), 78 | path_name_b => r2_matrix(cs_i-1)(rs_i * 2 + 1), 79 | path_valid => path_valid, 80 | path_name_out => r2_matrix(cs_i)(rs_i) 81 | ); 82 | end generate; 83 | end generate; 84 | 85 | label_out <= r2_matrix(r2_matrix'high)(0).name; 86 | 87 | end architecture; 88 | -------------------------------------------------------------------------------- /fpga/ip/nuand/viterbi_decoder/vhdl/tb/compile.do: -------------------------------------------------------------------------------- 1 | vcom -work work -2008 ../viterbi_p.vhd 2 | vcom -work work -2008 ../tracer.vhd 3 | vcom -work work -2008 ../comp2.vhd 4 | vcom -work work -2008 ../r2_comparator.vhd 5 | vcom -work work -2008 ../branch_compare.vhd 6 | vcom -work work -2008 ../traceback.vhd 7 | vcom -work work -2008 ../viterbi_decoder.vhd 8 | vcom -work work -2008 viterbi_decoder_tb.vhd 9 | vcom -work work -2008 r2_comparator_tb.vhd 10 | -------------------------------------------------------------------------------- /fpga/ip/nuand/viterbi_decoder/vhdl/tb/r2_comparator_tb.vhd: -------------------------------------------------------------------------------- 1 | -- This file is part of bladeRF-wiphy. 2 | -- 3 | -- Copyright (C) 2021 Nuand, LLC. 4 | -- 5 | -- This program is free software; you can redistribute it and/or modify 6 | -- it under the terms of the GNU General Public License as published by 7 | -- the Free Software Foundation; either version 2 of the License, or 8 | -- (at your option) any later version. 9 | -- 10 | -- This program is distributed in the hope that it will be useful, 11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | -- GNU General Public License for more details. 14 | -- 15 | -- You should have received a copy of the GNU General Public License along 16 | -- with this program; if not, write to the Free Software Foundation, Inc., 17 | -- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | 19 | library ieee; 20 | use ieee.std_logic_1164.all; 21 | use ieee.numeric_std.all; 22 | 23 | library work; 24 | use work.viterbi_p.all; 25 | 26 | entity r2_comparator_tb is 27 | end entity; 28 | 29 | architecture behv of r2_comparator_tb is 30 | signal clock : std_logic := '0'; 31 | signal reset : std_logic; 32 | signal valid : std_logic; 33 | signal paths : path_arr_t(63 downto 0); 34 | 35 | begin 36 | clock <= not clock after 10 ns; 37 | reset <= '1', '0' after 100 ns; 38 | valid <= '0', '1' after 198 ns, '0' after 548 ns; 39 | 40 | process 41 | variable i : integer; 42 | variable t_cost : integer; 43 | begin 44 | for i in paths'range loop 45 | if (i = 51) then 46 | t_cost := 10; 47 | else 48 | t_cost := 100 + i; 49 | end if; 50 | paths(i).cost <= to_unsigned(t_cost, paths(i).cost'high + 1); 51 | paths(i).active <= '0'; 52 | end loop; 53 | wait; 54 | end process; 55 | 56 | 57 | U_uut: entity work.r2_comparator 58 | port map( 59 | clock => clock, 60 | reset => reset, 61 | 62 | paths => paths, 63 | path_valid => valid, 64 | 65 | label_out => open, 66 | valid_out => open 67 | ); 68 | end architecture; 69 | 70 | -------------------------------------------------------------------------------- /fpga/ip/nuand/viterbi_decoder/vhdl/traceback.vhd: -------------------------------------------------------------------------------- 1 | -- This file is part of bladeRF-wiphy. 2 | -- 3 | -- Copyright (C) 2021 Nuand, LLC. 4 | -- 5 | -- This program is free software; you can redistribute it and/or modify 6 | -- it under the terms of the GNU General Public License as published by 7 | -- the Free Software Foundation; either version 2 of the License, or 8 | -- (at your option) any later version. 9 | -- 10 | -- This program is distributed in the hope that it will be useful, 11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | -- GNU General Public License for more details. 14 | -- 15 | -- You should have received a copy of the GNU General Public License along 16 | -- with this program; if not, write to the Free Software Foundation, Inc., 17 | -- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | 19 | library ieee; 20 | use ieee.std_logic_1164.all; 21 | use ieee.numeric_std.all; 22 | 23 | library work; 24 | use work.viterbi_p.all; 25 | 26 | entity traceback is 27 | generic( 28 | STATE_BITS : in integer; 29 | NUM_STATES : in integer; 30 | TB_LEN : in integer 31 | ); 32 | port( 33 | clock : in std_logic; 34 | reset : in std_logic; 35 | 36 | acs_reg : in std_logic_vector(NUM_STATES-1 downto 0); 37 | acs_valid : in std_logic; 38 | 39 | best_idx : in unsigned(STATE_BITS-1 downto 0); 40 | best_valid : in std_logic; 41 | 42 | bit_out : out std_logic; 43 | valid_out : out std_logic 44 | ); 45 | end entity; 46 | 47 | architecture arch of traceback is 48 | type history_t is array(7 + TB_LEN*2 downto 0) of std_logic_vector(NUM_STATES-1 downto 0); 49 | 50 | type fsm_t is (IDLE, START_TRACER); 51 | 52 | type state_t is record 53 | fsm : fsm_t; 54 | loaded : std_logic; 55 | history : history_t; 56 | acs_count : natural range 0 to TB_LEN+STATE_BITS*2; 57 | acs_enough : std_logic; 58 | bit_out : std_logic; 59 | valid_out : std_logic; 60 | end record; 61 | 62 | function NULL_STATE_T return state_t is 63 | variable ret : state_t; 64 | begin 65 | ret.fsm := IDLE; 66 | ret.loaded := '0'; 67 | for i in ret.history'range loop 68 | ret.history(i) := ( others => '0' ); 69 | end loop; 70 | ret.acs_count := 0; 71 | ret.acs_enough := '0'; 72 | ret.bit_out := '0'; 73 | ret.valid_out := '0'; 74 | return(ret); 75 | end function; 76 | 77 | signal current, future : state_t := NULL_STATE_T; 78 | 79 | type trace_state_t is array(TB_LEN downto 0) of unsigned(STATE_BITS-1 downto 0); 80 | 81 | signal trace_state : trace_state_t; 82 | signal trace_state_valid : std_logic_vector(TB_LEN downto 0); 83 | begin 84 | sync : process(clock, reset) 85 | begin 86 | if (reset = '1') then 87 | current <= NULL_STATE_T; 88 | elsif (rising_edge(clock)) then 89 | current <= future; 90 | end if; 91 | end process; 92 | 93 | trace_state(0) <= best_idx; 94 | trace_state_valid(0) <= current.acs_enough; 95 | 96 | gen_tracers: for i in 0 to TB_LEN-1 generate 97 | U_tracer: entity work.tracer 98 | generic map( 99 | STATE_BITS => STATE_BITS, 100 | NUM_STATES => NUM_STATES 101 | ) 102 | port map( 103 | clock => clock, 104 | reset => reset, 105 | 106 | state_in => trace_state(i), 107 | state_valid => trace_state_valid(i), 108 | acs_reg => current.history(6 + 2 * i), 109 | acs_valid => acs_valid, 110 | 111 | state_out => trace_state(i+1), 112 | valid_out => trace_state_valid(i+1) 113 | ); 114 | end generate; 115 | 116 | 117 | bit_out <= current.bit_out; 118 | valid_out <= current.valid_out; 119 | 120 | comb : process(all) 121 | begin 122 | future <= current; 123 | 124 | future.bit_out <= '0'; 125 | future.valid_out <= '0'; 126 | 127 | if (acs_valid = '1') then 128 | if (current.acs_enough = '0') then 129 | if (current.acs_count = TB_LEN + 6 + 5) then 130 | future.acs_enough <= '1'; 131 | else 132 | future.acs_count <= current.acs_count + 1; 133 | end if; 134 | end if; 135 | future.history <= current.history(current.history'high-1 downto 0) & acs_reg; 136 | end if; 137 | 138 | case current.fsm is 139 | when IDLE => 140 | if (current.acs_enough = '1' and acs_valid = '1') then 141 | future.fsm <= START_TRACER; 142 | end if; 143 | when START_TRACER => 144 | if (acs_valid = '1') then 145 | -- the bit that is about to be shifted out is actually the uncoded bit 146 | -- the new bit that is shifted in is from the current branch, the historical ACS reg basically determines the LSB of the new state 147 | future.bit_out <= trace_state(TB_LEN)(5); 148 | future.valid_out <= trace_state_valid(TB_LEN); 149 | end if; 150 | when others => 151 | future <= NULL_STATE_T; 152 | end case; 153 | end process; 154 | 155 | end architecture; 156 | -------------------------------------------------------------------------------- /fpga/ip/nuand/viterbi_decoder/vhdl/tracer.vhd: -------------------------------------------------------------------------------- 1 | -- This file is part of bladeRF-wiphy. 2 | -- 3 | -- Copyright (C) 2021 Nuand, LLC. 4 | -- 5 | -- This program is free software; you can redistribute it and/or modify 6 | -- it under the terms of the GNU General Public License as published by 7 | -- the Free Software Foundation; either version 2 of the License, or 8 | -- (at your option) any later version. 9 | -- 10 | -- This program is distributed in the hope that it will be useful, 11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | -- GNU General Public License for more details. 14 | -- 15 | -- You should have received a copy of the GNU General Public License along 16 | -- with this program; if not, write to the Free Software Foundation, Inc., 17 | -- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | 19 | library ieee; 20 | use ieee.std_logic_1164.all; 21 | use ieee.numeric_std.all; 22 | 23 | library work; 24 | use work.viterbi_p.all; 25 | 26 | entity tracer is 27 | generic( 28 | STATE_BITS : in integer; 29 | NUM_STATES : in integer 30 | ); 31 | port( 32 | clock : in std_logic; 33 | reset : in std_logic; 34 | 35 | state_in : in unsigned(STATE_BITS-1 downto 0); 36 | state_valid : in std_logic; 37 | acs_reg : in std_logic_vector(NUM_STATES-1 downto 0); 38 | acs_valid : in std_logic; 39 | 40 | state_out : out unsigned(STATE_BITS-1 downto 0); 41 | valid_out : out std_logic 42 | ); 43 | end entity; 44 | 45 | architecture arch of tracer is 46 | begin 47 | process(clock, reset) 48 | variable s_bit : std_logic; 49 | begin 50 | if (reset='1') then 51 | state_out <= ( others => '0' ); 52 | valid_out <= '0'; 53 | elsif (rising_edge(clock)) then 54 | s_bit := acs_reg(to_integer(state_in)); 55 | if (acs_valid = '1') then 56 | state_out <= s_bit & state_in(state_in'high downto 1); 57 | valid_out <= state_valid; 58 | end if; 59 | end if; 60 | end process; 61 | end architecture; 62 | -------------------------------------------------------------------------------- /fpga/ip/nuand/viterbi_decoder/vhdl/viterbi_p.vhd: -------------------------------------------------------------------------------- 1 | -- This file is part of bladeRF-wiphy. 2 | -- 3 | -- Copyright (C) 2021 Nuand, LLC. 4 | -- 5 | -- This program is free software; you can redistribute it and/or modify 6 | -- it under the terms of the GNU General Public License as published by 7 | -- the Free Software Foundation; either version 2 of the License, or 8 | -- (at your option) any later version. 9 | -- 10 | -- This program is distributed in the hope that it will be useful, 11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | -- GNU General Public License for more details. 14 | -- 15 | -- You should have received a copy of the GNU General Public License along 16 | -- with this program; if not, write to the Free Software Foundation, Inc., 17 | -- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | 19 | library ieee; 20 | use ieee.std_logic_1164.all; 21 | use ieee.numeric_std.all; 22 | 23 | package viterbi_p is 24 | type path_t is record 25 | --- path metric stuff 26 | cost : unsigned(23 downto 0); 27 | active : std_logic; 28 | end record; 29 | type path_arr_t is array(natural range <>) of path_t; 30 | 31 | type path_name_t is record 32 | path : path_t; 33 | name : unsigned(5 downto 0); 34 | end record; 35 | 36 | type path_name_arr_t is array(natural range <>) of path_name_t; 37 | 38 | 39 | type branch_t is record 40 | -- starting conditions 41 | start_state : natural; 42 | u_bit : std_logic; 43 | 44 | -- internal state keeping 45 | bit_s : std_logic; 46 | set : boolean; 47 | 48 | -- output 49 | bit_a : std_logic; 50 | bit_b : std_logic; 51 | bm_idx : integer; 52 | 53 | -- final state 54 | prev_state : integer; 55 | next_state : integer; 56 | end record; 57 | 58 | type branch_inputs_t is array(1 downto 0) of branch_t; 59 | 60 | type bsd_t is array(natural range <>) of unsigned(7 downto 0); 61 | 62 | type bm_t is array(natural range <>) of unsigned(15 downto 0); 63 | 64 | function NULL_PATH_RST(init_state : boolean) return path_t; 65 | function NULL_PATH_T return path_t; 66 | end package; 67 | 68 | package body viterbi_p is 69 | function NULL_PATH_RST(init_state : boolean) return path_t is 70 | variable ret : path_t; 71 | begin 72 | if (init_state) then 73 | ret.cost := ( others => '0' ); 74 | else 75 | ret.cost := ( others => '1' ); 76 | end if; 77 | ret.active := '0'; 78 | return ret; 79 | end function; 80 | 81 | function NULL_PATH_T return path_t is 82 | begin 83 | return NULL_PATH_RST(false); 84 | end function; 85 | end package body; 86 | -------------------------------------------------------------------------------- /fpga/modelsim/wlan.do: -------------------------------------------------------------------------------- 1 | # Library 2 | vlib wlan 3 | 4 | if { ! [info exists wlan_path] } { 5 | set wlan_path "." 6 | } 7 | 8 | set modelsim 1 9 | 10 | vlib nuand 11 | vcom -work nuand -2008 [file join $wlan_path ../../../bladeRF/hdl/fpga/ip/nuand/synthesis/fifo_readwrite_p.vhd ] 12 | 13 | # altera ip simulation models 14 | vlib fft64 15 | 16 | set QSYS_SIMDIR [file normalize [ file join $wlan_path ../ip/altera/fft64/fft64/simulation/ ] ] 17 | source [file normalize [ file join $wlan_path $QSYS_SIMDIR/mentor/msim_setup.tcl ] ] 18 | dev_com 19 | com 20 | vmap fft64 libraries/fft_ii_0/ 21 | 22 | vlog -work fft64 [ file join $wlan_path ../ip/altera/fft64/fft64/simulation/fft64.v ] 23 | set hexfiles [glob [file join $wlan_path "../ip/altera/fft64/fft64/simulation/submodules/*.hex"] ] 24 | foreach f $hexfiles { 25 | file copy -force $f . 26 | } 27 | 28 | vlib viterbi_decoder 29 | set QSYS_SIMDIR [file normalize [ file join $wlan_path ../ip/altera/viterbi_decoder/viterbi_decoder/simulation/ ] ] 30 | source [file normalize [ file join $wlan_path $QSYS_SIMDIR/mentor/msim_setup.tcl ] ] 31 | dev_com 32 | com 33 | vmap viterbi_decoder libraries/viterbi_ii_0/ 34 | 35 | vlog -work viterbi_decoder [ file join $wlan_path ../ip/altera/viterbi_decoder/viterbi_decoder/simulation/viterbi_decoder.v ] 36 | vlog -work viterbi_decoder [ file join $wlan_path ../ip/altera/viterbi_decoder/viterbi_decoder/simulation/submodules/viterbi_decoder_viterbi_ii_0.v ] 37 | 38 | 39 | vlib wlan_pll 40 | vlog -work wlan_pll [ file join $wlan_path ../ip/altera/wlan_pll/wlan_pll/wlan_pll.v ] 41 | 42 | source [file normalize [ file join $wlan_path ../common/wlan_files.tcl ] ] 43 | 44 | # Common packages 45 | foreach f $wlan_common { 46 | vcom -work wlan -2008 $f 47 | } 48 | 49 | # TX Synthesis 50 | foreach f $wlan_synthesis_tx { 51 | vcom -work wlan -2008 $f 52 | } 53 | 54 | # RX Synthesis 55 | foreach f $wlan_synthesis_rx { 56 | vcom -work wlan -2008 $f 57 | } 58 | 59 | # Top Level Synthesis 60 | foreach f $wlan_synthesis_top { 61 | vcom -work wlan -2008 $f 62 | } 63 | 64 | # Simulation 65 | foreach f $wlan_sim { 66 | vcom -work wlan -2008 $f 67 | } 68 | 69 | proc wlan_sim_entity { entity } { 70 | vsim -t ps -L work -L work_lib -L fft_ii_0 -L altera_ver -L lpm_ver -L sgate_ver -L altera_mf_ver -L wlan -L fft64 -L viterbi_decoder -L altera_lnsim_ver $entity 71 | } 72 | 73 | alias tb_wlan_rx { 74 | wlan_sim_entity wlan_rx_tb 75 | } 76 | -------------------------------------------------------------------------------- /fpga/quartus/wlan.qip: -------------------------------------------------------------------------------- 1 | # Altera FFT IP 2 | set_global_assignment -name QIP_FILE [file normalize "../../../../../bladeRF-wiphy/fpga/ip/altera/fft64/fft64/synthesis/fft64.qip"] 3 | set_global_assignment -name QIP_FILE [file normalize "../../../../../bladeRF-wiphy/fpga/ip/altera/viterbi_decoder/viterbi_decoder/synthesis/viterbi_decoder.qip"] 4 | set_global_assignment -library "wlan_pll" -name VERILOG_FILE [file normalize "../../../../../bladeRF-wiphy/fpga/ip/altera/wlan_pll/wlan_pll/wlan_pll.v"] 5 | set_global_assignment -library "wlan_pll" -name QIP_FILE [file normalize "../../../../../bladeRF-wiphy/fpga/ip/altera/wlan_pll/wlan_pll/wlan_pll.qip"] 6 | 7 | set modelsim 0 8 | 9 | # Nuand WLAN IP files 10 | source [file normalize [file join $::quartus(qip_path) ../common/wlan_files.tcl]] 11 | foreach f $wlan_common { 12 | set_global_assignment -library "wlan" -name VHDL_FILE [file normalize [file join $::quartus(qip_path) $f]] -hdl_version VHDL_2008 13 | } 14 | 15 | foreach f $wlan_synthesis_tx { 16 | set_global_assignment -library "wlan" -name VHDL_FILE [file normalize [file join $::quartus(qip_path) $f]] -hdl_version VHDL_2008 17 | } 18 | 19 | foreach f $wlan_synthesis_rx { 20 | set_global_assignment -library "wlan" -name VHDL_FILE [file normalize [file join $::quartus(qip_path) $f]] -hdl_version VHDL_2008 21 | } 22 | 23 | foreach f $wlan_synthesis_top { 24 | set_global_assignment -library "wlan" -name VHDL_FILE [file normalize [file join $::quartus(qip_path) $f]] -hdl_version VHDL_2008 25 | } 26 | 27 | -------------------------------------------------------------------------------- /fpga/vhdl/clock_sync_logic.vhd: -------------------------------------------------------------------------------- 1 | -- This file is part of bladeRF-wiphy. 2 | -- 3 | -- Copyright (C) 2020 Nuand, LLC. 4 | -- 5 | -- This program is free software; you can redistribute it and/or modify 6 | -- it under the terms of the GNU General Public License as published by 7 | -- the Free Software Foundation; either version 2 of the License, or 8 | -- (at your option) any later version. 9 | -- 10 | -- This program is distributed in the hope that it will be useful, 11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | -- GNU General Public License for more details. 14 | -- 15 | -- You should have received a copy of the GNU General Public License along 16 | -- with this program; if not, write to the Free Software Foundation, Inc., 17 | -- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | 19 | library ieee ; 20 | use ieee.std_logic_1164.all ; 21 | use ieee.numeric_std.all ; 22 | 23 | library wlan ; 24 | use wlan.wlan_rx_p.all ; 25 | 26 | entity clock_sync_logic is 27 | port ( 28 | from_signal : in std_logic ; 29 | 30 | to_clock : in std_logic ; 31 | to_reset : in std_logic ; 32 | 33 | to_signal : out std_logic 34 | ) ; 35 | end entity; 36 | 37 | architecture arch of clock_sync_logic is 38 | 39 | signal t_sig_r : std_logic ; 40 | signal t_sig_rr : std_logic ; 41 | 42 | attribute ALTERA_ATTRIBUTE : string; 43 | 44 | attribute ALTERA_ATTRIBUTE of arch: architecture is "-name SDC_STATEMENT ""set_false_path -to [get_registers *clock_sync_logic|*_r* ] "" "; 45 | 46 | begin 47 | 48 | process(all) 49 | begin 50 | if( to_reset = '1' ) then 51 | t_sig_rr <= '0' ; 52 | t_sig_r <= '0' ; 53 | to_signal <= '0' ; 54 | elsif( rising_edge( to_clock ) ) then 55 | t_sig_r <= from_signal ; 56 | t_sig_rr <= t_sig_r ; 57 | if( t_sig_rr = '0' and t_sig_r = '1' ) then 58 | to_signal <= '1' ; 59 | else 60 | to_signal <= '0' ; 61 | end if ; 62 | end if ; 63 | end process ; 64 | 65 | end architecture ; 66 | -------------------------------------------------------------------------------- /fpga/vhdl/clock_sync_logic_vector.vhd: -------------------------------------------------------------------------------- 1 | -- This file is part of bladeRF-wiphy. 2 | -- 3 | -- Copyright (C) 2020 Nuand, LLC. 4 | -- 5 | -- This program is free software; you can redistribute it and/or modify 6 | -- it under the terms of the GNU General Public License as published by 7 | -- the Free Software Foundation; either version 2 of the License, or 8 | -- (at your option) any later version. 9 | -- 10 | -- This program is distributed in the hope that it will be useful, 11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | -- GNU General Public License for more details. 14 | -- 15 | -- You should have received a copy of the GNU General Public License along 16 | -- with this program; if not, write to the Free Software Foundation, Inc., 17 | -- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | 19 | library ieee ; 20 | use ieee.std_logic_1164.all ; 21 | use ieee.numeric_std.all ; 22 | 23 | library wlan ; 24 | use wlan.wlan_rx_p.all ; 25 | 26 | entity clock_sync_logic_vector is 27 | generic ( 28 | LEN : integer := 8 29 | ) ; 30 | port ( 31 | from_signal : in std_logic_vector(LEN-1 downto 0) ; 32 | 33 | to_clock : in std_logic ; 34 | to_reset : in std_logic ; 35 | 36 | to_signal : out std_logic_vector(LEN-1 downto 0) 37 | ) ; 38 | end entity; 39 | 40 | architecture arch of clock_sync_logic_vector is 41 | 42 | signal t_sig_r : std_logic_vector(LEN-1 downto 0) ; 43 | 44 | attribute ALTERA_ATTRIBUTE : string; 45 | 46 | attribute ALTERA_ATTRIBUTE of arch: architecture is "-name SDC_STATEMENT ""set_false_path -to [get_registers *clock_sync_logic_vector|*_r* ] "" "; 47 | 48 | begin 49 | 50 | process(all) 51 | begin 52 | if( to_reset = '1' ) then 53 | t_sig_r <= ( others => '0' ) ; 54 | to_signal <= ( others => '0' ) ; 55 | elsif( rising_edge( to_clock ) ) then 56 | t_sig_r <= from_signal ; 57 | to_signal <= t_sig_r ; 58 | end if ; 59 | end process ; 60 | end architecture ; 61 | -------------------------------------------------------------------------------- /fpga/vhdl/clock_sync_params.vhd: -------------------------------------------------------------------------------- 1 | -- This file is part of bladeRF-wiphy. 2 | -- 3 | -- Copyright (C) 2020 Nuand, LLC. 4 | -- 5 | -- This program is free software; you can redistribute it and/or modify 6 | -- it under the terms of the GNU General Public License as published by 7 | -- the Free Software Foundation; either version 2 of the License, or 8 | -- (at your option) any later version. 9 | -- 10 | -- This program is distributed in the hope that it will be useful, 11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | -- GNU General Public License for more details. 14 | -- 15 | -- You should have received a copy of the GNU General Public License along 16 | -- with this program; if not, write to the Free Software Foundation, Inc., 17 | -- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | 19 | library ieee ; 20 | use ieee.std_logic_1164.all ; 21 | use ieee.numeric_std.all ; 22 | 23 | library wlan ; 24 | use wlan.wlan_rx_p.all ; 25 | 26 | entity clock_sync_params is 27 | port ( 28 | from_signal : in wlan_rx_params_t ; 29 | 30 | to_clock : in std_logic ; 31 | to_reset : in std_logic ; 32 | 33 | to_signal : out wlan_rx_params_t 34 | ) ; 35 | end entity; 36 | 37 | architecture arch of clock_sync_params is 38 | 39 | signal t_sig_r : wlan_rx_params_t ; 40 | 41 | attribute ALTERA_ATTRIBUTE : string; 42 | 43 | attribute ALTERA_ATTRIBUTE of arch: architecture is "-name SDC_STATEMENT ""set_false_path -to [get_registers *clock_sync_params|*_r* ] "" "; 44 | 45 | begin 46 | 47 | process(all) 48 | begin 49 | if( to_reset = '1' ) then 50 | t_sig_r <= NULL_PARAMS ; 51 | to_signal <= NULL_PARAMS ; 52 | elsif( rising_edge( to_clock ) ) then 53 | t_sig_r <= from_signal ; 54 | to_signal <= t_sig_r ; 55 | end if ; 56 | end process ; 57 | 58 | end architecture ; 59 | -------------------------------------------------------------------------------- /fpga/vhdl/tb/wlan_ack_generator_tb.vhd: -------------------------------------------------------------------------------- 1 | -- This file is part of bladeRF-wiphy. 2 | -- 3 | -- Copyright (C) 2020 Nuand, LLC. 4 | -- 5 | -- This program is free software; you can redistribute it and/or modify 6 | -- it under the terms of the GNU General Public License as published by 7 | -- the Free Software Foundation; either version 2 of the License, or 8 | -- (at your option) any later version. 9 | -- 10 | -- This program is distributed in the hope that it will be useful, 11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | -- GNU General Public License for more details. 14 | -- 15 | -- You should have received a copy of the GNU General Public License along 16 | -- with this program; if not, write to the Free Software Foundation, Inc., 17 | -- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | 19 | library ieee ; 20 | use ieee.std_logic_1164.all ; 21 | use ieee.numeric_std.all ; 22 | 23 | library wlan ; 24 | use wlan.wlan_rx_p.all ; 25 | 26 | entity wlan_ack_generator_tb is 27 | end entity ; 28 | 29 | architecture arch of wlan_ack_generator_tb is 30 | 31 | signal wclock : std_logic := '1' ; 32 | signal wreset : std_logic := '1' ; 33 | 34 | signal rclock : std_logic := '1' ; 35 | signal rreset : std_logic := '1' ; 36 | 37 | signal ack_valid : std_logic := '0' ; 38 | 39 | signal fifo_re : std_logic := '0' ; 40 | 41 | begin 42 | 43 | wclock <= not wclock after 5 ns ; 44 | wreset <= '1', '0' after 55 ns ; 45 | 46 | rclock <= not rclock after 6 ns ; 47 | rreset <= '1', '0' after 55 ns ; 48 | 49 | ack_valid <= '0', '1' after 72 ns, '0' after 82 ns ; 50 | 51 | fifo_re <= '0', '1' after 400 ns, '0' after 412 ns ; 52 | U_ack_gen : entity wlan.wlan_ack_generator 53 | port map ( 54 | wclock => wclock, 55 | wreset => wreset, 56 | 57 | ack_mac => x"1234567890ab", 58 | ack_valid => ack_valid, 59 | 60 | rclock => rclock, 61 | rreset => rreset, 62 | 63 | fifo_data => open, 64 | fifo_re => fifo_re, 65 | done_tx => '1', 66 | 67 | ack_ready => open 68 | ) ; 69 | 70 | end architecture ; 71 | -------------------------------------------------------------------------------- /fpga/vhdl/tb/wlan_acquisition_tb.vhd: -------------------------------------------------------------------------------- 1 | -- This file is part of bladeRF-wiphy. 2 | -- 3 | -- Copyright (C) 2020 Nuand, LLC. 4 | -- 5 | -- This program is free software; you can redistribute it and/or modify 6 | -- it under the terms of the GNU General Public License as published by 7 | -- the Free Software Foundation; either version 2 of the License, or 8 | -- (at your option) any later version. 9 | -- 10 | -- This program is distributed in the hope that it will be useful, 11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | -- GNU General Public License for more details. 14 | -- 15 | -- You should have received a copy of the GNU General Public License along 16 | -- with this program; if not, write to the Free Software Foundation, Inc., 17 | -- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | 19 | library ieee ; 20 | use ieee.std_logic_1164.all ; 21 | use ieee.numeric_std.all ; 22 | use ieee.math_real.all ; 23 | 24 | library wlan ; 25 | use wlan.wlan_p.all ; 26 | use wlan.wlan_rx_p.all ; 27 | 28 | library wlan; 29 | entity wlan_acquisition_tb is 30 | end entity ; 31 | 32 | architecture arch of wlan_acquisition_tb is 33 | 34 | signal clock : std_logic := '0' ; 35 | signal sample : wlan_sample_t ; 36 | signal fopen : std_logic; 37 | signal reset : std_logic; 38 | 39 | signal i_sum : signed(63 downto 0); 40 | signal q_sum : signed(63 downto 0); 41 | signal sum : signed(127 downto 0); 42 | 43 | signal acquired_packet : std_logic ; 44 | signal p_mag : signed(23 downto 0) ; 45 | 46 | type SAMPLE_ARRAY is array (integer range <>) of wlan_sample_t; 47 | signal samples : SAMPLE_ARRAY(0 to 159); 48 | 49 | begin 50 | 51 | clock <= not clock after 10 ns; 52 | reset <= '1', '0' after 50 ns ; 53 | fopen <= '0', '1' after 100 ns; 54 | 55 | U_sample_loader: entity wlan.wlan_sample_loader 56 | generic map ( 57 | FILENAME => "tx" 58 | ) port map ( 59 | clock => clock, 60 | fopen => fopen, 61 | sample => sample 62 | ); 63 | 64 | U_csma : entity wlan.wlan_csma 65 | port map ( 66 | clock => clock, 67 | reset => reset, 68 | 69 | in_sample => sample, 70 | quiet => open 71 | ) ; 72 | U_acquisition : entity wlan.wlan_acquisition 73 | port map ( 74 | clock => clock, 75 | reset => reset, 76 | 77 | in_sample => sample, 78 | acquired => acquired_packet, 79 | p_mag => p_mag, 80 | 81 | quiet => '0', 82 | burst => '0', 83 | 84 | out_sample => open 85 | ); 86 | 87 | tb : process(clock) 88 | variable tsum : signed(127 downto 0); 89 | variable isum : signed(63 downto 0); 90 | variable qsum : signed(63 downto 0); 91 | begin 92 | if( rising_edge( clock ) ) then 93 | if( sample.valid = '1' ) then 94 | for i in 0 to samples'high - 1 loop 95 | samples(i+1) <= samples(i); 96 | end loop ; 97 | samples(0) <= sample; 98 | 99 | isum := (others => '0'); 100 | qsum := (others => '0'); 101 | for i in 0 to 79 loop 102 | isum := isum + samples(i).i * samples(i + 80).i + samples(i).q * samples(i + 80).q; 103 | qsum := qsum - samples(i).i * samples(i + 80).q + samples(i).q * samples(i + 80).i; 104 | end loop ; 105 | i_sum <= isum; 106 | q_sum <= qsum; 107 | tsum := isum * isum + qsum * qsum; 108 | sum <= tsum; 109 | end if; 110 | end if ; 111 | end process ; 112 | 113 | end architecture ; 114 | 115 | -------------------------------------------------------------------------------- /fpga/vhdl/tb/wlan_bsd_tb.vhd: -------------------------------------------------------------------------------- 1 | -- This file is part of bladeRF-wiphy. 2 | -- 3 | -- Copyright (C) 2020 Nuand, LLC. 4 | -- 5 | -- This program is free software; you can redistribute it and/or modify 6 | -- it under the terms of the GNU General Public License as published by 7 | -- the Free Software Foundation; either version 2 of the License, or 8 | -- (at your option) any later version. 9 | -- 10 | -- This program is distributed in the hope that it will be useful, 11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | -- GNU General Public License for more details. 14 | -- 15 | -- You should have received a copy of the GNU General Public License along 16 | -- with this program; if not, write to the Free Software Foundation, Inc., 17 | -- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | 19 | library ieee ; 20 | use ieee.std_logic_1164.all ; 21 | use ieee.numeric_std.all ; 22 | 23 | library wlan ; 24 | use wlan.wlan_p.all ; 25 | 26 | entity wlan_bsd_tb is 27 | end entity ; 28 | 29 | architecture arch of wlan_bsd_tb is 30 | 31 | signal clock : std_logic := '1' ; 32 | signal reset : std_logic := '1' ; 33 | 34 | signal init : std_logic := '0' ; 35 | 36 | signal modulation : wlan_modulation_t := WLAN_BPSK ; 37 | 38 | signal data : std_logic_vector(287 downto 0) := (others =>'0') ; 39 | signal data_valid : std_logic := '0' ; 40 | 41 | signal mod_start : std_logic ; 42 | signal mod_end : std_logic ; 43 | signal mod_sample : wlan_sample_t ; 44 | 45 | signal bsds : wlan_bsds_t ; 46 | 47 | procedure nop( signal clock : in std_logic ; count : in natural ) is 48 | begin 49 | for i in 1 to count loop 50 | wait until rising_edge(clock) ; 51 | end loop ; 52 | end procedure ; 53 | 54 | begin 55 | 56 | clock <= not clock after 1 ns ; 57 | 58 | U_modulator : entity work.wlan_modulator 59 | port map ( 60 | clock => clock, 61 | reset => reset, 62 | 63 | init => init, 64 | 65 | data => data, 66 | modulation => modulation, 67 | in_valid => data_valid, 68 | 69 | ifft_ready => '1', 70 | 71 | symbol_start => mod_start, 72 | symbol_end => mod_end, 73 | symbol_sample => mod_sample 74 | ) ; 75 | 76 | U_bsd : entity work.wlan_bsd 77 | port map ( 78 | clock => clock, 79 | reset => reset, 80 | 81 | modulation => modulation, 82 | 83 | in_sample => mod_sample, 84 | 85 | bsds => bsds 86 | ) ; 87 | 88 | tb : process 89 | begin 90 | reset <= '1' ; 91 | nop( clock, 10 ) ; 92 | 93 | reset <= '0' ; 94 | nop( clock, 10 ) ; 95 | 96 | init <= '1' ; 97 | nop( clock, 1 ) ; 98 | init <= '0' ; 99 | nop( clock, 1 ) ; 100 | 101 | -- Run through modulations and populate data 102 | for m in 0 to wlan_modulation_t'pos(WLAN_64QAM) loop 103 | modulation <= wlan_modulation_t'val(m) ; 104 | data <= (others =>'0') ; 105 | data_valid <= '1' ; 106 | nop( clock, 1 ) ; 107 | data_valid <= '0' ; 108 | wait until rising_edge(clock) and mod_start = '1' ; 109 | wait until rising_edge(clock) and mod_end = '1' ; 110 | nop( clock, 10 ) ; 111 | end loop ; 112 | 113 | nop( clock, 100 ) ; 114 | report "-- End of Simulation --" severity failure ; 115 | end process ; 116 | 117 | end architecture ; 118 | 119 | -------------------------------------------------------------------------------- /fpga/vhdl/tb/wlan_clock_tb.vhd: -------------------------------------------------------------------------------- 1 | -- This file is part of bladeRF-wiphy. 2 | -- 3 | -- Copyright (C) 2020 Nuand, LLC. 4 | -- 5 | -- This program is free software; you can redistribute it and/or modify 6 | -- it under the terms of the GNU General Public License as published by 7 | -- the Free Software Foundation; either version 2 of the License, or 8 | -- (at your option) any later version. 9 | -- 10 | -- This program is distributed in the hope that it will be useful, 11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | -- GNU General Public License for more details. 14 | -- 15 | -- You should have received a copy of the GNU General Public License along 16 | -- with this program; if not, write to the Free Software Foundation, Inc., 17 | -- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | 19 | library ieee ; 20 | use ieee.std_logic_1164.all ; 21 | use ieee.numeric_std.all ; 22 | 23 | library wlan ; 24 | use wlan.wlan_p.all ; 25 | use wlan.wlan_rx_p.all ; 26 | 27 | library altera_mf ; 28 | use altera_mf.altera_mf_components.all ; 29 | 30 | library wlan_pll ; 31 | 32 | 33 | entity wlan_clock_tb is 34 | end entity ; 35 | 36 | architecture arch of wlan_clock_tb is 37 | 38 | signal wclock : std_logic := '1' ; 39 | signal wreset : std_logic := '1' ; 40 | signal wdata : unsigned(7 downto 0) := ( others => '0' ) ; 41 | signal wvalid : std_logic := '1' ; 42 | signal wfull : std_logic := '1' ; 43 | 44 | signal rclock : std_logic := '1' ; 45 | signal rreset : std_logic := '1' ; 46 | signal rempty : std_logic := '1' ; 47 | signal rdata : std_logic_vector(7 downto 0) := ( others => '0' ) ; 48 | 49 | signal ack_valid : std_logic := '0' ; 50 | 51 | signal fifo_re : std_logic := '0' ; 52 | 53 | signal alt : std_logic := '0' ; 54 | 55 | begin 56 | wclock <= not wclock after 20 ns; 57 | rclock <= not rclock after 10 ns; 58 | 59 | process(wclock) 60 | begin 61 | if( rising_edge( wclock ) ) then 62 | alt <= not alt; 63 | if (alt = '0' ) then 64 | wdata <= wdata + 1; 65 | end if; 66 | end if; 67 | end process; 68 | 69 | U_rx_data_dc_fifo: dcfifo 70 | generic map ( 71 | lpm_width => 8, 72 | lpm_widthu => 6, 73 | lpm_numwords => 32, 74 | lpm_showahead => "ON" 75 | ) 76 | port map ( 77 | wrclk => wclock, 78 | wrreq => alt and not wfull, 79 | data => std_logic_vector(wdata), 80 | 81 | wrfull => wfull, 82 | wrempty => open, 83 | wrusedw => open, 84 | 85 | rdclk => rclock, 86 | rdreq => not rempty, 87 | q => rdata, 88 | 89 | rdfull => open, 90 | rdempty => rempty, 91 | rdusedw => open 92 | ) ; 93 | 94 | 95 | end architecture ; 96 | -------------------------------------------------------------------------------- /fpga/vhdl/tb/wlan_dsss_plcp_crc_tb.vhd: -------------------------------------------------------------------------------- 1 | -- This file is part of bladeRF-wiphy. 2 | -- 3 | -- Copyright (C) 2020 Nuand, LLC. 4 | -- 5 | -- This program is free software; you can redistribute it and/or modify 6 | -- it under the terms of the GNU General Public License as published by 7 | -- the Free Software Foundation; either version 2 of the License, or 8 | -- (at your option) any later version. 9 | -- 10 | -- This program is distributed in the hope that it will be useful, 11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | -- GNU General Public License for more details. 14 | -- 15 | -- You should have received a copy of the GNU General Public License along 16 | -- with this program; if not, write to the Free Software Foundation, Inc., 17 | -- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | 19 | library ieee ; 20 | use ieee.std_logic_1164.all ; 21 | use ieee.numeric_std.all ; 22 | 23 | library wlan ; 24 | use wlan.wlan_rx_p.all ; 25 | 26 | entity wlan_dsss_plcp_crc_tb is 27 | end entity ; 28 | 29 | architecture arch of wlan_dsss_plcp_crc_tb is 30 | 31 | signal clock : std_logic := '1' ; 32 | signal reset : std_logic := '1' ; 33 | 34 | signal in_data : std_logic := '1' ; 35 | 36 | begin 37 | 38 | clock <= not clock after 5 ns ; 39 | reset <= '1', '0' after 55 ns ; 40 | in_data <= '0', 41 | '1' after 65 ns, 42 | '0' after 75 ns, 43 | '1' after 85 ns, 44 | '0' after 95 ns; 45 | 46 | 47 | U_plcp_crc : entity wlan.wlan_dsss_plcp_crc 48 | port map ( 49 | clock => clock, 50 | reset => reset, 51 | 52 | in_data => in_data, 53 | in_valid => '1', 54 | crc => open 55 | ) ; 56 | 57 | end architecture ; 58 | -------------------------------------------------------------------------------- /fpga/vhdl/tb/wlan_interleaver_tb.vhd: -------------------------------------------------------------------------------- 1 | -- This file is part of bladeRF-wiphy. 2 | -- 3 | -- Copyright (C) 2020 Nuand, LLC. 4 | -- 5 | -- This program is free software; you can redistribute it and/or modify 6 | -- it under the terms of the GNU General Public License as published by 7 | -- the Free Software Foundation; either version 2 of the License, or 8 | -- (at your option) any later version. 9 | -- 10 | -- This program is distributed in the hope that it will be useful, 11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | -- GNU General Public License for more details. 14 | -- 15 | -- You should have received a copy of the GNU General Public License along 16 | -- with this program; if not, write to the Free Software Foundation, Inc., 17 | -- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | 19 | library ieee ; 20 | use ieee.std_logic_1164.all ; 21 | use ieee.numeric_std.all ; 22 | 23 | library work ; 24 | use work.wlan_p.all ; 25 | use work.wlan_interleaver_p.all ; 26 | 27 | library std ; 28 | use std.textio.all ; 29 | 30 | entity wlan_interleaver_tb is 31 | end entity ; 32 | 33 | architecture arch of wlan_interleaver_tb is 34 | 35 | procedure print( table : integer_array_t ; n : natural ) is 36 | begin 37 | for i in 0 to n-1 loop 38 | write(output, integer'image(i) & " -> " & integer'image(table(i)) & CR ) ; 39 | end loop ; 40 | end procedure ; 41 | 42 | begin 43 | 44 | tb : process 45 | variable l : line ; 46 | begin 47 | 48 | write( output, "-- BPSK Table --" & CR ) ; 49 | print( WLAN_INTERLEAVER_BPSK, 48 ) ; 50 | wait ; 51 | 52 | end process ; 53 | 54 | end architecture ; 55 | 56 | -------------------------------------------------------------------------------- /fpga/vhdl/tb/wlan_lfsr_tb.vhd: -------------------------------------------------------------------------------- 1 | -- This file is part of bladeRF-wiphy. 2 | -- 3 | -- Copyright (C) 2020 Nuand, LLC. 4 | -- 5 | -- This program is free software; you can redistribute it and/or modify 6 | -- it under the terms of the GNU General Public License as published by 7 | -- the Free Software Foundation; either version 2 of the License, or 8 | -- (at your option) any later version. 9 | -- 10 | -- This program is distributed in the hope that it will be useful, 11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | -- GNU General Public License for more details. 14 | -- 15 | -- You should have received a copy of the GNU General Public License along 16 | -- with this program; if not, write to the Free Software Foundation, Inc., 17 | -- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | 19 | library ieee ; 20 | use ieee.std_logic_1164.all ; 21 | use ieee.numeric_std.all ; 22 | 23 | library work ; 24 | use work.wlan_p.all ; 25 | use work.wlan_tables_p.all ; 26 | 27 | entity wlan_lfsr_tb is 28 | end entity ; 29 | 30 | architecture arch of wlan_lfsr_tb is 31 | 32 | signal clock : std_logic := '1' ; 33 | signal reset : std_logic := '1' ; 34 | 35 | signal init : unsigned(6 downto 0) := (others =>'1') ; 36 | signal init_valid : std_logic := '0' ; 37 | 38 | signal advance : std_logic := '0' ; 39 | signal data : std_logic_vector(7 downto 0) ; 40 | signal data_valid : std_logic ; 41 | 42 | function reverse(x : in std_logic_vector) return std_logic_vector is 43 | variable rv : std_logic_vector(x'range) ; 44 | begin 45 | for i in x'range loop 46 | rv(rv'high-i) := x(i) ; 47 | end loop ; 48 | return rv ; 49 | end function ; 50 | 51 | begin 52 | 53 | clock <= not clock after 0.5 ns ; 54 | 55 | U_lfsr : entity work.wlan_lfsr 56 | generic map ( 57 | WIDTH => data'length 58 | ) port map ( 59 | clock => clock, 60 | reset => reset, 61 | 62 | init => init, 63 | init_valid => init_valid, 64 | 65 | advance => advance, 66 | data => data, 67 | data_valid => data_valid 68 | ) ; 69 | 70 | tb : process 71 | begin 72 | nop( clock, 100 ) ; 73 | reset <= '0' ; 74 | 75 | nop( clock, 100 ) ; 76 | 77 | init <= "1011101" ; -- L-14 from standard 78 | init_valid <= '1' ; 79 | nop( clock, 1 ) ; 80 | 81 | init_valid <= '0' ; 82 | nop( clock, 100 ) ; 83 | 84 | for i in TABLE_L_13'range loop 85 | advance <= '1' ; 86 | nop( clock, 1 ) ; 87 | end loop ; 88 | 89 | advance <= '0' ; 90 | nop( clock, 100 ) ; 91 | 92 | report "-- End of Simulation --" severity failure ; 93 | 94 | end process ; 95 | 96 | verification : process 97 | variable indata : std_logic_vector(data'range) ; 98 | variable result : std_logic_vector(data'range) ; 99 | variable rev_result : std_logic_vector(data'range) ; 100 | begin 101 | result := (others =>'0') ; 102 | indata := (others =>'0') ; 103 | rev_result := (others =>'0') ; 104 | for i in 0 to TABLE_L_15'high loop 105 | wait until rising_edge(clock) and data_valid = '1' ; 106 | indata := std_logic_vector(to_unsigned(TABLE_L_13(i),data'length)); 107 | result := data xor indata ; 108 | -- Location of tail bits that have to be 0 going into Viterbi Encoder 109 | if( i = 102 ) then 110 | result(5 downto 0) := (others =>'0') ; 111 | end if ; 112 | rev_result := reverse(result) ; 113 | assert rev_result = std_logic_vector(to_unsigned(TABLE_L_15(i),result'length)) 114 | report "Incorrect scrambling sequence at index " & integer'image(i) 115 | severity error ; 116 | end loop ; 117 | wait ; 118 | end process ; 119 | 120 | end architecture ; 121 | 122 | -------------------------------------------------------------------------------- /fpga/vhdl/tb/wlan_modulator_tb.vhd: -------------------------------------------------------------------------------- 1 | -- This file is part of bladeRF-wiphy. 2 | -- 3 | -- Copyright (C) 2020 Nuand, LLC. 4 | -- 5 | -- This program is free software; you can redistribute it and/or modify 6 | -- it under the terms of the GNU General Public License as published by 7 | -- the Free Software Foundation; either version 2 of the License, or 8 | -- (at your option) any later version. 9 | -- 10 | -- This program is distributed in the hope that it will be useful, 11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | -- GNU General Public License for more details. 14 | -- 15 | -- You should have received a copy of the GNU General Public License along 16 | -- with this program; if not, write to the Free Software Foundation, Inc., 17 | -- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | 19 | library ieee ; 20 | use ieee.std_logic_1164.all ; 21 | use ieee.numeric_std.all ; 22 | 23 | library work ; 24 | use work.wlan_p.all ; 25 | use work.wlan_tables_p.all ; 26 | 27 | entity wlan_modulator_tb is 28 | end entity ; 29 | 30 | architecture arch of wlan_modulator_tb is 31 | 32 | signal clock : std_logic := '1' ; 33 | signal reset : std_logic := '1' ; 34 | 35 | signal init : std_logic := '0' ; 36 | 37 | signal data : std_logic_vector(287 downto 0) := TABLE_L_19 ; 38 | signal modulation : wlan_modulation_t := WLAN_16QAM ; 39 | signal in_valid : std_logic := '0' ; 40 | 41 | signal symbol_start : std_logic ; 42 | signal symbol_end : std_logic ; 43 | signal symbol_sample : wlan_sample_t ; 44 | 45 | signal ifft_sample : wlan_sample_t ; 46 | signal ifft_valid_cp : std_logic ; 47 | signal ifft_done : std_logic ; 48 | 49 | begin 50 | 51 | clock <= not clock after (0.5 sec / 40.0e6) ; 52 | 53 | U_modulator : entity work.wlan_modulator 54 | port map ( 55 | clock => clock, 56 | reset => reset, 57 | 58 | init => init, 59 | 60 | data => data, 61 | modulation => modulation, 62 | in_valid => in_valid, 63 | 64 | ifft_ready => '1', 65 | 66 | symbol_start => symbol_start, 67 | symbol_end => symbol_end, 68 | symbol_sample => symbol_sample 69 | ) ; 70 | 71 | U_ifft : entity work.wlan_ifft64 72 | port map ( 73 | clock => clock, 74 | reset => reset, 75 | 76 | symbol_start => symbol_start, 77 | symbol_end => symbol_end, 78 | in_sample => symbol_sample, 79 | 80 | out_sample => ifft_sample, 81 | out_valid_cp => ifft_valid_cp, 82 | done => ifft_done 83 | ) ; 84 | 85 | tb : process 86 | begin 87 | reset <= '1' ; 88 | nop( clock, 100 ) ; 89 | 90 | reset <= '0' ; 91 | nop( clock, 100 ) ; 92 | 93 | init <= '1' ; 94 | nop( clock, 1 ) ; 95 | init <= '0' ; 96 | nop( clock, 10 ) ; 97 | 98 | for i in 1 to 10 loop 99 | in_valid <= '1' ; 100 | nop( clock, 1 ) ; 101 | in_valid <= '0' ; 102 | nop( clock, 1 ) ; 103 | wait until rising_edge(clock) and symbol_end = '1' ; 104 | nop( clock, 1 ) ; 105 | end loop ; 106 | 107 | nop( clock, 1000 ) ; 108 | report "-- End of Simulation --" severity failure ; 109 | end process ; 110 | 111 | end architecture ; 112 | 113 | -------------------------------------------------------------------------------- /fpga/vhdl/tb/wlan_peak_finder_tb.vhd: -------------------------------------------------------------------------------- 1 | -- This file is part of bladeRF-wiphy. 2 | -- 3 | -- Copyright (C) 2020 Nuand, LLC. 4 | -- 5 | -- This program is free software; you can redistribute it and/or modify 6 | -- it under the terms of the GNU General Public License as published by 7 | -- the Free Software Foundation; either version 2 of the License, or 8 | -- (at your option) any later version. 9 | -- 10 | -- This program is distributed in the hope that it will be useful, 11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | -- GNU General Public License for more details. 14 | -- 15 | -- You should have received a copy of the GNU General Public License along 16 | -- with this program; if not, write to the Free Software Foundation, Inc., 17 | -- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | 19 | library ieee ; 20 | use ieee.std_logic_1164.all ; 21 | use ieee.numeric_std.all ; 22 | 23 | library work ; 24 | use work.wlan_p.all ; 25 | use work.wlan_tables_p.all ; 26 | 27 | entity wlan_peak_finder_tb is 28 | end entity ; 29 | 30 | architecture arch of wlan_peak_finder_tb is 31 | 32 | signal clock : std_logic := '1' ; 33 | signal reset : std_logic := '1' ; 34 | 35 | signal init : unsigned(6 downto 0) := (others =>'1') ; 36 | signal init_valid : std_logic := '0' ; 37 | 38 | signal advance : std_logic := '0' ; 39 | signal data : std_logic_vector(7 downto 0) ; 40 | signal data_valid : std_logic ; 41 | 42 | signal sample : unsigned( 127 downto 0 ) ; 43 | signal inc : std_logic := '1'; 44 | begin 45 | 46 | clock <= not clock after 0.5 ns ; 47 | reset <= '1', '0' after 10 ns; 48 | U_peak_finder : entity work.wlan_peak_finder 49 | port map ( 50 | clock => clock, 51 | reset => reset, 52 | 53 | sample => sample, 54 | sample_valid=> '1', 55 | peak => open 56 | ) ; 57 | 58 | process(clock) 59 | begin 60 | if( reset = '1' ) then 61 | sample <= (others => '0') ; 62 | elsif( rising_edge( clock ) ) then 63 | if( inc = '1' ) then 64 | sample <= sample + 1 ; 65 | if (sample = 45) then 66 | inc <= '0'; 67 | end if; 68 | else 69 | sample <= sample - 1 ; 70 | end if; 71 | end if; 72 | end process; 73 | 74 | end architecture ; 75 | 76 | 77 | -------------------------------------------------------------------------------- /fpga/vhdl/tb/wlan_sample_loader.vhd: -------------------------------------------------------------------------------- 1 | -- This file is part of bladeRF-wiphy. 2 | -- 3 | -- Copyright (C) 2020 Nuand, LLC. 4 | -- 5 | -- This program is free software; you can redistribute it and/or modify 6 | -- it under the terms of the GNU General Public License as published by 7 | -- the Free Software Foundation; either version 2 of the License, or 8 | -- (at your option) any later version. 9 | -- 10 | -- This program is distributed in the hope that it will be useful, 11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | -- GNU General Public License for more details. 14 | -- 15 | -- You should have received a copy of the GNU General Public License along 16 | -- with this program; if not, write to the Free Software Foundation, Inc., 17 | -- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | 19 | library ieee ; 20 | use ieee.std_logic_1164.all ; 21 | use ieee.numeric_std.all ; 22 | 23 | library std ; 24 | use std.textio.all ; 25 | 26 | library wlan ; 27 | use wlan.wlan_p.all ; 28 | 29 | entity wlan_sample_loader is 30 | generic ( 31 | FILENAME : string := "tx" 32 | ) ; 33 | port ( 34 | clock : in std_logic ; 35 | fopen : in std_logic ; 36 | sample : out wlan_sample_t ; 37 | ad_ctrl : out std_logic_vector( 7 downto 0 ) 38 | ) ; 39 | end entity ; 40 | 41 | architecture arch of wlan_sample_loader is 42 | 43 | begin 44 | 45 | save : process 46 | file f : text ; 47 | variable l : line ; 48 | variable li : integer ; 49 | variable comma : character ; 50 | variable status : file_open_status ; 51 | variable fcount : natural := 0 ; 52 | variable scount : natural := 0 ; 53 | function fname( b : string ; count : natural ) return string is 54 | begin 55 | return b & "-" & integer'image(count) & ".csv" ; 56 | end function ; 57 | begin 58 | wait until rising_edge(clock) and fopen = '1' ; 59 | file_open(status, f, fname( FILENAME, fcount ), read_mode) ; 60 | assert status = OPEN_OK 61 | report "Could not open file: " & fname( FILENAME, fcount ) 62 | severity failure ; 63 | scount := 0 ; 64 | while true loop 65 | sample.valid <= '0'; 66 | wait until rising_edge(clock) ; 67 | readline( f, l ); 68 | read( l, li ); 69 | sample.i <= to_signed(li, sample.i'length); 70 | 71 | read( l, comma ); 72 | 73 | read( l, li ); 74 | sample.q <= to_signed(li, sample.q'length); 75 | sample.valid <= '1'; 76 | 77 | read( l, comma ); 78 | read( l, li ); 79 | ad_ctrl <= std_logic_vector(to_signed(li, ad_ctrl'length)); 80 | wait until rising_edge(clock) ; 81 | scount := scount + 1 ; 82 | if( endfile( f ) ) then 83 | file_close( f ) ; 84 | write( output, "Read " & integer'image(scount) & " samples from " & fname( FILENAME, fcount ) & CR ) ; 85 | fcount := fcount + 1 ; 86 | exit ; 87 | end if ; 88 | end loop ; 89 | end process ; 90 | 91 | end architecture ; 92 | 93 | -------------------------------------------------------------------------------- /fpga/vhdl/tb/wlan_sample_saver.vhd: -------------------------------------------------------------------------------- 1 | -- This file is part of bladeRF-wiphy. 2 | -- 3 | -- Copyright (C) 2020 Nuand, LLC. 4 | -- 5 | -- This program is free software; you can redistribute it and/or modify 6 | -- it under the terms of the GNU General Public License as published by 7 | -- the Free Software Foundation; either version 2 of the License, or 8 | -- (at your option) any later version. 9 | -- 10 | -- This program is distributed in the hope that it will be useful, 11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | -- GNU General Public License for more details. 14 | -- 15 | -- You should have received a copy of the GNU General Public License along 16 | -- with this program; if not, write to the Free Software Foundation, Inc., 17 | -- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | 19 | library ieee ; 20 | use ieee.std_logic_1164.all ; 21 | use ieee.numeric_std.all ; 22 | 23 | library std ; 24 | use std.textio.all ; 25 | 26 | library work ; 27 | use work.wlan_p.all ; 28 | 29 | entity wlan_sample_saver is 30 | generic ( 31 | FILENAME : string := "samples" 32 | ) ; 33 | port ( 34 | clock : in std_logic ; 35 | fopen : in std_logic ; 36 | sample : in wlan_sample_t ; 37 | done : in std_logic 38 | ) ; 39 | end entity ; 40 | 41 | architecture arch of wlan_sample_saver is 42 | 43 | begin 44 | 45 | save : process 46 | file f : text ; 47 | variable l : line ; 48 | variable status : file_open_status ; 49 | variable fcount : natural := 0 ; 50 | variable scount : natural := 0 ; 51 | function fname( b : string ; count : natural ) return string is 52 | begin 53 | return b & "-" & integer'image(count) & ".csv" ; 54 | end function ; 55 | begin 56 | wait until rising_edge(clock) and fopen = '1' ; 57 | file_open(status, f, fname( FILENAME, fcount ), write_mode) ; 58 | assert status = OPEN_OK 59 | report "Could not open file: " & fname( FILENAME, fcount ) 60 | severity failure ; 61 | scount := 0 ; 62 | while true loop 63 | wait until rising_edge(clock) and sample.valid = '1' ; 64 | write( l, to_integer(sample.i) ) ; 65 | write( l, ',' ) ; 66 | write( l, to_integer(sample.q) ) ; 67 | writeline( f, l ) ; 68 | flush( f ) ; 69 | scount := scount + 1 ; 70 | if( done = '1' ) then 71 | file_close( f ) ; 72 | write( output, "Wrote " & integer'image(scount) & " samples to " & fname( FILENAME, fcount ) & CR ) ; 73 | fcount := fcount + 1 ; 74 | exit ; 75 | end if ; 76 | end loop ; 77 | end process ; 78 | 79 | end architecture ; 80 | 81 | -------------------------------------------------------------------------------- /fpga/vhdl/tb/wlan_symbol_shaper_tb.vhd: -------------------------------------------------------------------------------- 1 | -- This file is part of bladeRF-wiphy. 2 | -- 3 | -- Copyright (C) 2020 Nuand, LLC. 4 | -- 5 | -- This program is free software; you can redistribute it and/or modify 6 | -- it under the terms of the GNU General Public License as published by 7 | -- the Free Software Foundation; either version 2 of the License, or 8 | -- (at your option) any later version. 9 | -- 10 | -- This program is distributed in the hope that it will be useful, 11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | -- GNU General Public License for more details. 14 | -- 15 | -- You should have received a copy of the GNU General Public License along 16 | -- with this program; if not, write to the Free Software Foundation, Inc., 17 | -- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | 19 | library ieee ; 20 | use ieee.std_logic_1164.all ; 21 | use ieee.numeric_std.all ; 22 | 23 | library work ; 24 | use work.wlan_p.all ; 25 | 26 | entity wlan_symbol_shaper_tb is 27 | end entity ; 28 | 29 | architecture arch of wlan_symbol_shaper_tb is 30 | 31 | signal clock : std_logic := '1' ; 32 | signal reset : std_logic := '1' ; 33 | 34 | signal cp_i : signed(15 downto 0) := (others =>'0') ; 35 | signal cp_q : signed(15 downto 0) := (others =>'0') ; 36 | signal cp_re : std_logic ; 37 | signal cp_empty : std_logic := '1' ; 38 | 39 | signal sample_i : signed(15 downto 0) := (others =>'0') ; 40 | signal sample_q : signed(15 downto 0) := (others =>'0') ; 41 | signal sample_re : std_logic ; 42 | signal sample_empty : std_logic := '1' ; 43 | 44 | signal out_sample : wlan_sample_t ; 45 | signal done : std_logic ; 46 | 47 | begin 48 | 49 | clock <= not clock after (0.5 / 40.0e6) * 1 sec ; 50 | 51 | U_shaper : entity work.wlan_symbol_shaper 52 | port map ( 53 | clock => clock, 54 | reset => reset, 55 | 56 | cp_i => cp_i, 57 | cp_q => cp_q, 58 | cp_re => cp_re, 59 | cp_empty => cp_empty, 60 | 61 | sample_i => sample_i, 62 | sample_q => sample_q, 63 | sample_re => sample_re, 64 | sample_empty => sample_empty, 65 | 66 | out_sample => out_sample, 67 | done => done 68 | ) ; 69 | 70 | tb : process 71 | begin 72 | reset <= '1' ; 73 | nop(clock, 100) ; 74 | 75 | reset <= '0' ; 76 | nop(clock, 100) ; 77 | 78 | nop(clock,10000) ; 79 | 80 | report "-- End of Simulation --" severity failure ; 81 | end process ; 82 | 83 | emulate_cp : process 84 | variable count : natural := 1 ; 85 | begin 86 | wait until rising_edge(clock) and reset = '0' ; 87 | nop(clock, 100) ; 88 | cp_empty <= '0' ; 89 | -- Long sequence CP 90 | cp_i <= to_signed(1, cp_i'length) ; 91 | cp_q <= to_signed(1, cp_q'length) ; 92 | for i in 1 to 32 loop 93 | wait until rising_edge(clock) and cp_re = '1' ; 94 | end loop ; 95 | 96 | -- 10 data symbols 97 | for i in 1 to 10 loop 98 | cp_i <= cp_i + 1 ; 99 | cp_q <= cp_q + 1 ; 100 | for i in 1 to 16 loop 101 | wait until rising_edge(clock) and cp_re = '1' ; 102 | end loop ; 103 | end loop ; 104 | 105 | -- 11th data symbol is the last 106 | cp_i <= cp_i + 1 ; 107 | cp_q <= cp_q + 1 ; 108 | for i in 1 to 15 loop 109 | wait until rising_edge(clock) and cp_re = '1' ; 110 | end loop ; 111 | cp_empty <= '1' ; 112 | wait until rising_edge(clock) and cp_re = '1' ; 113 | nop(clock, 100) ; 114 | wait ; 115 | end process ; 116 | 117 | emulate_sample : process 118 | variable count : natural := 0 ; 119 | begin 120 | wait until rising_edge(clock) and reset = '0' ; 121 | nop(clock, 100) ; 122 | -- Short sequence 123 | count := 160 ; 124 | sample_empty <= '0' ; 125 | sample_i <= to_signed(0, sample_i'length) ; 126 | sample_q <= to_signed(0, sample_q'length) ; 127 | for i in 1 to 160 loop 128 | wait until rising_edge(clock) and sample_re = '1' ; 129 | end loop ; 130 | -- Long sequence 131 | sample_i <= sample_i + 1 ; 132 | sample_q <= sample_q + 1 ; 133 | for i in 1 to 128 loop 134 | wait until rising_edge(clock) and sample_re = '1' ; 135 | end loop ; 136 | 137 | -- 10 data symbols 138 | for i in 1 to 10 loop 139 | sample_i <= sample_i + 1 ; 140 | sample_q <= sample_q + 1 ; 141 | for i in 1 to 64 loop 142 | wait until rising_edge(clock) and sample_re = '1' ; 143 | end loop ; 144 | end loop ; 145 | 146 | -- 11th symbol is the last one 147 | sample_i <= sample_i + 1 ; 148 | sample_q <= sample_q + 1 ; 149 | for i in 1 to 63 loop 150 | wait until rising_edge(clock) and sample_re = '1' ; 151 | end loop ; 152 | sample_empty <= '1' ; 153 | wait until rising_edge(clock) and sample_re = '1' ; 154 | 155 | nop(clock, 100) ; 156 | wait ; 157 | end process ; 158 | 159 | end architecture ; 160 | 161 | -------------------------------------------------------------------------------- /fpga/vhdl/tb/wlan_tb.vhd: -------------------------------------------------------------------------------- 1 | -- This file is part of bladeRF-wiphy. 2 | -- 3 | -- Copyright (C) 2020 Nuand, LLC. 4 | -- 5 | -- This program is free software; you can redistribute it and/or modify 6 | -- it under the terms of the GNU General Public License as published by 7 | -- the Free Software Foundation; either version 2 of the License, or 8 | -- (at your option) any later version. 9 | -- 10 | -- This program is distributed in the hope that it will be useful, 11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | -- GNU General Public License for more details. 14 | -- 15 | -- You should have received a copy of the GNU General Public License along 16 | -- with this program; if not, write to the Free Software Foundation, Inc., 17 | -- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | 19 | library ieee ; 20 | use ieee.std_logic_1164.all ; 21 | use ieee.numeric_std.all ; 22 | use ieee.math_real.all ; 23 | 24 | library work ; 25 | use work.wlan_p.all ; 26 | use work.wlan_rx_p.all ; 27 | use work.wlan_tx_p.all ; 28 | 29 | entity wlan_tb is 30 | end entity ; 31 | 32 | architecture arch of wlan_tb is 33 | 34 | begin 35 | 36 | end architecture ; 37 | 38 | -------------------------------------------------------------------------------- /fpga/vhdl/tb/wlan_tx_long_tb.vhd: -------------------------------------------------------------------------------- 1 | -- This file is part of bladeRF-wiphy. 2 | -- 3 | -- Copyright (C) 2020 Nuand, LLC. 4 | -- 5 | -- This program is free software; you can redistribute it and/or modify 6 | -- it under the terms of the GNU General Public License as published by 7 | -- the Free Software Foundation; either version 2 of the License, or 8 | -- (at your option) any later version. 9 | -- 10 | -- This program is distributed in the hope that it will be useful, 11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | -- GNU General Public License for more details. 14 | -- 15 | -- You should have received a copy of the GNU General Public License along 16 | -- with this program; if not, write to the Free Software Foundation, Inc., 17 | -- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | 19 | library ieee ; 20 | use ieee.std_logic_1164.all ; 21 | use ieee.numeric_std.all ; 22 | 23 | library work ; 24 | use work.wlan_p.all ; 25 | use work.wlan_tx_p.all ; 26 | 27 | entity wlan_tx_long_tb is 28 | end entity ; 29 | 30 | architecture arch of wlan_tx_long_tb is 31 | 32 | signal clock : std_logic := '1' ; 33 | signal reset : std_logic := '1' ; 34 | signal start : std_logic := '0' ; 35 | signal done : std_logic ; 36 | signal sample : wlan_sample_t ; 37 | signal valid_cp : std_logic ; 38 | 39 | begin 40 | 41 | clock <= not clock after 1 ns ; 42 | 43 | U_tx_long : entity work.wlan_tx_long 44 | port map ( 45 | clock => clock, 46 | reset => reset, 47 | start => start, 48 | done => done, 49 | out_sample => sample, 50 | out_valid_cp => valid_cp 51 | ) ; 52 | 53 | tb : process 54 | begin 55 | reset <= '1' ; 56 | nop(clock, 100) ; 57 | 58 | reset <= '0' ; 59 | nop(clock, 100) ; 60 | 61 | start <= '1' ; 62 | nop(clock, 1) ; 63 | start <= '0' ; 64 | nop(clock, 1) ; 65 | 66 | nop(clock, 1000 ) ; 67 | 68 | report "-- End of Simulation --" severity failure ; 69 | end process ; 70 | 71 | end architecture ; 72 | 73 | -------------------------------------------------------------------------------- /fpga/vhdl/tb/wlan_tx_short_tb.vhd: -------------------------------------------------------------------------------- 1 | -- This file is part of bladeRF-wiphy. 2 | -- 3 | -- Copyright (C) 2020 Nuand, LLC. 4 | -- 5 | -- This program is free software; you can redistribute it and/or modify 6 | -- it under the terms of the GNU General Public License as published by 7 | -- the Free Software Foundation; either version 2 of the License, or 8 | -- (at your option) any later version. 9 | -- 10 | -- This program is distributed in the hope that it will be useful, 11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | -- GNU General Public License for more details. 14 | -- 15 | -- You should have received a copy of the GNU General Public License along 16 | -- with this program; if not, write to the Free Software Foundation, Inc., 17 | -- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | 19 | library ieee ; 20 | use ieee.std_logic_1164.all ; 21 | use ieee.numeric_std.all ; 22 | 23 | library work ; 24 | use work.wlan_p.all ; 25 | use work.wlan_tx_p.all ; 26 | 27 | entity wlan_tx_short_tb is 28 | end entity ; 29 | 30 | architecture arch of wlan_tx_short_tb is 31 | 32 | signal clock : std_logic := '1' ; 33 | signal reset : std_logic := '1' ; 34 | signal start : std_logic := '0' ; 35 | signal done : std_logic ; 36 | signal sample : wlan_sample_t ; 37 | 38 | begin 39 | 40 | clock <= not clock after 1 ns ; 41 | 42 | U_tx_short : entity work.wlan_tx_short 43 | port map ( 44 | clock => clock, 45 | reset => reset, 46 | start => start, 47 | done => done, 48 | out_sample => sample 49 | ) ; 50 | 51 | tb : process 52 | begin 53 | reset <= '1' ; 54 | nop(clock, 100) ; 55 | 56 | reset <= '0' ; 57 | nop(clock, 100) ; 58 | 59 | start <= '1' ; 60 | nop(clock, 1) ; 61 | start <= '0' ; 62 | nop(clock, 1) ; 63 | 64 | nop(clock, 1000 ) ; 65 | 66 | report "-- End of Simulation --" severity failure ; 67 | end process ; 68 | 69 | end architecture ; 70 | 71 | -------------------------------------------------------------------------------- /fpga/vhdl/wlan_ack_generator.vhd: -------------------------------------------------------------------------------- 1 | -- This file is part of bladeRF-wiphy. 2 | -- 3 | -- Copyright (C) 2020 Nuand, LLC. 4 | -- 5 | -- This program is free software; you can redistribute it and/or modify 6 | -- it under the terms of the GNU General Public License as published by 7 | -- the Free Software Foundation; either version 2 of the License, or 8 | -- (at your option) any later version. 9 | -- 10 | -- This program is distributed in the hope that it will be useful, 11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | -- GNU General Public License for more details. 14 | -- 15 | -- You should have received a copy of the GNU General Public License along 16 | -- with this program; if not, write to the Free Software Foundation, Inc., 17 | -- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | 19 | library ieee ; 20 | use ieee.std_logic_1164.all ; 21 | use ieee.numeric_std.all ; 22 | 23 | library wlan; 24 | use wlan.wlan_p.all ; 25 | use wlan.wlan_tx_p.all ; 26 | use wlan.wlan_rx_p.all ; 27 | 28 | library altera_mf ; 29 | use altera_mf.altera_mf_components.all ; 30 | 31 | entity wlan_ack_generator is 32 | port ( 33 | wclock : in std_logic ; 34 | wreset : in std_logic ; 35 | 36 | ack_mac : in std_logic_vector( 47 downto 0 ); 37 | ack_valid : in std_logic ; 38 | 39 | rclock : in std_logic ; 40 | rreset : in std_logic ; 41 | 42 | fifo_data : out std_logic_vector( 7 downto 0 ); 43 | fifo_re : in std_logic ; 44 | done_tx : in std_logic ; 45 | 46 | ack_ready : out std_logic 47 | ) ; 48 | end entity ; 49 | 50 | architecture arch of wlan_ack_generator is 51 | signal wfull : std_logic ; 52 | signal rempty : std_logic ; 53 | signal rread : std_logic ; 54 | 55 | type fsm_t is (IDLE, READ, DONE); 56 | 57 | type state_t is record 58 | fsm : fsm_t; 59 | payload : std_logic_vector( 79 downto 0 ); 60 | rread : std_logic ; 61 | byte_idx : natural range 0 to 10 ; 62 | end record ; 63 | 64 | signal current_state : state_t; 65 | signal future_state : state_t; 66 | 67 | function NULL_STATE return state_t is 68 | variable rv : state_t; 69 | begin 70 | rv.fsm := IDLE ; 71 | rv.payload := (others => '0' ) ; 72 | rv.rread := '0' ; 73 | rv.byte_idx := 0 ; 74 | 75 | return rv ; 76 | end function ; 77 | 78 | signal mac_address : std_logic_vector( 47 downto 0 ); 79 | begin 80 | 81 | U_mac_dc_fifo: dcfifo 82 | generic map ( 83 | lpm_width => 48, 84 | lpm_widthu => 4, 85 | lpm_numwords => 16, 86 | lpm_showahead => "ON" 87 | ) 88 | port map ( 89 | aclr => wreset or rreset, 90 | 91 | wrclk => wclock, 92 | wrreq => ack_valid and not wfull, 93 | data => ack_mac, 94 | 95 | wrfull => wfull, 96 | wrempty => open, 97 | wrusedw => open, 98 | 99 | rdclk => rclock, 100 | rdreq => rread, 101 | q => mac_address, 102 | 103 | rdfull => open, 104 | rdempty => rempty, 105 | rdusedw => open 106 | ) ; 107 | 108 | ack_ready <= not rempty; 109 | fifo_data <= current_state.payload(79 downto 72); 110 | rread <= current_state.rread; 111 | 112 | process(all) 113 | begin 114 | future_state <= current_state ; 115 | 116 | future_state.rread <= '0'; 117 | 118 | case current_state.fsm is 119 | 120 | when IDLE => 121 | future_state.payload <= x"D400" & x"0000" & mac_address; 122 | if( fifo_re = '1' and rempty = '0' ) then 123 | future_state.fsm <= READ ; 124 | future_state.byte_idx <= 0 ; 125 | future_state.rread <= '1' ; 126 | future_state.payload <= current_state.payload(71 downto 0) & x"00"; 127 | else 128 | future_state.payload <= x"D400" & x"0000" & mac_address; 129 | end if; 130 | 131 | when READ => 132 | if( fifo_re = '1' ) then 133 | future_state.byte_idx <= current_state.byte_idx + 1; 134 | future_state.payload <= current_state.payload(71 downto 0) & x"00"; 135 | if( current_state.byte_idx = 9 ) then 136 | future_state.fsm <= DONE ; 137 | end if; 138 | end if; 139 | 140 | when DONE => 141 | if (done_tx = '1') then 142 | future_state.fsm <= IDLE ; 143 | end if ; 144 | future_state.byte_idx <= 0 ; 145 | 146 | when others => 147 | future_state <= NULL_STATE ; 148 | 149 | end case; 150 | 151 | end process; 152 | 153 | process(rclock, rreset) 154 | begin 155 | if( rreset = '1' ) then 156 | current_state <= NULL_STATE ; 157 | elsif( rising_edge( rclock ) ) then 158 | current_state <= future_state ; 159 | end if; 160 | end process; 161 | 162 | end architecture ; 163 | 164 | -------------------------------------------------------------------------------- /fpga/vhdl/wlan_cfo_correction.vhd: -------------------------------------------------------------------------------- 1 | -- This file is part of bladeRF-wiphy. 2 | -- 3 | -- Copyright (C) 2020 Nuand, LLC. 4 | -- 5 | -- This program is free software; you can redistribute it and/or modify 6 | -- it under the terms of the GNU General Public License as published by 7 | -- the Free Software Foundation; either version 2 of the License, or 8 | -- (at your option) any later version. 9 | -- 10 | -- This program is distributed in the hope that it will be useful, 11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | -- GNU General Public License for more details. 14 | -- 15 | -- You should have received a copy of the GNU General Public License along 16 | -- with this program; if not, write to the Free Software Foundation, Inc., 17 | -- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | 19 | library ieee ; 20 | use ieee.std_logic_1164.all ; 21 | use ieee.numeric_std.all ; 22 | use ieee.math_real.all ; 23 | 24 | library wlan ; 25 | use wlan.wlan_p.all ; 26 | use wlan.wlan_rx_p.all ; 27 | use wlan.cordic_p.all ; 28 | use wlan.nco_p.all ; 29 | 30 | entity wlan_cfo_correction is 31 | port ( 32 | clock : in std_logic ; 33 | reset : in std_logic ; 34 | 35 | dphase : in signed( 15 downto 0 ) ; 36 | dphase_valid : in std_logic ; 37 | 38 | p_mag : in signed( 23 downto 0 ) ; 39 | p_mag_valid : in std_logic ; 40 | 41 | in_sample : in wlan_sample_t ; 42 | out_sample : out wlan_sample_t 43 | ) ; 44 | end entity; 45 | 46 | architecture arch of wlan_cfo_correction is 47 | signal nco_inputs : nco_input_t ; 48 | signal nco_outputs : nco_output_t ; 49 | begin 50 | 51 | U_nco : entity work.nco 52 | port map ( 53 | clock => clock, 54 | reset => reset, 55 | inputs => nco_inputs, 56 | outputs => nco_outputs 57 | ) ; 58 | 59 | process( clock ) 60 | begin 61 | if( rising_edge( clock ) ) then 62 | nco_inputs.valid <= in_sample.valid ; 63 | out_sample.valid <= in_sample.valid ; 64 | if( in_sample.valid = '1' ) then 65 | if( p_mag_valid = '0' ) then 66 | out_sample.i <= in_sample.i ; 67 | out_sample.q <= in_sample.q ; 68 | else 69 | out_sample.i <= resize( shift_right( in_sample.i * p_mag , 15 ), 16 ) ; 70 | out_sample.q <= resize( shift_right( in_sample.q * p_mag , 15 ), 16 ) ; 71 | end if ; 72 | end if ; 73 | end if ; 74 | end process ; 75 | end architecture ; 76 | -------------------------------------------------------------------------------- /fpga/vhdl/wlan_correlator.vhd: -------------------------------------------------------------------------------- 1 | -- This file is part of bladeRF-wiphy. 2 | -- 3 | -- Copyright (C) 2020 Nuand, LLC. 4 | -- 5 | -- This program is free software; you can redistribute it and/or modify 6 | -- it under the terms of the GNU General Public License as published by 7 | -- the Free Software Foundation; either version 2 of the License, or 8 | -- (at your option) any later version. 9 | -- 10 | -- This program is distributed in the hope that it will be useful, 11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | -- GNU General Public License for more details. 14 | -- 15 | -- You should have received a copy of the GNU General Public License along 16 | -- with this program; if not, write to the Free Software Foundation, Inc., 17 | -- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | 19 | library ieee ; 20 | use ieee.std_logic_1164.all ; 21 | use ieee.numeric_std.all ; 22 | 23 | library wlan ; 24 | use wlan.wlan_p.all ; 25 | use wlan.wlan_rx_p.all ; 26 | 27 | entity wlan_correlator is 28 | port ( 29 | clock : in std_logic ; 30 | reset : in std_logic ; 31 | 32 | sample : in wlan_sample_t ; 33 | value : out signed( 31 downto 0 ) 34 | ) ; 35 | end entity ; 36 | 37 | architecture arch of wlan_correlator is 38 | 39 | constant preamble : sample_array_t( 15 downto 0 ) := ( 40 | (valid => '1', i => to_signed( 269, 16), q => to_signed( 269, 16)), 41 | (valid => '1', i => to_signed(-775, 16), q => to_signed( 14, 16)), 42 | (valid => '1', i => to_signed( -79, 16), q => to_signed(-460, 16)), 43 | (valid => '1', i => to_signed( 835, 16), q => to_signed( -74, 16)), 44 | (valid => '1', i => to_signed( 538, 16), q => to_signed( 0, 16)), 45 | (valid => '1', i => to_signed( 835, 16), q => to_signed( -74, 16)), 46 | (valid => '1', i => to_signed( -79, 16), q => to_signed(-460, 16)), 47 | (valid => '1', i => to_signed(-775, 16), q => to_signed( 14, 16)), 48 | (valid => '1', i => to_signed( 269, 16), q => to_signed( 269, 16)), 49 | (valid => '1', i => to_signed( 14, 16), q => to_signed(-775, 16)), 50 | (valid => '1', i => to_signed(-460, 16), q => to_signed( -79, 16)), 51 | (valid => '1', i => to_signed( -74, 16), q => to_signed( 835, 16)), 52 | (valid => '1', i => to_signed( 0, 16), q => to_signed( 538, 16)), 53 | (valid => '1', i => to_signed( -74, 16), q => to_signed( 835, 16)), 54 | (valid => '1', i => to_signed(-460, 16), q => to_signed( -79, 16)), 55 | (valid => '1', i => to_signed( 14, 16), q => to_signed(-775, 16)) 56 | ); 57 | 58 | type correlator_result_t is record 59 | i : signed(15 downto 0) ; 60 | q : signed(15 downto 0) ; 61 | valid : std_logic ; 62 | end record ; 63 | 64 | type eq_array_t is array(natural range <>) of correlator_result_t ; 65 | signal accum : eq_array_t(15 downto 0); 66 | 67 | begin 68 | 69 | process( clock ) 70 | variable isum : signed( 100 downto 0 ) ; 71 | variable qsum : signed( 100 downto 0 ) ; 72 | begin 73 | if( reset = '1' ) then 74 | value <= ( others => '0' ) ; 75 | elsif( rising_edge( clock ) ) then 76 | if( sample.valid = '1' ) then 77 | for i in accum'range loop 78 | if i = accum'high then 79 | accum(i).i <= resize(shift_right(preamble(i).i*sample.i + preamble(i).q*sample.q, 14),16); 80 | accum(i).q <= resize(shift_right(- preamble(i).q*sample.i + preamble(i).i*sample.q, 14),16); 81 | else 82 | accum(i).i <= resize(accum(i+1).i + shift_right(preamble(i).i*sample.i + preamble(i).q*sample.q, 14),16); 83 | accum(i).q <= resize(accum(i+1).q + shift_right(- preamble(i).q*sample.i + preamble(i).i*sample.q, 14),16); 84 | end if; 85 | end loop; 86 | value <= resize(accum(0).i * accum(0).i + accum(0).q * accum(0).q,32); 87 | 88 | end if ; 89 | end if ; 90 | end process ; 91 | 92 | end architecture ; 93 | -------------------------------------------------------------------------------- /fpga/vhdl/wlan_csma.vhd: -------------------------------------------------------------------------------- 1 | -- This file is part of bladeRF-wiphy. 2 | -- 3 | -- Copyright (C) 2020 Nuand, LLC. 4 | -- 5 | -- This program is free software; you can redistribute it and/or modify 6 | -- it under the terms of the GNU General Public License as published by 7 | -- the Free Software Foundation; either version 2 of the License, or 8 | -- (at your option) any later version. 9 | -- 10 | -- This program is distributed in the hope that it will be useful, 11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | -- GNU General Public License for more details. 14 | -- 15 | -- You should have received a copy of the GNU General Public License along 16 | -- with this program; if not, write to the Free Software Foundation, Inc., 17 | -- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | 19 | library ieee ; 20 | use ieee.std_logic_1164.all ; 21 | use ieee.numeric_std.all ; 22 | 23 | library wlan ; 24 | use wlan.wlan_p.all ; 25 | use wlan.wlan_rx_p.all ; 26 | 27 | entity wlan_csma is 28 | port ( 29 | clock : in std_logic ; 30 | reset : in std_logic ; 31 | 32 | in_sample : in wlan_sample_t ; 33 | 34 | quiet : out std_logic 35 | ) ; 36 | end entity ; 37 | 38 | architecture arch of wlan_csma is 39 | type fsm_t is (IDLE, CAPTURE_PHY_NOISE, CSMA) ; 40 | 41 | type unsigned_array_t is array (natural range 0 to 79) of unsigned( 31 downto 0 ) ; 42 | type state_t is record 43 | fsm : fsm_t ; 44 | quiet : std_logic ; 45 | timer : unsigned( 23 downto 0 ) ; 46 | powersum : unsigned( 31 downto 0 ) ; 47 | min_phy_noise : unsigned( 31 downto 0 ) ; 48 | history : unsigned_array_t ; 49 | end record ; 50 | 51 | function NULL_STATE return state_t is 52 | variable rv : state_t ; 53 | begin 54 | rv.fsm := IDLE ; 55 | rv.timer := ( others => '0' ) ; 56 | rv.min_phy_noise := ( others => '1' ) ; 57 | rv.powersum := ( others => '0' ) ; 58 | for i in rv.history'range loop 59 | rv.history(i) := ( others => '0' ) ; 60 | end loop ; 61 | return rv ; 62 | end function ; 63 | 64 | signal current, future : state_t := NULL_STATE ; 65 | 66 | begin 67 | 68 | quiet <= current.quiet ; 69 | 70 | sync : process( clock ) 71 | begin 72 | if( reset = '1' ) then 73 | current <= NULL_STATE ; 74 | elsif( rising_edge( clock ) ) then 75 | current <= future ; 76 | end if ; 77 | end process ; 78 | 79 | comb: process(all) 80 | begin 81 | future <= current ; 82 | 83 | case current.fsm is 84 | when IDLE => 85 | future.fsm <= CAPTURE_PHY_NOISE ; 86 | future.quiet <= '0' ; 87 | when CAPTURE_PHY_NOISE => 88 | future.quiet <= '0' ; 89 | --if( current.timer > 100000 ) then 90 | if( current.timer > 110 ) then 91 | future.fsm <= CSMA ; 92 | future.powersum <= ( others => '0' ) ; 93 | for i in future.history'range loop 94 | future.history(i) <= ( others => '0' ) ; 95 | end loop ; 96 | future.timer <= ( others => '0' ) ; 97 | end if ; 98 | 99 | if( in_sample.valid = '1' ) then 100 | future.timer <= current.timer + 1 ; 101 | for i in 0 to current.history'high - 1 loop 102 | future.history( i + 1 ) <= current.history( i ) ; 103 | end loop ; 104 | future.history(0) <= unsigned(resize(in_sample.i * in_sample.i + in_sample.q * in_sample.q, 32 )); 105 | future.powersum <= current.powersum + current.history(0) 106 | - current.history(79); 107 | if( current.timer > 100 ) then 108 | if( current.powersum < current.min_phy_noise ) then 109 | future.min_phy_noise <= current.powersum ; 110 | end if ; 111 | end if ; 112 | end if ; 113 | when CSMA => 114 | if( in_sample.valid = '1' ) then 115 | for i in 0 to current.history'high - 1 loop 116 | future.history( i + 1 ) <= current.history( i ) ; 117 | end loop ; 118 | future.history(0) <= unsigned(resize(in_sample.i * in_sample.i + in_sample.q * in_sample.q, 32 )); 119 | future.powersum <= current.powersum + current.history(0) 120 | - current.history(9); 121 | 122 | if( current.timer > 20 ) then 123 | if( (current.min_phy_noise / 8 ) * 4 > current.powersum ) then 124 | future.quiet <= '1' ; 125 | else 126 | future.quiet <= '0' ; 127 | end if ; 128 | else 129 | future.timer <= current.timer + 1 ; 130 | end if ; 131 | end if ; 132 | end case ; 133 | end process ; 134 | end architecture ; 135 | -------------------------------------------------------------------------------- /fpga/vhdl/wlan_deinterleaver.vhd: -------------------------------------------------------------------------------- 1 | -- This file is part of bladeRF-wiphy. 2 | -- 3 | -- Copyright (C) 2020 Nuand, LLC. 4 | -- 5 | -- This program is free software; you can redistribute it and/or modify 6 | -- it under the terms of the GNU General Public License as published by 7 | -- the Free Software Foundation; either version 2 of the License, or 8 | -- (at your option) any later version. 9 | -- 10 | -- This program is distributed in the hope that it will be useful, 11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | -- GNU General Public License for more details. 14 | -- 15 | -- You should have received a copy of the GNU General Public License along 16 | -- with this program; if not, write to the Free Software Foundation, Inc., 17 | -- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | 19 | library ieee ; 20 | use ieee.std_logic_1164.all ; 21 | use ieee.numeric_std.all ; 22 | 23 | library work ; 24 | use work.wlan_p.all ; 25 | use work.wlan_interleaver_p.all ; 26 | 27 | entity wlan_deinterleaver is 28 | port ( 29 | clock : in std_logic ; 30 | reset : in std_logic ; 31 | 32 | modulation : in wlan_modulation_t ; 33 | data : in bsd_array_t(287 downto 0) ; 34 | in_valid : in std_logic ; 35 | 36 | depuncturer_empty : in std_logic ; 37 | 38 | deinterleaved_mod : out wlan_modulation_t ; 39 | deinterleaved : out bsd_array_t(287 downto 0) ; 40 | deinterleaved_valid : out std_logic 41 | ) ; 42 | end entity ; 43 | 44 | architecture arch of wlan_deinterleaver is 45 | signal data_new : std_logic ; 46 | signal data_r : bsd_array_t(287 downto 0) ; 47 | begin 48 | 49 | permute_bits : process(clock, reset) 50 | begin 51 | if( reset = '1' ) then 52 | deinterleaved <= (others =>(others =>'0')) ; 53 | deinterleaved_mod <= WLAN_BPSK ; 54 | deinterleaved_valid <= '0' ; 55 | data_new <= '0' ; 56 | elsif( rising_edge(clock) ) then 57 | deinterleaved_valid <= '0' ; 58 | if( in_valid = '1' ) then 59 | data_r <= data ; 60 | data_new <= '1' ; 61 | end if; 62 | if( depuncturer_empty = '1' and data_new = '1' ) then 63 | data_new <= '0' ; 64 | deinterleaved_valid <= '1' ; 65 | deinterleaved <= deinterleave(modulation, data) ; 66 | if( modulation = WLAN_BPSK ) then 67 | deinterleaved( 287 downto 48 ) <= (others =>(others => '0' )) ; 68 | end if ; 69 | deinterleaved_mod <= modulation ; 70 | end if ; 71 | end if ; 72 | end process ; 73 | 74 | end architecture ; 75 | 76 | -------------------------------------------------------------------------------- /fpga/vhdl/wlan_delay_correlator.vhd: -------------------------------------------------------------------------------- 1 | -- This file is part of bladeRF-wiphy. 2 | -- 3 | -- Copyright (C) 2020 Nuand, LLC. 4 | -- 5 | -- This program is free software; you can redistribute it and/or modify 6 | -- it under the terms of the GNU General Public License as published by 7 | -- the Free Software Foundation; either version 2 of the License, or 8 | -- (at your option) any later version. 9 | -- 10 | -- This program is distributed in the hope that it will be useful, 11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | -- GNU General Public License for more details. 14 | -- 15 | -- You should have received a copy of the GNU General Public License along 16 | -- with this program; if not, write to the Free Software Foundation, Inc., 17 | -- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | 19 | library ieee ; 20 | use ieee.std_logic_1164.all ; 21 | use ieee.numeric_std.all ; 22 | 23 | library wlan ; 24 | use wlan.wlan_p.all ; 25 | use wlan.wlan_rx_p.all ; 26 | 27 | entity wlan_delay_correlator is 28 | generic ( 29 | SAMPLE_DELTA : integer 30 | ) ; 31 | port ( 32 | clock : in std_logic ; 33 | reset : in std_logic ; 34 | 35 | sample : in wlan_sample_t ; 36 | value : out signed( 127 downto 0 ) 37 | ) ; 38 | end entity ; 39 | 40 | architecture arch of wlan_delay_correlator is 41 | 42 | signal samples : sample_array_t( 0 to SAMPLE_DELTA * 2 - 1 ) ; 43 | 44 | begin 45 | 46 | process( clock ) 47 | variable isum : signed( 63 downto 0 ) ; 48 | variable qsum : signed( 63 downto 0 ) ; 49 | begin 50 | if( rising_edge( clock ) ) then 51 | if( sample.valid = '1' ) then 52 | for i in 0 to samples'high - 1 loop 53 | samples(i+1) <= samples(i) ; 54 | end loop ; 55 | samples(0) <= sample ; 56 | 57 | isum := (others => '0') ; 58 | qsum := (others => '0') ; 59 | for i in 0 to SAMPLE_DELTA - 1 loop 60 | isum := isum + samples(i).i * samples(i + SAMPLE_DELTA).i + 61 | samples(i).q * samples(i + SAMPLE_DELTA).q ; 62 | qsum := qsum - samples(i).i * samples(i + SAMPLE_DELTA).q + 63 | samples(i).q * samples(i + SAMPLE_DELTA).i ; 64 | end loop ; 65 | value <= isum * isum + qsum * qsum ; 66 | end if ; 67 | end if ; 68 | end process ; 69 | 70 | end architecture ; 71 | 72 | -------------------------------------------------------------------------------- /fpga/vhdl/wlan_divide.vhd: -------------------------------------------------------------------------------- 1 | -- This file is part of bladeRF-wiphy. 2 | -- 3 | -- Copyright (C) 2020 Nuand, LLC. 4 | -- 5 | -- This program is free software; you can redistribute it and/or modify 6 | -- it under the terms of the GNU General Public License as published by 7 | -- the Free Software Foundation; either version 2 of the License, or 8 | -- (at your option) any later version. 9 | -- 10 | -- This program is distributed in the hope that it will be useful, 11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | -- GNU General Public License for more details. 14 | -- 15 | -- You should have received a copy of the GNU General Public License along 16 | -- with this program; if not, write to the Free Software Foundation, Inc., 17 | -- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | 19 | library ieee ; 20 | use ieee.std_logic_1164.all ; 21 | use ieee.numeric_std.all ; 22 | 23 | library lpm ; 24 | use lpm.lpm_components.all ; 25 | 26 | entity wlan_divide is 27 | generic ( 28 | SAMPLE_WIDTH : natural ; 29 | DENOM_WIDTH : natural ; 30 | NUM_PIPELINE : natural 31 | ) ; 32 | port ( 33 | clock : in std_logic ; 34 | reset : in std_logic ; 35 | 36 | in_i : in signed(SAMPLE_WIDTH-1 downto 0) ; 37 | in_q : in signed(SAMPLE_WIDTH-1 downto 0) ; 38 | in_denom : in unsigned(DENOM_WIDTH-1 downto 0) ; 39 | in_valid : in std_logic ; 40 | in_done : in std_logic ; 41 | 42 | out_i : out signed(SAMPLE_WIDTH-1 downto 0) ; 43 | out_q : out signed(SAMPLE_WIDTH-1 downto 0) ; 44 | out_valid : out std_logic ; 45 | out_done : out std_logic 46 | ) ; 47 | end entity ; 48 | 49 | architecture altera of wlan_divide is 50 | 51 | signal done : std_logic_vector(NUM_PIPELINE-1 downto 0) ; 52 | signal valid : std_logic_vector(NUM_PIPELINE-1 downto 0) ; 53 | 54 | begin 55 | 56 | register_valids_and_done : process(clock, reset) 57 | begin 58 | if( reset = '1' ) then 59 | done <= (others =>'0') ; 60 | valid <= (others =>'0') ; 61 | elsif( rising_edge(clock) ) then 62 | done <= done(done'high-1 downto 0) & in_done ; 63 | valid <= valid(valid'high-1 downto 0) & in_valid ; 64 | end if ; 65 | end process ; 66 | 67 | out_done <= done(done'high) ; 68 | out_valid <= valid(valid'high) ; 69 | 70 | div_i : lpm_divide 71 | generic map ( 72 | lpm_nrepresentation => "SIGNED", 73 | lpm_drepresentation => "UNSIGNED", 74 | lpm_hint => "LPM_REMAINDERPOSITIVE=TRUE", 75 | lpm_pipeline => NUM_PIPELINE, 76 | lpm_type => "LPM_DIVIDE", 77 | lpm_widthd => DENOM_WIDTH, 78 | lpm_widthn => SAMPLE_WIDTH 79 | ) port map ( 80 | clock => clock, 81 | aclr => reset, 82 | numer => std_logic_vector(in_i), 83 | denom => std_logic_vector(in_denom), 84 | remain => open, 85 | signed(quotient) => out_i 86 | ) ; 87 | 88 | div_q : lpm_divide 89 | generic map ( 90 | lpm_nrepresentation => "SIGNED", 91 | lpm_drepresentation => "UNSIGNED", 92 | lpm_hint => "LPM_REMAINDERPOSITIVE=TRUE", 93 | lpm_pipeline => NUM_PIPELINE, 94 | lpm_type => "LPM_DIVIDE", 95 | lpm_widthd => DENOM_WIDTH, 96 | lpm_widthn => SAMPLE_WIDTH 97 | ) port map ( 98 | clock => clock, 99 | aclr => reset, 100 | numer => std_logic_vector(in_q), 101 | denom => std_logic_vector(in_denom), 102 | remain => open, 103 | signed(quotient) => out_q 104 | ) ; 105 | 106 | end architecture ; 107 | -------------------------------------------------------------------------------- /fpga/vhdl/wlan_dsss_demodulator.vhd: -------------------------------------------------------------------------------- 1 | -- This file is part of bladeRF-wiphy. 2 | -- 3 | -- Copyright (C) 2020 Nuand, LLC. 4 | -- 5 | -- This program is free software; you can redistribute it and/or modify 6 | -- it under the terms of the GNU General Public License as published by 7 | -- the Free Software Foundation; either version 2 of the License, or 8 | -- (at your option) any later version. 9 | -- 10 | -- This program is distributed in the hope that it will be useful, 11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | -- GNU General Public License for more details. 14 | -- 15 | -- You should have received a copy of the GNU General Public License along 16 | -- with this program; if not, write to the Free Software Foundation, Inc., 17 | -- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | 19 | library ieee ; 20 | use ieee.std_logic_1164.all ; 21 | use ieee.numeric_std.all ; 22 | 23 | library wlan ; 24 | use wlan.wlan_p.all ; 25 | use wlan.wlan_rx_p.all ; 26 | 27 | entity wlan_dsss_demodulator is 28 | port ( 29 | clock : in std_logic ; 30 | reset : in std_logic ; 31 | 32 | modulation : in wlan_modulation_t ; 33 | 34 | in_bin_idx : in natural ; 35 | despread : in wlan_sample_t ; 36 | 37 | out_bin_idx : out natural ; 38 | out_bits : out std_logic_vector( 1 downto 0 ) ; 39 | out_valid : out std_logic 40 | ) ; 41 | end entity ; 42 | 43 | architecture arch of wlan_dsss_demodulator is 44 | 45 | signal history : sample_array_t( 19 downto 0 ); 46 | 47 | signal res_i : signed( 19 downto 0 ) ; 48 | signal a_i, a_q, b_i, b_q : signed(15 downto 0) ; 49 | signal res_q : signed( 19 downto 0 ) ; 50 | 51 | signal res_valid : std_logic ; 52 | 53 | signal coded_bits : std_logic_vector( 1 downto 0 ) ; 54 | signal coded_valid : std_logic ; 55 | signal coded_idx : natural ; 56 | 57 | signal decoded_bits : std_logic_vector( 19 downto 0 ) ; 58 | signal demod_bits : std_logic_vector( 19 downto 0 ) ; 59 | 60 | type bit_history_t is array(0 to 20) of std_logic_vector(7 downto 0) ; 61 | signal bit_history : bit_history_t ; 62 | begin 63 | 64 | -- demodulate bits 65 | process( clock ) 66 | variable wtf : signed (19 downto 0 ); 67 | begin 68 | if( reset = '1' ) then 69 | history <= ( others => NULL_SAMPLE ) ; 70 | coded_bits <= ( others => '0' ) ; 71 | coded_valid <= '0' ; 72 | coded_idx <= 0 ; 73 | demod_bits <= ( others => '0' ) ; 74 | 75 | elsif( rising_edge( clock ) ) then 76 | coded_valid <= '0' ; 77 | 78 | if( despread.valid = '1' ) then 79 | for i in 0 to history'high - 1 loop 80 | history(i+1) <= history(i) ; 81 | end loop ; 82 | history(0) <= despread ; 83 | 84 | if( modulation = WLAN_DBPSK ) then 85 | coded_idx <= in_bin_idx ; 86 | a_i <= despread.i; 87 | a_q <= history(19).i; 88 | b_i <= despread.q; 89 | b_q <= history(19).q; 90 | wtf := resize((shift_right(despread.i * history(19).i,4) + shift_right(despread.q * history(19).q,4)), 20); 91 | res_i <= wtf; 92 | if( wtf < 0 ) then 93 | demod_bits(in_bin_idx) <= '1' ; 94 | coded_bits(0) <= '1' ; 95 | else 96 | demod_bits(in_bin_idx) <= '0' ; 97 | coded_bits(0) <= '0' ; 98 | end if ; 99 | coded_valid <= '1' ; 100 | end if ; 101 | end if ; 102 | 103 | end if ; 104 | end process ; 105 | 106 | -- descramble decoded bits 107 | process( clock ) 108 | begin 109 | if( reset = '1' ) then 110 | out_bin_idx <= 0 ; 111 | out_bits <= ( others => '0' ) ; 112 | out_valid <= '0' ; 113 | bit_history <= ( others => ( others => '0' ) ) ; 114 | decoded_bits<= ( others => '0' ) ; 115 | elsif( rising_edge( clock ) ) then 116 | out_valid <= '0' ; 117 | if( coded_valid = '1' ) then 118 | if( modulation = WLAN_DBPSK ) then 119 | -- save per bin descrambler register 120 | bit_history(coded_idx) <= bit_history(coded_idx)(6 downto 0) & coded_bits(0) ; 121 | 122 | -- descramble bit 123 | out_bits(0) <= coded_bits(0) xor bit_history(coded_idx)(3) xor bit_history(coded_idx)(6) ; 124 | decoded_bits(coded_idx) <= coded_bits(0) xor bit_history(coded_idx)(3) xor bit_history(coded_idx)(6) ; 125 | out_bin_idx <= coded_idx ; 126 | out_valid <= '1' ; 127 | end if ; 128 | end if ; 129 | end if ; 130 | end process ; 131 | 132 | end architecture ; 133 | -------------------------------------------------------------------------------- /fpga/vhdl/wlan_dsss_despreader.vhd: -------------------------------------------------------------------------------- 1 | -- This file is part of bladeRF-wiphy. 2 | -- 3 | -- Copyright (C) 2020 Nuand, LLC. 4 | -- 5 | -- This program is free software; you can redistribute it and/or modify 6 | -- it under the terms of the GNU General Public License as published by 7 | -- the Free Software Foundation; either version 2 of the License, or 8 | -- (at your option) any later version. 9 | -- 10 | -- This program is distributed in the hope that it will be useful, 11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | -- GNU General Public License for more details. 14 | -- 15 | -- You should have received a copy of the GNU General Public License along 16 | -- with this program; if not, write to the Free Software Foundation, Inc., 17 | -- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | 19 | library ieee ; 20 | use ieee.std_logic_1164.all ; 21 | use ieee.numeric_std.all ; 22 | 23 | library wlan ; 24 | use wlan.wlan_p.all ; 25 | use wlan.wlan_rx_p.all ; 26 | 27 | entity wlan_dsss_despreader is 28 | port ( 29 | clock : in std_logic ; 30 | reset : in std_logic ; 31 | 32 | sample : in wlan_sample_t ; 33 | despread : out wlan_sample_t 34 | ) ; 35 | end entity ; 36 | 37 | architecture arch of wlan_dsss_despreader is 38 | 39 | constant preamble : sample_array_t( 19 downto 0 ) := ( 40 | (valid => '1', i => to_signed( 128, 16), q => to_signed( 128, 16)), 41 | (valid => '1', i => to_signed( -14, 16), q => to_signed( -14, 16)), 42 | (valid => '1', i => to_signed(-135, 16), q => to_signed(-135, 16)), 43 | (valid => '1', i => to_signed( -20, 16), q => to_signed( -20, 16)), 44 | (valid => '1', i => to_signed( 197, 16), q => to_signed( 197, 16)), 45 | (valid => '1', i => to_signed( 210, 16), q => to_signed( 210, 16)), 46 | (valid => '1', i => to_signed( 1, 16), q => to_signed( 1, 16)), 47 | (valid => '1', i => to_signed(-135, 16), q => to_signed(-135, 16)), 48 | (valid => '1', i => to_signed( -34, 16), q => to_signed( -34, 16)), 49 | (valid => '1', i => to_signed( 120, 16), q => to_signed( 120, 16)), 50 | (valid => '1', i => to_signed( 147, 16), q => to_signed( 147, 16)), 51 | (valid => '1', i => to_signed( 128, 16), q => to_signed( 128, 16)), 52 | (valid => '1', i => to_signed( 148, 16), q => to_signed( 148, 16)), 53 | (valid => '1', i => to_signed( 102, 16), q => to_signed( 102, 16)), 54 | (valid => '1', i => to_signed( -54, 16), q => to_signed( -54, 16)), 55 | (valid => '1', i => to_signed(-159, 16), q => to_signed(-159, 16)), 56 | (valid => '1', i => to_signed(-142, 16), q => to_signed(-142, 16)), 57 | (valid => '1', i => to_signed(-119, 16), q => to_signed(-119, 16)), 58 | (valid => '1', i => to_signed(-130, 16), q => to_signed(-130, 16)), 59 | (valid => '1', i => to_signed( -86, 16), q => to_signed( -86, 16)) 60 | ); 61 | 62 | type despreader_result_t is record 63 | i : signed(15 downto 0) ; 64 | q : signed(15 downto 0) ; 65 | valid : std_logic ; 66 | end record ; 67 | 68 | type eq_array_t is array(natural range <>) of despreader_result_t ; 69 | signal accum : eq_array_t(19 downto 0); 70 | 71 | begin 72 | 73 | process( clock ) 74 | begin 75 | if( reset = '1' ) then 76 | elsif( rising_edge( clock ) ) then 77 | despread.valid <= '0' ; 78 | if( sample.valid = '1' ) then 79 | for i in accum'range loop 80 | if i = accum'high then 81 | accum(i).i <= resize(shift_right(preamble(i).i*sample.i, 9), 16); 82 | accum(i).q <= resize(shift_right(preamble(i).q*sample.q, 9), 16); 83 | accum(i).valid <= '1'; 84 | else 85 | accum(i).i <= resize(accum(i+1).i + shift_right(preamble(i).i*sample.i, 9), 16); 86 | accum(i).q <= resize(accum(i+1).q + shift_right(preamble(i).q*sample.q, 9), 16); 87 | accum(i).valid <= accum(i+1).valid; 88 | end if; 89 | end loop; 90 | despread.i <= accum(0).i ; 91 | despread.q <= accum(0).q ; 92 | despread.valid <= accum(0).valid ; 93 | end if ; 94 | end if ; 95 | end process ; 96 | 97 | end architecture ; 98 | -------------------------------------------------------------------------------- /fpga/vhdl/wlan_dsss_p_norm.vhd: -------------------------------------------------------------------------------- 1 | -- This file is part of bladeRF-wiphy. 2 | -- 3 | -- Copyright (C) 2020 Nuand, LLC. 4 | -- 5 | -- This program is free software; you can redistribute it and/or modify 6 | -- it under the terms of the GNU General Public License as published by 7 | -- the Free Software Foundation; either version 2 of the License, or 8 | -- (at your option) any later version. 9 | -- 10 | -- This program is distributed in the hope that it will be useful, 11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | -- GNU General Public License for more details. 14 | -- 15 | -- You should have received a copy of the GNU General Public License along 16 | -- with this program; if not, write to the Free Software Foundation, Inc., 17 | -- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | 19 | library ieee ; 20 | use ieee.std_logic_1164.all ; 21 | use ieee.numeric_std.all ; 22 | use ieee.math_real.all ; 23 | 24 | library wlan ; 25 | use wlan.wlan_p.all ; 26 | use wlan.wlan_rx_p.all ; 27 | 28 | entity wlan_dsss_p_norm is 29 | port ( 30 | -- 40MHz clock and async asserted, sync deasserted reset 31 | clock : in std_logic ; 32 | reset : in std_logic ; 33 | 34 | in_sample : in wlan_sample_t ; 35 | p_normed : out wlan_sample_t 36 | ) ; 37 | end entity ; 38 | 39 | architecture arch of wlan_dsss_p_norm is 40 | signal pow_set : signed( 31 downto 0 ) ; 41 | signal iir : signed( 31 downto 0 ) ; 42 | signal dat : signed( 31 downto 0 ) ; 43 | signal log2 : unsigned ( 8 downto 0 ) ; 44 | signal ptemp : signed( 31 downto 0 ) ; 45 | signal p_mag : signed( 23 downto 0 ) ; 46 | signal timer : unsigned( 8 downto 0 ) ; 47 | 48 | signal second_blip : std_logic ; 49 | 50 | type unsigned_array_t is array (natural range 0 to 511) of signed( 23 downto 0 ) ; 51 | 52 | function calc_lut return unsigned_array_t is 53 | variable rv : unsigned_array_t ; 54 | variable i : real ; 55 | variable two : real ; 56 | begin 57 | for x in rv'range loop 58 | i := ( 24.0 - (real(x) / 16.0) ) / 2.0 + 12.0; -- i is in log2 59 | report integer'image(x) & " LUT " & real'image(i); 60 | two := 2 ** i ; 61 | if (real(two) > 5.7e5) then 62 | two := 5.7e5; 63 | end if; 64 | rv(x) := to_signed(integer(round(two)), 24) ; 65 | end loop ; 66 | return rv ; 67 | end; 68 | constant mult_lut : unsigned_array_t := calc_lut; 69 | 70 | function log2x( x : signed( 31 downto 0) ) 71 | return unsigned is 72 | variable bits : unsigned( 8 downto 0 ) ; 73 | begin 74 | bits := (others => '0') ; 75 | for i in x'range loop 76 | if (x(i) = '1') then 77 | bits(8 downto 4) := to_unsigned(i, 5) ; 78 | if (real(i) < 4.0) then 79 | bits(3 downto 4 - i) := unsigned(x(i - 1 downto 0)) ; 80 | else 81 | bits(3 downto 0) := unsigned(x(i - 1 downto i - 4)) ; 82 | end if; 83 | exit ; 84 | end if ; 85 | end loop ; 86 | return bits ; 87 | end log2x ; 88 | 89 | function run_iir( x : signed( 31 downto 0); y : signed ( 31 downto 0) ) 90 | return signed 91 | is 92 | variable ret : signed(31 downto 0) ; 93 | begin 94 | ret := resize( x - shift_right(x, 4) + shift_right(y, 4), 32 ); 95 | return ret; 96 | end; 97 | 98 | begin 99 | process( clock ) 100 | variable gain_req : std_logic ; 101 | begin 102 | if( reset = '1' ) then 103 | iir <= ( others => '0' ) ; 104 | ptemp <= ( others => '0' ) ; 105 | p_mag <= ( others => '0' ) ; 106 | timer <= ( others => '0' ) ; 107 | pow_set <= ( others => '0' ) ; 108 | second_blip <= '0' ; 109 | elsif( rising_edge( clock )) then 110 | p_mag <= signed(resize(mult_lut(to_integer(log2x(pow_set))), 24)) ; 111 | p_normed.valid <= '0' ; 112 | if (in_sample.valid = '1') then 113 | ptemp <= in_sample.i * in_sample.i + in_sample.q * in_sample.q ; 114 | iir <= run_iir(iir, ptemp) ; 115 | 116 | gain_req := '0' ; 117 | if( iir*2 < pow_set or iir > pow_set*2 ) then 118 | gain_req := '1' ; 119 | end if ; 120 | 121 | if( timer = 59 ) then 122 | timer <= ( others => '0' ) ; 123 | if( gain_req = '1' ) then 124 | second_blip <= '1' ; 125 | end if ; 126 | else 127 | timer <= timer + 1 ; 128 | end if; 129 | 130 | if( second_blip = '1' ) then 131 | if( gain_req = '1' ) then 132 | pow_set <= iir ; 133 | end if ; 134 | second_blip <= '0' ; 135 | end if ; 136 | 137 | p_normed.i <= resize(shift_right(in_sample.i * p_mag, 16), 16) ; 138 | p_normed.q <= resize(shift_right(in_sample.q * p_mag, 16), 16) ; 139 | p_normed.valid <= '1' ; 140 | end if ; 141 | end if ; 142 | end process ; 143 | end architecture ; 144 | -------------------------------------------------------------------------------- /fpga/vhdl/wlan_dsss_plcp_crc.vhd: -------------------------------------------------------------------------------- 1 | -- This file is part of bladeRF-wiphy. 2 | -- 3 | -- Copyright (C) 2020 Nuand, LLC. 4 | -- 5 | -- This program is free software; you can redistribute it and/or modify 6 | -- it under the terms of the GNU General Public License as published by 7 | -- the Free Software Foundation; either version 2 of the License, or 8 | -- (at your option) any later version. 9 | -- 10 | -- This program is distributed in the hope that it will be useful, 11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | -- GNU General Public License for more details. 14 | -- 15 | -- You should have received a copy of the GNU General Public License along 16 | -- with this program; if not, write to the Free Software Foundation, Inc., 17 | -- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | 19 | library ieee ; 20 | use ieee.std_logic_1164.all ; 21 | use ieee.numeric_std.all ; 22 | 23 | entity wlan_dsss_plcp_crc is 24 | port ( 25 | clock : in std_logic ; 26 | reset : in std_logic ; 27 | 28 | in_data : in std_logic ; 29 | in_valid : in std_logic ; 30 | 31 | crc : out std_logic_vector(15 downto 0) 32 | ) ; 33 | end entity ; 34 | 35 | architecture arch of wlan_dsss_plcp_crc is 36 | 37 | signal crc_next : std_logic_vector(15 downto 0); 38 | 39 | begin 40 | 41 | process( reset, clock ) 42 | begin 43 | if( reset = '1' ) then 44 | crc_next <= ( others => '1' ) ; 45 | elsif( rising_edge( clock ) ) then 46 | if (in_valid = '1' ) then 47 | crc_next(15) <= crc_next(14); 48 | crc_next(14) <= crc_next(13); 49 | crc_next(13) <= crc_next(12); 50 | crc_next(12) <= crc_next(11) xor crc_next(15) xor in_data; 51 | crc_next(11) <= crc_next(10); 52 | crc_next(10) <= crc_next(9); 53 | crc_next(9) <= crc_next(8); 54 | crc_next(8) <= crc_next(7); 55 | crc_next(7) <= crc_next(6); 56 | crc_next(6) <= crc_next(5); 57 | crc_next(5) <= crc_next(4) xor crc_next(15) xor in_data; 58 | crc_next(4) <= crc_next(3); 59 | crc_next(3) <= crc_next(2); 60 | crc_next(2) <= crc_next(1); 61 | crc_next(1) <= crc_next(0); 62 | crc_next(0) <= crc_next(15) xor in_data ; 63 | end if; 64 | end if; 65 | end process; 66 | 67 | crc <= crc_next xor x"FFFF"; 68 | 69 | end architecture ; 70 | 71 | -------------------------------------------------------------------------------- /fpga/vhdl/wlan_dsss_rx.vhd: -------------------------------------------------------------------------------- 1 | -- This file is part of bladeRF-wiphy. 2 | -- 3 | -- Copyright (C) 2020 Nuand, LLC. 4 | -- 5 | -- This program is free software; you can redistribute it and/or modify 6 | -- it under the terms of the GNU General Public License as published by 7 | -- the Free Software Foundation; either version 2 of the License, or 8 | -- (at your option) any later version. 9 | -- 10 | -- This program is distributed in the hope that it will be useful, 11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | -- GNU General Public License for more details. 14 | -- 15 | -- You should have received a copy of the GNU General Public License along 16 | -- with this program; if not, write to the Free Software Foundation, Inc., 17 | -- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | 19 | library ieee ; 20 | use ieee.std_logic_1164.all ; 21 | use ieee.numeric_std.all ; 22 | 23 | library wlan ; 24 | use wlan.nco_p.all ; 25 | use wlan.wlan_p.all ; 26 | use wlan.wlan_rx_p.all ; 27 | 28 | library altera_mf ; 29 | use altera_mf.altera_mf_components.all ; 30 | 31 | library wlan_pll ; 32 | 33 | entity wlan_dsss_rx is 34 | port ( 35 | -- 40MHz clock and async asserted, sync deasserted reset 36 | clock : in std_logic ; 37 | reset : in std_logic ; 38 | 39 | -- Baseband input signals 40 | sample : in wlan_sample_t ; 41 | 42 | params : out wlan_rx_params_t ; 43 | params_valid : out std_logic ; 44 | 45 | data : out std_logic_vector( 7 downto 0 ) ; 46 | data_valid : out std_logic ; 47 | 48 | framer_done : out std_logic ; 49 | crc_correct : out std_logic 50 | ) ; 51 | end entity ; 52 | 53 | architecture arch of wlan_dsss_rx is 54 | signal despread : wlan_sample_t ; 55 | signal p_norm_sample : wlan_sample_t ; 56 | signal modulation : wlan_modulation_t ; 57 | signal bin_idx : natural range 0 to 20 ; 58 | signal mode_bin : natural range 0 to 20 ; 59 | 60 | signal demod_bits : std_logic_vector( 1 downto 0 ) ; 61 | signal demod_idx : natural range 0 to 20 ; 62 | signal demod_valid : std_logic ; 63 | 64 | begin 65 | U_dsss_rx_controller : entity work.wlan_dsss_rx_controller 66 | port map ( 67 | clock => clock, 68 | reset => reset, 69 | 70 | in_sample => sample, 71 | modulation => modulation, 72 | out_bin_idx => bin_idx 73 | ) ; 74 | 75 | U_dsss_p_norm : entity work.wlan_dsss_p_norm 76 | port map ( 77 | clock => clock, 78 | reset => reset, 79 | 80 | in_sample => sample, 81 | p_normed => p_norm_sample 82 | ) ; 83 | 84 | U_dsss_despreader : entity work.wlan_dsss_despreader 85 | port map ( 86 | clock => clock, 87 | reset => reset, 88 | 89 | sample => p_norm_sample, 90 | despread => despread 91 | ) ; 92 | 93 | U_dsss_peak_finder : entity work.wlan_dsss_peak_finder 94 | port map ( 95 | clock => clock, 96 | reset => reset, 97 | 98 | despread => despread, 99 | 100 | bin_idx => bin_idx, 101 | 102 | out_mode_bin => mode_bin 103 | ) ; 104 | 105 | U_dsss_demodulator : entity work.wlan_dsss_demodulator 106 | port map ( 107 | clock => clock, 108 | reset => reset, 109 | 110 | modulation => modulation, 111 | 112 | in_bin_idx => bin_idx, 113 | despread => despread, 114 | 115 | out_bin_idx => demod_idx, 116 | out_bits => demod_bits, 117 | out_valid => demod_valid 118 | ) ; 119 | 120 | U_dsss_rx_framer : entity work.wlan_dsss_rx_framer 121 | port map ( 122 | clock => clock, 123 | reset => reset, 124 | 125 | mode_bin => mode_bin, 126 | 127 | demod_idx => demod_idx, 128 | demod_bits => demod_bits, 129 | demod_valid => demod_valid, 130 | 131 | params => params, 132 | params_valid => params_valid, 133 | data => data, 134 | data_valid => data_valid, 135 | 136 | framer_done => framer_done, 137 | crc_correct => crc_correct 138 | ) ; 139 | 140 | end architecture ; 141 | -------------------------------------------------------------------------------- /fpga/vhdl/wlan_dsss_rx_controller.vhd: -------------------------------------------------------------------------------- 1 | -- This file is part of bladeRF-wiphy. 2 | -- 3 | -- Copyright (C) 2020 Nuand, LLC. 4 | -- 5 | -- This program is free software; you can redistribute it and/or modify 6 | -- it under the terms of the GNU General Public License as published by 7 | -- the Free Software Foundation; either version 2 of the License, or 8 | -- (at your option) any later version. 9 | -- 10 | -- This program is distributed in the hope that it will be useful, 11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | -- GNU General Public License for more details. 14 | -- 15 | -- You should have received a copy of the GNU General Public License along 16 | -- with this program; if not, write to the Free Software Foundation, Inc., 17 | -- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | 19 | library ieee ; 20 | use ieee.std_logic_1164.all ; 21 | use ieee.numeric_std.all ; 22 | 23 | library wlan ; 24 | use wlan.wlan_p.all ; 25 | use wlan.wlan_rx_p.all ; 26 | 27 | entity wlan_dsss_rx_controller is 28 | port ( 29 | clock : in std_logic ; 30 | reset : in std_logic ; 31 | 32 | in_sample : in wlan_sample_t ; 33 | 34 | modulation : out wlan_modulation_t; 35 | out_bin_idx : out natural 36 | ) ; 37 | end entity; 38 | 39 | architecture arch of wlan_dsss_rx_controller is 40 | 41 | type fsm_t is (IDLE) ; 42 | 43 | type state_t is record 44 | fsm : fsm_t ; 45 | bin_idx : natural range 0 to 20 ; 46 | end record ; 47 | 48 | function NULL_STATE return state_t is 49 | variable rv : state_t ; 50 | begin 51 | rv.fsm := IDLE ; 52 | rv.bin_idx := 0 ; 53 | return rv ; 54 | end function ; 55 | 56 | signal current, future : state_t := NULL_STATE ; 57 | begin 58 | out_bin_idx <= current.bin_idx ; 59 | modulation <= WLAN_DBPSK ; 60 | 61 | sync : process( clock ) 62 | begin 63 | if( reset = '1' ) then 64 | current <= NULL_STATE ; 65 | elsif( rising_edge( clock ) ) then 66 | current <= future ; 67 | end if ; 68 | end process ; 69 | 70 | comb: process(all) 71 | begin 72 | future <= current ; 73 | if( in_sample.valid = '1' ) then 74 | if( current.bin_idx = 19 ) then 75 | future.bin_idx <= 0 ; 76 | else 77 | future.bin_idx <= current.bin_idx + 1 ; 78 | end if ; 79 | end if ; 80 | end process ; 81 | end architecture ; 82 | -------------------------------------------------------------------------------- /fpga/vhdl/wlan_interleaver.vhd: -------------------------------------------------------------------------------- 1 | -- This file is part of bladeRF-wiphy. 2 | -- 3 | -- Copyright (C) 2020 Nuand, LLC. 4 | -- 5 | -- This program is free software; you can redistribute it and/or modify 6 | -- it under the terms of the GNU General Public License as published by 7 | -- the Free Software Foundation; either version 2 of the License, or 8 | -- (at your option) any later version. 9 | -- 10 | -- This program is distributed in the hope that it will be useful, 11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | -- GNU General Public License for more details. 14 | -- 15 | -- You should have received a copy of the GNU General Public License along 16 | -- with this program; if not, write to the Free Software Foundation, Inc., 17 | -- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | 19 | library ieee ; 20 | use ieee.std_logic_1164.all ; 21 | use ieee.numeric_std.all ; 22 | 23 | library work ; 24 | use work.wlan_p.all ; 25 | use work.wlan_interleaver_p.all ; 26 | 27 | entity wlan_interleaver is 28 | port ( 29 | clock : in std_logic ; 30 | reset : in std_logic ; 31 | 32 | modulation : in wlan_modulation_t ; 33 | data : in std_logic_vector(287 downto 0) ; 34 | in_valid : in std_logic ; 35 | 36 | interleaved : out std_logic_vector(287 downto 0) ; 37 | interleaved_mod : out wlan_modulation_t ; 38 | interleaved_valid : out std_logic 39 | ) ; 40 | end entity ; 41 | 42 | architecture arch of wlan_interleaver is 43 | 44 | begin 45 | 46 | permute_bits : process(clock, reset) 47 | begin 48 | if( reset = '1' ) then 49 | interleaved <= (others =>'0') ; 50 | interleaved_mod <= WLAN_BPSK ; 51 | interleaved_valid <= '0' ; 52 | elsif( rising_edge(clock) ) then 53 | interleaved_valid <= in_valid ; 54 | if( in_valid = '1' ) then 55 | interleaved <= interleave(modulation, data) ; 56 | interleaved_mod <= modulation ; 57 | end if ; 58 | end if ; 59 | end process ; 60 | 61 | end architecture ; 62 | 63 | -------------------------------------------------------------------------------- /fpga/vhdl/wlan_interleaver_p.vhd: -------------------------------------------------------------------------------- 1 | -- This file is part of bladeRF-wiphy. 2 | -- 3 | -- Copyright (C) 2020 Nuand, LLC. 4 | -- 5 | -- This program is free software; you can redistribute it and/or modify 6 | -- it under the terms of the GNU General Public License as published by 7 | -- the Free Software Foundation; either version 2 of the License, or 8 | -- (at your option) any later version. 9 | -- 10 | -- This program is distributed in the hope that it will be useful, 11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | -- GNU General Public License for more details. 14 | -- 15 | -- You should have received a copy of the GNU General Public License along 16 | -- with this program; if not, write to the Free Software Foundation, Inc., 17 | -- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | 19 | library ieee ; 20 | use ieee.std_logic_1164.all ; 21 | use ieee.math_real.all ; 22 | 23 | library work ; 24 | use work.wlan_p.all ; 25 | 26 | package wlan_interleaver_p is 27 | 28 | -- Deferred initialization in package body after function definition 29 | constant WLAN_INTERLEAVER_BPSK : integer_array_t ; 30 | constant WLAN_INTERLEAVER_QPSK : integer_array_t ; 31 | constant WLAN_INTERLEAVER_16QAM : integer_array_t ; 32 | constant WLAN_INTERLEAVER_64QAM : integer_array_t ; 33 | 34 | -- Interleaving occurs on bits 35 | function interleave( modulation : wlan_modulation_t ; x : std_logic_vector(287 downto 0) ) return std_logic_vector ; 36 | 37 | -- Deinterleaving occurs on bit soft decisions 38 | function deinterleave( modulation : wlan_modulation_t ; x : bsd_array_t(287 downto 0) ) return bsd_array_t ; 39 | 40 | end package ; 41 | 42 | package body wlan_interleaver_p is 43 | 44 | function get_table( modulation : wlan_modulation_t ) return integer_array_t is 45 | begin 46 | case modulation is 47 | when WLAN_BPSK => return WLAN_INTERLEAVER_BPSK ; 48 | when WLAN_QPSK => return WLAN_INTERLEAVER_QPSK ; 49 | when WLAN_16QAM => return WLAN_INTERLEAVER_16QAM ; 50 | when WLAN_64QAM => return WLAN_INTERLEAVER_64QAM ; 51 | when others => return WLAN_INTERLEAVER_BPSK ; 52 | end case ; 53 | report "get_table: Could not figure out modulation" severity failure ; 54 | end function ; 55 | 56 | function interleave( modulation : wlan_modulation_t ; x : std_logic_vector(287 downto 0) ) return std_logic_vector is 57 | variable t : integer_array_t(0 to 287) ; 58 | variable y : std_logic_vector(287 downto 0) := (others =>'-') ; 59 | begin 60 | t := get_table( modulation ) ; 61 | for i in t'range loop 62 | -- 0 only happens for the 0 entry, so stop there 63 | if( i > 0 and t(i) = 0 ) then 64 | exit ; 65 | else 66 | y(t(i)) := x(i) ; 67 | end if ; 68 | end loop ; 69 | return y ; 70 | end function ; 71 | 72 | function deinterleave( modulation : wlan_modulation_t ; x : bsd_array_t(287 downto 0) ) return bsd_array_t is 73 | variable t : integer_array_t(0 to 287) ; 74 | variable y : bsd_array_t(287 downto 0) ; 75 | begin 76 | y := (others => (others => '0' )) ; 77 | t := get_table( modulation ) ; 78 | for i in t'range loop 79 | -- Stop at the next 0 entry 80 | if( i > 0 and t(i) = 0 ) then 81 | exit ; 82 | else 83 | y(i) := x(t(i)) ; 84 | end if ; 85 | end loop ; 86 | return y ; 87 | end function ; 88 | 89 | function calculate_interleaver_table( modulation : wlan_modulation_t ) return integer_array_t is 90 | variable n_cbps : natural ; 91 | variable n_bpsc : natural ; 92 | variable i : natural ; 93 | variable j : natural ; 94 | variable s : natural ; 95 | variable rv : integer_array_t(0 to 287) := (others => 0) ; 96 | begin 97 | case modulation is 98 | when WLAN_BPSK => 99 | n_bpsc := 1 ; 100 | n_cbps := 48 ; 101 | s := 1 ; 102 | when WLAN_QPSK => 103 | n_bpsc := 2 ; 104 | n_cbps := 96 ; 105 | s := 1 ; 106 | when WLAN_16QAM => 107 | n_bpsc := 4 ; 108 | n_cbps := 192 ; 109 | s := 2 ; 110 | when WLAN_64QAM => 111 | n_bpsc := 6 ; 112 | n_cbps := 288 ; 113 | s := 3 ; 114 | when others => 115 | end case ; 116 | 117 | for k in 0 to n_cbps-1 loop 118 | i := (n_cbps/16)*(k mod 16) + k/16 ; 119 | j := s*integer(floor(real(i)/real(s))) + ((i + n_cbps - (16*i)/n_cbps) mod s) ; 120 | rv(k) := j ; 121 | end loop ; 122 | 123 | return rv ; 124 | end function ; 125 | 126 | -- Deferred initialization of table 127 | constant WLAN_INTERLEAVER_BPSK : integer_array_t := calculate_interleaver_table( WLAN_BPSK ) ; 128 | constant WLAN_INTERLEAVER_QPSK : integer_array_t := calculate_interleaver_table( WLAN_QPSK ) ; 129 | constant WLAN_INTERLEAVER_16QAM : integer_array_t := calculate_interleaver_table( WLAN_16QAM ) ; 130 | constant WLAN_INTERLEAVER_64QAM : integer_array_t := calculate_interleaver_table( WLAN_64QAM ) ; 131 | 132 | end package body ; 133 | 134 | -------------------------------------------------------------------------------- /fpga/vhdl/wlan_lfsr.vhd: -------------------------------------------------------------------------------- 1 | -- This file is part of bladeRF-wiphy. 2 | -- 3 | -- Copyright (C) 2020 Nuand, LLC. 4 | -- 5 | -- This program is free software; you can redistribute it and/or modify 6 | -- it under the terms of the GNU General Public License as published by 7 | -- the Free Software Foundation; either version 2 of the License, or 8 | -- (at your option) any later version. 9 | -- 10 | -- This program is distributed in the hope that it will be useful, 11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | -- GNU General Public License for more details. 14 | -- 15 | -- You should have received a copy of the GNU General Public License along 16 | -- with this program; if not, write to the Free Software Foundation, Inc., 17 | -- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | 19 | library ieee ; 20 | use ieee.std_logic_1164.all ; 21 | use ieee.numeric_std.all ; 22 | 23 | entity wlan_lfsr is 24 | generic ( 25 | WIDTH : positive := 8 26 | ) ; 27 | port ( 28 | clock : in std_logic ; 29 | reset : in std_logic ; 30 | 31 | init : in unsigned(6 downto 0) ; 32 | init_valid : in std_logic ; 33 | 34 | advance : in std_logic ; 35 | data : out std_logic_vector(WIDTH-1 downto 0) ; 36 | data_valid : out std_logic 37 | ) ; 38 | end entity ; 39 | 40 | architecture arch of wlan_lfsr is 41 | 42 | signal state : unsigned(6 downto 0) := (others =>'0') ; 43 | 44 | begin 45 | 46 | lfsr : process(clock, reset) 47 | variable tempstate : unsigned(6 downto 0) := (others =>'0') ; 48 | begin 49 | if( reset = '1' ) then 50 | state <= (others =>'0') ; 51 | data <= (others =>'0') ; 52 | data_valid <= '0' ; 53 | tempstate := (others =>'0') ; 54 | elsif( rising_edge(clock) ) then 55 | data_valid <= '0' ; 56 | if( init_valid = '1' ) then 57 | tempstate := init ; 58 | -- Initialize output to the first word, like a look-ahead FIFO 59 | for i in 0 to data'high loop 60 | tempstate := tempstate(5 downto 0) & (tempstate(6) xor tempstate(3)) ; 61 | data(i) <= tempstate(0) ; 62 | end loop ; 63 | state <= tempstate ; 64 | else 65 | data_valid <= advance ; 66 | if( advance = '1' ) then 67 | tempstate := state ; 68 | for i in 0 to data'high loop 69 | tempstate := tempstate(5 downto 0) & (tempstate(6) xor tempstate(3)) ; 70 | data(i) <= tempstate(0) ; 71 | end loop ; 72 | state <= tempstate ; 73 | end if ; 74 | end if ; 75 | end if ; 76 | end process ; 77 | 78 | end architecture ; 79 | 80 | -------------------------------------------------------------------------------- /fpga/vhdl/wlan_p_norm.vhd: -------------------------------------------------------------------------------- 1 | -- This file is part of bladeRF-wiphy. 2 | -- 3 | -- Copyright (C) 2020 Nuand, LLC. 4 | -- 5 | -- This program is free software; you can redistribute it and/or modify 6 | -- it under the terms of the GNU General Public License as published by 7 | -- the Free Software Foundation; either version 2 of the License, or 8 | -- (at your option) any later version. 9 | -- 10 | -- This program is distributed in the hope that it will be useful, 11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | -- GNU General Public License for more details. 14 | -- 15 | -- You should have received a copy of the GNU General Public License along 16 | -- with this program; if not, write to the Free Software Foundation, Inc., 17 | -- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | 19 | library ieee ; 20 | use ieee.std_logic_1164.all ; 21 | use ieee.numeric_std.all ; 22 | use ieee.math_real.all ; 23 | 24 | library wlan ; 25 | use wlan.wlan_p.all ; 26 | use wlan.wlan_rx_p.all ; 27 | 28 | entity wlan_p_norm is 29 | port ( 30 | -- 40MHz clock and async asserted, sync deasserted reset 31 | clock : in std_logic ; 32 | reset : in std_logic ; 33 | quiet : in std_logic ; 34 | 35 | 36 | sample : in wlan_sample_t ; 37 | p_normed : out wlan_sample_t ; 38 | 39 | p_mag : out signed( 23 downto 0 ) 40 | ) ; 41 | end entity ; 42 | 43 | architecture arch of wlan_p_norm is 44 | signal iir : signed( 31 downto 0 ) ; 45 | signal saved_iir: signed( 31 downto 0 ) ; 46 | signal dat : signed( 31 downto 0 ) ; 47 | signal log2 : unsigned ( 8 downto 0 ) ; 48 | signal ptemp : signed( 31 downto 0 ) ; 49 | signal timer : unsigned( 8 downto 0 ) ; 50 | type unsigned_array_t is array (natural range 0 to 511) of signed( 23 downto 0 ) ; 51 | 52 | function calc_lut return unsigned_array_t is 53 | variable rv : unsigned_array_t ; 54 | variable i : real ; 55 | variable two : real ; 56 | begin 57 | for x in rv'range loop 58 | i := ( 24.0 - (real(x) / 16.0) ) / 2.0 + 12.0; -- i is in log2 59 | report integer'image(x) & " LUT " & real'image(i); 60 | -- if (i > 5.0) then 61 | -- i := 5.0; 62 | -- end if; 63 | two := 2 ** i ; 64 | if (real(two) > 5.7e5) then 65 | two := 5.7e5; 66 | end if; 67 | report integer'image(x) & " pow " & real'image(two); 68 | rv(x) := to_signed(integer(round(two)), 24) ; 69 | end loop ; 70 | return rv ; 71 | end; 72 | constant mult_lut : unsigned_array_t := calc_lut; 73 | 74 | function log2x( x : signed( 31 downto 0) ) 75 | return unsigned is 76 | variable bits : unsigned( 8 downto 0 ) ; 77 | begin 78 | bits := (others => '0') ; 79 | for i in x'range loop 80 | if (x(i) = '1') then 81 | bits(8 downto 4) := to_unsigned(i, 5) ; 82 | if (real(i) < 4.0) then 83 | bits(3 downto 4 - i) := unsigned(x(i - 1 downto 0)) ; 84 | else 85 | bits(3 downto 0) := unsigned(x(i - 1 downto i - 4)) ; 86 | end if; 87 | -- bits(3 downto 0) <= 88 | exit ; 89 | end if ; 90 | end loop ; 91 | return bits ; 92 | end log2x ; 93 | 94 | function run_iir( x : signed( 31 downto 0); y : signed ( 31 downto 0) ) 95 | return signed 96 | is 97 | variable amrea : signed(31 downto 0) ; 98 | begin 99 | amrea := resize( x - shift_right(x, 6) + shift_right(y, 6), 32 ); 100 | return amrea; 101 | end; 102 | begin 103 | process( clock ) 104 | variable t : signed( 31 downto 0 ) ; 105 | begin 106 | if( reset = '1' ) then 107 | iir <= ( others => '0' ) ; 108 | saved_iir <= ( others => '0' ) ; 109 | ptemp <= ( others => '0' ) ; 110 | timer <= ( others => '0' ) ; 111 | p_mag <= ( others => '0' ) ; 112 | elsif( rising_edge( clock )) then 113 | if( quiet = '1' ) then 114 | ptemp <= ( others => '0' ) ; 115 | timer <= ( others => '0' ) ; 116 | else 117 | if( timer < 200 ) then 118 | timer <= timer + 1 ; 119 | end if ; 120 | if( timer = 18 ) then 121 | iir <= ptemp; 122 | end if ; 123 | if( timer = 30 ) then 124 | saved_iir <= iir ; 125 | end if ; 126 | end if ; 127 | if (sample.valid = '1') then 128 | ptemp <= sample.i * sample.i + sample.q * sample.q ; 129 | iir <= run_iir(iir, ptemp) ; 130 | p_normed.i <= resize(shift_right(sample.i * mult_lut(to_integer(log2x(saved_iir))) ,12),16); 131 | p_normed.q <= resize(shift_right(sample.q * mult_lut(to_integer(log2x(saved_iir))) ,12),16); 132 | p_mag <= signed(resize(mult_lut(to_integer(log2x(saved_iir))), 24)); 133 | --p_normed.q <= sample.q * mult_lut(log2x(t)); 134 | --dat <= log2x(t) * ; 135 | log2 <= log2x(iir) ; 136 | end if ; 137 | if (timer < 30 ) then 138 | p_normed.valid <= '0' ; 139 | else 140 | p_normed.valid <= sample.valid ; 141 | end if ; 142 | end if ; 143 | end process ; 144 | end architecture ; 145 | -------------------------------------------------------------------------------- /fpga/vhdl/wlan_peak_finder.vhd: -------------------------------------------------------------------------------- 1 | -- This file is part of bladeRF-wiphy. 2 | -- 3 | -- Copyright (C) 2020 Nuand, LLC. 4 | -- 5 | -- This program is free software; you can redistribute it and/or modify 6 | -- it under the terms of the GNU General Public License as published by 7 | -- the Free Software Foundation; either version 2 of the License, or 8 | -- (at your option) any later version. 9 | -- 10 | -- This program is distributed in the hope that it will be useful, 11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | -- GNU General Public License for more details. 14 | -- 15 | -- You should have received a copy of the GNU General Public License along 16 | -- with this program; if not, write to the Free Software Foundation, Inc., 17 | -- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | 19 | library ieee ; 20 | use ieee.std_logic_1164.all ; 21 | use ieee.numeric_std.all ; 22 | 23 | library wlan ; 24 | use wlan.wlan_p.all ; 25 | use wlan.wlan_rx_p.all ; 26 | 27 | entity wlan_peak_finder is 28 | generic ( 29 | SAMPLE_WINDOW : integer := 31 30 | ) ; 31 | port ( 32 | clock : in std_logic ; 33 | reset : in std_logic ; 34 | 35 | sample : in unsigned(127 downto 0 ) ; 36 | sample_valid : in std_logic; 37 | peak : out std_logic 38 | ) ; 39 | end entity ; 40 | 41 | architecture arch of wlan_peak_finder is 42 | 43 | type peak_array_t is array(0 to SAMPLE_WINDOW-1) of unsigned(sample'range) ; 44 | 45 | signal samples : peak_array_t ; 46 | 47 | begin 48 | 49 | process( clock ) 50 | variable highest : std_logic; 51 | begin 52 | if( rising_edge( clock ) ) then 53 | if( sample_valid = '1' ) then 54 | for i in 0 to samples'high - 1 loop 55 | samples(i+1) <= samples(i) ; 56 | end loop ; 57 | samples(0) <= sample ; 58 | 59 | highest := '1'; 60 | for i in samples'range loop 61 | if (i /= 15 and samples(i) > samples(15)) then 62 | highest := '0'; 63 | end if; 64 | end loop; 65 | if (samples(15) < 300000000) then 66 | highest := '0'; 67 | end if; 68 | 69 | peak <= highest; 70 | 71 | end if ; 72 | end if ; 73 | end process ; 74 | 75 | end architecture ; 76 | 77 | -------------------------------------------------------------------------------- /fpga/vhdl/wlan_rx_p.vhd: -------------------------------------------------------------------------------- 1 | -- This file is part of bladeRF-wiphy. 2 | -- 3 | -- Copyright (C) 2020 Nuand, LLC. 4 | -- 5 | -- This program is free software; you can redistribute it and/or modify 6 | -- it under the terms of the GNU General Public License as published by 7 | -- the Free Software Foundation; either version 2 of the License, or 8 | -- (at your option) any later version. 9 | -- 10 | -- This program is distributed in the hope that it will be useful, 11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | -- GNU General Public License for more details. 14 | -- 15 | -- You should have received a copy of the GNU General Public License along 16 | -- with this program; if not, write to the Free Software Foundation, Inc., 17 | -- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | 19 | library ieee ; 20 | use ieee.std_logic_1164.all ; 21 | use ieee.numeric_std.all ; 22 | use ieee.math_real.all ; 23 | 24 | library work ; 25 | use work.wlan_p.all ; 26 | 27 | package wlan_rx_p is 28 | 29 | type wlan_rx_status_t is (RX_IDLE, RX_ACTIVE, RX_FAULT_SIGNAL_INVALID, RX_FAULT_OVERFLOW) ; 30 | 31 | type wlan_rx_vector_t is record 32 | length : positive range 1 to 4095 ; 33 | datarate : wlan_datarate_t ; 34 | bandwidth : wlan_bandwidth_t ; 35 | end record ; 36 | 37 | type wlan_rx_params_t is record 38 | n_bpsc : natural range 1 to 6 ; 39 | n_cbps : natural range 48 to 288 ; 40 | n_dbps : natural range 24 to 216 ; 41 | bandwidth : wlan_bandwidth_t ; 42 | modulation : wlan_modulation_t ; 43 | datarate : wlan_datarate_t ; 44 | length : natural range 1 to 4095 ; 45 | lfsr_init : unsigned(6 downto 0) ; 46 | num_data_symbols : natural range 1 to 12000 ; 47 | num_padding_bits : natural range 0 to 287 ; 48 | num_decoded_bits : natural range 0 to 32768 ; 49 | packet_valid : std_logic ; 50 | end record ; 51 | 52 | function NULL_PARAMS return wlan_rx_params_t ; 53 | function NULL_RX_VECTOR return wlan_rx_vector_t ; 54 | 55 | end package ; 56 | 57 | package body wlan_rx_p is 58 | 59 | function NULL_PARAMS return wlan_rx_params_t is 60 | variable rv : wlan_rx_params_t ; 61 | begin 62 | rv.n_bpsc := 1 ; 63 | rv.n_cbps := 48 ; 64 | rv.n_dbps := 24 ; 65 | rv.bandwidth := WLAN_BW_20 ; 66 | rv.modulation := WLAN_BPSK ; 67 | rv.datarate := WLAN_RATE_6 ; 68 | rv.length := 1 ; 69 | rv.lfsr_init := (others =>'1') ; 70 | rv.num_data_symbols := 1 ; 71 | rv.num_padding_bits := 0 ; 72 | return rv ; 73 | end function ; 74 | 75 | function NULL_RX_VECTOR return wlan_rx_vector_t is 76 | variable rv : wlan_rx_vector_t ; 77 | begin 78 | rv.length := 1 ; 79 | rv.datarate := WLAN_RATE_6 ; 80 | rv.bandwidth := WLAN_BW_20 ; 81 | return rv ; 82 | end function ; 83 | 84 | end package body ; 85 | -------------------------------------------------------------------------------- /fpga/vhdl/wlan_sample_buffer.vhd: -------------------------------------------------------------------------------- 1 | -- This file is part of bladeRF-wiphy. 2 | -- 3 | -- Copyright (C) 2020 Nuand, LLC. 4 | -- 5 | -- This program is free software; you can redistribute it and/or modify 6 | -- it under the terms of the GNU General Public License as published by 7 | -- the Free Software Foundation; either version 2 of the License, or 8 | -- (at your option) any later version. 9 | -- 10 | -- This program is distributed in the hope that it will be useful, 11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | -- GNU General Public License for more details. 14 | -- 15 | -- You should have received a copy of the GNU General Public License along 16 | -- with this program; if not, write to the Free Software Foundation, Inc., 17 | -- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | 19 | library ieee ; 20 | use ieee.std_logic_1164.all ; 21 | use ieee.numeric_std.all ; 22 | 23 | library work ; 24 | use work.wlan_p.all ; 25 | 26 | library altera_mf ; 27 | use altera_mf.altera_mf_components.all ; 28 | 29 | entity wlan_sample_buffer is 30 | port ( 31 | clock : in std_logic ; 32 | reset : in std_logic ; 33 | 34 | -- Status 35 | room : out std_logic ; 36 | 37 | -- Short sequence inputs 38 | short : in wlan_sample_t ; 39 | 40 | -- Long sequence inputs 41 | long : in wlan_sample_t ; 42 | 43 | -- Symbol IFFT inputs 44 | symbol : in wlan_sample_t ; 45 | 46 | -- Sample FIFO outputs 47 | sample : out wlan_sample_t ; 48 | sample_i : out signed(15 downto 0) ; 49 | sample_q : out signed(15 downto 0) ; 50 | sample_re : in std_logic ; 51 | sample_empty : out std_logic 52 | ) ; 53 | end entity ; 54 | 55 | architecture arch of wlan_sample_buffer is 56 | 57 | signal fifo_write : std_logic ; 58 | signal fifo_read : std_logic ; 59 | signal fifo_input : std_logic_vector(31 downto 0) ; 60 | signal fifo_output : std_logic_vector(31 downto 0) ; 61 | signal fifo_empty : std_logic ; 62 | signal fifo_full : std_logic ; 63 | signal fifo_usedw : std_logic_vector(9 downto 0) ; 64 | 65 | signal mux_i : signed(15 downto 0) ; 66 | signal mux_q : signed(15 downto 0) ; 67 | 68 | begin 69 | 70 | check_fifo : process(clock) 71 | begin 72 | if( rising_edge(clock) ) then 73 | if( fifo_full = '1' and fifo_write = '1' ) then 74 | report "Writing to a full FIFO" 75 | severity error ; 76 | end if ; 77 | end if ; 78 | end process ; 79 | 80 | fifo_input <= std_logic_vector(mux_i) & std_logic_vector(mux_q) ; 81 | fifo_write <= short.valid or long.valid or symbol.valid ; 82 | fifo_read <= sample_re ; 83 | sample_i <= signed(fifo_output(31 downto 16)) ; 84 | sample_q <= signed(fifo_output(15 downto 0)) ; 85 | sample_empty <= fifo_empty ; 86 | 87 | mux_input : process(all) 88 | begin 89 | if( short.valid = '1' ) then 90 | mux_i <= short.i ; 91 | mux_q <= short.q ; 92 | elsif( long.valid = '1' ) then 93 | mux_i <= long.i ; 94 | mux_q <= long.q ; 95 | elsif( symbol.valid = '1' ) then 96 | mux_i <= symbol.i ; 97 | mux_q <= symbol.q ; 98 | else 99 | mux_i <= (others =>'0') ; 100 | mux_q <= (others =>'0') ; 101 | end if ; 102 | end process ; 103 | 104 | room <= '1' when unsigned(fifo_usedw) < 2**(fifo_usedw'length)-128 else '0' ; 105 | 106 | U_fifo : scfifo 107 | generic map ( 108 | lpm_width => fifo_input'length, 109 | lpm_widthu => fifo_usedw'length, 110 | lpm_numwords => 2**(fifo_usedw'length), 111 | lpm_showahead => "ON" 112 | ) port map ( 113 | clock => clock, 114 | aclr => reset, 115 | data => fifo_input, 116 | wrreq => fifo_write, 117 | rdreq => fifo_read, 118 | q => fifo_output, 119 | full => fifo_full, 120 | empty => fifo_empty, 121 | usedw => fifo_usedw 122 | ) ; 123 | 124 | end architecture ; 125 | 126 | -------------------------------------------------------------------------------- /fpga/vhdl/wlan_tx_long.vhd: -------------------------------------------------------------------------------- 1 | -- This file is part of bladeRF-wiphy. 2 | -- 3 | -- Copyright (C) 2020 Nuand, LLC. 4 | -- 5 | -- This program is free software; you can redistribute it and/or modify 6 | -- it under the terms of the GNU General Public License as published by 7 | -- the Free Software Foundation; either version 2 of the License, or 8 | -- (at your option) any later version. 9 | -- 10 | -- This program is distributed in the hope that it will be useful, 11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | -- GNU General Public License for more details. 14 | -- 15 | -- You should have received a copy of the GNU General Public License along 16 | -- with this program; if not, write to the Free Software Foundation, Inc., 17 | -- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | 19 | library ieee ; 20 | use ieee.std_logic_1164.all ; 21 | use ieee.numeric_std.all ; 22 | use ieee.math_real.all ; 23 | 24 | library work ; 25 | use work.wlan_p.all ; 26 | use work.wlan_tx_p.all ; 27 | 28 | entity wlan_tx_long is 29 | port ( 30 | clock : in std_logic ; 31 | reset : in std_logic ; 32 | start : in std_logic ; 33 | done : out std_logic ; 34 | out_sample : out wlan_sample_t ; 35 | out_valid_cp : out std_logic 36 | ) ; 37 | end entity ; 38 | 39 | architecture arch of wlan_tx_long is 40 | 41 | function create_long_sequence return sample_array_t is 42 | variable rv : sample_array_t(LONG_SEQ_TIME'range) ; 43 | begin 44 | for i in rv'range loop 45 | rv(i).i := to_signed(integer(round(LONG_SEQ_TIME(i).re*4096.0*4.0)),rv(i).i'length) ; 46 | rv(i).q := to_signed(integer(round(LONG_SEQ_TIME(i).im*4096.0*4.0)),rv(i).q'length) ; 47 | rv(i).valid := '1' ; 48 | end loop; 49 | return rv ; 50 | end function ; 51 | 52 | constant LONG_SEQ : sample_array_t := create_long_sequence ; 53 | 54 | type fsm_t is (IDLE, CYCLIC_PREFIX, T_SEQ) ; 55 | 56 | type state_t is record 57 | fsm : fsm_t ; 58 | repeat : natural range 1 to 2 ; 59 | index : natural range LONG_SEQ'range ; 60 | sample : wlan_sample_t ; 61 | valid_cp : std_logic ; 62 | done : std_logic ; 63 | end record ; 64 | 65 | constant NULL_STATE : state_t := ( 66 | fsm => IDLE, 67 | repeat => 2, 68 | index => 32, 69 | sample => NULL_SAMPLE, 70 | valid_cp => '0', 71 | done => '0' 72 | ) ; 73 | 74 | -- FSM state 75 | signal current, future : state_t := NULL_STATE ; 76 | 77 | begin 78 | 79 | done <= current.done ; 80 | out_sample <= current.sample ; 81 | out_valid_cp <= current.valid_cp ; 82 | 83 | seq : process(clock, reset) 84 | begin 85 | if( reset = '1' ) then 86 | current <= NULL_STATE ; 87 | elsif( rising_edge(clock) ) then 88 | current <= future ; 89 | end if ; 90 | end process ; 91 | 92 | comb : process(all) 93 | begin 94 | future <= current ; 95 | case current.fsm is 96 | when IDLE => 97 | future <= NULL_STATE ; 98 | if( start = '1' ) then 99 | future.fsm <= CYCLIC_PREFIX ; 100 | end if ; 101 | 102 | when CYCLIC_PREFIX => 103 | future.sample <= LONG_SEQ(current.index) ; 104 | future.valid_cp <= '1' ; 105 | future.sample.valid <= '0' ; 106 | if( current.index < LONG_SEQ'high ) then 107 | future.index <= current.index + 1 ; 108 | else 109 | future.fsm <= T_SEQ ; 110 | future.index <= 0 ; 111 | end if ; 112 | 113 | when T_SEQ => 114 | future.sample <= LONG_SEQ(current.index) ; 115 | future.valid_cp <= '0' ; 116 | if( current.index < LONG_SEQ'high ) then 117 | future.index <= current.index + 1 ; 118 | else 119 | if( current.repeat = 1 ) then 120 | future.fsm <= IDLE ; 121 | future.done <= '1' ; 122 | else 123 | future.repeat <= current.repeat - 1 ; 124 | future.index <= 0 ; 125 | end if ; 126 | end if ; 127 | 128 | when others => 129 | future <= NULL_STATE ; 130 | 131 | end case ; 132 | end process ; 133 | 134 | end architecture ; 135 | 136 | -------------------------------------------------------------------------------- /fpga/vhdl/wlan_tx_p.vhd: -------------------------------------------------------------------------------- 1 | -- This file is part of bladeRF-wiphy. 2 | -- 3 | -- Copyright (C) 2020 Nuand, LLC. 4 | -- 5 | -- This program is free software; you can redistribute it and/or modify 6 | -- it under the terms of the GNU General Public License as published by 7 | -- the Free Software Foundation; either version 2 of the License, or 8 | -- (at your option) any later version. 9 | -- 10 | -- This program is distributed in the hope that it will be useful, 11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | -- GNU General Public License for more details. 14 | -- 15 | -- You should have received a copy of the GNU General Public License along 16 | -- with this program; if not, write to the Free Software Foundation, Inc., 17 | -- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | 19 | library ieee ; 20 | use ieee.std_logic_1164.all ; 21 | use ieee.numeric_std.all ; 22 | use ieee.math_real.all ; 23 | 24 | library work ; 25 | use work.wlan_p.all ; 26 | 27 | package wlan_tx_p is 28 | 29 | type wlan_tx_vector_t is record 30 | length : positive range 1 to 4095 ; 31 | datarate : wlan_datarate_t ; 32 | bandwidth : wlan_bandwidth_t ; 33 | end record ; 34 | 35 | type wlan_tx_params_t is record 36 | n_bpsc : natural range 1 to 6 ; 37 | n_cbps : natural range 48 to 288 ; 38 | n_dbps : natural range 24 to 216 ; 39 | modulation : wlan_modulation_t ; 40 | datarate : wlan_datarate_t ; 41 | length : natural range 1 to 4095 ; 42 | lfsr_init : unsigned(6 downto 0) ; 43 | num_decoded_bits : natural range 8 to 11224 ; 44 | num_data_symbols : natural range 1 to 1366 ; 45 | num_padding_bits : natural range 0 to 287 ; 46 | end record ; 47 | 48 | function NULL_PARAMS return wlan_tx_params_t ; 49 | function NULL_TX_VECTOR return wlan_tx_vector_t ; 50 | 51 | type wlan_tx_status_t is (TX_IDLE, TX_SHORT, TX_LONG, TX_DATA, TX_FAULT_NODATA, TX_FAULT_UNDERRUN) ; 52 | 53 | end package ; 54 | 55 | package body wlan_tx_p is 56 | 57 | function NULL_PARAMS return wlan_tx_params_t is 58 | variable rv : wlan_tx_params_t ; 59 | begin 60 | rv.n_bpsc := 1 ; 61 | rv.n_cbps := 48 ; 62 | rv.n_dbps := 24 ; 63 | rv.modulation := WLAN_BPSK ; 64 | rv.datarate := WLAN_RATE_6 ; 65 | rv.length := 1 ; 66 | rv.lfsr_init := (others =>'1') ; 67 | rv.num_data_symbols := 0 ; 68 | rv.num_data_symbols := 1 ; 69 | rv.num_padding_bits := 0 ; 70 | return rv ; 71 | end function ; 72 | 73 | function NULL_TX_VECTOR return wlan_tx_vector_t is 74 | variable rv : wlan_tx_vector_t ; 75 | begin 76 | rv.length := 1 ; 77 | rv.datarate := WLAN_RATE_6 ; 78 | rv.bandwidth := WLAN_BW_20 ; 79 | return rv ; 80 | end function ; 81 | 82 | end package body ; 83 | -------------------------------------------------------------------------------- /fpga/vhdl/wlan_tx_short.vhd: -------------------------------------------------------------------------------- 1 | -- This file is part of bladeRF-wiphy. 2 | -- 3 | -- Copyright (C) 2020 Nuand, LLC. 4 | -- 5 | -- This program is free software; you can redistribute it and/or modify 6 | -- it under the terms of the GNU General Public License as published by 7 | -- the Free Software Foundation; either version 2 of the License, or 8 | -- (at your option) any later version. 9 | -- 10 | -- This program is distributed in the hope that it will be useful, 11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | -- GNU General Public License for more details. 14 | -- 15 | -- You should have received a copy of the GNU General Public License along 16 | -- with this program; if not, write to the Free Software Foundation, Inc., 17 | -- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | 19 | library ieee ; 20 | use ieee.std_logic_1164.all ; 21 | use ieee.numeric_std.all ; 22 | use ieee.math_real.all ; 23 | 24 | library work ; 25 | use work.wlan_p.all ; 26 | use work.wlan_tx_p.all ; 27 | 28 | entity wlan_tx_short is 29 | port ( 30 | clock : in std_logic ; 31 | reset : in std_logic ; 32 | start : in std_logic ; 33 | done : out std_logic ; 34 | out_sample : out wlan_sample_t 35 | ) ; 36 | end entity ; 37 | 38 | architecture arch of wlan_tx_short is 39 | 40 | function create_short_sequence return sample_array_t is 41 | variable rv : sample_array_t(SHORT_SEQ_TIME'range) ; 42 | begin 43 | for i in rv'range loop 44 | rv(i).i := to_signed(integer(round(SHORT_SEQ_TIME(i).re*4.0*4096.0)),rv(i).i'length) ; 45 | rv(i).q := to_signed(integer(round(SHORT_SEQ_TIME(i).im*4.0*4096.0)),rv(i).i'length) ; 46 | rv(i).valid := '1' ; 47 | end loop ; 48 | return rv ; 49 | end function ; 50 | 51 | constant SHORT_SEQ : sample_array_t := create_short_sequence ; 52 | 53 | type fsm_t is (IDLE, COUNTING) ; 54 | 55 | type state_t is record 56 | fsm : fsm_t ; 57 | repeat : natural range 1 to 10 ; 58 | index : natural range short_seq'range ; 59 | sample : wlan_sample_t ; 60 | done : std_logic ; 61 | end record ; 62 | 63 | constant NULL_STATE : state_t := ( 64 | fsm => IDLE, 65 | repeat => 10, 66 | index => 0, 67 | sample => NULL_SAMPLE, 68 | done => '0' 69 | ) ; 70 | 71 | -- FSM state 72 | signal current, future : state_t := NULL_STATE ; 73 | 74 | begin 75 | 76 | done <= current.done ; 77 | out_sample <= current.sample ; 78 | 79 | seq : process(clock, reset) 80 | begin 81 | if( reset = '1' ) then 82 | current <= NULL_STATE ; 83 | elsif( rising_edge(clock) ) then 84 | current <= future ; 85 | end if ; 86 | end process ; 87 | 88 | comb : process(all) 89 | begin 90 | future <= current ; 91 | case current.fsm is 92 | when IDLE => 93 | future <= NULL_STATE ; 94 | if( start = '1' ) then 95 | future.fsm <= COUNTING ; 96 | end if ; 97 | 98 | when COUNTING => 99 | future.sample <= short_seq(current.index) ; 100 | if( current.index < short_seq'high ) then 101 | future.index <= current.index + 1 ; 102 | else 103 | if( current.repeat = 1 ) then 104 | future.fsm <= IDLE ; 105 | future.done <= '1' ; 106 | else 107 | future.repeat <= current.repeat - 1 ; 108 | future.index <= 0 ; 109 | end if ; 110 | end if ; 111 | 112 | when others => 113 | future <= NULL_STATE ; 114 | end case ; 115 | end process ; 116 | 117 | end architecture ; 118 | 119 | -------------------------------------------------------------------------------- /fpga/vhdl/wlan_viterbi_decoder.vhd: -------------------------------------------------------------------------------- 1 | -- This file is part of bladeRF-wiphy. 2 | -- 3 | -- Copyright (C) 2020 Nuand, LLC. 4 | -- 5 | -- This program is free software; you can redistribute it and/or modify 6 | -- it under the terms of the GNU General Public License as published by 7 | -- the Free Software Foundation; either version 2 of the License, or 8 | -- (at your option) any later version. 9 | -- 10 | -- This program is distributed in the hope that it will be useful, 11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | -- GNU General Public License for more details. 14 | -- 15 | -- You should have received a copy of the GNU General Public License along 16 | -- with this program; if not, write to the Free Software Foundation, Inc., 17 | -- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | 19 | library ieee ; 20 | use ieee.std_logic_1164.all ; 21 | use ieee.numeric_std.all ; 22 | 23 | library wlan ; 24 | use wlan.wlan_p.all ; 25 | use wlan.wlan_rx_p.all ; 26 | 27 | library work ; 28 | library viterbi_decoder ; 29 | 30 | entity wlan_viterbi_decoder is 31 | port ( 32 | clock : in std_logic ; 33 | reset : in std_logic ; 34 | 35 | init : in std_logic ; 36 | 37 | in_soft_a : in signed(7 downto 0) ; 38 | in_soft_b : in signed(7 downto 0) ; 39 | in_erasure : in std_logic_vector(1 downto 0) ; 40 | in_valid : in std_logic ; 41 | 42 | params : in wlan_rx_params_t ; 43 | params_valid : in std_logic ; 44 | 45 | done : out std_logic ; 46 | 47 | out_dec_bit : out std_logic ; 48 | out_dec_valid : out std_logic 49 | ) ; 50 | end entity ; 51 | 52 | architecture arch of wlan_viterbi_decoder is 53 | 54 | type fsm_t is (IDLE, DECODE, RESET_CORE ) ; 55 | 56 | type state_t is record 57 | fsm : fsm_t ; 58 | num_decoded_bits : unsigned( 13 downto 0 ) ; 59 | done : std_logic ; 60 | end record ; 61 | 62 | function NULL_STATE return state_t is 63 | variable rv : state_t ; 64 | begin 65 | rv.fsm := IDLE ; 66 | rv.num_decoded_bits := ( others => '0' ); 67 | rv.done := '0' ; 68 | return rv ; 69 | end function ; 70 | 71 | signal sink_rdy : std_logic ; 72 | signal sink_val : std_logic ; 73 | 74 | signal source_rdy : std_logic ; 75 | signal source_val : std_logic ; 76 | 77 | signal rr : std_logic_vector(15 downto 0) ; 78 | 79 | signal decbit : std_logic ; 80 | 81 | signal normalizations : std_logic_vector(7 downto 0) ; 82 | 83 | signal core_reset : std_logic ; 84 | 85 | signal current, future : state_t := NULL_STATE ; 86 | 87 | function fix_var( x : signed(7 downto 0) ) return std_logic_vector is 88 | variable ret : std_logic_vector(7 downto 0); 89 | begin 90 | ret(6 downto 0) := not(std_logic_vector(x(6 downto 0))); 91 | ret(7) := x(7); 92 | return (ret); 93 | end function; 94 | 95 | begin 96 | 97 | done <= current.done ; 98 | 99 | sync : process(clock, reset) 100 | begin 101 | if( reset = '1' ) then 102 | current <= NULL_STATE ; 103 | elsif( rising_edge(clock) ) then 104 | if( init = '1' ) then 105 | current <= NULL_STATE ; 106 | else 107 | current <= future ; 108 | end if ; 109 | end if ; 110 | end process ; 111 | 112 | comb : process(all) 113 | begin 114 | future <= current ; 115 | future.done <= '0' ; 116 | 117 | case current.fsm is 118 | when IDLE => 119 | if( params_valid = '1' ) then 120 | future.num_decoded_bits <= to_unsigned(params.num_decoded_bits - 1, future.num_decoded_bits'length ) ; 121 | future.fsm <= DECODE ; 122 | end if ; 123 | 124 | when DECODE => 125 | if( source_val = '1' ) then 126 | future.num_decoded_bits <= current.num_decoded_bits - 1; 127 | end if ; 128 | if( current.num_decoded_bits = 0 ) then 129 | future.done <= '1' ; 130 | future.fsm <= RESET_CORE ; 131 | end if ; 132 | 133 | when RESET_CORE => 134 | future.fsm <= IDLE ; 135 | end case ; 136 | end process ; 137 | 138 | core_reset <= '1' when current.fsm = RESET_CORE or current.fsm = IDLE or reset = '1' else '0' ; 139 | rr <= std_logic_vector(in_soft_a) & std_logic_vector(in_soft_b) ; 140 | sink_val <= in_valid ; 141 | 142 | --U_altera_decoder : entity viterbi_decoder.viterbi_decoder 143 | -- port map ( 144 | -- clk => clock, 145 | -- reset => core_reset, 146 | 147 | -- sink_val => sink_val, 148 | -- sink_rdy => sink_rdy, 149 | -- rr => rr, 150 | -- eras_sym => in_erasure, 151 | 152 | -- source_rdy => source_rdy, 153 | -- source_val => source_val, 154 | -- decbit => decbit, 155 | -- normalizations => normalizations 156 | -- ) ; 157 | U_vit : entity work.viterbi_decoder 158 | generic map( 159 | TB_LEN => 60 160 | ) 161 | port map( 162 | clock => clock, 163 | reset => core_reset, 164 | in_a => (fix_var(in_soft_a)), 165 | in_b => (fix_var(in_soft_b)), 166 | erasure => in_erasure(0) & in_erasure(1), 167 | bsd_valid => in_valid, 168 | 169 | out_bit => decbit, 170 | out_valid => source_val 171 | ); 172 | 173 | 174 | 175 | out_dec_bit <= decbit ; 176 | out_dec_valid <= source_val ; 177 | source_rdy <= '1' ; 178 | 179 | end architecture ; 180 | 181 | -------------------------------------------------------------------------------- /fpga/vhdl/wlan_viterbi_encoder.vhd: -------------------------------------------------------------------------------- 1 | -- This file is part of bladeRF-wiphy. 2 | -- 3 | -- Copyright (C) 2020 Nuand, LLC. 4 | -- 5 | -- This program is free software; you can redistribute it and/or modify 6 | -- it under the terms of the GNU General Public License as published by 7 | -- the Free Software Foundation; either version 2 of the License, or 8 | -- (at your option) any later version. 9 | -- 10 | -- This program is distributed in the hope that it will be useful, 11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | -- GNU General Public License for more details. 14 | -- 15 | -- You should have received a copy of the GNU General Public License along 16 | -- with this program; if not, write to the Free Software Foundation, Inc., 17 | -- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | 19 | library ieee ; 20 | use ieee.std_logic_1164.all ; 21 | use ieee.numeric_std.all ; 22 | 23 | library work ; 24 | 25 | entity wlan_viterbi_encoder is 26 | generic ( 27 | WIDTH : positive := 4 28 | ) ; 29 | port ( 30 | clock : in std_logic ; 31 | reset : in std_logic ; 32 | 33 | init : in std_logic ; 34 | 35 | in_data : in std_logic_vector(WIDTH-1 downto 0) ; 36 | in_valid : in std_logic ; 37 | in_done : in std_logic ; 38 | 39 | out_a : out std_logic_vector(WIDTH-1 downto 0) ; 40 | out_b : out std_logic_vector(WIDTH-1 downto 0) ; 41 | out_done : out std_logic ; 42 | out_valid : out std_logic 43 | ) ; 44 | end entity ; 45 | 46 | architecture arch of wlan_viterbi_encoder is 47 | 48 | signal state : unsigned(5 downto 0) := (others =>'0') ; 49 | 50 | begin 51 | 52 | encode : process(clock, reset) 53 | variable tempstate : unsigned(state'range) := (others =>'0') ; 54 | begin 55 | if( reset = '1' ) then 56 | state <= (others =>'0') ; 57 | out_a <= (others =>'0') ; 58 | out_b <= (others =>'0') ; 59 | out_valid <= '0' ; 60 | out_done <= '0' ; 61 | tempstate := (others =>'0') ; 62 | elsif( rising_edge(clock) ) then 63 | out_valid <= '0' ; 64 | out_done <= in_done ; 65 | if( init = '1' ) then 66 | state <= (others =>'0') ; 67 | else 68 | out_valid <= in_valid ; 69 | if( in_valid = '1' ) then 70 | tempstate := state ; 71 | for i in 0 to in_data'high loop 72 | out_a(i) <= tempstate(5) xor tempstate(4) xor tempstate(2) xor tempstate(1) xor in_data(i) ; 73 | out_b(i) <= tempstate(5) xor tempstate(2) xor tempstate(1) xor tempstate(0) xor in_data(i) ; 74 | tempstate := tempstate(4 downto 0) & in_data(i) ; 75 | end loop ; 76 | state <= tempstate ; 77 | end if ; 78 | end if ; 79 | end if ; 80 | end process ; 81 | 82 | end architecture ; 83 | 84 | -------------------------------------------------------------------------------- /matlab/util.m: -------------------------------------------------------------------------------- 1 | % This file is part of bladeRF-wiphy. 2 | % 3 | % Copyright (C) 2020 Nuand, LLC. 4 | % 5 | % This program is free software; you can redistribute it and/or modify 6 | % it under the terms of the GNU General Public License as published by 7 | % the Free Software Foundation; either version 2 of the License, or 8 | % (at your option) any later version. 9 | % 10 | % This program is distributed in the hope that it will be useful, 11 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | % GNU General Public License for more details. 14 | % 15 | % You should have received a copy of the GNU General Public License along 16 | % with this program; if not, write to the Free Software Foundation, Inc., 17 | % 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | 19 | % Null OFDM symbol 20 | null = zeros(64,1) ; 21 | 22 | % Short preamble generation 23 | SHORT_ONE = 1.472 + 1.472*1j ; 24 | 25 | % Bins for positive and negative values 26 | % NOTE: MATLAB has bin 1 as the DC bin, but standard uses 27 | % bin 0 as DC, so we will define all bins here similar to the 28 | % standard, and when indexing them, we will add the MATLAB offset. 29 | SHORT_POS = [12, 16, 20, 24, 40, 48, 60] ; 30 | SHORT_NEG = [4, 8, 44, 52, 56] ; 31 | 32 | short_preamble.freq = zeros(64,1) ; 33 | short_preamble.freq(SHORT_POS+1) = SHORT_ONE ; 34 | short_preamble.freq(SHORT_NEG+1) = -SHORT_ONE ; 35 | short_preamble.time = ifft(short_preamble.freq) ; 36 | 37 | % Long preamble generation 38 | LONG_ONE = 1 ; 39 | 40 | % Bins for positive and negative values 41 | LONG_POS = [1, 4, 5, 7, 9, 15, 16, 19, 21, 23, 24, 25, 26, 38, 39, 42, 43, 45, 47, 48, 49, 50, 51, 52, 55, 56, 58, 60, 61, 62, 63 ] ; 42 | LONG_NEG = [2, 3, 6, 8, 10, 11, 12, 13, 14, 17, 18, 20, 22, 40, 41, 44, 46, 53, 54, 57, 59 ] ; 43 | 44 | long_preamble.freq = zeros(64,1) ; 45 | long_preamble.freq(LONG_POS+1) = LONG_ONE ; 46 | long_preamble.freq(LONG_NEG+1) = -LONG_ONE ; 47 | long_preamble.time = ifft(long_preamble.freq) ; 48 | 49 | 50 | -------------------------------------------------------------------------------- /matlab/wlan_rx.m: -------------------------------------------------------------------------------- 1 | % This file is part of bladeRF-wiphy. 2 | % 3 | % Copyright (C) 2020 Nuand, LLC. 4 | % 5 | % This program is free software; you can redistribute it and/or modify 6 | % it under the terms of the GNU General Public License as published by 7 | % the Free Software Foundation; either version 2 of the License, or 8 | % (at your option) any later version. 9 | % 10 | % This program is distributed in the hope that it will be useful, 11 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | % GNU General Public License for more details. 14 | % 15 | % You should have received a copy of the GNU General Public License along 16 | % with this program; if not, write to the Free Software Foundation, Inc., 17 | % 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | 19 | %% User Parameters 20 | snr = 99 ; 21 | 22 | %% Initialization 23 | 24 | % Get common stuff, x is input signal 25 | util 26 | clear rx 27 | idx = 1 ; 28 | 29 | %% AWGN Channel with some phase offset 30 | % TODO: Make this more interesting 31 | %h = [1] ; 32 | % h = [ randn+1j*randn 0 (randn+1j*randn)/2 0 (randn+1j*randn)/4 ]; 33 | h = [ 0.85 0.1 0 0.05 0 0.05 ] ; 34 | % Add noise 35 | noise = (randn(length(x),1) + randn(length(x),1)*1j) ; 36 | sp = sum(abs(x).^2) ; 37 | np = sum(abs(noise).^2) ; 38 | 39 | % Scale noise based on signal and noise power 40 | nl = sp / (10^(snr/10)) / np ; 41 | noise = sqrt(nl).*noise ; 42 | 43 | sp = sum(abs(x).^2) ; 44 | np = sum(abs(noise).^2) ; 45 | rx.actual_snr = 10*log10(sp/np) ; 46 | 47 | % Finally add the noise 48 | % NOTE: Channel impulse response does not have a group delay, so don't 49 | % delay the input, just chop it off. 50 | xn = conv(x,h) ; xn = xn(1:length(x)) ; 51 | xn = xn + noise ; 52 | 53 | % Add a phase rotation 54 | xn = xn .* exp(1j*pi/8) ; 55 | 56 | %% Acquisition 57 | % Acquire 58 | % TODO: Actually acquire here, but for now we know we just advance 160 59 | % samples into the signal 60 | rx.short = xn(idx:idx+160-1) ; 61 | idx = idx + 160 ; % short sequence 62 | 63 | %% Save off T1 and T2 after GI2 64 | % Initialize frequency offset correction 65 | idx = idx + 32 ; % GI2 66 | rx.t1 = xn(idx:idx+64-1) ; 67 | rx.T1 = fft(rx.t1) ; 68 | rx.T1(rx.T1==0) = 1e-20 ; 69 | idx = idx + 64 ; % T1 70 | 71 | % Figure out initial equalizer taps 72 | rx.t2 = xn(idx:idx+64-1) ; 73 | rx.T2 = fft(rx.t2) ; 74 | rx.T2(rx.T2==0) = 1e-20 ; 75 | idx = idx + 64 ; % T2 76 | 77 | %% Initialize Equalizer from average of T1 and T2 78 | % Since T1 and T2 should be the same, we should be able to average the 79 | % observed samples together and try to get rid of some noise. 80 | rx.tavg = (rx.t1 + rx.t2)./2 ; 81 | rx.TAVG = fft(rx.tavg) ; 82 | 83 | %rx.TAVG = fft([ h, zeros(1,64-length(h))].') ; 84 | 85 | % Equalizer is just the reference signal divided by received signal 86 | rx.EQ = long_preamble.freq .* conj(rx.TAVG) ./ (abs(rx.TAVG).^2 + 10^(-snr/10)) ; 87 | 88 | %% Extract SIGNAL frame 89 | idx = idx + 16 ; % GI 90 | rx.signal = xn(idx:idx+64-1) ; 91 | rx.SIGNAL = fft(rx.signal) ; 92 | rx.SIGNAL_EQ = rx.SIGNAL .* rx.EQ ; 93 | idx = idx + 64 ; 94 | 95 | %% Extract DATA frames 96 | n = 1 ; 97 | num_data_frames = floor((length(x) - idx)/80) ; 98 | rx.data = zeros(num_data_frames, 64) ; 99 | rx.DATA = zeros(num_data_frames, 64) ; 100 | idx = idx + 16 ; % GI 101 | while n <= num_data_frames 102 | rx.data(n,:) = xn(idx:idx+64-1) ; 103 | rx.DATA(n,:) = fft(rx.data(n,:)) ; 104 | rx.DATA_EQ(n,:) = rx.DATA(n,:) .* rx.EQ.' ; 105 | % Increment 106 | n = n + 1 ; 107 | idx = idx + 80 ; 108 | end 109 | --------------------------------------------------------------------------------