From: jcorgan Date: Mon, 21 May 2007 05:58:05 +0000 (+0000) Subject: Merged r5463:5504 from jcorgan/snd into trunk. Work in progress, adds digital loopbac... X-Git-Url: https://git.gag.com/?a=commitdiff_plain;h=2711e51f33e4c83b07d8293ceca5d6db7830656e;p=debian%2Fgnuradio Merged r5463:5504 from jcorgan/snd into trunk. Work in progress, adds digital loopback and receive to FPGA code. Host receive code is still debugging only. git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@5505 221aa14e-8319-0410-a670-987f0aec2ac5 --- diff --git a/config/grc_gr_sounder.m4 b/config/grc_gr_sounder.m4 index a821ce4a..929be53a 100644 --- a/config/grc_gr_sounder.m4 +++ b/config/grc_gr_sounder.m4 @@ -27,7 +27,7 @@ AC_DEFUN([GRC_GR_SOUNDER],[ gr-sounder/src/fpga/Makefile \ gr-sounder/src/fpga/top/Makefile \ gr-sounder/src/fpga/lib/Makefile \ - gr-sounder/src/fpga/rbf/Makefile \ + gr-sounder/src/fpga/tb/Makefile \ gr-sounder/src/lib/Makefile \ gr-sounder/src/python/Makefile \ gr-sounder/src/python/run_tests diff --git a/gr-sounder/src/fpga/Makefile.am b/gr-sounder/src/fpga/Makefile.am index f4cd4fd4..2e8d8e3f 100644 --- a/gr-sounder/src/fpga/Makefile.am +++ b/gr-sounder/src/fpga/Makefile.am @@ -21,4 +21,4 @@ include $(top_srcdir)/Makefile.common -SUBDIRS = top lib rbf +SUBDIRS = top lib tb diff --git a/gr-sounder/src/fpga/lib/Makefile.am b/gr-sounder/src/fpga/lib/Makefile.am index 450981f1..0a03147a 100644 --- a/gr-sounder/src/fpga/lib/Makefile.am +++ b/gr-sounder/src/fpga/lib/Makefile.am @@ -28,3 +28,4 @@ EXTRA_DIST = \ sounder_rx.v \ sounder_tx.v +MOSTLYCLEANFILES = *~ \ No newline at end of file diff --git a/gr-sounder/src/fpga/lib/dac_interface.v b/gr-sounder/src/fpga/lib/dac_interface.v index b97ffa77..9042e1c5 100644 --- a/gr-sounder/src/fpga/lib/dac_interface.v +++ b/gr-sounder/src/fpga/lib/dac_interface.v @@ -27,16 +27,16 @@ module dac_interface(clk_i,rst_i,ena_i,strobe_i,tx_i_i,tx_q_i,tx_data_o,tx_sync_ input ena_i; input strobe_i; - input [15:0] tx_i_i; - input [15:0] tx_q_i; + input [13:0] tx_i_i; + input [13:0] tx_q_i; - output [15:0] tx_data_o; + output [13:0] tx_data_o; output tx_sync_o; `ifdef TX_RATE_MAX wire clk128; reg clk64_d; - reg [15:0] tx_data_o; + reg [13:0] tx_data_o; // Create a 128 MHz clock dacpll pll128(.areset(rst_i),.inclk0(clk_i),.c0(clk128)); diff --git a/gr-sounder/src/fpga/lib/lfsr_constants.v b/gr-sounder/src/fpga/lib/lfsr_constants.v index 79fcb1a2..55ee613d 100755 --- a/gr-sounder/src/fpga/lib/lfsr_constants.v +++ b/gr-sounder/src/fpga/lib/lfsr_constants.v @@ -24,8 +24,8 @@ module lfsr_constants(degree_i,mask_o,len_o); output reg [15:0] mask_o; output wire [15:0] len_o; - assign len_o = (16'b1 << degree_i) - 1; - + assign len_o = (1 << degree_i) - 1; + always @* case (degree_i) 5'd00: mask_o = 16'h0000; diff --git a/gr-sounder/src/fpga/lib/sounder.v b/gr-sounder/src/fpga/lib/sounder.v index ea4007cb..58b56344 100644 --- a/gr-sounder/src/fpga/lib/sounder.v +++ b/gr-sounder/src/fpga/lib/sounder.v @@ -22,10 +22,10 @@ `include "../../../../usrp/firmware/include/fpga_regs_common.v" `include "../../../../usrp/firmware/include/fpga_regs_standard.v" -module sounder(clk_i,saddr_i,sdata_i,s_strobe_i,tx_rst_i,tx_enable_i,tx_strobe_i, - tx_dac_i_o,tx_dac_q_o, - rx_rst_i,rx_enable_i,rx_strobe_i,rx_strobe_o, - rx_adc_i_i,rx_adc_q_i,rx_imp_i_o,rx_imp_q_o); +module sounder(clk_i, saddr_i, sdata_i, s_strobe_i, + tx_strobe_i, tx_dac_i_o,tx_dac_q_o, + rx_strobe_i, rx_adc_i_i,rx_adc_q_i, + rx_strobe_o, rx_imp_i_o,rx_imp_q_o); // System interface input clk_i; // Master clock @ 64 MHz @@ -34,53 +34,59 @@ module sounder(clk_i,saddr_i,sdata_i,s_strobe_i,tx_rst_i,tx_enable_i,tx_strobe_i input s_strobe_i; // Configuration bus write // Transmit subsystem - input tx_rst_i; // Independent subsystem reset - input tx_enable_i; // Turn on transmitter functionality input tx_strobe_i; // Generate an transmitter output sample - output [15:0] tx_dac_i_o; // I channel transmitter output to DAC - output [15:0] tx_dac_q_o; // Q channel transmitter output to DAC + output [13:0] tx_dac_i_o; // I channel transmitter output to DAC + output [13:0] tx_dac_q_o; // Q channel transmitter output to DAC // Receive subsystem - input rx_rst_i; // Independent subsystem reset - input rx_enable_i; // Turn on receiver functionality input rx_strobe_i; // Indicates receive sample ready from ADC output rx_strobe_o; // Indicates output samples ready for Rx FIFO - input [15:0] rx_adc_i_i; // I channel input from ADC - input [15:0] rx_adc_q_i; // Q channel input from ADC + input [15:0] rx_adc_i_i; // I channel input from ADC interface module + input [15:0] rx_adc_q_i; // Q channel input from ADC interface module output [15:0] rx_imp_i_o; // I channel impulse response to Rx FIFO output [15:0] rx_imp_q_o; // Q channel impulse response to Rx FIFO + + // Internal variables + wire reset; + wire transmit; + wire receive; + wire loopback; - // Configuration - wire [4:0] degree; // LFSR register length - wire [15:0] mask; // LFSR parity mask - wire [15:0] len; // PN code sequence length - wire loopback; // Enable digital loopback + wire [4:0] degree; + wire [15:0] mask; + wire [15:0] len; - // Loopback implementation - wire [15:0] tx_i, tx_q, rx_i, rx_q; // Internal transmit and receive data bus + setting_reg #(`FR_USER_0) sr_mode + ( .clock(clk_i),.reset(1'b0),.strobe(s_strobe_i),.addr(saddr_i),.in(sdata_i), + .out({loopback,receive,transmit,reset}) ); - assign tx_dac_i_o = loopback ? 16'b0 : tx_i; - assign tx_dac_q_o = loopback ? 16'b0 : tx_q; - assign rx_i = loopback ? tx_i : rx_adc_i_i; - assign rx_q = loopback ? tx_q : rx_adc_q_i; - - setting_reg #(`FR_USER_0) sr_lfsr_degree + setting_reg #(`FR_USER_1) sr_lfsr_degree ( .clock(clk_i),.reset(1'b0),.strobe(s_strobe_i),.addr(saddr_i),.in(sdata_i),.out(degree) ); + + lfsr_constants constants(.degree_i(degree),.mask_o(mask),.len_o(len)); - setting_reg #(`FR_USER_1) sr_mode - ( .clock(clk_i),.reset(1'b0),.strobe(s_strobe_i),.addr(saddr_i),.in(sdata_i), - .out({loopback}) ); + // Loopback implementation + wire [13:0] tx_i, tx_q; + wire [15:0] tx_i_ext, tx_q_ext; + wire [15:0] rx_i, rx_q; - lfsr_constants constants(.degree_i(degree),.mask_o(mask),.len_o(len)); + sign_extend #(14,16) tx_i_extender(tx_i, tx_i_ext); + sign_extend #(14,16) tx_q_extender(tx_q, tx_q_ext); + assign tx_dac_i_o = loopback ? 14'b0 : tx_i; + assign tx_dac_q_o = loopback ? 14'b0 : tx_q; + assign rx_i = loopback ? tx_i_ext : rx_adc_i_i; + assign rx_q = loopback ? tx_q_ext : rx_adc_q_i; + sounder_tx transmitter - ( .clk_i(clk_i),.rst_i(tx_rst_i),.ena_i(tx_enable_i),.strobe_i(tx_strobe_i),.mask_i(mask), + ( .clk_i(clk_i),.rst_i(reset),.ena_i(transmit), + .strobe_i(tx_strobe_i),.mask_i(mask), .tx_i_o(tx_i),.tx_q_o(tx_q) ); sounder_rx receiver - ( .clk_i(clk_i),.rst_i(rx_rst_i),.ena_i(rx_enable_i), - .rx_strobe_i(rx_strobe_i),.tx_strobe_i(tx_strobe_i),.mask_i(mask),.len_i(len), + ( .clk_i(clk_i),.rst_i(reset),.ena_i(receive), + .rx_strobe_i(rx_strobe_i),.tx_strobe_i(tx_strobe_i),.mask_i(mask),.degree_i(degree),.len_i(len), .rx_in_i_i(rx_i),.rx_in_q_i(rx_q),.rx_i_o(rx_imp_i_o),.rx_q_o(rx_imp_q_o), - .rx_strobe_o(rx_strobe_o) ); - + .rx_strobe_o(rx_strobe_o),.loop_i(loopback)); + endmodule // sounder diff --git a/gr-sounder/src/fpga/lib/sounder_rx.v b/gr-sounder/src/fpga/lib/sounder_rx.v index b7c5f487..338afd55 100644 --- a/gr-sounder/src/fpga/lib/sounder_rx.v +++ b/gr-sounder/src/fpga/lib/sounder_rx.v @@ -19,8 +19,9 @@ // Foundation, Inc., 51 Franklin Street, Boston, MA 02110-1301 USA // -module sounder_rx(clk_i,rst_i,ena_i,rx_strobe_i,tx_strobe_i,mask_i,len_i, - rx_in_i_i,rx_in_q_i,rx_i_o,rx_q_o,rx_strobe_o); +module sounder_rx(clk_i,rst_i,ena_i,rx_strobe_i,tx_strobe_i,mask_i,degree_i,len_i, + rx_in_i_i,rx_in_q_i,rx_i_o,rx_q_o,rx_strobe_o, + loop_i); input clk_i; // Master clock input rst_i; // Subsystem reset @@ -29,6 +30,7 @@ module sounder_rx(clk_i,rst_i,ena_i,rx_strobe_i,tx_strobe_i,mask_i,len_i, input tx_strobe_i; // Strobe every transmitted sample input [15:0] mask_i; // PN code LFSR mask + input [4:0] degree_i; // PN code LFSR sequency degree input [15:0] len_i; // PN code LFSR sequence length input [15:0] rx_in_i_i; // I channel on receive input [15:0] rx_in_q_i; // Q channel on receive @@ -37,48 +39,57 @@ module sounder_rx(clk_i,rst_i,ena_i,rx_strobe_i,tx_strobe_i,mask_i,len_i, output [15:0] rx_q_o; // Q channel of impulse response output rx_strobe_o; // Impulse response value ready - // LFSR phase counter - reg [15:0] count; - wire cycle = (count == (len_i - 1)); + input loop_i; // Implement loopback + + wire strobe_in = loop_i ? tx_strobe_i : rx_strobe_i; + wire [16:0] len = loop_i ? (len_i - 1) : ((len_i << 1) - 2); + + strobe #(17) phase_strobe(.clk_i(clk_i),.rst_i(rst_i),.ena_i(ena_i), + .rate_i(len),.strobe_i(strobe_in),.strobe_o(rx_strobe_o), + .count_o()); - always @(posedge clk_i) - if (rst_i | ~ena_i) - count <= 16'b0; - else - if (cycle) - count <= 16'b0; - else - count <= count + 16'b1; - - // Retard LFSR phase once per cycle - wire lfsr_strobe = (tx_strobe_i & ~cycle); + wire pn_ref; + wire ref_strobe = tx_strobe_i & ~rx_strobe_o; // Retard reference phase once per period + lfsr ref_code + ( .clk_i(clk_i),.rst_i(rst_i),.ena_i(ena_i),.strobe_i(ref_strobe),.mask_i(mask_i),.pn_o(pn_ref) ); - // Recreate local reference of transmitted PN code - wire pn; - lfsr reference - ( .clk_i(clk_i),.rst_i(rst_i),.ena_i(ena_i),.strobe_i(lfsr_strobe),.mask_i(mask_i),.pn_o(pn) ); + wire [5:0] offset = (5'd16-degree_i); + + reg [31:0] sum_i, sum_q; + reg [31:0] total_i, total_q; + wire [31:0] scaled_i = total_i << offset; + wire [31:0] scaled_q = total_q << offset; + wire [31:0] i_ext, q_ext; - wire [31:0] rx_i_ext, rx_q_ext; - sign_extend #(16,32) i_extend(rx_in_i_i, rx_i_ext); - sign_extend #(16,32) q_extend(rx_in_q_i, rx_q_ext); + sign_extend #(16,32) i_extender(rx_in_i_i, i_ext); + sign_extend #(16,32) q_extender(rx_in_q_i, q_ext); - reg [31:0] accum; + wire [31:0] prod_i = pn_ref ? i_ext : -i_ext; + wire [31:0] prod_q = pn_ref ? q_ext : -q_ext; + always @(posedge clk_i) if (rst_i | ~ena_i) - accum <= 32'b0; - else - if (rx_strobe_i) - if (cycle) - accum <= 32'b0; - else - if (pn) - accum <= accum + rx_i_ext; - else - accum <= accum - rx_i_ext; + begin + sum_i <= 0; + sum_q <= 0; + total_i <= 0; + total_q <= 0; + end + else if (rx_strobe_o) + begin + total_i <= sum_i + prod_i; + total_q <= sum_q + prod_q; + sum_i <= 0; + sum_q <= 0; + end + else if (strobe_in) + begin + sum_i = sum_i + prod_i; + sum_q = sum_q + prod_q; + end + + assign rx_i_o = scaled_i[31:16]; + assign rx_q_o = scaled_q[31:16]; - assign rx_i_o = accum[31:16]; - assign rx_q_o = accum[15:0]; - assign rx_strobe_o = rx_strobe_i & cycle; - endmodule // sounder_rx diff --git a/gr-sounder/src/fpga/lib/sounder_tx.v b/gr-sounder/src/fpga/lib/sounder_tx.v index d5300fec..46165dde 100644 --- a/gr-sounder/src/fpga/lib/sounder_tx.v +++ b/gr-sounder/src/fpga/lib/sounder_tx.v @@ -22,8 +22,8 @@ `include "../../../../usrp/firmware/include/fpga_regs_common.v" `include "../../../../usrp/firmware/include/fpga_regs_standard.v" -`define MAX_VALUE 16'h7FFF // 2s complement -`define MIN_VALUE 16'h8000 +`define MAX_VALUE 14'h1FFF // 2s complement +`define MIN_VALUE 14'h2001 module sounder_tx(clk_i,rst_i,ena_i,strobe_i,mask_i,tx_i_o,tx_q_o); input clk_i; @@ -31,15 +31,15 @@ module sounder_tx(clk_i,rst_i,ena_i,strobe_i,mask_i,tx_i_o,tx_q_o); input ena_i; input strobe_i; input [15:0] mask_i; - output [15:0] tx_i_o; - output [15:0] tx_q_o; + output [13:0] tx_i_o; + output [13:0] tx_q_o; wire pn; lfsr pn_code ( .clk_i(clk_i),.rst_i(rst_i),.ena_i(ena_i),.strobe_i(strobe_i),.mask_i(mask_i),.pn_o(pn) ); - assign tx_i_o = pn ? `MAX_VALUE : `MIN_VALUE; // Bipolar - assign tx_q_o = 16'b0; + assign tx_i_o = ena_i ? (pn ? `MAX_VALUE : `MIN_VALUE) : 14'b0; // Bipolar + assign tx_q_o = 14'b0; endmodule // sounder_tx diff --git a/gr-sounder/src/fpga/lib/strobe.v b/gr-sounder/src/fpga/lib/strobe.v new file mode 100644 index 00000000..ed07f21f --- /dev/null +++ b/gr-sounder/src/fpga/lib/strobe.v @@ -0,0 +1,48 @@ +// -*- verilog -*- +// +// USRP - Universal Software Radio Peripheral +// +// Copyright (C) 2007 Corgan Enterprises LLC +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Boston, MA 02110-1301 USA +// + +module strobe(clk_i,rst_i,ena_i,rate_i,strobe_i,strobe_o,count_o); + parameter width = 16; + + input clk_i; + input rst_i; + input ena_i; + input [width-1:0] rate_i; // Desired period minus one + input strobe_i; + output strobe_o; + output [width-1:0] count_o; + + + reg [width-1:0] counter; + + always @(posedge clk_i) + if(rst_i | ~ena_i) + counter <= 32'hFFFFFFFF; // First period is short by one + else if(strobe_i) + if(counter == rate_i) + counter <= 0; + else + counter <= counter + 1; + + assign strobe_o = (counter == rate_i) & strobe_i; + assign count_o = counter; + +endmodule // strobe diff --git a/gr-sounder/src/fpga/rbf/Makefile.am b/gr-sounder/src/fpga/rbf/Makefile.am deleted file mode 100644 index 5a8b709d..00000000 --- a/gr-sounder/src/fpga/rbf/Makefile.am +++ /dev/null @@ -1,44 +0,0 @@ -# -# Copyright 2005,2006,2007 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# GNU Radio is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2, or (at your option) -# any later version. -# -# GNU Radio is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with GNU Radio; see the file COPYING. If not, write to -# the Free Software Foundation, Inc., 51 Franklin Street, -# Boston, MA 02110-1301, USA. -# - -include $(top_srcdir)/Makefile.common - -datadir = $(prefix)/share/usrp - -rbfs = \ - rev2/usrp_sounder.rbf \ - rev4/usrp_sounder.rbf - -EXTRA_DIST = \ - $(rbfs) - - -install-data-local: - @for file in $(rbfs); do \ - echo "$(INSTALL_DATA) $(srcdir)/$$file $(DESTDIR)$(datadir)/$$file"; \ - $(INSTALL_DATA) $(srcdir)/$$file $(DESTDIR)$(datadir)/$$file; \ - done - -uninstall-local: - @for file in $(rbfs); do \ - echo "$(RM) $(DESTDIR)$(datadir)/$$file"; \ - $(RM) $(DESTDIR)$(datadir)/$$file; \ - done diff --git a/gr-sounder/src/fpga/rbf/rev2/usrp_sounder.rbf b/gr-sounder/src/fpga/rbf/rev2/usrp_sounder.rbf deleted file mode 100755 index 47a0c98f..00000000 Binary files a/gr-sounder/src/fpga/rbf/rev2/usrp_sounder.rbf and /dev/null differ diff --git a/gr-sounder/src/fpga/rbf/rev4/usrp_sounder.rbf b/gr-sounder/src/fpga/rbf/rev4/usrp_sounder.rbf deleted file mode 100755 index 47a0c98f..00000000 Binary files a/gr-sounder/src/fpga/rbf/rev4/usrp_sounder.rbf and /dev/null differ diff --git a/gr-sounder/src/fpga/tb/Makefile.am b/gr-sounder/src/fpga/tb/Makefile.am new file mode 100644 index 00000000..e668d456 --- /dev/null +++ b/gr-sounder/src/fpga/tb/Makefile.am @@ -0,0 +1,30 @@ +# +# Copyright 2007 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# + +include $(top_srcdir)/Makefile.common + +EXTRA_DIST = \ + sounder_tb.v \ + sounder_tb.sav \ + sounder_tb.sh \ + sounder_tb_wave.sh + +MOSTLYCLEANFILES = *~ *.vcd *.out* sounder_tb \ No newline at end of file diff --git a/gr-sounder/src/fpga/tb/sounder_tb.sav b/gr-sounder/src/fpga/tb/sounder_tb.sav new file mode 100644 index 00000000..74019f5e --- /dev/null +++ b/gr-sounder/src/fpga/tb/sounder_tb.sav @@ -0,0 +1,34 @@ +*-26.117517 250000000 -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 +@28 +sounder_tb.uut.clk_i +sounder_tb.rst +sounder_tb.s_strobe +@22 +sounder_tb.sdata[31:0] +@28 +sounder_tb.uut.reset +sounder_tb.uut.transmit +sounder_tb.uut.receive +sounder_tb.uut.loopback +@200 +- +@22 +sounder_tb.uut.degree[4:0] +sounder_tb.uut.len[15:0] +@200 +- +@28 +sounder_tb.tx_dac_i[13:0] +@200 +- +@22 +sounder_tb.fifo_strobe +sounder_tb.fifo_i[15:0] +sounder_tb.fifo_q[15:0] +@200 +- +@22 +sounder_tb.uut.transmitter.pn_code.pn_o +sounder_tb.uut.receiver.pn_ref +@200 +- diff --git a/gr-sounder/src/fpga/tb/sounder_tb.sh b/gr-sounder/src/fpga/tb/sounder_tb.sh new file mode 100755 index 00000000..9bc71438 --- /dev/null +++ b/gr-sounder/src/fpga/tb/sounder_tb.sh @@ -0,0 +1,7 @@ +#!/bin/sh +iverilog -y ../lib/ -y ../../../../usrp/fpga/sdr_lib \ + sounder_tb.v -o sounder_tb && \ +./sounder_tb > sounder_tb.out && \ +grep 'rst=0' sounder_tb.out | grep 'clk=1' > sounder_tb.out2 && \ +grep 'tx_strobe=1' sounder_tb.out2 > sounder_tb.out3 + diff --git a/gr-sounder/src/fpga/tb/sounder_tb.v b/gr-sounder/src/fpga/tb/sounder_tb.v new file mode 100644 index 00000000..045791e4 --- /dev/null +++ b/gr-sounder/src/fpga/tb/sounder_tb.v @@ -0,0 +1,212 @@ +// -*- verilog -*- +// +// USRP - Universal Software Radio Peripheral +// +// Copyright (C) 2007 Corgan Enterprises LLC +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Boston, MA 02110-1301 USA +// + +`timescale 1ns/1ps + +`include "../lib/sounder.v" + +`define FR_MODE 7'd64 +`define bmFR_MODE_RESET 32'h0001 +`define bmFR_MODE_TX 32'h0002 +`define bmFR_MODE_RX 32'h0004 +`define bmFR_MODE_LP 32'h0008 + +`define FR_DEGREE 7'd65 + +module sounder_tb; + + // System bus + reg clk; + reg rst; + reg ena; + + // Configuration bus + reg [6:0] saddr; + reg [31:0] sdata; + reg s_strobe; + + // DAC bus + reg tx_strobe; + wire [13:0] tx_dac_i; + wire [13:0] tx_dac_q; + + // ADC bus + reg rx_strobe; + reg [15:0] rx_adc_i; + reg [15:0] rx_adc_q; + + // FIFO bus + wire fifo_strobe; + wire [15:0] fifo_i; + wire [15:0] fifo_q; + + // Configuration shadow registers + reg [31:0] mode; + reg [31:0] degree; + + sounder uut + (.clk_i(clk),.saddr_i(saddr),.sdata_i(sdata),.s_strobe_i(s_strobe), + .tx_strobe_i(tx_strobe),.tx_dac_i_o(tx_dac_i),.tx_dac_q_o(tx_dac_q), + .rx_strobe_i(rx_strobe),.rx_adc_i_i(rx_adc_i),.rx_adc_q_i(rx_adc_q), + .rx_strobe_o(fifo_strobe),.rx_imp_i_o(fifo_i),.rx_imp_q_o(fifo_q)); + + // Drive tx_strobe @ half clock rate + always @(posedge clk) + tx_strobe <= ~tx_strobe; + + // Start up initialization + initial + begin + clk = 0; + rst = 0; + ena = 0; + saddr = 0; + sdata = 0; + s_strobe = 0; + tx_strobe = 0; + rx_strobe = 1; + rx_adc_i = 0; + rx_adc_q = 0; + mode = 0; + degree = 0; + + @(posedge clk); + rst = 1; + @(posedge clk); + rst = 0; + @(posedge clk); + ena = 1; + end + + always + #5 clk <= ~clk; + + initial + begin + $monitor($time, " clk=%b rst=%b tx_strobe=%b fifo_strobe=%b phs=%x pn_o=%b pn_ref=%b fifo_i=%x fifo_q=", + clk, uut.reset, tx_strobe, fifo_strobe, uut.receiver.phase_strobe.count_o, + uut.transmitter.pn, uut.receiver.pn_ref, fifo_i, fifo_q); + $dumpfile("sounder_tb.vcd"); + $dumpvars(0, sounder_tb); + end + + // Test tasks + task write_cfg_register; + input [6:0] regno; + input [31:0] value; + + begin + @(posedge clk); + saddr <= regno; + sdata <= value; + s_strobe <= 1'b1; + @(posedge clk); + s_strobe <= 0; + end + endtask // write_cfg_register + + // Application reset line + task set_reset; + input reset; + + begin + mode = reset ? (mode | `bmFR_MODE_RESET) : (mode & ~`bmFR_MODE_RESET); + write_cfg_register(`FR_MODE, mode); + end + endtask // reset + + // Set the PN code degree + task set_degree; + input [5:0] degree; + begin + write_cfg_register(`FR_DEGREE, degree); + end + endtask // set_degree + + // Turn on or off the transmitter + task enable_tx; + input tx; + + begin + mode = tx ? (mode | `bmFR_MODE_TX) : (mode & ~`bmFR_MODE_TX); + write_cfg_register(`FR_MODE, mode); + end + endtask // enable_tx + + // Turn on or off the receiver + task enable_rx; + input rx; + + begin + mode = rx ? (mode | `bmFR_MODE_RX) : (mode & ~`bmFR_MODE_RX); + write_cfg_register(`FR_MODE, mode); + end + endtask // enable_rx + + + // Turn on or off digital loopback + task enable_lp; + input lp; + + begin + mode = lp ? (mode | `bmFR_MODE_LP) : (mode & ~`bmFR_MODE_LP); + write_cfg_register(`FR_MODE, mode); + end + endtask // enable_lp + + // Test transmitter functionality + task test_tx; + input [5:0] degree; + + begin + #20 set_reset(1); + #20 set_degree(degree); + #20 enable_tx(1); + #20 set_reset(0); + #(uut.len*20); // One PN code period + + end + endtask // test_tx + + // Test loopback functionality + task test_lp; + input [5:0] degree; + + begin + #20 set_reset(1); + #20 set_degree(degree); + #20 enable_tx(1); + #20 enable_rx(1); + #20 enable_lp(1); + #20 set_reset(0); + #((uut.len+1)*uut.len*20); + end + endtask // test_lp + + // Execute tests + initial + begin + #20 test_tx(12); + #20 test_lp(12); + #100 $finish; + end +endmodule + diff --git a/gr-sounder/src/fpga/tb/sounder_tb_wave.sh b/gr-sounder/src/fpga/tb/sounder_tb_wave.sh new file mode 100755 index 00000000..4551d5c5 --- /dev/null +++ b/gr-sounder/src/fpga/tb/sounder_tb_wave.sh @@ -0,0 +1,2 @@ +#!/bin/sh +gtkwave sounder_tb.vcd sounder_tb.sav diff --git a/gr-sounder/src/fpga/top/Makefile.am b/gr-sounder/src/fpga/top/Makefile.am index 69f6fef9..9498d434 100644 --- a/gr-sounder/src/fpga/top/Makefile.am +++ b/gr-sounder/src/fpga/top/Makefile.am @@ -21,23 +21,43 @@ include $(top_srcdir)/Makefile.common +datadir = $(prefix)/share/usrp + EXTRA_DIST = \ config.vh \ usrp_sounder.v \ usrp_sounder.csf \ usrp_sounder.esf \ usrp_sounder.psf \ - usrp_sounder.qpf + usrp_sounder.qpf \ + $(RBFS) + +RBFS = usrp_sounder.rbf + +install-data-local: + @for file in $(RBFS); do \ + echo "$(INSTALL_DATA) $(srcdir)/$$file $(DESTDIR)$(datadir)/rev2/$$file"; \ + $(INSTALL_DATA) $(srcdir)/$$file $(DESTDIR)$(datadir)/rev2/$$file; \ + echo "$(INSTALL_DATA) $(srcdir)/$$file $(DESTDIR)$(datadir)/rev4/$$file"; \ + $(INSTALL_DATA) $(srcdir)/$$file $(DESTDIR)$(datadir)/rev4/$$file; \ + done + +uninstall-local: + @for file in $(rbfs); do \ + echo "$(RM) $(DESTDIR)$(datadir)/rev2/$$file"; \ + $(RM) $(DESTDIR)$(datadir)/rev2/$$file; \ + echo "$(RM) $(DESTDIR)$(datadir)/rev4/$$file"; \ + $(RM) $(DESTDIR)$(datadir)/rev4/$$file; \ + done MOSTLYCLEANFILES = \ db/* \ *.rpt \ *.summary \ - *.rbf \ *.qws \ *.smsg \ *.done \ *.pin \ - *.sof - + *.sof \ + *~ diff --git a/gr-sounder/src/fpga/top/usrp_sounder.qsf b/gr-sounder/src/fpga/top/usrp_sounder.qsf index bda317db..5ff52583 100755 --- a/gr-sounder/src/fpga/top/usrp_sounder.qsf +++ b/gr-sounder/src/fpga/top/usrp_sounder.qsf @@ -368,15 +368,16 @@ set_instance_assignment -name CLOCK_SETTINGS master_clk -to master_clk set_instance_assignment -name PARTITION_HIERARCHY no_file_for_top_partition -to | -section_id Top set_global_assignment -name PARTITION_NETLIST_TYPE SOURCE -section_id Top -set_global_assignment -name VERILOG_FILE ../../../../usrp/fpga/sdr_lib/sign_extend.v +set_global_assignment -name VERILOG_FILE ../lib/strobe.v set_global_assignment -name VERILOG_FILE ../lib/lfsr_constants.v -set_global_assignment -name VERILOG_FILE ../lib/sounder.v set_global_assignment -name VERILOG_FILE ../lib/lfsr.v -set_global_assignment -name VERILOG_FILE ../../../../usrp/fpga/sdr_lib/atr_delay.v set_global_assignment -name VERILOG_FILE ../lib/dac_interface.v set_global_assignment -name VERILOG_FILE ../lib/dacpll.v set_global_assignment -name VERILOG_FILE ../lib/sounder_rx.v set_global_assignment -name VERILOG_FILE ../lib/sounder_tx.v +set_global_assignment -name VERILOG_FILE ../lib/sounder.v +set_global_assignment -name VERILOG_FILE ../../../../usrp/fpga/sdr_lib/atr_delay.v +set_global_assignment -name VERILOG_FILE ../../../../usrp/fpga/sdr_lib/sign_extend.v set_global_assignment -name VERILOG_FILE ../../../../usrp/fpga/sdr_lib/rx_buffer.v set_global_assignment -name VERILOG_FILE ../../../../usrp/fpga/sdr_lib/setting_reg.v set_global_assignment -name VERILOG_FILE ../../../../usrp/fpga/sdr_lib/strobe_gen.v diff --git a/gr-sounder/src/fpga/top/usrp_sounder.rbf b/gr-sounder/src/fpga/top/usrp_sounder.rbf new file mode 100755 index 00000000..b6f49422 Binary files /dev/null and b/gr-sounder/src/fpga/top/usrp_sounder.rbf differ diff --git a/gr-sounder/src/fpga/top/usrp_sounder.v b/gr-sounder/src/fpga/top/usrp_sounder.v index 05b71bbb..bb630569 100644 --- a/gr-sounder/src/fpga/top/usrp_sounder.v +++ b/gr-sounder/src/fpga/top/usrp_sounder.v @@ -103,14 +103,14 @@ module usrp_sounder //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Transmit Side - wire [15:0] tx_i, tx_q; - wire [15:0] tx_dac; + wire [13:0] tx_i, tx_q; + wire [13:0] tx_dac; dac_interface dac(.clk_i(clk64),.rst_i(tx_dsp_reset),.ena_i(enable_tx), .strobe_i(tx_sample_strobe),.tx_i_i(tx_i),.tx_q_i(tx_q), .tx_data_o(tx_dac),.tx_sync_o(TXSYNC_A)); - assign tx_a = tx_dac[15:2]; + assign tx_a = tx_dac; // Wedge DAC #2 at zero assign TXSYNC_B = 1'b0; @@ -151,10 +151,9 @@ module usrp_sounder sounder sounder ( .clk_i(clk64),.saddr_i(serial_addr),.sdata_i(serial_data),.s_strobe_i(serial_strobe), - .tx_rst_i(tx_dsp_reset),.tx_enable_i(enable_tx),.tx_strobe_i(tx_sample_strobe), - .tx_dac_i_o(tx_i),.tx_dac_q_o(tx_q), - .rx_rst_i(rx_dsp_reset),.rx_enable_i(enable_rx),.rx_strobe_i(rx_sample_strobe),.rx_strobe_o(rx_strobe), - .rx_adc_i_i(rx_adc0_i),.rx_adc_q_i(rx_adc0_q),.rx_imp_i_o(rx_buf_i),.rx_imp_q_o(rx_buf_q) + .tx_strobe_i(tx_sample_strobe),.tx_dac_i_o(tx_i),.tx_dac_q_o(tx_q), + .rx_strobe_i(rx_sample_strobe),.rx_adc_i_i(rx_adc0_i),.rx_adc_q_i(rx_adc0_q), + .rx_strobe_o(rx_strobe),.rx_imp_i_o(rx_buf_i),.rx_imp_q_o(rx_buf_q) ); diff --git a/gr-sounder/src/python/Makefile.am b/gr-sounder/src/python/Makefile.am index ecc9d839..7ce18127 100644 --- a/gr-sounder/src/python/Makefile.am +++ b/gr-sounder/src/python/Makefile.am @@ -29,4 +29,4 @@ EXTRA_DIST = \ bin_SCRIPTS = \ usrp_sounder.py -MOSTLYCLEANFILES = *~ *.pyc *.pyo +MOSTLYCLEANFILES = *~ *.pyc *.pyo output.* diff --git a/gr-sounder/src/python/test_lp.sh b/gr-sounder/src/python/test_lp.sh new file mode 100755 index 00000000..fbcc3f53 --- /dev/null +++ b/gr-sounder/src/python/test_lp.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +usrp_sounder.py -r -l -t -n5000 -d12 +hexdump output.dat >output.hex diff --git a/gr-sounder/src/python/test_rx.sh b/gr-sounder/src/python/test_rx.sh new file mode 100755 index 00000000..21998b4d --- /dev/null +++ b/gr-sounder/src/python/test_rx.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +usrp_sounder.py -r -n5000 -d12 +hexdump output.dat >output.hex diff --git a/gr-sounder/src/python/test_tx.sh b/gr-sounder/src/python/test_tx.sh new file mode 100755 index 00000000..f29ba1f3 --- /dev/null +++ b/gr-sounder/src/python/test_tx.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +usrp_sounder.py -t -f 16M -d12 diff --git a/gr-sounder/src/python/usrp_sounder.py b/gr-sounder/src/python/usrp_sounder.py index ca722a49..31e766ef 100755 --- a/gr-sounder/src/python/usrp_sounder.py +++ b/gr-sounder/src/python/usrp_sounder.py @@ -28,68 +28,141 @@ import sys, time n2s = eng_notation.num_to_str -# Set to 0 for 32 MHz tx clock, 1 for 64 MHz tx clock -# Must match config.vh in FPGA code -TX_RATE_MAX = 0 -_tx_freq_divisor = 32e6*(TX_RATE_MAX+1) - -class sounder_tx: - def __init__(self, frequency, degree, loopback): - self.trans = usrp.sink_s(fpga_filename='usrp_sounder.rbf') - self.subdev_spec = usrp.pick_tx_subdevice(self.trans) - self.subdev = usrp.selected_subdev(self.trans, self.subdev_spec) - self.trans.tune(0, self.subdev, frequency) - self.set_degree(degree); - self.set_loopback(loopback) - - def turn_on(self): - self.trans.start() +FR_MODE = usrp.FR_USER_0 +bmFR_MODE_RESET = 1 << 0 # bit 0: active high reset +bmFR_MODE_TX = 1 << 1 # bit 1: enable transmitter +bmFR_MODE_RX = 1 << 2 # bit 2: enable receiver +bmFR_MODE_LP = 1 << 3 # bit 3: enable digital loopback + +FR_DEGREE = usrp.FR_USER_1 + +class sounder: + def __init__(self, options): + self._options = options + self._mode = 0 - def turn_off(self): - self.trans.stop() - - def set_degree(self, value): - return self.trans._write_fpga_reg(usrp.FR_USER_0, value); - + self._u = None + self._trans = None + self._rcvr = None + self._transmitting = False + self._receiving = False + + if options.transmit: + print "Creating sounder transmitter." + self._trans = usrp.sink_s(fpga_filename='usrp_sounder.rbf') + self._trans_subdev_spec = usrp.pick_tx_subdevice(self._trans) + self._trans_subdev = usrp.selected_subdev(self._trans, self._trans_subdev_spec) + self._trans.start() + self._u = self._trans + + if options.receive: + print "Creating sounder receiver." + self._fg = gr.flow_graph() + self._rcvr = usrp.source_s(fpga_filename='usrp_sounder.rbf', decim_rate=128) + self._rcvr_subdev_spec = usrp.pick_rx_subdevice(self._rcvr) + self._rcvr_subdev = usrp.selected_subdev(self._rcvr, self._rcvr_subdev_spec) + self._sink = gr.file_sink(gr.sizeof_short, "output.dat") + + if options.samples >= 0: + self._head = gr.head(gr.sizeof_short, options.samples*gr.sizeof_short) + self._fg.connect(self._rcvr, self._head, self._sink) + else: + self._fg.connect(self._rcvr, self._sink) + self._u = self._rcvr # either receiver or transmitter object will do + + self.set_reset(True) + self.set_freq(options.frequency) + self.set_degree(options.degree) + self.set_loopback(options.loopback) + self.set_reset(False) + + def set_freq(self, frequency): + print "Setting center frequency to", n2s(frequency) + if self._rcvr: + self._rcvr.tune(0, self._rcvr_subdev, frequency) + + if self._trans: + self._trans.tune(0, self._trans_subdev, frequency) + + def set_degree(self, degree): + print "Setting PN code degree to", degree + self._u._write_fpga_reg(FR_DEGREE, degree); + + def _write_mode(self): + print "Writing mode register with:", hex(self._mode) + self._u._write_fpga_reg(FR_MODE, self._mode) + + def enable_tx(self, value): + if value: + print "Enabling transmitter." + self._mode |= bmFR_MODE_TX + self._transmitting = True + else: + print "Disabling transmitter." + self._mode &= ~bmFR_MODE_TX + self._write_mode() + + def enable_rx(self, value): + if value: + print "Starting receiver flow graph." + self._mode |= bmFR_MODE_RX + self._write_mode() + self._fg.start() + self._receiving = True + if self._options.samples >= 0: + self._fg.wait() + else: + print "Stopping receiver flow graph." + if self._options.samples < 0: + self._fg.stop() + print "Waiting for threads..." + self._fg.wait() + print "Receiver flow graph stopped." + self._mode &= ~bmFR_MODE_RX + self._write_mode() + self._receiving = False + def set_loopback(self, value): - return self.trans._write_fpga_reg(usrp.FR_USER_1, value==True); - -class sounder_rx: - def __init__(self, frequency, degree, samples): - self.fg = gr.flow_graph() - self.rcvr = usrp.source_s(fpga_filename='usrp_sounder.rbf', decim_rate=8) - self.subdev_spec = usrp.pick_rx_subdevice(self.rcvr) - self.subdev = usrp.selected_subdev(self.rcvr, self.subdev_spec) - self.rcvr.tune(0, self.subdev, frequency) - self.set_degree(degree); - self.sink = gr.file_sink(gr.sizeof_short, "output.dat") - - if samples >= 0: - self.head = gr.head(gr.sizeof_short, 2*samples*gr.sizeof_short) - self.fg.connect(self.rcvr, self.head, self.sink) + if value: + print "Enabling digital loopback." + self._mode |= bmFR_MODE_LP else: - self.fg.connect(self.rcvr, self.sink) - - def receive(self): - self.fg.run() - - def set_degree(self, value): - return self.rcvr._write_fpga_reg(usrp.FR_USER_0, value); - + print "Disabling digital loopback." + self._mode &= ~bmFR_MODE_LP + self._write_mode() + + def set_reset(self, value): + if value: + print "Asserting reset." + self._mode |= bmFR_MODE_RESET + else: + print "De-asserting reset." + self._mode &= ~bmFR_MODE_RESET + self._write_mode() + + def __del__(self): + if self._transmitting: + self.enable_tx(False) + + if self._receiving: + self.enable_rx(False) + +# ------------------------------------------------------------------------------ + def main(): parser = OptionParser(option_class=eng_option) parser.add_option("-f", "--frequency", type="eng_float", default=0.0, help="set frequency to FREQ in Hz, default is %default", metavar="FREQ") + parser.add_option("-d", "--degree", type="int", default=16, + help="set souding sequence degree (len=2^degree-1), default is %default") + parser.add_option("-t", "--transmit", action="store_true", default=False, help="enable sounding transmitter") parser.add_option("-r", "--receive", action="store_true", default=False, help="enable sounding receiver") - parser.add_option("-d", "--degree", type="int", default=16, - help="set souding sequence degree (len=2^degree-1), default is %default") - parser.add_option("-n", "--samples", type="int", default=-1, help="number of samples to capture on receive, default is infinite") @@ -105,26 +178,16 @@ def main(): print "Using PN code degree of", options.degree, "length", 2**options.degree-1 print "Sounding frequency range is", n2s(options.frequency-16e6), "to", n2s(options.frequency+16e6) - if (options.transmit): - print "Enabling sounder transmitter." - if (options.loopback): - print "Enabling digital loopback." - tx = sounder_tx(options.frequency, options.degree, options.loopback) - tx.turn_on() - - try: - if (options.receive): - print "Enabling sounder receiver." - rx = sounder_rx(options.frequency, options.degree, options.samples) - rx.receive() - else: - if (options.transmit): - while (True): time.sleep(1.0) + s = sounder(options) + + if options.transmit: + s.enable_tx(True) - except KeyboardInterrupt: - if (options.transmit): - tx.turn_off() + if options.receive: + s.enable_rx(True) + if options.samples < 0: + raw_input("Press enter to exit.") if __name__ == "__main__": main()