diff options
Diffstat (limited to 'fpga/usrp2/sdr_lib')
-rw-r--r-- | fpga/usrp2/sdr_lib/Makefile.srcs | 9 | ||||
-rw-r--r-- | fpga/usrp2/sdr_lib/cordic_z24.v | 2 | ||||
-rw-r--r-- | fpga/usrp2/sdr_lib/ddc_chain.v | 190 | ||||
-rw-r--r-- | fpga/usrp2/sdr_lib/dsp_core_rx.v | 144 | ||||
-rw-r--r-- | fpga/usrp2/sdr_lib/dsp_core_rx_old.v | 200 | ||||
-rw-r--r-- | fpga/usrp2/sdr_lib/dsp_core_rx_tb.v | 10 | ||||
-rw-r--r-- | fpga/usrp2/sdr_lib/dsp_core_rx_udp.v | 200 | ||||
-rw-r--r-- | fpga/usrp2/sdr_lib/dsp_rx_glue.v | 98 | ||||
-rw-r--r-- | fpga/usrp2/sdr_lib/dsp_tx_glue.v | 98 | ||||
-rw-r--r-- | fpga/usrp2/sdr_lib/dspengine_16to8.v | 38 | ||||
-rw-r--r-- | fpga/usrp2/sdr_lib/dspengine_8to16.v | 203 | ||||
-rw-r--r-- | fpga/usrp2/sdr_lib/duc_chain.v (renamed from fpga/usrp2/sdr_lib/dsp_core_tx.v) | 74 | ||||
-rw-r--r-- | fpga/usrp2/sdr_lib/dummy_rx.v | 2 |
13 files changed, 658 insertions, 610 deletions
diff --git a/fpga/usrp2/sdr_lib/Makefile.srcs b/fpga/usrp2/sdr_lib/Makefile.srcs index 629b92cc8..e6c4c5343 100644 --- a/fpga/usrp2/sdr_lib/Makefile.srcs +++ b/fpga/usrp2/sdr_lib/Makefile.srcs @@ -1,5 +1,5 @@ # -# Copyright 2010 Ettus Research LLC +# Copyright 2010-2012 Ettus Research LLC # ################################################## @@ -23,9 +23,10 @@ clip_reg.v \ cordic.v \ cordic_z24.v \ cordic_stage.v \ -dsp_core_rx.v \ -dsp_core_tx.v \ +ddc_chain.v \ +duc_chain.v \ dspengine_16to8.v \ +dspengine_8to16.v \ hb_dec.v \ hb_interp.v \ pipectrl.v \ @@ -39,4 +40,6 @@ sign_extend.v \ small_hb_dec.v \ small_hb_int.v \ tx_frontend.v \ +dsp_tx_glue.v \ +dsp_rx_glue.v \ )) diff --git a/fpga/usrp2/sdr_lib/cordic_z24.v b/fpga/usrp2/sdr_lib/cordic_z24.v index 97b7beaf7..51b074a33 100644 --- a/fpga/usrp2/sdr_lib/cordic_z24.v +++ b/fpga/usrp2/sdr_lib/cordic_z24.v @@ -119,8 +119,6 @@ module cordic_z24(clock, reset, enable, xi, yi, zi, xo, yo, zo ); assign xo = x20[bitwidth:1]; assign yo = y20[bitwidth:1]; assign zo = z20; - //assign xo = x20[bitwidth+1:2]; // CORDIC gain is ~1.6, plus gain from rotating vectors - //assign yo = y20[bitwidth+1:2]; endmodule // cordic diff --git a/fpga/usrp2/sdr_lib/ddc_chain.v b/fpga/usrp2/sdr_lib/ddc_chain.v new file mode 100644 index 000000000..c32c9f491 --- /dev/null +++ b/fpga/usrp2/sdr_lib/ddc_chain.v @@ -0,0 +1,190 @@ +// +// Copyright 2011-2012 Ettus Research 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 3 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, see <http://www.gnu.org/licenses/>. +// + +//! The USRP digital down-conversion chain + +module ddc_chain + #( + parameter BASE = 0, + parameter DSPNO = 0, + parameter WIDTH = 24 + ) + (input clk, input rst, input clr, + input set_stb, input [7:0] set_addr, input [31:0] set_data, + input set_stb_user, input [7:0] set_addr_user, input [31:0] set_data_user, + + // From RX frontend + input [WIDTH-1:0] rx_fe_i, + input [WIDTH-1:0] rx_fe_q, + + // To RX control + output [31:0] sample, + input run, + output strobe, + output [31:0] debug + ); + + localparam cwidth = 25; + localparam zwidth = 24; + + wire ddc_enb; + wire [31:0] phase_inc; + reg [31:0] phase; + + wire [17:0] scale_factor; + wire [cwidth-1:0] i_cordic, q_cordic; + wire [WIDTH-1:0] i_cordic_clip, q_cordic_clip; + wire [WIDTH-1:0] i_cic, q_cic; + wire [WIDTH-1:0] i_hb1, q_hb1; + wire [WIDTH-1:0] i_hb2, q_hb2; + + wire strobe_cic, strobe_hb1, strobe_hb2; + wire enable_hb1, enable_hb2; + wire [7:0] cic_decim_rate; + + reg [WIDTH-1:0] rx_fe_i_mux, rx_fe_q_mux; + wire realmode; + wire swap_iq; + + setting_reg #(.my_addr(BASE+0)) sr_0 + (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr), + .in(set_data),.out(phase_inc),.changed()); + + setting_reg #(.my_addr(BASE+1), .width(18)) sr_1 + (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr), + .in(set_data),.out(scale_factor),.changed()); + + setting_reg #(.my_addr(BASE+2), .width(10)) sr_2 + (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr), + .in(set_data),.out({enable_hb1, enable_hb2, cic_decim_rate}),.changed()); + + setting_reg #(.my_addr(BASE+3), .width(2)) sr_3 + (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr), + .in(set_data),.out({realmode,swap_iq}),.changed()); + + // MUX so we can do realmode signals on either input + + always @(posedge clk) + if(swap_iq) + begin + rx_fe_i_mux <= rx_fe_q; + rx_fe_q_mux <= realmode ? 0 : rx_fe_i; + end + else + begin + rx_fe_i_mux <= rx_fe_i; + rx_fe_q_mux <= realmode ? 0 : rx_fe_q; + end + + // NCO + always @(posedge clk) + if(rst) + phase <= 0; + else if(~ddc_enb) + phase <= 0; + else + phase <= phase + phase_inc; + + //sign extension of cordic input + wire [WIDTH-1:0] to_ddc_chain_i, to_ddc_chain_q; + wire [cwidth-1:0] to_cordic_i, to_cordic_q; + sign_extend #(.bits_in(WIDTH), .bits_out(cwidth)) sign_extend_cordic_i (.in(to_ddc_chain_i), .out(to_cordic_i)); + sign_extend #(.bits_in(WIDTH), .bits_out(cwidth)) sign_extend_cordic_q (.in(to_ddc_chain_q), .out(to_cordic_q)); + + // CORDIC 24-bit I/O + cordic_z24 #(.bitwidth(cwidth)) + cordic(.clock(clk), .reset(rst), .enable(ddc_enb), + .xi(to_cordic_i),. yi(to_cordic_q), .zi(phase[31:32-zwidth]), + .xo(i_cordic),.yo(q_cordic),.zo() ); + + clip_reg #(.bits_in(cwidth), .bits_out(WIDTH)) clip_i + (.clk(clk), .in(i_cordic), .strobe_in(1'b1), .out(i_cordic_clip)); + clip_reg #(.bits_in(cwidth), .bits_out(WIDTH)) clip_q + (.clk(clk), .in(q_cordic), .strobe_in(1'b1), .out(q_cordic_clip)); + + // CIC decimator 24 bit I/O + cic_strober cic_strober(.clock(clk),.reset(rst),.enable(ddc_enb),.rate(cic_decim_rate), + .strobe_fast(1),.strobe_slow(strobe_cic) ); + + cic_decim #(.bw(WIDTH)) + decim_i (.clock(clk),.reset(rst),.enable(ddc_enb), + .rate(cic_decim_rate),.strobe_in(1'b1),.strobe_out(strobe_cic), + .signal_in(i_cordic_clip),.signal_out(i_cic)); + + cic_decim #(.bw(WIDTH)) + decim_q (.clock(clk),.reset(rst),.enable(ddc_enb), + .rate(cic_decim_rate),.strobe_in(1'b1),.strobe_out(strobe_cic), + .signal_in(q_cordic_clip),.signal_out(q_cic)); + + // First (small) halfband 24 bit I/O + small_hb_dec #(.WIDTH(WIDTH)) small_hb_i + (.clk(clk),.rst(rst),.bypass(~enable_hb1),.run(ddc_enb), + .stb_in(strobe_cic),.data_in(i_cic),.stb_out(strobe_hb1),.data_out(i_hb1)); + + small_hb_dec #(.WIDTH(WIDTH)) small_hb_q + (.clk(clk),.rst(rst),.bypass(~enable_hb1),.run(ddc_enb), + .stb_in(strobe_cic),.data_in(q_cic),.stb_out(),.data_out(q_hb1)); + + // Second (large) halfband 24 bit I/O + wire [8:0] cpi_hb = enable_hb1 ? {cic_decim_rate,1'b0} : {1'b0,cic_decim_rate}; + hb_dec #(.WIDTH(WIDTH)) hb_i + (.clk(clk),.rst(rst),.bypass(~enable_hb2),.run(ddc_enb),.cpi(cpi_hb), + .stb_in(strobe_hb1),.data_in(i_hb1),.stb_out(strobe_hb2),.data_out(i_hb2)); + + hb_dec #(.WIDTH(WIDTH)) hb_q + (.clk(clk),.rst(rst),.bypass(~enable_hb2),.run(ddc_enb),.cpi(cpi_hb), + .stb_in(strobe_hb1),.data_in(q_hb1),.stb_out(),.data_out(q_hb2)); + + //scalar operation (gain of 6 bits) + wire [35:0] prod_i, prod_q; + + MULT18X18S mult_i + (.P(prod_i), .A(i_hb2[WIDTH-1:WIDTH-18]), .B(scale_factor), .C(clk), .CE(strobe_hb2), .R(rst) ); + MULT18X18S mult_q + (.P(prod_q), .A(q_hb2[WIDTH-1:WIDTH-18]), .B(scale_factor), .C(clk), .CE(strobe_hb2), .R(rst) ); + + //pipeline for the multiplier (gain of 10 bits) + reg [WIDTH-1:0] prod_reg_i, prod_reg_q; + reg strobe_mult; + + always @(posedge clk) begin + strobe_mult <= strobe_hb2; + prod_reg_i <= prod_i[33:34-WIDTH]; + prod_reg_q <= prod_q[33:34-WIDTH]; + end + + // Round final answer to 16 bits + wire [31:0] ddc_chain_out; + wire ddc_chain_stb; + + round_sd #(.WIDTH_IN(WIDTH),.WIDTH_OUT(16)) round_i + (.clk(clk),.reset(rst), .in(prod_reg_i),.strobe_in(strobe_mult), .out(ddc_chain_out[31:16]), .strobe_out(ddc_chain_stb)); + + round_sd #(.WIDTH_IN(WIDTH),.WIDTH_OUT(16)) round_q + (.clk(clk),.reset(rst), .in(prod_reg_q),.strobe_in(strobe_mult), .out(ddc_chain_out[15:0]), .strobe_out()); + + dsp_rx_glue #(.DSPNO(DSPNO), .WIDTH(WIDTH)) custom( + .clock(clk), .reset(rst), .clear(clr), .enable(run), + .set_stb(set_stb_user), .set_addr(set_addr_user), .set_data(set_data_user), + .frontend_i(rx_fe_i_mux), .frontend_q(rx_fe_q_mux), + .ddc_in_i(to_ddc_chain_i), .ddc_in_q(to_ddc_chain_q), + .ddc_out_sample(ddc_chain_out), .ddc_out_strobe(ddc_chain_stb), .ddc_out_enable(ddc_enb), + .bb_sample(sample), .bb_strobe(strobe)); + + assign debug = {enable_hb1, enable_hb2, run, strobe, strobe_cic, strobe_hb1, strobe_hb2}; + +endmodule // ddc_chain diff --git a/fpga/usrp2/sdr_lib/dsp_core_rx.v b/fpga/usrp2/sdr_lib/dsp_core_rx.v deleted file mode 100644 index d1c7e238a..000000000 --- a/fpga/usrp2/sdr_lib/dsp_core_rx.v +++ /dev/null @@ -1,144 +0,0 @@ -// -// Copyright 2011 Ettus Research 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 3 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, see <http://www.gnu.org/licenses/>. -// - - -module dsp_core_rx - #(parameter BASE = 160) - (input clk, input rst, - input set_stb, input [7:0] set_addr, input [31:0] set_data, - - input [23:0] adc_i, input adc_ovf_i, - input [23:0] adc_q, input adc_ovf_q, - - output [31:0] sample, - input run, - output strobe, - output [31:0] debug - ); - - wire [31:0] phase_inc; - reg [31:0] phase; - - wire [24:0] i_cordic, q_cordic; - wire [23:0] i_cordic_clip, q_cordic_clip; - wire [23:0] i_cic, q_cic; - wire [23:0] i_hb1, q_hb1; - wire [23:0] i_hb2, q_hb2; - - wire strobe_cic, strobe_hb1, strobe_hb2; - wire enable_hb1, enable_hb2; - wire [7:0] cic_decim_rate; - - reg [23:0] adc_i_mux, adc_q_mux; - wire realmode; - wire swap_iq; - - setting_reg #(.my_addr(BASE+0)) sr_0 - (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr), - .in(set_data),.out(phase_inc),.changed()); - - /* - setting_reg #(.my_addr(BASE+1)) sr_1 - (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr), - .in(set_data),.out({scale_i,scale_q}),.changed()); - */ - - setting_reg #(.my_addr(BASE+2), .width(10)) sr_2 - (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr), - .in(set_data),.out({enable_hb1, enable_hb2, cic_decim_rate}),.changed()); - - setting_reg #(.my_addr(BASE+3), .width(2)) sr_3 - (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr), - .in(set_data),.out({realmode,swap_iq}),.changed()); - - // MUX so we can do realmode signals on either input - - always @(posedge clk) - if(swap_iq) - begin - adc_i_mux <= adc_q; - adc_q_mux <= realmode ? 24'd0 : adc_i; - end - else - begin - adc_i_mux <= adc_i; - adc_q_mux <= realmode ? 24'd0 : adc_q; - end - - // NCO - always @(posedge clk) - if(rst) - phase <= 0; - else if(~run) - phase <= 0; - else - phase <= phase + phase_inc; - - // CORDIC 24-bit I/O - cordic_z24 #(.bitwidth(25)) - cordic(.clock(clk), .reset(rst), .enable(run), - .xi({adc_i_mux[23],adc_i_mux}),. yi({adc_q_mux[23],adc_q_mux}), .zi(phase[31:8]), - .xo(i_cordic),.yo(q_cordic),.zo() ); - - clip_reg #(.bits_in(25), .bits_out(24)) clip_i - (.clk(clk), .in(i_cordic), .strobe_in(1'b1), .out(i_cordic_clip)); - clip_reg #(.bits_in(25), .bits_out(24)) clip_q - (.clk(clk), .in(q_cordic), .strobe_in(1'b1), .out(q_cordic_clip)); - - // CIC decimator 24 bit I/O - cic_strober cic_strober(.clock(clk),.reset(rst),.enable(run),.rate(cic_decim_rate), - .strobe_fast(1),.strobe_slow(strobe_cic) ); - - cic_decim #(.bw(24)) - decim_i (.clock(clk),.reset(rst),.enable(run), - .rate(cic_decim_rate),.strobe_in(1'b1),.strobe_out(strobe_cic), - .signal_in(i_cordic_clip),.signal_out(i_cic)); - - cic_decim #(.bw(24)) - decim_q (.clock(clk),.reset(rst),.enable(run), - .rate(cic_decim_rate),.strobe_in(1'b1),.strobe_out(strobe_cic), - .signal_in(q_cordic_clip),.signal_out(q_cic)); - - // First (small) halfband 24 bit I/O - small_hb_dec #(.WIDTH(24)) small_hb_i - (.clk(clk),.rst(rst),.bypass(~enable_hb1),.run(run), - .stb_in(strobe_cic),.data_in(i_cic),.stb_out(strobe_hb1),.data_out(i_hb1)); - - small_hb_dec #(.WIDTH(24)) small_hb_q - (.clk(clk),.rst(rst),.bypass(~enable_hb1),.run(run), - .stb_in(strobe_cic),.data_in(q_cic),.stb_out(),.data_out(q_hb1)); - - // Second (large) halfband 24 bit I/O - wire [8:0] cpi_hb = enable_hb1 ? {cic_decim_rate,1'b0} : {1'b0,cic_decim_rate}; - hb_dec #(.WIDTH(24)) hb_i - (.clk(clk),.rst(rst),.bypass(~enable_hb2),.run(run),.cpi(cpi_hb), - .stb_in(strobe_hb1),.data_in(i_hb1),.stb_out(strobe_hb2),.data_out(i_hb2)); - - hb_dec #(.WIDTH(24)) hb_q - (.clk(clk),.rst(rst),.bypass(~enable_hb2),.run(run),.cpi(cpi_hb), - .stb_in(strobe_hb1),.data_in(q_hb1),.stb_out(),.data_out(q_hb2)); - - // Round final answer to 16 bits - round_sd #(.WIDTH_IN(24),.WIDTH_OUT(16)) round_i - (.clk(clk),.reset(rst), .in(i_hb2),.strobe_in(strobe_hb2), .out(sample[31:16]), .strobe_out(strobe)); - - round_sd #(.WIDTH_IN(24),.WIDTH_OUT(16)) round_q - (.clk(clk),.reset(rst), .in(q_hb2),.strobe_in(strobe_hb2), .out(sample[15:0]), .strobe_out()); - - assign debug = {enable_hb1, enable_hb2, run, strobe, strobe_cic, strobe_hb1, strobe_hb2}; - -endmodule // dsp_core_rx diff --git a/fpga/usrp2/sdr_lib/dsp_core_rx_old.v b/fpga/usrp2/sdr_lib/dsp_core_rx_old.v deleted file mode 100644 index 90d5d839f..000000000 --- a/fpga/usrp2/sdr_lib/dsp_core_rx_old.v +++ /dev/null @@ -1,200 +0,0 @@ -// -// Copyright 2011 Ettus Research 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 3 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, see <http://www.gnu.org/licenses/>. -// - - -`define DSP_CORE_RX_BASE 160 -module dsp_core_rx_old - (input clk, input rst, - input set_stb, input [7:0] set_addr, input [31:0] set_data, - - input [13:0] adc_a, input adc_ovf_a, - input [13:0] adc_b, input adc_ovf_b, - - input [15:0] io_rx, - - output [31:0] sample, - input run, - output strobe, - output [31:0] debug - ); - - wire [15:0] scale_i, scale_q; - wire [13:0] adc_a_ofs, adc_b_ofs; - reg [13:0] adc_i, adc_q; - wire [31:0] phase_inc; - reg [31:0] phase; - - wire [35:0] prod_i, prod_q; - wire [23:0] i_cordic, q_cordic; - wire [23:0] i_cic, q_cic; - wire [17:0] i_cic_scaled, q_cic_scaled; - wire [17:0] i_hb1, q_hb1; - wire [17:0] i_hb2, q_hb2; - wire [15:0] i_out, q_out; - - wire strobe_cic, strobe_hb1, strobe_hb2; - wire enable_hb1, enable_hb2; - wire [7:0] cic_decim_rate; - - wire [31:10] UNUSED_1; - wire [31:4] UNUSED_2; - wire [31:2] UNUSED_3; - - setting_reg #(.my_addr(`DSP_CORE_RX_BASE+0)) sr_0 - (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr), - .in(set_data),.out(phase_inc),.changed()); - - setting_reg #(.my_addr(`DSP_CORE_RX_BASE+1)) sr_1 - (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr), - .in(set_data),.out({scale_i,scale_q}),.changed()); - - setting_reg #(.my_addr(`DSP_CORE_RX_BASE+2)) sr_2 - (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr), - .in(set_data),.out({UNUSED_1, enable_hb1, enable_hb2, cic_decim_rate}),.changed()); - - rx_dcoffset #(.WIDTH(14),.ADDR(`DSP_CORE_RX_BASE+6)) rx_dcoffset_a - (.clk(clk),.rst(rst),.set_stb(set_stb),.set_addr(set_addr),.set_data(set_data), - .adc_in(adc_a),.adc_out(adc_a_ofs)); - - rx_dcoffset #(.WIDTH(14),.ADDR(`DSP_CORE_RX_BASE+7)) rx_dcoffset_b - (.clk(clk),.rst(rst),.set_stb(set_stb),.set_addr(set_addr),.set_data(set_data), - .adc_in(adc_b),.adc_out(adc_b_ofs)); - - wire [3:0] muxctrl; - setting_reg #(.my_addr(`DSP_CORE_RX_BASE+8)) sr_8 - (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr), - .in(set_data),.out({UNUSED_2,muxctrl}),.changed()); - - wire [1:0] gpio_ena; - setting_reg #(.my_addr(`DSP_CORE_RX_BASE+9)) sr_9 - (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr), - .in(set_data),.out({UNUSED_3,gpio_ena}),.changed()); - - // The TVRX connects to what is called adc_b, thus A and B are - // swapped throughout the design. - // - // In the interest of expediency and keeping the s/w sane, we just remap them here. - // The I & Q fields are mapped the same: - // 0 -> "the real A" (as determined by the TVRX) - // 1 -> "the real B" - // 2 -> const zero - - always @(posedge clk) - case(muxctrl[1:0]) // The I mapping - 0: adc_i <= adc_b_ofs; // "the real A" - 1: adc_i <= adc_a_ofs; - 2: adc_i <= 0; - default: adc_i <= 0; - endcase // case(muxctrl[1:0]) - - always @(posedge clk) - case(muxctrl[3:2]) // The Q mapping - 0: adc_q <= adc_b_ofs; // "the real A" - 1: adc_q <= adc_a_ofs; - 2: adc_q <= 0; - default: adc_q <= 0; - endcase // case(muxctrl[3:2]) - - always @(posedge clk) - if(rst) - phase <= 0; - else if(~run) - phase <= 0; - else - phase <= phase + phase_inc; - - MULT18X18S mult_i - (.P(prod_i), // 36-bit multiplier output - .A({{4{adc_i[13]}},adc_i} ), // 18-bit multiplier input - .B({{2{scale_i[15]}},scale_i}), // 18-bit multiplier input - .C(clk), // Clock input - .CE(1), // Clock enable input - .R(rst) // Synchronous reset input - ); - - MULT18X18S mult_q - (.P(prod_q), // 36-bit multiplier output - .A({{4{adc_q[13]}},adc_q} ), // 18-bit multiplier input - .B({{2{scale_q[15]}},scale_q}), // 18-bit multiplier input - .C(clk), // Clock input - .CE(1), // Clock enable input - .R(rst) // Synchronous reset input - ); - - - cordic_z24 #(.bitwidth(24)) - cordic(.clock(clk), .reset(rst), .enable(run), - .xi(prod_i[23:0]),. yi(prod_q[23:0]), .zi(phase[31:8]), - .xo(i_cordic),.yo(q_cordic),.zo() ); - - cic_strober cic_strober(.clock(clk),.reset(rst),.enable(run),.rate(cic_decim_rate), - .strobe_fast(1),.strobe_slow(strobe_cic) ); - - cic_decim #(.bw(24)) - decim_i (.clock(clk),.reset(rst),.enable(run), - .rate(cic_decim_rate),.strobe_in(1'b1),.strobe_out(strobe_cic), - .signal_in(i_cordic),.signal_out(i_cic)); - - cic_decim #(.bw(24)) - decim_q (.clock(clk),.reset(rst),.enable(run), - .rate(cic_decim_rate),.strobe_in(1'b1),.strobe_out(strobe_cic), - .signal_in(q_cordic),.signal_out(q_cic)); - - round_reg #(.bits_in(24),.bits_out(18)) round_icic (.clk(clk),.in(i_cic),.out(i_cic_scaled)); - round_reg #(.bits_in(24),.bits_out(18)) round_qcic (.clk(clk),.in(q_cic),.out(q_cic_scaled)); - reg strobe_cic_d1; - always @(posedge clk) strobe_cic_d1 <= strobe_cic; - - small_hb_dec #(.WIDTH(18)) small_hb_i - (.clk(clk),.rst(rst),.bypass(~enable_hb1),.run(run), - .stb_in(strobe_cic_d1),.data_in(i_cic_scaled),.stb_out(strobe_hb1),.data_out(i_hb1)); - - small_hb_dec #(.WIDTH(18)) small_hb_q - (.clk(clk),.rst(rst),.bypass(~enable_hb1),.run(run), - .stb_in(strobe_cic_d1),.data_in(q_cic_scaled),.stb_out(),.data_out(q_hb1)); - - wire [8:0] cpi_hb = enable_hb1 ? {cic_decim_rate,1'b0} : {1'b0,cic_decim_rate}; - hb_dec #(.IWIDTH(18), .OWIDTH(18), .CWIDTH(18), .ACCWIDTH(24)) hb_i - (.clk(clk),.rst(rst),.bypass(~enable_hb2),.run(run),.cpi(cpi_hb), - .stb_in(strobe_hb1),.data_in(i_hb1),.stb_out(strobe_hb2),.data_out(i_hb2)); - - hb_dec #(.IWIDTH(18), .OWIDTH(18), .CWIDTH(18), .ACCWIDTH(24)) hb_q - (.clk(clk),.rst(rst),.bypass(~enable_hb2),.run(run),.cpi(cpi_hb), - .stb_in(strobe_hb1),.data_in(q_hb1),.stb_out(),.data_out(q_hb2)); - - round #(.bits_in(18),.bits_out(16)) round_iout (.in(i_hb2),.out(i_out)); - round #(.bits_in(18),.bits_out(16)) round_qout (.in(q_hb2),.out(q_out)); - - // Streaming GPIO - // - // io_rx[15] => I channel LSB if gpio_ena[0] high - // io_rx[14] => Q channel LSB if gpio_ena[1] high - - reg [31:0] sample_reg; - always @(posedge clk) - begin - sample_reg[31:17] <= i_out[15:1]; - sample_reg[15:1] <= q_out[15:1]; - sample_reg[16] <= gpio_ena[0] ? io_rx[15] : i_out[0]; - sample_reg[0] <= gpio_ena[1] ? io_rx[14] : q_out[0]; - end - - assign sample = sample_reg; - assign strobe = strobe_hb2; - assign debug = {enable_hb1, enable_hb2, run, strobe, strobe_cic, strobe_cic_d1, strobe_hb1, strobe_hb2}; - -endmodule // dsp_core_rx diff --git a/fpga/usrp2/sdr_lib/dsp_core_rx_tb.v b/fpga/usrp2/sdr_lib/dsp_core_rx_tb.v index 271db8cef..a221bed44 100644 --- a/fpga/usrp2/sdr_lib/dsp_core_rx_tb.v +++ b/fpga/usrp2/sdr_lib/dsp_core_rx_tb.v @@ -1,6 +1,6 @@ `timescale 1ns/1ns -module dsp_core_rx_tb(); +module ddc_chain_tb(); reg clk, rst; @@ -9,8 +9,8 @@ module dsp_core_rx_tb(); initial clk = 0; always #5 clk = ~clk; - initial $dumpfile("dsp_core_rx_tb.vcd"); - initial $dumpvars(0,dsp_core_rx_tb); + initial $dumpfile("ddc_chain_tb.vcd"); + initial $dumpvars(0,ddc_chain_tb); reg signed [23:0] adc_in; wire signed [15:0] adc_out_i, adc_out_q; @@ -27,7 +27,7 @@ module dsp_core_rx_tb(); reg [7:0] set_addr; reg [31:0] set_data; - dsp_core_rx #(.BASE(0)) dsp_core_rx + ddc_chain #(.BASE(0)) ddc_chain (.clk(clk),.rst(rst), .set_stb(set_stb),.set_addr(set_addr),.set_data(set_data), .adc_i(adc_in), .adc_ovf_i(0), @@ -70,4 +70,4 @@ module dsp_core_rx_tb(); adc_in <= adc_in + 4; //adc_in <= (($random % 473) + 23)/4; */ -endmodule // dsp_core_rx_tb +endmodule // ddc_chain_tb diff --git a/fpga/usrp2/sdr_lib/dsp_core_rx_udp.v b/fpga/usrp2/sdr_lib/dsp_core_rx_udp.v deleted file mode 100644 index 08dab37e6..000000000 --- a/fpga/usrp2/sdr_lib/dsp_core_rx_udp.v +++ /dev/null @@ -1,200 +0,0 @@ -// -// Copyright 2011 Ettus Research 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 3 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, see <http://www.gnu.org/licenses/>. -// - - -module dsp_core_rx - #(parameter BASE = 160) - (input clk, input rst, - input set_stb, input [7:0] set_addr, input [31:0] set_data, - - input [13:0] adc_a, input adc_ovf_a, - input [13:0] adc_b, input adc_ovf_b, - - input [15:0] io_rx, - - output [31:0] sample, - input run, - output strobe, - output [31:0] debug - ); - - wire [15:0] scale_i, scale_q; - wire [13:0] adc_a_ofs, adc_b_ofs; - reg [13:0] adc_i, adc_q; - wire [31:0] phase_inc; - reg [31:0] phase; - - wire [35:0] prod_i, prod_q; - wire [23:0] i_cordic, q_cordic; - wire [23:0] i_cic, q_cic; - wire [17:0] i_cic_scaled, q_cic_scaled; - wire [17:0] i_hb1, q_hb1; - wire [17:0] i_hb2, q_hb2; - wire [15:0] i_out, q_out; - - wire strobe_cic, strobe_hb1, strobe_hb2; - wire enable_hb1, enable_hb2; - wire [7:0] cic_decim_rate; - - wire [31:10] UNUSED_1; - wire [31:4] UNUSED_2; - wire [31:2] UNUSED_3; - - setting_reg #(.my_addr(BASE+0)) sr_0 - (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr), - .in(set_data),.out(phase_inc),.changed()); - - setting_reg #(.my_addr(BASE+1)) sr_1 - (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr), - .in(set_data),.out({scale_i,scale_q}),.changed()); - - setting_reg #(.my_addr(BASE+2)) sr_2 - (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr), - .in(set_data),.out({UNUSED_1, enable_hb1, enable_hb2, cic_decim_rate}),.changed()); - - rx_dcoffset #(.WIDTH(14),.ADDR(BASE+3)) rx_dcoffset_a - (.clk(clk),.rst(rst),.set_stb(set_stb),.set_addr(set_addr),.set_data(set_data), - .adc_in(adc_a),.adc_out(adc_a_ofs)); - - rx_dcoffset #(.WIDTH(14),.ADDR(BASE+4)) rx_dcoffset_b - (.clk(clk),.rst(rst),.set_stb(set_stb),.set_addr(set_addr),.set_data(set_data), - .adc_in(adc_b),.adc_out(adc_b_ofs)); - - wire [3:0] muxctrl; - setting_reg #(.my_addr(BASE+5)) sr_8 - (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr), - .in(set_data),.out({UNUSED_2,muxctrl}),.changed()); - - wire [1:0] gpio_ena; - setting_reg #(.my_addr(BASE+6)) sr_9 - (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr), - .in(set_data),.out({UNUSED_3,gpio_ena}),.changed()); - - // The TVRX connects to what is called adc_b, thus A and B are - // swapped throughout the design. - // - // In the interest of expediency and keeping the s/w sane, we just remap them here. - // The I & Q fields are mapped the same: - // 0 -> "the real A" (as determined by the TVRX) - // 1 -> "the real B" - // 2 -> const zero - - always @(posedge clk) - case(muxctrl[1:0]) // The I mapping - 0: adc_i <= adc_b_ofs; // "the real A" - 1: adc_i <= adc_a_ofs; - 2: adc_i <= 0; - default: adc_i <= 0; - endcase // case(muxctrl[1:0]) - - always @(posedge clk) - case(muxctrl[3:2]) // The Q mapping - 0: adc_q <= adc_b_ofs; // "the real A" - 1: adc_q <= adc_a_ofs; - 2: adc_q <= 0; - default: adc_q <= 0; - endcase // case(muxctrl[3:2]) - - always @(posedge clk) - if(rst) - phase <= 0; - else if(~run) - phase <= 0; - else - phase <= phase + phase_inc; - - MULT18X18S mult_i - (.P(prod_i), // 36-bit multiplier output - .A({{4{adc_i[13]}},adc_i} ), // 18-bit multiplier input - .B({{2{scale_i[15]}},scale_i}), // 18-bit multiplier input - .C(clk), // Clock input - .CE(1), // Clock enable input - .R(rst) // Synchronous reset input - ); - - MULT18X18S mult_q - (.P(prod_q), // 36-bit multiplier output - .A({{4{adc_q[13]}},adc_q} ), // 18-bit multiplier input - .B({{2{scale_q[15]}},scale_q}), // 18-bit multiplier input - .C(clk), // Clock input - .CE(1), // Clock enable input - .R(rst) // Synchronous reset input - ); - - - cordic_z24 #(.bitwidth(24)) - cordic(.clock(clk), .reset(rst), .enable(run), - .xi(prod_i[23:0]),. yi(prod_q[23:0]), .zi(phase[31:8]), - .xo(i_cordic),.yo(q_cordic),.zo() ); - - cic_strober cic_strober(.clock(clk),.reset(rst),.enable(run),.rate(cic_decim_rate), - .strobe_fast(1),.strobe_slow(strobe_cic) ); - - cic_decim #(.bw(24)) - decim_i (.clock(clk),.reset(rst),.enable(run), - .rate(cic_decim_rate),.strobe_in(1'b1),.strobe_out(strobe_cic), - .signal_in(i_cordic),.signal_out(i_cic)); - - cic_decim #(.bw(24)) - decim_q (.clock(clk),.reset(rst),.enable(run), - .rate(cic_decim_rate),.strobe_in(1'b1),.strobe_out(strobe_cic), - .signal_in(q_cordic),.signal_out(q_cic)); - - round_reg #(.bits_in(24),.bits_out(18)) round_icic (.clk(clk),.in(i_cic),.out(i_cic_scaled)); - round_reg #(.bits_in(24),.bits_out(18)) round_qcic (.clk(clk),.in(q_cic),.out(q_cic_scaled)); - reg strobe_cic_d1; - always @(posedge clk) strobe_cic_d1 <= strobe_cic; - - small_hb_dec #(.WIDTH(18)) small_hb_i - (.clk(clk),.rst(rst),.bypass(~enable_hb1),.run(run), - .stb_in(strobe_cic_d1),.data_in(i_cic_scaled),.stb_out(strobe_hb1),.data_out(i_hb1)); - - small_hb_dec #(.WIDTH(18)) small_hb_q - (.clk(clk),.rst(rst),.bypass(~enable_hb1),.run(run), - .stb_in(strobe_cic_d1),.data_in(q_cic_scaled),.stb_out(),.data_out(q_hb1)); - - wire [8:0] cpi_hb = enable_hb1 ? {cic_decim_rate,1'b0} : {1'b0,cic_decim_rate}; - hb_dec #(.IWIDTH(18), .OWIDTH(18), .CWIDTH(18), .ACCWIDTH(24)) hb_i - (.clk(clk),.rst(rst),.bypass(~enable_hb2),.run(run),.cpi(cpi_hb), - .stb_in(strobe_hb1),.data_in(i_hb1),.stb_out(strobe_hb2),.data_out(i_hb2)); - - hb_dec #(.IWIDTH(18), .OWIDTH(18), .CWIDTH(18), .ACCWIDTH(24)) hb_q - (.clk(clk),.rst(rst),.bypass(~enable_hb2),.run(run),.cpi(cpi_hb), - .stb_in(strobe_hb1),.data_in(q_hb1),.stb_out(),.data_out(q_hb2)); - - round #(.bits_in(18),.bits_out(16)) round_iout (.in(i_hb2),.out(i_out)); - round #(.bits_in(18),.bits_out(16)) round_qout (.in(q_hb2),.out(q_out)); - - // Streaming GPIO - // - // io_rx[15] => I channel LSB if gpio_ena[0] high - // io_rx[14] => Q channel LSB if gpio_ena[1] high - - reg [31:0] sample_reg; - always @(posedge clk) - begin - sample_reg[31:17] <= i_out[15:1]; - sample_reg[15:1] <= q_out[15:1]; - sample_reg[16] <= gpio_ena[0] ? io_rx[15] : i_out[0]; - sample_reg[0] <= gpio_ena[1] ? io_rx[14] : q_out[0]; - end - - assign sample = sample_reg; - assign strobe = strobe_hb2; - assign debug = {enable_hb1, enable_hb2, run, strobe, strobe_cic, strobe_cic_d1, strobe_hb1, strobe_hb2}; - -endmodule // dsp_core_rx diff --git a/fpga/usrp2/sdr_lib/dsp_rx_glue.v b/fpga/usrp2/sdr_lib/dsp_rx_glue.v new file mode 100644 index 000000000..038a67a29 --- /dev/null +++ b/fpga/usrp2/sdr_lib/dsp_rx_glue.v @@ -0,0 +1,98 @@ +// +// Copyright 2012 Ettus Research 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 3 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, see <http://www.gnu.org/licenses/>. +// + +//The following module effects the IO of the DDC chain. +//By default, this entire module is a simple pass-through. + +module dsp_rx_glue +#( + //the dsp unit number: 0, 1, 2... + parameter DSPNO = 0, + + //frontend bus width + parameter WIDTH = 24 +) +( + //control signals + input clock, input reset, input clear, input enable, + + //user settings bus, controlled through user setting regs API + input set_stb, input [7:0] set_addr, input [31:0] set_data, + + //full rate inputs directly from the RX frontend + input [WIDTH-1:0] frontend_i, + input [WIDTH-1:0] frontend_q, + + //full rate outputs directly to the DDC chain + output [WIDTH-1:0] ddc_in_i, + output [WIDTH-1:0] ddc_in_q, + + //strobed samples {I16,Q16} from the RX DDC chain + input [31:0] ddc_out_sample, + input ddc_out_strobe, //high on valid sample + output ddc_out_enable, //enables DDC module + + //strobbed baseband samples {I16,Q16} from this module + output [31:0] bb_sample, + output bb_strobe, //high on valid sample + + //debug output (optional) + output [31:0] debug +); + + generate + if (DSPNO==0) begin + `ifndef RX_DSP0_MODULE + assign ddc_in_i = frontend_i; + assign ddc_in_q = frontend_q; + assign bb_sample = ddc_out_sample; + assign bb_strobe = ddc_out_strobe; + assign ddc_out_enable = enable; + `else + `RX_DSP0_MODULE #(.WIDTH(WIDTH)) rx_dsp0_custom + ( + .clock(clock), .reset(reset), .clear(clear), .enable(enable), + .set_stb(set_stb), .set_addr(set_addr), .set_data(set_data), + .frontend_i(frontend_i), .frontend_q(frontend_q), + .ddc_in_i(ddc_in_i), .ddc_in_q(ddc_in_q), + .ddc_out_sample(ddc_out_sample), .ddc_out_strobe(ddc_out_strobe), .ddc_out_enable(ddc_out_enable), + .bb_sample(bb_sample), .bb_strobe(bb_strobe) + ); + `endif + end + else begin + `ifndef RX_DSP1_MODULE + assign ddc_in_i = frontend_i; + assign ddc_in_q = frontend_q; + assign bb_sample = ddc_out_sample; + assign bb_strobe = ddc_out_strobe; + assign ddc_out_enable = enable; + `else + `RX_DSP1_MODULE #(.WIDTH(WIDTH)) rx_dsp1_custom + ( + .clock(clock), .reset(reset), .clear(clear), .enable(enable), + .set_stb(set_stb), .set_addr(set_addr), .set_data(set_data), + .frontend_i(frontend_i), .frontend_q(frontend_q), + .ddc_in_i(ddc_in_i), .ddc_in_q(ddc_in_q), + .ddc_out_sample(ddc_out_sample), .ddc_out_strobe(ddc_out_strobe), .ddc_out_enable(ddc_out_enable), + .bb_sample(bb_sample), .bb_strobe(bb_strobe) + ); + `endif + end + endgenerate + +endmodule //dsp_rx_glue diff --git a/fpga/usrp2/sdr_lib/dsp_tx_glue.v b/fpga/usrp2/sdr_lib/dsp_tx_glue.v new file mode 100644 index 000000000..46f6789ee --- /dev/null +++ b/fpga/usrp2/sdr_lib/dsp_tx_glue.v @@ -0,0 +1,98 @@ +// +// Copyright 2012 Ettus Research 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 3 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, see <http://www.gnu.org/licenses/>. +// + +//The following module effects the IO of the DUC chain. +//By default, this entire module is a simple pass-through. + +module dsp_tx_glue +#( + //the dsp unit number: 0, 1, 2... + parameter DSPNO = 0, + + //frontend bus width + parameter WIDTH = 24 +) +( + //control signals + input clock, input reset, input clear, input enable, + + //user settings bus, controlled through user setting regs API + input set_stb, input [7:0] set_addr, input [31:0] set_data, + + //full rate outputs directly to the TX frontend + output [WIDTH-1:0] frontend_i, + output [WIDTH-1:0] frontend_q, + + //full rate outputs directly from the DUC chain + input [WIDTH-1:0] duc_out_i, + input [WIDTH-1:0] duc_out_q, + + //strobed samples {I16,Q16} to the TX DUC chain + output [31:0] duc_in_sample, + input duc_in_strobe, //this is a backpressure signal + output duc_in_enable, //enables DUC module + + //strobbed baseband samples {I16,Q16} to this module + input [31:0] bb_sample, + output bb_strobe, //this is a backpressure signal + + //debug output (optional) + output [31:0] debug +); + + generate + if (DSPNO==0) begin + `ifndef TX_DSP0_MODULE + assign frontend_i = duc_out_i; + assign frontend_q = duc_out_q; + assign duc_in_sample = bb_sample; + assign bb_strobe = duc_in_strobe; + assign duc_in_enable = enable; + `else + `TX_DSP0_MODULE #(.WIDTH(WIDTH)) tx_dsp0_custom + ( + .clock(clock), .reset(reset), .clear(clear), .enable(enable), + .set_stb(set_stb), .set_addr(set_addr), .set_data(set_data), + .frontend_i(frontend_i), .frontend_q(frontend_q), + .duc_out_i(duc_out_i), .duc_out_q(duc_out_q), + .duc_in_sample(duc_in_sample), .duc_in_strobe(duc_in_strobe), .duc_in_enable(duc_in_enable), + .bb_sample(bb_sample), .bb_strobe(bb_strobe) + ); + `endif + end + else begin + `ifndef TX_DSP1_MODULE + assign frontend_i = duc_out_i; + assign frontend_q = duc_out_q; + assign duc_in_sample = bb_sample; + assign bb_strobe = duc_in_strobe; + assign duc_in_enable = enable; + `else + `TX_DSP1_MODULE #(.WIDTH(WIDTH)) tx_dsp1_custom + ( + .clock(clock), .reset(reset), .clear(clear), .enable(enable), + .set_stb(set_stb), .set_addr(set_addr), .set_data(set_data), + .frontend_i(frontend_i), .frontend_q(frontend_q), + .duc_out_i(duc_out_i), .duc_out_q(duc_out_q), + .duc_in_sample(duc_in_sample), .duc_in_strobe(duc_in_strobe), .duc_in_enable(duc_in_enable), + .bb_sample(bb_sample), .bb_strobe(bb_strobe) + ); + `endif + end + endgenerate + +endmodule //dsp_tx_glue diff --git a/fpga/usrp2/sdr_lib/dspengine_16to8.v b/fpga/usrp2/sdr_lib/dspengine_16to8.v index 53c5d29da..448c57d35 100644 --- a/fpga/usrp2/sdr_lib/dspengine_16to8.v +++ b/fpga/usrp2/sdr_lib/dspengine_16to8.v @@ -1,5 +1,5 @@ -// Copyright 2011 Ettus Research LLC +// Copyright 2011-2012 Ettus Research 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 @@ -32,13 +32,11 @@ module dspengine_16to8 input [35:0] access_dat_i ); - wire convert; - wire [17:0] scale_factor; - - setting_reg #(.my_addr(BASE),.width(19)) sr_16to8 + wire convert; + setting_reg #(.my_addr(BASE),.width(1)) sr_16to8 (.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr), - .in(set_data),.out({convert,scale_factor}),.changed()); - + .in(set_data),.out(convert),.changed()); + reg [2:0] dsp_state; localparam DSP_IDLE = 0; localparam DSP_PARSE_HEADER = 1; @@ -63,7 +61,7 @@ module dspengine_16to8 wire [15:0] scaled_i, scaled_q; wire [7:0] i8, q8; reg [7:0] i8_reg, q8_reg; - wire stb_read, stb_mult, stb_clip, stb_round, val_read, val_mult, val_clip, val_round; + wire stb_read, stb_clip, val_read, val_clip; wire stb_out, stb_reg; reg even; @@ -193,29 +191,21 @@ module dspengine_16to8 wire [15:0] i16 = access_dat_i[31:16]; wire [15:0] q16 = access_dat_i[15:0]; - pipectrl #(.STAGES(4), .TAGWIDTH(2)) pipectrl + pipectrl #(.STAGES(2), .TAGWIDTH(2)) pipectrl (.clk(clk), .reset(reset), .src_rdy_i(send_to_pipe), .dst_rdy_o(), // dst_rdy_o will always be 1 since dst_rdy_i is 1, below .src_rdy_o(stb_out), .dst_rdy_i(1), // always accept output of chain - .strobes({stb_round,stb_clip,stb_mult,stb_read}), .valids({val_round,val_clip,val_mult,val_read}), + .strobes({stb_clip,stb_read}), .valids({val_clip,val_read}), .tag_i({last,even}), .tag_o({last_o,even_o})); always @(posedge clk) if(stb_out & ~even_o) {i8_reg,q8_reg} <= {i8,q8}; - - MULT18X18S mult_i - (.P(prod_i), .A(scale_factor), .B({i16,2'b00}), .C(clk), .CE(stb_mult), .R(reset) ); - clip_reg #(.bits_in(24),.bits_out(16),.STROBED(1)) clip_i - (.clk(clk), .in(prod_i[35:12]), .out(scaled_i), .strobe_in(stb_clip), .strobe_out()); - round_sd #(.WIDTH_IN(16),.WIDTH_OUT(8),.DISABLE_SD(1)) round_i - (.clk(clk), .reset(reset), .in(scaled_i), .strobe_in(stb_round), .out(i8), .strobe_out()); - - MULT18X18S mult_q - (.P(prod_q), .A(scale_factor), .B({q16,2'b00}), .C(clk), .CE(stb_mult), .R(reset) ); - clip_reg #(.bits_in(24),.bits_out(16),.STROBED(1)) clip_q - (.clk(clk), .in(prod_q[35:12]), .out(scaled_q), .strobe_in(stb_clip), .strobe_out()); - round_sd #(.WIDTH_IN(16),.WIDTH_OUT(8),.DISABLE_SD(1)) round_q - (.clk(clk), .reset(reset), .in(scaled_q), .strobe_in(stb_round), .out(q8), .strobe_out()); + + clip_reg #(.bits_in(16),.bits_out(8),.STROBED(1)) clip_i + (.clk(clk), .in(i16), .out(i8), .strobe_in(stb_clip), .strobe_out()); + + clip_reg #(.bits_in(16),.bits_out(8),.STROBED(1)) clip_q + (.clk(clk), .in(q16), .out(q8), .strobe_in(stb_clip), .strobe_out()); endmodule // dspengine_16to8 diff --git a/fpga/usrp2/sdr_lib/dspengine_8to16.v b/fpga/usrp2/sdr_lib/dspengine_8to16.v new file mode 100644 index 000000000..85187d78d --- /dev/null +++ b/fpga/usrp2/sdr_lib/dspengine_8to16.v @@ -0,0 +1,203 @@ + +// Copyright 2012 Ettus Research 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 3 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, see <http://www.gnu.org/licenses/>. +// + +module dspengine_8to16 + #(parameter BASE = 0, + parameter BUF_SIZE = 9, + parameter HEADER_OFFSET = 0) + (input clk, input reset, input clear, + input set_stb, input [7:0] set_addr, input [31:0] set_data, + + output access_we, + output access_stb, + input access_ok, + output access_done, + output access_skip_read, + output [BUF_SIZE-1:0] access_adr, + input [BUF_SIZE-1:0] access_len, + output [35:0] access_dat_o, + input [35:0] access_dat_i + ); + + wire convert; + + setting_reg #(.my_addr(BASE),.width(1)) sr_8to16 + (.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr), + .in(set_data),.out(convert),.changed()); + + reg [3:0] dsp_state; + localparam DSP_IDLE = 0; + localparam DSP_IDLE_RD = 1; + localparam DSP_PARSE_HEADER = 2; + localparam DSP_READ = 3; + localparam DSP_READ_WAIT = 4; + localparam DSP_WRITE_1 = 5; + localparam DSP_WRITE_0 = 6; + localparam DSP_READ_TRAILER = 7; + localparam DSP_WRITE_TRAILER = 8; + localparam DSP_WRITE_HEADER = 9; + localparam DSP_DONE = 10; + + // Parse VITA header + wire is_if_data = (access_dat_i[31:29] == 3'b000); + wire has_streamid = access_dat_i[28]; + wire has_classid = access_dat_i[27]; + wire has_trailer = access_dat_i[26]; + // 25:24 reserved, aka SOB/EOB + wire has_secs = |access_dat_i[23:22]; + wire has_tics = |access_dat_i[21:20]; + wire [3:0] hdr_length = 1 + has_streamid + has_classid + has_classid + has_secs + has_tics + has_tics; + reg [15:0] hdr_length_reg; + + reg odd; + + reg [BUF_SIZE-1:0] read_adr, write_adr; + reg has_trailer_reg; + + reg [31:0] new_header, new_trailer, trailer_mask; + reg wait_for_trailer; + reg [15:0] data_in_len; + wire is_odd = access_dat_i[22] & access_dat_i[10]; + wire [15:0] data_in_lenx2 = {data_in_len[14:0], 1'b0} - is_odd; + + reg [7:0] i8_0, q8_0; + wire [7:0] i8_1 = access_dat_i[31:24]; + wire [7:0] q8_1 = access_dat_i[23:16]; + reg skip; + + + always @(posedge clk) + { i8_0, q8_0 } <= access_dat_i[15:0]; + + always @(posedge clk) + if(reset | clear) + dsp_state <= DSP_IDLE; + else + case(dsp_state) + DSP_IDLE : + begin + read_adr <= HEADER_OFFSET; + write_adr <= HEADER_OFFSET; + if(access_ok) + dsp_state <= DSP_IDLE_RD; + end + + DSP_IDLE_RD: //extra idle state for read to become valid + dsp_state <= DSP_PARSE_HEADER; + + DSP_PARSE_HEADER : + begin + has_trailer_reg <= has_trailer; + new_header[31:0] <= access_dat_i[31:0]; + hdr_length_reg <= hdr_length; + if(~is_if_data | ~convert | ~has_trailer) + // ~convert is valid (16 bit mode) but both ~trailer and ~is_if_data are both + // really error conditions on the TX side. We shouldn't ever see them in the TX chain + dsp_state <= DSP_WRITE_HEADER; + else + begin + read_adr <= access_dat_i[15:0] + HEADER_OFFSET - 1; // point to trailer + dsp_state <= DSP_READ_TRAILER; + wait_for_trailer <= 0; + data_in_len <= access_dat_i[15:0] - hdr_length - 1 /*trailer*/; + end + end + + DSP_READ_TRAILER : + begin + wait_for_trailer <= 1; + if(wait_for_trailer) + dsp_state <= DSP_WRITE_TRAILER; + new_trailer <= access_dat_i[31:0]; // Leave trailer unchanged + odd <= is_odd; + write_adr <= hdr_length_reg + data_in_lenx2 + HEADER_OFFSET; + end + + DSP_WRITE_TRAILER : + begin + dsp_state <= DSP_READ; + write_adr <= write_adr - 1; + read_adr <= read_adr - 1; + new_header[15:0] <= write_adr + (1 - HEADER_OFFSET); // length = addr of trailer + 1 + end + + DSP_READ : + begin + read_adr <= read_adr - 1; + if(odd) + dsp_state <= DSP_READ_WAIT; + else + dsp_state <= DSP_WRITE_1; + odd <= 0; + end + + DSP_READ_WAIT : + dsp_state <= DSP_WRITE_0; + + DSP_WRITE_1 : + begin + write_adr <= write_adr - 1; + if(write_adr == (hdr_length_reg+HEADER_OFFSET)) + begin + write_adr <= HEADER_OFFSET; + dsp_state <= DSP_WRITE_HEADER; + end + dsp_state <= DSP_WRITE_0; + end + + DSP_WRITE_0 : + begin + write_adr <= write_adr - 1; + if(write_adr == (hdr_length_reg+HEADER_OFFSET)) + begin + write_adr <= HEADER_OFFSET; + dsp_state <= DSP_WRITE_HEADER; + end + else + dsp_state <= DSP_READ; + end + + DSP_WRITE_HEADER : + dsp_state <= DSP_DONE; + + DSP_DONE : + begin + read_adr <= HEADER_OFFSET; + write_adr <= HEADER_OFFSET; + dsp_state <= DSP_IDLE; + end + endcase // case (dsp_state) + + assign access_skip_read = 0; + assign access_done = (dsp_state == DSP_DONE); + + assign access_stb = 1; + + assign access_we = (dsp_state == DSP_WRITE_HEADER) | + (dsp_state == DSP_WRITE_TRAILER) | + (dsp_state == DSP_WRITE_0) | + (dsp_state == DSP_WRITE_1); + + assign access_dat_o = (dsp_state == DSP_WRITE_HEADER) ? { 4'h0, new_header } : + (dsp_state == DSP_WRITE_TRAILER) ? { 4'h2, new_trailer } : + (dsp_state == DSP_WRITE_0) ? { 4'h0, i8_0, 8'd0, q8_0, 8'd0 } : + (dsp_state == DSP_WRITE_1) ? { 4'h0, i8_1, 8'd0, q8_1, 8'd0 } : + 34'h0DEADBEEF; + + assign access_adr = access_we ? write_adr : read_adr; + +endmodule // dspengine_16to8 diff --git a/fpga/usrp2/sdr_lib/dsp_core_tx.v b/fpga/usrp2/sdr_lib/duc_chain.v index 4e0163e0a..bd3402a1f 100644 --- a/fpga/usrp2/sdr_lib/dsp_core_tx.v +++ b/fpga/usrp2/sdr_lib/duc_chain.v @@ -1,5 +1,5 @@ // -// Copyright 2011 Ettus Research LLC +// Copyright 2011-2012 Ettus Research 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 @@ -15,26 +15,35 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. // +//! The USRP digital up-conversion chain -module dsp_core_tx - #(parameter BASE=0) - (input clk, input rst, +module duc_chain + #( + parameter BASE = 0, + parameter DSPNO = 0, + parameter WIDTH = 24 + ) + (input clk, input rst, input clr, input set_stb, input [7:0] set_addr, input [31:0] set_data, + input set_stb_user, input [7:0] set_addr_user, input [31:0] set_data_user, - output [23:0] tx_i, output [23:0] tx_q, + // To TX frontend + output [WIDTH-1:0] tx_fe_i, + output [WIDTH-1:0] tx_fe_q, - // To tx_control + // From TX control input [31:0] sample, input run, output strobe, output [31:0] debug ); - wire [15:0] i, q, scale_i, scale_q; + wire duc_enb; + wire [17:0] scale_factor; wire [31:0] phase_inc; reg [31:0] phase; wire [7:0] interp_rate; - wire [3:0] dacmux_a, dacmux_b; + wire [3:0] tx_femux_a, tx_femux_b; wire enable_hb1, enable_hb2; wire rate_change; @@ -42,9 +51,9 @@ module dsp_core_tx (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr), .in(set_data),.out(phase_inc),.changed()); - setting_reg #(.my_addr(BASE+1)) sr_1 + setting_reg #(.my_addr(BASE+1), .width(18)) sr_1 (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr), - .in(set_data),.out({scale_i,scale_q}),.changed()); + .in(set_data),.out(scale_factor),.changed()); setting_reg #(.my_addr(BASE+2), .width(10)) sr_2 (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr), @@ -57,13 +66,13 @@ module dsp_core_tx reg strobe_hb2 = 1; cic_strober #(.WIDTH(8)) - cic_strober(.clock(clk),.reset(rst),.enable(run & ~rate_change),.rate(interp_rate), + cic_strober(.clock(clk),.reset(rst),.enable(duc_enb & ~rate_change),.rate(interp_rate), .strobe_fast(1),.strobe_slow(strobe_cic_pre) ); cic_strober #(.WIDTH(2)) - hb2_strober(.clock(clk),.reset(rst),.enable(run & ~rate_change),.rate(enable_hb2 ? 2 : 1), + hb2_strober(.clock(clk),.reset(rst),.enable(duc_enb & ~rate_change),.rate(enable_hb2 ? 2 : 1), .strobe_fast(strobe_cic_pre),.strobe_slow(strobe_hb2_pre) ); cic_strober #(.WIDTH(2)) - hb1_strober(.clock(clk),.reset(rst),.enable(run & ~rate_change),.rate(enable_hb1 ? 2 : 1), + hb1_strober(.clock(clk),.reset(rst),.enable(duc_enb & ~rate_change),.rate(enable_hb1 ? 2 : 1), .strobe_fast(strobe_hb2_pre),.strobe_slow(strobe_hb1_pre) ); always @(posedge clk) strobe_hb1 <= strobe_hb1_pre; @@ -74,7 +83,7 @@ module dsp_core_tx always @(posedge clk) if(rst) phase <= 0; - else if(~run) + else if(~duc_enb) phase <= 0; else phase <= phase + phase_inc; @@ -82,8 +91,8 @@ module dsp_core_tx wire signed [17:0] da, db; wire signed [35:0] prod_i, prod_q; - wire [17:0] bb_i = {sample[31:16],2'b0}; - wire [17:0] bb_q = {sample[15:0],2'b0}; + wire [15:0] bb_i; + wire [15:0] bb_q; wire [17:0] i_interp, q_interp; wire [17:0] hb1_i, hb1_q, hb2_i, hb2_q; @@ -92,10 +101,10 @@ module dsp_core_tx // Note that max CIC rate is 128, which would give an overflow on cpo if enable_hb2 is true, // but the default case inside hb_interp handles this - hb_interp #(.IWIDTH(18),.OWIDTH(18),.ACCWIDTH(24)) hb_interp_i - (.clk(clk),.rst(rst),.bypass(~enable_hb1),.cpo(cpo),.stb_in(strobe_hb1),.data_in(bb_i),.stb_out(strobe_hb2),.data_out(hb1_i)); - hb_interp #(.IWIDTH(18),.OWIDTH(18),.ACCWIDTH(24)) hb_interp_q - (.clk(clk),.rst(rst),.bypass(~enable_hb1),.cpo(cpo),.stb_in(strobe_hb1),.data_in(bb_q),.stb_out(strobe_hb2),.data_out(hb1_q)); + hb_interp #(.IWIDTH(18),.OWIDTH(18),.ACCWIDTH(WIDTH)) hb_interp_i + (.clk(clk),.rst(rst),.bypass(~enable_hb1),.cpo(cpo),.stb_in(strobe_hb1),.data_in({bb_i, 2'b0}),.stb_out(strobe_hb2),.data_out(hb1_i)); + hb_interp #(.IWIDTH(18),.OWIDTH(18),.ACCWIDTH(WIDTH)) hb_interp_q + (.clk(clk),.rst(rst),.bypass(~enable_hb1),.cpo(cpo),.stb_in(strobe_hb1),.data_in({bb_q, 2'b0}),.stb_out(strobe_hb2),.data_out(hb1_q)); small_hb_int #(.WIDTH(18)) small_hb_interp_i (.clk(clk),.rst(rst),.bypass(~enable_hb2),.stb_in(strobe_hb2),.data_in(hb1_i), @@ -105,24 +114,22 @@ module dsp_core_tx .output_rate(interp_rate),.stb_out(strobe_cic),.data_out(hb2_q)); cic_interp #(.bw(18),.N(4),.log2_of_max_rate(7)) - cic_interp_i(.clock(clk),.reset(rst),.enable(run & ~rate_change),.rate(interp_rate), + cic_interp_i(.clock(clk),.reset(rst),.enable(duc_enb & ~rate_change),.rate(interp_rate), .strobe_in(strobe_cic),.strobe_out(1), .signal_in(hb2_i),.signal_out(i_interp)); cic_interp #(.bw(18),.N(4),.log2_of_max_rate(7)) - cic_interp_q(.clock(clk),.reset(rst),.enable(run & ~rate_change),.rate(interp_rate), + cic_interp_q(.clock(clk),.reset(rst),.enable(duc_enb & ~rate_change),.rate(interp_rate), .strobe_in(strobe_cic),.strobe_out(1), .signal_in(hb2_q),.signal_out(q_interp)); - assign strobe = strobe_hb1; - - localparam cwidth = 24; // was 18 + localparam cwidth = WIDTH; // was 18 localparam zwidth = 24; // was 16 wire [cwidth-1:0] da_c, db_c; cordic_z24 #(.bitwidth(cwidth)) - cordic(.clock(clk), .reset(rst), .enable(run), + cordic(.clock(clk), .reset(rst), .enable(duc_enb), .xi({i_interp,{(cwidth-18){1'b0}}}),.yi({q_interp,{(cwidth-18){1'b0}}}), .zi(phase[31:32-zwidth]), .xo(da_c),.yo(db_c),.zo() ); @@ -130,7 +137,7 @@ module dsp_core_tx MULT18X18S MULT18X18S_inst (.P(prod_i), // 36-bit multiplier output .A(da_c[cwidth-1:cwidth-18]), // 18-bit multiplier input - .B({{2{scale_i[15]}},scale_i}), // 18-bit multiplier input + .B(scale_factor), // 18-bit multiplier input .C(clk), // Clock input .CE(1), // Clock enable input .R(rst) // Synchronous reset input @@ -139,15 +146,20 @@ module dsp_core_tx MULT18X18S MULT18X18S_inst_2 (.P(prod_q), // 36-bit multiplier output .A(db_c[cwidth-1:cwidth-18]), // 18-bit multiplier input - .B({{2{scale_q[15]}},scale_q}), // 18-bit multiplier input + .B(scale_factor), // 18-bit multiplier input .C(clk), // Clock input .CE(1), // Clock enable input .R(rst) // Synchronous reset input ); - assign tx_i = prod_i[28:5]; - assign tx_q = prod_q[28:5]; - + dsp_tx_glue #(.DSPNO(DSPNO), .WIDTH(WIDTH)) dsp_tx_glue( + .clock(clk), .reset(rst), .clear(clr), .enable(run), + .set_stb(set_stb_user), .set_addr(set_addr_user), .set_data(set_data_user), + .frontend_i(tx_fe_i), .frontend_q(tx_fe_q), + .duc_out_i(prod_i[33:34-WIDTH]), .duc_out_q(prod_q[33:34-WIDTH]), + .duc_in_sample({bb_i, bb_q}), .duc_in_strobe(strobe_hb1), .duc_in_enable(duc_enb), + .bb_sample(sample), .bb_strobe(strobe)); + assign debug = {strobe_cic, strobe_hb1, strobe_hb2,run}; endmodule // dsp_core diff --git a/fpga/usrp2/sdr_lib/dummy_rx.v b/fpga/usrp2/sdr_lib/dummy_rx.v index b22d5f896..42bbe36b2 100644 --- a/fpga/usrp2/sdr_lib/dummy_rx.v +++ b/fpga/usrp2/sdr_lib/dummy_rx.v @@ -76,4 +76,4 @@ module dummy_rx q_out <= q_out + 1; -endmodule // dsp_core_rx +endmodule // ddc_chain |