diff options
Diffstat (limited to 'fpga/usrp3/lib/dsp')
43 files changed, 3815 insertions, 0 deletions
diff --git a/fpga/usrp3/lib/dsp/Makefile.srcs b/fpga/usrp3/lib/dsp/Makefile.srcs new file mode 100644 index 000000000..a32251109 --- /dev/null +++ b/fpga/usrp3/lib/dsp/Makefile.srcs @@ -0,0 +1,47 @@ +# +# Copyright 2013 Ettus Research LLC +# Copyright 2016 Ettus Research, a National Instruments Company +# +# SPDX-License-Identifier: LGPL-3.0-or-later +# + +################################################## +# DSP Sources +################################################## +DSP_SRCS = $(abspath $(addprefix $(BASE_DIR)/../lib/dsp/, \ +acc.v \ +add2_and_clip_reg.v \ +add2_and_clip.v \ +add2_and_round_reg.v \ +add2_and_round.v \ +add2_reg.v \ +add2.v \ +add_then_mac.v \ +cic_decim.v \ +cic_dec_shifter.v \ +cic_interp.v \ +cic_int_shifter.v \ +cic_strober.v \ +clip_reg.v \ +clip.v \ +cordic_stage.v \ +cordic_z24.v \ +ddc_chain.v \ +duc_chain.v \ +hb47_int.v \ +hb_dec.v \ +hb_interp.v \ +Makefile.srcs \ +mult_add_clip.v \ +round_reg.v \ +round_sd.v \ +round.v \ +rx_dcoffset.v \ +rx_frontend.v \ +sign_extend.v \ +small_hb_dec.v \ +small_hb_int.v \ +srl.v \ +tx_frontend.v \ +variable_delay_line.v \ +)) diff --git a/fpga/usrp3/lib/dsp/acc.v b/fpga/usrp3/lib/dsp/acc.v new file mode 100644 index 000000000..623b75da3 --- /dev/null +++ b/fpga/usrp3/lib/dsp/acc.v @@ -0,0 +1,36 @@ +// +// Copyright 2011 Ettus Research LLC +// Copyright 2018 Ettus Research, a National Instruments Company +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// + + + +module acc + #(parameter IWIDTH=16, OWIDTH=30) + (input clk, + input clear, + input acc, + input [IWIDTH-1:0] in, + output reg [OWIDTH-1:0] out); + + wire [OWIDTH-1:0] in_signext; + sign_extend #(.bits_in(IWIDTH),.bits_out(OWIDTH)) + acc_signext (.in(in),.out(in_signext)); + + // CLEAR & ~ACC --> clears the accumulator + // CLEAR & ACC --> loads the accumulator + // ~CLEAR & ACC --> accumulates + // ~CLEAR & ~ACC --> hold + + wire [OWIDTH-1:0] addend1 = clear ? 0 : out; + wire [OWIDTH-1:0] addend2 = ~acc ? 0 : in_signext; + wire [OWIDTH-1:0] sum_int = addend1 + addend2; + + always @(posedge clk) + out <= sum_int; + +endmodule // acc + + diff --git a/fpga/usrp3/lib/dsp/add2.v b/fpga/usrp3/lib/dsp/add2.v new file mode 100644 index 000000000..0876b0320 --- /dev/null +++ b/fpga/usrp3/lib/dsp/add2.v @@ -0,0 +1,19 @@ +// +// Copyright 2011 Ettus Research LLC +// Copyright 2018 Ettus Research, a National Instruments Company +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// + + + +module add2 + #(parameter WIDTH=16) + (input [WIDTH-1:0] in1, + input [WIDTH-1:0] in2, + output [WIDTH-1:0] sum); + + wire [WIDTH:0] sum_int = {in1[WIDTH-1],in1} + {in2[WIDTH-1],in2}; + assign sum = sum_int[WIDTH:1]; // Note -- will have some bias + +endmodule // add2 diff --git a/fpga/usrp3/lib/dsp/add2_and_clip.v b/fpga/usrp3/lib/dsp/add2_and_clip.v new file mode 100644 index 000000000..86980e967 --- /dev/null +++ b/fpga/usrp3/lib/dsp/add2_and_clip.v @@ -0,0 +1,18 @@ +// +// Copyright 2014 Ettus Research LLC +// Copyright 2018 Ettus Research, a National Instruments Company +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// + +module add2_and_clip + #(parameter WIDTH=16) + (input [WIDTH-1:0] in1, + input [WIDTH-1:0] in2, + output [WIDTH-1:0] sum); + + wire [WIDTH:0] sum_int = {in1[WIDTH-1],in1} + {in2[WIDTH-1],in2}; + clip #(.bits_in(WIDTH+1),.bits_out(WIDTH)) clip + (.in(sum_int),.out(sum)); + +endmodule // add2_and_clip diff --git a/fpga/usrp3/lib/dsp/add2_and_clip_reg.v b/fpga/usrp3/lib/dsp/add2_and_clip_reg.v new file mode 100644 index 000000000..8fe343ab2 --- /dev/null +++ b/fpga/usrp3/lib/dsp/add2_and_clip_reg.v @@ -0,0 +1,30 @@ +// +// Copyright 2014 Ettus Research LLC +// Copyright 2018 Ettus Research, a National Instruments Company +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// + +module add2_and_clip_reg + #(parameter WIDTH=16) + (input clk, + input rst, + input [WIDTH-1:0] in1, + input [WIDTH-1:0] in2, + input strobe_in, + output reg [WIDTH-1:0] sum, + output reg strobe_out); + + wire [WIDTH-1:0] sum_int; + + add2_and_clip #(.WIDTH(WIDTH)) add2_and_clip (.in1(in1),.in2(in2),.sum(sum_int)); + + always @(posedge clk) + if(rst) + sum <= 0; + else if(strobe_in) + sum <= sum_int; + + always @(posedge clk) strobe_out <= rst ? 1'b0 : strobe_in; + +endmodule // add2_and_clip_reg diff --git a/fpga/usrp3/lib/dsp/add2_and_round.v b/fpga/usrp3/lib/dsp/add2_and_round.v new file mode 100644 index 000000000..b15cb9987 --- /dev/null +++ b/fpga/usrp3/lib/dsp/add2_and_round.v @@ -0,0 +1,19 @@ +// +// Copyright 2011 Ettus Research LLC +// Copyright 2018 Ettus Research, a National Instruments Company +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// + + + +module add2_and_round + #(parameter WIDTH=16) + (input [WIDTH-1:0] in1, + input [WIDTH-1:0] in2, + output [WIDTH-1:0] sum); + + wire [WIDTH:0] sum_int = {in1[WIDTH-1],in1} + {in2[WIDTH-1],in2}; + assign sum = sum_int[WIDTH:1] + (sum_int[WIDTH] & sum_int[0]); + +endmodule // add2_and_round diff --git a/fpga/usrp3/lib/dsp/add2_and_round_reg.v b/fpga/usrp3/lib/dsp/add2_and_round_reg.v new file mode 100644 index 000000000..f64acd6ba --- /dev/null +++ b/fpga/usrp3/lib/dsp/add2_and_round_reg.v @@ -0,0 +1,24 @@ +// +// Copyright 2011 Ettus Research LLC +// Copyright 2018 Ettus Research, a National Instruments Company +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// + + + +module add2_and_round_reg + #(parameter WIDTH=16) + (input clk, + input [WIDTH-1:0] in1, + input [WIDTH-1:0] in2, + output reg [WIDTH-1:0] sum); + + wire [WIDTH-1:0] sum_int; + + add2_and_round #(.WIDTH(WIDTH)) add2_n_rnd (.in1(in1),.in2(in2),.sum(sum_int)); + + always @(posedge clk) + sum <= sum_int; + +endmodule // add2_and_round_reg diff --git a/fpga/usrp3/lib/dsp/add2_reg.v b/fpga/usrp3/lib/dsp/add2_reg.v new file mode 100644 index 000000000..44b2ed66e --- /dev/null +++ b/fpga/usrp3/lib/dsp/add2_reg.v @@ -0,0 +1,25 @@ +// +// Copyright 2011 Ettus Research LLC +// Copyright 2018 Ettus Research, a National Instruments Company +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// + + + +module add2_reg + #(parameter WIDTH=16) + (input clk, + input [WIDTH-1:0] in1, + input [WIDTH-1:0] in2, + output reg [WIDTH-1:0] sum); + + wire [WIDTH-1:0] sum_int; + + add2 #(.WIDTH(WIDTH)) add2 (.in1(in1),.in2(in2),.sum(sum_int)); + + always @(posedge clk) + sum <= sum_int; + +endmodule // add2_reg + diff --git a/fpga/usrp3/lib/dsp/add_then_mac.v b/fpga/usrp3/lib/dsp/add_then_mac.v new file mode 100644 index 000000000..b56d9e9d4 --- /dev/null +++ b/fpga/usrp3/lib/dsp/add_then_mac.v @@ -0,0 +1,164 @@ +// +// Copyright 2015 Ettus Research, a National Instruments Company +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// + +`timescale 1 ps / 1 ps + +// +// Implements acc=((a+d)*b)+c or acc=((a+d)*b)+acc' +// + +module add_then_mac + #(parameter DEVICE = "VIRTEX6") + ( + // Output ports + output [47:0] acc, + + // Input ports + input carryin, + input ce, + input clk, + input [17:0] b, + input load, + input [47:0] c, + input [17:0] a, + input [17:0] d, + input rst + ); + + + wire [24:0] a_in; + wire [24:0] d_in; + + localparam AREG_IN = 1; + localparam BREG_IN = 1; + localparam MREG_IN = 1; + localparam PREG_IN = 1; + localparam A1REG_IN = 1; + localparam A0REG_IN = 0; + localparam B1REG_IN = 1; + localparam B0REG_IN = 1; + + // Sign extend inputs + assign a_in = (a[17] == 1'b1) ? {7'hff, a} : {7'h00, a}; + assign d_in = (d[17] == 1'b1) ? {7'hff, d} : {7'h00, d}; + + generate + case(DEVICE) + // begin generate virtex6 + "VIRTEX6", "7SERIES" : + begin + DSP48E1 #( + .ACASCREG(AREG_IN), + .AREG(AREG_IN), + .BCASCREG(BREG_IN), + .BREG(BREG_IN), + .MREG(MREG_IN), + .PREG(PREG_IN), + .USE_DPORT("TRUE") + ) + DSP48E_BL ( + .ACOUT(), + .BCOUT(), + .CARRYCASCOUT(), + .CARRYOUT(), + .MULTSIGNOUT(), + .OVERFLOW(), + .P(acc), + .PATTERNBDETECT(), + .PATTERNDETECT(), + .PCOUT(), + .UNDERFLOW(), + .A({5'b0, a_in[24:0]}), + .ACIN(30'b0), + .ALUMODE(4'b0000), + .B(b[17:0]), + .BCIN(18'b0), + .C(c), + .CARRYCASCIN(1'b0), + .CARRYIN(carryin), + .CARRYINSEL(3'b0), + .CEA1(1'b0), + .CEA2(ce), + .CEAD(ce), + .CEALUMODE(ce), + .CEB1(1'b0), + .CEB2(ce), + .CEC(ce), + .CECARRYIN(ce), + .CECTRL(ce), + .CED(ce), + .CEINMODE(ce), + .CEM(ce), + .CEP(ce), + .CLK(clk), + .D(d_in[24:0]), + .INMODE(5'b00100), + .MULTSIGNIN(1'b0), + .OPMODE({2'b01,load,4'b0101}), + .PCIN(48'b0), + .RSTA(rst), + .RSTALLCARRYIN(rst), + .RSTALUMODE(rst), + .RSTB(rst), + .RSTC(rst), + .RSTCTRL(rst), + .RSTD(rst), + .RSTINMODE(rst), + .RSTM(rst), + .RSTP(rst) + ); + end // end generate virtex6 + // begin generate spartan6 + "SPARTAN6" : + begin + // DSP48A1 has 18b+18b=18b pre-adder, must discard LSB of A and D and compensate by shifting ACC. + wire discard;; + assign acc[0] = 1'b0; + + DSP48A1 #( + .A0REG(A0REG_IN), + .A1REG(A1REG_IN), + .B0REG(B0REG_IN), + .B1REG(B1REG_IN), + .MREG(MREG_IN), + .PREG(PREG_IN) + ) + DSP48AST ( + .BCOUT(), + .CARRYOUT(), + .CARRYOUTF(), + .M(), + .P({discard,acc[47:1]}), + .PCOUT(), + .A(b[17:0]), + .B({a_in[17],a_in[17:1]}), + .C(c), + .CARRYIN(carryin), + .CEA(ce), + .CEB(ce), + .CEC(ce), + .CECARRYIN(ce), + .CED(ce), + .CEM(ce), + .CEOPMODE(ce), + .CEP(ce), + .CLK(clk), + .D({d_in[17],d_in[17:1]}), + .OPMODE({5'b00011,load, 2'b01}), + .PCIN(48'b0), + .RSTA(rst), + .RSTB(rst), + .RSTC(rst), + .RSTCARRYIN(rst), + .RSTD(rst), + .RSTM(rst), + .RSTOPMODE(rst), + .RSTP(rst) + ); + end // end generate spartan6 + endcase + endgenerate +endmodule diff --git a/fpga/usrp3/lib/dsp/cic_dec_shifter.v b/fpga/usrp3/lib/dsp/cic_dec_shifter.v new file mode 100644 index 000000000..f4bab3469 --- /dev/null +++ b/fpga/usrp3/lib/dsp/cic_dec_shifter.v @@ -0,0 +1,96 @@ +// -*- verilog -*- +// +// USRP - Universal Software Radio Peripheral +// +// Copyright (C) 2003 Matt Ettus +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// + +// + + +// NOTE This only works for N=4, max decim rate of 128 +// NOTE signal "rate" is EQUAL TO the actual rate, no more -1 BS + +module cic_dec_shifter(rate,signal_in,signal_out); + parameter bw = 16; + parameter maxbitgain = 28; + + input [7:0] rate; + input wire [bw+maxbitgain-1:0] signal_in; + output reg [bw-1:0] signal_out; + + function [4:0] bitgain; + input [7:0] rate; + case(rate) + // Exact Cases -- N*log2(rate) + 8'd1 : bitgain = 0; + 8'd2 : bitgain = 4; + 8'd4 : bitgain = 8; + 8'd8 : bitgain = 12; + 8'd16 : bitgain = 16; + 8'd32 : bitgain = 20; + 8'd64 : bitgain = 24; + 8'd128 : bitgain = 28; + + // Nearest without overflow -- ceil(N*log2(rate)) + 8'd3 : bitgain = 7; + 8'd5 : bitgain = 10; + 8'd6 : bitgain = 11; + 8'd7 : bitgain = 12; + 8'd9 : bitgain = 13; + 8'd10,8'd11 : bitgain = 14; + 8'd12,8'd13 : bitgain = 15; + 8'd14,8'd15 : bitgain = 16; + 8'd17,8'd18,8'd19 : bitgain = 17; + 8'd20,8'd21,8'd22 : bitgain = 18; + 8'd23,8'd24,8'd25,8'd26 : bitgain = 19; + 8'd27,8'd28,8'd29,8'd30,8'd31 : bitgain = 20; + 8'd33,8'd34,8'd35,8'd36,8'd37,8'd38 : bitgain = 21; + 8'd39,8'd40,8'd41,8'd42,8'd43,8'd44,8'd45 : bitgain = 22; + 8'd46,8'd47,8'd48,8'd49,8'd50,8'd51,8'd52,8'd53 : bitgain = 23; + 8'd54,8'd55,8'd56,8'd57,8'd58,8'd59,8'd60,8'd61,8'd62,8'd63 : bitgain = 24; + 8'd65,8'd66,8'd67,8'd68,8'd69,8'd70,8'd71,8'd72,8'd73,8'd74,8'd75,8'd76 : bitgain = 25; + 8'd77,8'd78,8'd79,8'd80,8'd81,8'd82,8'd83,8'd84,8'd85,8'd86,8'd87,8'd88,8'd89,8'd90 : bitgain = 26; + 8'd91,8'd92,8'd93,8'd94,8'd95,8'd96,8'd97,8'd98,8'd99,8'd100,8'd101,8'd102,8'd103,8'd104,8'd105,8'd106,8'd107 : bitgain = 27; + default : bitgain = 28; + endcase // case(rate) + endfunction // bitgain + + wire [4:0] shift = bitgain(rate); + + // We should be able to do this, but can't .... + // assign signal_out = signal_in[shift+bw-1:shift]; + + always @* + case(shift) + 5'd0 : signal_out = signal_in[0+bw-1:0]; + 5'd4 : signal_out = signal_in[4+bw-1:4]; + 5'd7 : signal_out = signal_in[7+bw-1:7]; + 5'd8 : signal_out = signal_in[8+bw-1:8]; + 5'd10 : signal_out = signal_in[10+bw-1:10]; + 5'd11 : signal_out = signal_in[11+bw-1:11]; + 5'd12 : signal_out = signal_in[12+bw-1:12]; + 5'd13 : signal_out = signal_in[13+bw-1:13]; + 5'd14 : signal_out = signal_in[14+bw-1:14]; + 5'd15 : signal_out = signal_in[15+bw-1:15]; + 5'd16 : signal_out = signal_in[16+bw-1:16]; + 5'd17 : signal_out = signal_in[17+bw-1:17]; + 5'd18 : signal_out = signal_in[18+bw-1:18]; + 5'd19 : signal_out = signal_in[19+bw-1:19]; + 5'd20 : signal_out = signal_in[20+bw-1:20]; + 5'd21 : signal_out = signal_in[21+bw-1:21]; + 5'd22 : signal_out = signal_in[22+bw-1:22]; + 5'd23 : signal_out = signal_in[23+bw-1:23]; + 5'd24 : signal_out = signal_in[24+bw-1:24]; + 5'd25 : signal_out = signal_in[25+bw-1:25]; + 5'd26 : signal_out = signal_in[26+bw-1:26]; + 5'd27 : signal_out = signal_in[27+bw-1:27]; + 5'd28 : signal_out = signal_in[28+bw-1:28]; + + default : signal_out = signal_in[28+bw-1:28]; + endcase // case(shift) + +endmodule // cic_dec_shifter + diff --git a/fpga/usrp3/lib/dsp/cic_decim.v b/fpga/usrp3/lib/dsp/cic_decim.v new file mode 100644 index 000000000..747ef8d99 --- /dev/null +++ b/fpga/usrp3/lib/dsp/cic_decim.v @@ -0,0 +1,78 @@ +// -*- verilog -*- +// +// USRP - Universal Software Radio Peripheral +// +// Copyright (C) 2003 Matt Ettus +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// + +// + + +module cic_decim + #(parameter bw = 16, parameter N = 4, parameter log2_of_max_rate = 7) + (input clock, + input reset, + input enable, + input [7:0] rate, + input strobe_in, + input strobe_out, + input [bw-1:0] signal_in, + output reg [bw-1:0] signal_out); + + localparam maxbitgain = N * log2_of_max_rate; + + wire [bw+maxbitgain-1:0] signal_in_ext; + reg [bw+maxbitgain-1:0] integrator [0:N-1]; + reg [bw+maxbitgain-1:0] differentiator [0:N-1]; + reg [bw+maxbitgain-1:0] pipeline [0:N-1]; + reg [bw+maxbitgain-1:0] sampler; + + integer i; + + sign_extend #(bw,bw+maxbitgain) + ext_input (.in(signal_in),.out(signal_in_ext)); + + always @(posedge clock) + if(~enable) + for(i=0;i<N;i=i+1) + integrator[i] <= 0; + else if (strobe_in) + begin + integrator[0] <= integrator[0] + signal_in_ext; + for(i=1;i<N;i=i+1) + integrator[i] <= integrator[i] + integrator[i-1]; + end + + always @(posedge clock) + if(~enable) + begin + sampler <= 0; + for(i=0;i<N;i=i+1) + begin + pipeline[i] <= 0; + differentiator[i] <= 0; + end + end + else if (strobe_out) + begin + sampler <= integrator[N-1]; + differentiator[0] <= sampler; + pipeline[0] <= sampler - differentiator[0]; + for(i=1;i<N;i=i+1) + begin + differentiator[i] <= pipeline[i-1]; + pipeline[i] <= pipeline[i-1] - differentiator[i]; + end + end // if (enable && strobe_out) + + wire [bw-1:0] signal_out_unreg; + + cic_dec_shifter #(bw) + cic_dec_shifter(rate,pipeline[N-1],signal_out_unreg); + + always @(posedge clock) + signal_out <= signal_out_unreg; + +endmodule // cic_decim diff --git a/fpga/usrp3/lib/dsp/cic_int_shifter.v b/fpga/usrp3/lib/dsp/cic_int_shifter.v new file mode 100644 index 000000000..f18cddf1e --- /dev/null +++ b/fpga/usrp3/lib/dsp/cic_int_shifter.v @@ -0,0 +1,90 @@ +// -*- verilog -*- +// +// USRP - Universal Software Radio Peripheral +// +// Copyright (C) 2003 Matt Ettus +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// + +// + + +// NOTE This only works for N=4, max interp rate of 128 +// NOTE signal "rate" is EQUAL TO the actual rate (no more -1 BS) + +module cic_int_shifter(rate,signal_in,signal_out); + parameter bw = 16; + parameter maxbitgain = 21; + + input [7:0] rate; + input wire [bw+maxbitgain-1:0] signal_in; + output reg [bw-1:0] signal_out; + + function [4:0] bitgain; + input [7:0] rate; + case(rate) + // Exact Cases + 8'd1 : bitgain = 0; + 8'd2 : bitgain = 3; + 8'd4 : bitgain = 6; + 8'd8 : bitgain = 9; + 8'd16 : bitgain = 12; + 8'd32 : bitgain = 15; + 8'd64 : bitgain = 18; + 8'd128 : bitgain = 21; + + // Nearest without overflow + 8'd3 : bitgain = 5; + 8'd5 : bitgain = 7; + 8'd6 : bitgain = 8; + 8'd7 : bitgain = 9; + 8'd9,8'd10 : bitgain = 10; + 8'd11,8'd12 : bitgain = 11; + 8'd13,8'd14,8'd15 : bitgain = 12; + 8'd17,8'd18,8'd19,8'd20 : bitgain = 13; + 8'd21,8'd22,8'd23,8'd24,8'd25 : bitgain = 14; + 8'd26,8'd27,8'd28,8'd29,8'd30,8'd31 : bitgain = 15; + 8'd33,8'd34,8'd35,8'd36,8'd37,8'd38,8'd39,8'd40 : bitgain = 16; + 8'd41,8'd42,8'd43,8'd44,8'd45,8'd46,8'd47,8'd48,8'd49,8'd50 : bitgain = 17; + 8'd51,8'd52,8'd53,8'd54,8'd55,8'd56,8'd57,8'd58,8'd59,8'd60,8'd61,8'd62,8'd63 : bitgain = 18; + 8'd65,8'd66,8'd67,8'd68,8'd69,8'd70,8'd71,8'd72,8'd73,8'd74,8'd75,8'd76,8'd77,8'd78,8'd79,8'd80 : bitgain = 19; + 8'd81,8'd82,8'd83,8'd84,8'd85,8'd86,8'd87,8'd88,8'd89,8'd90,8'd91,8'd92,8'd93,8'd94,8'd95,8'd96,8'd97,8'd98,8'd99,8'd100,8'd101 : bitgain = 20; + + default : bitgain = 21; + endcase // case(rate) + endfunction // bitgain + + wire [4:0] shift = bitgain(rate); + + // We should be able to do this, but can't .... + // assign signal_out = signal_in[shift+bw-1:shift]; + + always @* + case(shift) + 5'd0 : signal_out = signal_in[0+bw-1:0]; + 5'd3 : signal_out = signal_in[3+bw-1:3]; + 5'd6 : signal_out = signal_in[6+bw-1:6]; + 5'd9 : signal_out = signal_in[9+bw-1:9]; + 5'd12 : signal_out = signal_in[12+bw-1:12]; + 5'd15 : signal_out = signal_in[15+bw-1:15]; + 5'd18 : signal_out = signal_in[18+bw-1:18]; + 5'd21 : signal_out = signal_in[21+bw-1:21]; + + 5'd5 : signal_out = signal_in[5+bw-1:5]; + 5'd7 : signal_out = signal_in[7+bw-1:7]; + 5'd8 : signal_out = signal_in[8+bw-1:8]; + 5'd10 : signal_out = signal_in[10+bw-1:10]; + 5'd11 : signal_out = signal_in[11+bw-1:11]; + 5'd13 : signal_out = signal_in[13+bw-1:13]; + 5'd14 : signal_out = signal_in[14+bw-1:14]; + 5'd16 : signal_out = signal_in[16+bw-1:16]; + 5'd17 : signal_out = signal_in[17+bw-1:17]; + 5'd19 : signal_out = signal_in[19+bw-1:19]; + 5'd20 : signal_out = signal_in[20+bw-1:20]; + + default : signal_out = signal_in[21+bw-1:21]; + endcase // case(shift) + +endmodule // cic_int_shifter + diff --git a/fpga/usrp3/lib/dsp/cic_interp.v b/fpga/usrp3/lib/dsp/cic_interp.v new file mode 100644 index 000000000..b0fc74993 --- /dev/null +++ b/fpga/usrp3/lib/dsp/cic_interp.v @@ -0,0 +1,77 @@ +// -*- verilog -*- +// +// USRP - Universal Software Radio Peripheral +// +// Copyright (C) 2003 Matt Ettus +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// + +// + + +module cic_interp + #(parameter bw = 16, parameter N = 4, parameter log2_of_max_rate = 7) + (input clock, + input reset, + input enable, + input [7:0] rate, + input strobe_in, + input strobe_out, + input [bw-1:0] signal_in, + output reg [bw-1:0] signal_out); + + integer i; + localparam maxbitgain = (N-1)*log2_of_max_rate; + + wire [bw+maxbitgain-1:0] signal_in_ext; + reg [bw+maxbitgain-1:0] integrator [0:N-1]; + reg [bw+maxbitgain-1:0] differentiator [0:N-1]; + reg [bw+maxbitgain-1:0] pipeline [0:N-1]; + + sign_extend #(bw,bw+maxbitgain) + ext_input (.in(signal_in),.out(signal_in_ext)); + + //FIXME Note that this section has pipe and diff reversed + // It still works, but is confusing + always @(posedge clock) + if(reset | ~enable) + for(i=0;i<N;i=i+1) + integrator[i] <= 0; + else if (enable & strobe_out) + begin + if(strobe_in) + integrator[0] <= integrator[0] + pipeline[N-1]; + for(i=1;i<N;i=i+1) + integrator[i] <= integrator[i] + integrator[i-1]; + end + + always @(posedge clock) + if(reset | ~enable) + begin + for(i=0;i<N;i=i+1) + begin + differentiator[i] <= 0; + pipeline[i] <= 0; + end + end + else if (enable && strobe_in) + begin + differentiator[0] <= signal_in_ext; + pipeline[0] <= signal_in_ext - differentiator[0]; + for(i=1;i<N;i=i+1) + begin + differentiator[i] <= pipeline[i-1]; + pipeline[i] <= pipeline[i-1] - differentiator[i]; + end + end + + wire [bw-1:0] signal_out_unreg; + cic_int_shifter #(bw) + cic_int_shifter(rate,integrator[N-1],signal_out_unreg); + + always @(posedge clock) + signal_out <= signal_out_unreg; + +endmodule // cic_interp + diff --git a/fpga/usrp3/lib/dsp/cic_strober.v b/fpga/usrp3/lib/dsp/cic_strober.v new file mode 100644 index 000000000..f37b11e6d --- /dev/null +++ b/fpga/usrp3/lib/dsp/cic_strober.v @@ -0,0 +1,35 @@ +// +// USRP2 - Universal Software Radio Peripheral Mk II +// +// Copyright (C) 2008 Matt Ettus +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// + +// + +module cic_strober + #(parameter WIDTH=8) + ( input clock, + input reset, + input enable, + input [WIDTH-1:0] rate, // Rate should EQUAL to your desired divide ratio, no more -1 BS + input strobe_fast, + output wire strobe_slow ); + + reg [WIDTH-1:0] counter; + wire now = (counter==1); + assign strobe_slow = now && enable && strobe_fast; + + always @(posedge clock) + if(reset) + counter <= 0; + else if (~enable) + counter <= rate; + else if(strobe_fast) + if(now) + counter <= rate; + else + counter <= counter - 1; + +endmodule // cic_strober diff --git a/fpga/usrp3/lib/dsp/clip.v b/fpga/usrp3/lib/dsp/clip.v new file mode 100644 index 000000000..e68254e1f --- /dev/null +++ b/fpga/usrp3/lib/dsp/clip.v @@ -0,0 +1,26 @@ +// -*- verilog -*- +// +// USRP - Universal Software Radio Peripheral +// +// Copyright (C) 2008 Matt Ettus +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// + +// + +// Clipping "macro", keeps the bottom bits + +module clip + #(parameter bits_in=0, + parameter bits_out=0) + (input [bits_in-1:0] in, + output [bits_out-1:0] out); + + wire overflow = |in[bits_in-1:bits_out-1] & ~(&in[bits_in-1:bits_out-1]); + assign out = overflow ? + (in[bits_in-1] ? {1'b1,{(bits_out-1){1'b0}}} : {1'b0,{(bits_out-1){1'b1}}}) : + in[bits_out-1:0]; + +endmodule // clip + diff --git a/fpga/usrp3/lib/dsp/clip_reg.v b/fpga/usrp3/lib/dsp/clip_reg.v new file mode 100644 index 000000000..b46491528 --- /dev/null +++ b/fpga/usrp3/lib/dsp/clip_reg.v @@ -0,0 +1,36 @@ +// -*- verilog -*- +// +// USRP - Universal Software Radio Peripheral +// +// Copyright (C) 2008 Matt Ettus +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// + +// + +// Clipping "macro", keeps the bottom bits + +module clip_reg + #(parameter bits_in=0, + parameter bits_out=0, + parameter STROBED=1'b0) + (input clk, + input reset, + input [bits_in-1:0] in, + output reg [bits_out-1:0] out, + input strobe_in, + output reg strobe_out); + + wire [bits_out-1:0] temp; + + clip #(.bits_in(bits_in),.bits_out(bits_out)) clip (.in(in),.out(temp)); + + always @(posedge clk) strobe_out <= reset ? 1'b0 : strobe_in; + + always @(posedge clk) + if(strobe_in | ~STROBED) + out <= temp; + +endmodule // clip_reg + diff --git a/fpga/usrp3/lib/dsp/cordic_stage.v b/fpga/usrp3/lib/dsp/cordic_stage.v new file mode 100644 index 000000000..64ce6ab62 --- /dev/null +++ b/fpga/usrp3/lib/dsp/cordic_stage.v @@ -0,0 +1,50 @@ +// -*- verilog -*- +// +// USRP - Universal Software Radio Peripheral +// +// Copyright (C) 2003 Matt Ettus +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// + +// + +module cordic_stage( clock, reset, enable, xi,yi,zi,constant,xo,yo,zo); + parameter bitwidth = 16; + parameter zwidth = 16; + parameter shift = 1; + + input clock; + input reset; + input enable; + input [bitwidth-1:0] xi,yi; + input [zwidth-1:0] zi; + input [zwidth-1:0] constant; + output [bitwidth-1:0] xo,yo; + output [zwidth-1:0] zo; + + wire z_is_pos = ~zi[zwidth-1]; + + reg [bitwidth-1:0] xo,yo; + reg [zwidth-1:0] zo; + + always @(posedge clock) + if(reset) + begin + xo <= 0; + yo <= 0; + zo <= 0; + end + else //if(enable) + begin + xo <= z_is_pos ? + xi - {{shift+1{yi[bitwidth-1]}},yi[bitwidth-2:shift]} : + xi + {{shift+1{yi[bitwidth-1]}},yi[bitwidth-2:shift]}; + yo <= z_is_pos ? + yi + {{shift+1{xi[bitwidth-1]}},xi[bitwidth-2:shift]} : + yi - {{shift+1{xi[bitwidth-1]}},xi[bitwidth-2:shift]}; + zo <= z_is_pos ? + zi - constant : + zi + constant; + end +endmodule diff --git a/fpga/usrp3/lib/dsp/cordic_z24.v b/fpga/usrp3/lib/dsp/cordic_z24.v new file mode 100644 index 000000000..7eab3478e --- /dev/null +++ b/fpga/usrp3/lib/dsp/cordic_z24.v @@ -0,0 +1,114 @@ +// -*- verilog -*- +// +// USRP - Universal Software Radio Peripheral +// +// Copyright (C) 2003, 2007 Matt Ettus +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// + +// + +module cordic_z24(clock, reset, enable, xi, yi, zi, xo, yo, zo ); + parameter bitwidth = 16; + parameter stages = 19; + localparam zwidth = 24; + + input clock; + input reset; + input enable; + input [bitwidth-1:0] xi, yi; + output [bitwidth-1:0] xo, yo; + input [zwidth-1:0] zi; + output [zwidth-1:0] zo; + + reg [bitwidth+1:0] x0,y0; + reg [zwidth-2:0] z0; + wire [bitwidth+1:0] x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,x11,x12,x13,x14,x15,x16,x17,x18,x19,x20; + wire [bitwidth+1:0] y1,y2,y3,y4,y5,y6,y7,y8,y9,y10,y11,y12,y13,y14,y15,y16,y17,y18,y19,y20; + wire [zwidth-2:0] z1,z2,z3,z4,z5,z6,z7,z8,z9,z10,z11,z12,z13,z14,z15,z16,z17,z18,z19,z20; + + wire [bitwidth+1:0] xi_ext = {{2{xi[bitwidth-1]}},xi}; + wire [bitwidth+1:0] yi_ext = {{2{yi[bitwidth-1]}},yi}; + + // Compute consts. Would be easier if vlog had atan... + // see gen_cordic_consts.py + + // constants for 24 bit wide phase + localparam c00 = 23'd2097152; + localparam c01 = 23'd1238021; + localparam c02 = 23'd654136; + localparam c03 = 23'd332050; + localparam c04 = 23'd166669; + localparam c05 = 23'd83416; + localparam c06 = 23'd41718; + localparam c07 = 23'd20860; + localparam c08 = 23'd10430; + localparam c09 = 23'd5215; + localparam c10 = 23'd2608; + localparam c11 = 23'd1304; + localparam c12 = 23'd652; + localparam c13 = 23'd326; + localparam c14 = 23'd163; + localparam c15 = 23'd81; + localparam c16 = 23'd41; + localparam c17 = 23'd20; + localparam c18 = 23'd10; + localparam c19 = 23'd5; + localparam c20 = 23'd3; + localparam c21 = 23'd1; + localparam c22 = 23'd1; + localparam c23 = 23'd0; + + always @(posedge clock) + if(reset) + begin + x0 <= 0; y0 <= 0; z0 <= 0; + end + else// if(enable) + begin + z0 <= zi[zwidth-2:0]; + case (zi[zwidth-1:zwidth-2]) + 2'b00, 2'b11 : + begin + x0 <= xi_ext; + y0 <= yi_ext; + end + 2'b01, 2'b10 : + begin + x0 <= -xi_ext; + y0 <= -yi_ext; + end + endcase // case(zi[zwidth-1:zwidth-2]) + end // else: !if(reset) + + // FIXME need to handle variable number of stages + // This would be easier if arrays worked better in vlog... + + cordic_stage #(bitwidth+2,zwidth-1,0) cordic_stage0 (clock,reset,enable,x0,y0,z0,c00,x1,y1,z1); + cordic_stage #(bitwidth+2,zwidth-1,1) cordic_stage1 (clock,reset,enable,x1,y1,z1,c01,x2,y2,z2); + cordic_stage #(bitwidth+2,zwidth-1,2) cordic_stage2 (clock,reset,enable,x2,y2,z2,c02,x3,y3,z3); + cordic_stage #(bitwidth+2,zwidth-1,3) cordic_stage3 (clock,reset,enable,x3,y3,z3,c03,x4,y4,z4); + cordic_stage #(bitwidth+2,zwidth-1,4) cordic_stage4 (clock,reset,enable,x4,y4,z4,c04,x5,y5,z5); + cordic_stage #(bitwidth+2,zwidth-1,5) cordic_stage5 (clock,reset,enable,x5,y5,z5,c05,x6,y6,z6); + cordic_stage #(bitwidth+2,zwidth-1,6) cordic_stage6 (clock,reset,enable,x6,y6,z6,c06,x7,y7,z7); + cordic_stage #(bitwidth+2,zwidth-1,7) cordic_stage7 (clock,reset,enable,x7,y7,z7,c07,x8,y8,z8); + cordic_stage #(bitwidth+2,zwidth-1,8) cordic_stage8 (clock,reset,enable,x8,y8,z8,c08,x9,y9,z9); + cordic_stage #(bitwidth+2,zwidth-1,9) cordic_stage9 (clock,reset,enable,x9,y9,z9,c09,x10,y10,z10); + cordic_stage #(bitwidth+2,zwidth-1,10) cordic_stage10 (clock,reset,enable,x10,y10,z10,c10,x11,y11,z11); + cordic_stage #(bitwidth+2,zwidth-1,11) cordic_stage11 (clock,reset,enable,x11,y11,z11,c11,x12,y12,z12); + cordic_stage #(bitwidth+2,zwidth-1,12) cordic_stage12 (clock,reset,enable,x12,y12,z12,c12,x13,y13,z13); + cordic_stage #(bitwidth+2,zwidth-1,13) cordic_stage13 (clock,reset,enable,x13,y13,z13,c13,x14,y14,z14); + cordic_stage #(bitwidth+2,zwidth-1,14) cordic_stage14 (clock,reset,enable,x14,y14,z14,c14,x15,y15,z15); + cordic_stage #(bitwidth+2,zwidth-1,15) cordic_stage15 (clock,reset,enable,x15,y15,z15,c15,x16,y16,z16); + cordic_stage #(bitwidth+2,zwidth-1,16) cordic_stage16 (clock,reset,enable,x16,y16,z16,c16,x17,y17,z17); + cordic_stage #(bitwidth+2,zwidth-1,17) cordic_stage17 (clock,reset,enable,x17,y17,z17,c17,x18,y18,z18); + cordic_stage #(bitwidth+2,zwidth-1,18) cordic_stage18 (clock,reset,enable,x18,y18,z18,c18,x19,y19,z19); + cordic_stage #(bitwidth+2,zwidth-1,19) cordic_stage19 (clock,reset,enable,x19,y19,z19,c19,x20,y20,z20); + + assign xo = x20[bitwidth:1]; + assign yo = y20[bitwidth:1]; + assign zo = z20; + +endmodule // cordic + diff --git a/fpga/usrp3/lib/dsp/ddc_chain.v b/fpga/usrp3/lib/dsp/ddc_chain.v new file mode 100644 index 000000000..9c25d8e43 --- /dev/null +++ b/fpga/usrp3/lib/dsp/ddc_chain.v @@ -0,0 +1,375 @@ +// +// Copyright 2011-2013 Ettus Research LLC +// Copyright 2018 Ettus Research, a National Instruments Company +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// + + +//! The USRP digital down-conversion chain + +module ddc_chain + #( + parameter BASE = 0, + parameter DSPNO = 0, + parameter WIDTH = 24, + parameter NEW_HB_DECIM = 0, + parameter DEVICE = "SPARTAN6" + ) + (input clk, input rst, input clr, + input set_stb, input [7:0] set_addr, input [31:0] set_data, + + // 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 [31:0] phase_inc; + reg [31:0] phase; + + wire [17:0] scale_factor; + wire [cwidth-1:0] to_cordic_i, to_cordic_q; + wire [cwidth-1:0] i_cordic, q_cordic; + reg [WIDTH-1:0] i_cordic_pipe, q_cordic_pipe; + wire [WIDTH-1:0] i_cic, q_cic; + + + 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; + wire invert_i; + wire invert_q; + + 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(4)) sr_3 + (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr), + .in(set_data),.out({invert_i,invert_q,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 <= invert_i ? ~rx_fe_q : rx_fe_q; + rx_fe_q_mux <= realmode ? {WIDTH{1'b0}} : invert_q ? ~rx_fe_i : rx_fe_i; + end + else + begin + rx_fe_i_mux <= invert_i ? ~rx_fe_i : rx_fe_i; + rx_fe_q_mux <= realmode ? {WIDTH{1'b0}} : invert_q ? ~rx_fe_q : rx_fe_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 + // (Algorithmic gain through CORDIC => 1.647 * 0.5 = 0.8235) + // (Worst case gain through rotation => SQRT(2) = 1.4142) + // Total worst case gain => 0.8235 * 1.4142 = 1.1646 + // So add an extra MSB bit for word growth. + + sign_extend #(.bits_in(WIDTH), .bits_out(cwidth)) sign_extend_cordic_i (.in(rx_fe_i_mux), .out(to_cordic_i)); + sign_extend #(.bits_in(WIDTH), .bits_out(cwidth)) sign_extend_cordic_q (.in(rx_fe_q_mux), .out(to_cordic_q)); + + cordic_z24 #(.bitwidth(cwidth)) + cordic(.clock(clk), .reset(rst), .enable(run), + .xi(to_cordic_i),. yi(to_cordic_q), .zi(phase[31:32-zwidth]), + .xo(i_cordic),.yo(q_cordic),.zo() ); + + always @(posedge clk) begin + i_cordic_pipe[23:0] <= i_cordic[24:1]; + q_cordic_pipe[23:0] <= q_cordic[24:1]; + end + + + // CIC decimator 24 bit I/O + // Applies crude 1/(2^N) right shift gain compensation internally to prevent excesive downstream word growth. + // Output gain is = algo_gain/(POW(2,CEIL(LOG2(algo_gain))) where algo_gain is = cic_decim_rate^4 + // Thus output gain is <= 1.0 and no word growth occurs. + cic_strober cic_strober(.clock(clk),.reset(rst),.enable(run),.rate(cic_decim_rate), + .strobe_fast(1'b1),.strobe_slow(strobe_cic) ); + + cic_decim #(.bw(WIDTH)) + decim_i (.clock(clk),.reset(rst),.enable(run), + .rate(cic_decim_rate),.strobe_in(1'b1),.strobe_out(strobe_cic), + .signal_in(i_cordic_pipe),.signal_out(i_cic)); + + cic_decim #(.bw(WIDTH)) + decim_q (.clock(clk),.reset(rst),.enable(run), + .rate(cic_decim_rate),.strobe_in(1'b1),.strobe_out(strobe_cic), + .signal_in(q_cordic_pipe),.signal_out(q_cic)); + + ////////////////////////////////////////////////////////////////////////// + // + // Conditional compilation of either: + // 1) New X300 style decimation filters, or + // 2) Traditional N210 style decimation filters. + // + ////////////////////////////////////////////////////////////////////////// + generate + if (NEW_HB_DECIM == 1) begin: new_hb + + wire reload_go, reload_we1, reload_we2, reload_ld1, reload_ld2; + wire [17:0] coef_din; + + setting_reg #(.my_addr(BASE+4), .width(22)) sr_4 + (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr), + .in(set_data),.out({reload_ld2,reload_we2,reload_ld1,reload_we1,coef_din[17:0]}),.changed(reload_go)); + + // Halfbands + wire nd1, nd2, nd3; + wire rfd1, rfd2, rfd3; + wire rdy1, rdy2, rdy3; + wire data_valid1, data_valid2, data_valid3; + wire [46:0] i_hb1, q_hb1; + wire [46:0] i_hb2, q_hb2; + localparam HB1_SCALE = 18; + localparam HB2_SCALE = 18; + + + assign strobe_hb1 = data_valid1; + assign strobe_hb2 = data_valid2; + + assign nd1 = strobe_cic; + assign nd2 = strobe_hb1; + + // Default Coeffs have gain of ~1.0 + hbdec1 hbdec1 + (.clk(clk), // input clk + .sclr(rst), // input sclr + .ce(enable_hb1), // input ce + .coef_ld(reload_go & reload_ld1), // input coef_ld + .coef_we(reload_go & reload_we1), // input coef_we + .coef_din(coef_din), // input [17 : 0] coef_din + .rfd(rfd1), // output rfd + .nd(nd1), // input nd + .din_1(i_cic), // input [23 : 0] din_1 + .din_2(q_cic), // input [23 : 0] din_2 + .rdy(rdy1), // output rdy + .data_valid(data_valid1), // output data_valid + .dout_1(i_hb1), // output [46 : 0] dout_1 + .dout_2(q_hb1)); // output [46 : 0] dout_2 + + // Default Coeffs have gain of ~1.0 + hbdec2 hbdec2 + (.clk(clk), // input clk + .sclr(rst), // input sclr + .ce(enable_hb2), // input ce + .coef_ld(reload_go & reload_ld2), // input coef_ld + .coef_we(reload_go & reload_we2), // input coef_we + .coef_din(coef_din), // input [17 : 0] coef_din + .rfd(rfd2), // output rfd + .nd(nd2), // input nd + .din_1(i_hb1[23+HB1_SCALE:HB1_SCALE]), // input [23 : 0] din_1 + .din_2(q_hb1[23+HB1_SCALE:HB1_SCALE]), // input [23 : 0] din_2 + .rdy(rdy2), // output rdy + .data_valid(data_valid2), // output data_valid + .dout_1(i_hb2), // output [46 : 0] dout_1 + .dout_2(q_hb2)); // output [46 : 0] dout_2 + + + + reg [18:0] i_unscaled, q_unscaled; + reg strobe_unscaled; + + always @(posedge clk) + case({enable_hb1,enable_hb2}) + // No Halfbands enabled, no decimation. + 2'd0 : + begin + strobe_unscaled <= strobe_cic; + i_unscaled <= i_cic[23:5]; + q_unscaled <= q_cic[23:5]; + end + // ILLEGAL. Only half sample rate half band enabled. + 2'd1 : + begin + strobe_unscaled <= strobe_cic; + i_unscaled <= i_cic[23:5]; + q_unscaled <= q_cic[23:5]; + end + // One Halfband enabled, decimate by 2. + 2'd2 : + begin + strobe_unscaled <= strobe_hb1; + i_unscaled <= i_hb1[23+HB1_SCALE:5+HB1_SCALE]; + q_unscaled <= q_hb1[23+HB1_SCALE:5+HB1_SCALE]; + end + // Both Halfbands enabled, decimate by 4. + 2'd3 : + begin + strobe_unscaled <= strobe_hb2; + i_unscaled <= i_hb2[23+HB2_SCALE:5+HB2_SCALE]; + q_unscaled <= q_hb2[23+HB2_SCALE:5+HB2_SCALE]; + end + endcase // case (hb_rate) + + // Need to clip 1 bit here or we loose small signal performance out the truncated LSB's for worst case CIC gain cases. + // NOTE: We can only clip here with CORDIC rotating, CIC in it's highest gain configurations and an input signal thats + // saturated. + wire strobe_unscaled_clip; + wire [17:0] i_unscaled_clip, q_unscaled_clip; + + clip_reg #(.bits_in(19), .bits_out(18), .STROBED(1)) unscaled_clip_i + (.clk(clk), .in(i_unscaled[18:0]), .strobe_in(strobe_unscaled), .out(i_unscaled_clip[17:0]), .strobe_out(strobe_unscaled_clip)); + clip_reg #(.bits_in(19), .bits_out(18), .STROBED(1)) unscaled_clip_q + (.clk(clk), .in(q_unscaled[18:0]), .strobe_in(strobe_unscaled), .out(q_unscaled_clip[17:0]), .strobe_out()); + + // Apply scaling gain to compensate for CORDIC and CIC gain adjustments so that signal swing over network transport has + // optimal dynamic range. + wire [35:0] prod_i, prod_q; + + MULT_MACRO #(.DEVICE(DEVICE), // Target Device: "VIRTEX5", "VIRTEX6", "SPARTAN6","7SERIES" + .LATENCY(1), // Desired clock cycle latency, 0-4 + .WIDTH_A(18), // Multiplier A-input bus width, 1-25 + .WIDTH_B(18)) // Multiplier B-input bus width, 1-18 + mult_i (.P(prod_i), // Multiplier output bus, width determined by WIDTH_P parameter + .A(i_unscaled_clip), // Multiplier input A bus, width determined by WIDTH_A parameter + .B(scale_factor), // Multiplier input B bus, width determined by WIDTH_B parameter + .CE(strobe_unscaled_clip), // 1-bit active high input clock enable + .CLK(clk), // 1-bit positive edge clock input + .RST(rst)); // 1-bit input active high reset + + MULT_MACRO #(.DEVICE(DEVICE), // Target Device: "VIRTEX5", "VIRTEX6", "SPARTAN6","7SERIES" + .LATENCY(1), // Desired clock cycle latency, 0-4 + .WIDTH_A(18), // Multiplier A-input bus width, 1-25 + .WIDTH_B(18)) // Multiplier B-input bus width, 1-18 + mult_q (.P(prod_q), // Multiplier output bus, width determined by WIDTH_P parameter + .A(q_unscaled_clip), // Multiplier input A bus, width determined by WIDTH_A parameter + .B(scale_factor), // Multiplier input B bus, width determined by WIDTH_B parameter + .CE(strobe_unscaled_clip), // 1-bit active high input clock enable + .CLK(clk), // 1-bit positive edge clock input + .RST(rst)); // 1-bit input active high reset + + reg strobe_scaled; + wire strobe_clip; + wire [32:0] i_clip, q_clip; + + always @(posedge clk) strobe_scaled <= strobe_unscaled_clip; + + clip_reg #(.bits_in(36), .bits_out(33), .STROBED(1)) clip_i + (.clk(clk), .in(prod_i[35:0]), .strobe_in(strobe_scaled), .out(i_clip), .strobe_out(strobe_clip)); + clip_reg #(.bits_in(36), .bits_out(33), .STROBED(1)) clip_q + (.clk(clk), .in(prod_q[35:0]), .strobe_in(strobe_scaled), .out(q_clip), .strobe_out()); + + round_sd #(.WIDTH_IN(33), .WIDTH_OUT(16)) round_i + (.clk(clk), .reset(rst), .in(i_clip), .strobe_in(strobe_clip), .out(sample[31:16]), .strobe_out(strobe)); + round_sd #(.WIDTH_IN(33), .WIDTH_OUT(16)) round_q + (.clk(clk), .reset(rst), .in(q_clip), .strobe_in(strobe_clip), .out(sample[15:0]), .strobe_out()); + + end else begin: old_hb // block: new_hb + /////////////////////////////////////////////// + // + // Legacy Decimation Filters from USRP2 + // + /////////////////////////////////////////////// + wire [WIDTH-1:0] i_hb1, q_hb1; + wire [WIDTH-1:0] i_hb2, q_hb2; + // First (small) halfband 24 bit I/O + small_hb_dec #(.WIDTH(WIDTH),.DEVICE(DEVICE)) 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(WIDTH),.DEVICE(DEVICE)) 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(WIDTH),.DEVICE(DEVICE)) 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(WIDTH),.DEVICE(DEVICE)) 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)); + + // Need to clip 1 bit here or we loose small signal performance out the truncated LSB's for worst case CIC gain cases. + wire strobe_unscaled_clip; + wire [17:0] i_unscaled_clip, q_unscaled_clip; + + clip_reg #(.bits_in(19), .bits_out(18), .STROBED(1)) unscaled_clip_i + (.clk(clk), .in(i_hb2[WIDTH-1:WIDTH-19]), .strobe_in(strobe_hb2), .out(i_unscaled_clip[17:0]), .strobe_out(strobe_unscaled_clip)); + clip_reg #(.bits_in(19), .bits_out(18), .STROBED(1)) unscaled_clip_q + (.clk(clk), .in(q_hb2[WIDTH-1:WIDTH-19]), .strobe_in(strobe_hb2), .out(q_unscaled_clip[17:0]), .strobe_out()); + + //scalar operation (gain of 6 bits) + wire [35:0] prod_i, prod_q; + + MULT_MACRO #(.DEVICE(DEVICE), // Target Device: "VIRTEX5", "VIRTEX6", "SPARTAN6","7SERIES" + .LATENCY(1), // Desired clock cycle latency, 0-4 + .WIDTH_A(18), // Multiplier A-input bus width, 1-25 + .WIDTH_B(18)) // Multiplier B-input bus width, 1-18 + mult_i (.P(prod_i), // Multiplier output bus, width determined by WIDTH_P parameter + .A(i_unscaled_clip),// Multiplier input A bus, width determined by WIDTH_A parameter + .B(scale_factor), // Multiplier input B bus, width determined by WIDTH_B parameter + .CE(strobe_unscaled_clip), // 1-bit active high input clock enable + .CLK(clk), // 1-bit positive edge clock input + .RST(rst)); // 1-bit input active high reset + + MULT_MACRO #(.DEVICE(DEVICE), // Target Device: "VIRTEX5", "VIRTEX6", "SPARTAN6","7SERIES" + .LATENCY(1), // Desired clock cycle latency, 0-4 + .WIDTH_A(18), // Multiplier A-input bus width, 1-25 + .WIDTH_B(18)) // Multiplier B-input bus width, 1-18 + mult_q (.P(prod_q), // Multiplier output bus, width determined by WIDTH_P parameter + .A(q_unscaled_clip),// Multiplier input A bus, width determined by WIDTH_A parameter + .B(scale_factor), // Multiplier input B bus, width determined by WIDTH_B parameter + .CE(strobe_unscaled_clip), // 1-bit active high input clock enable + .CLK(clk), // 1-bit positive edge clock input + .RST(rst)); // 1-bit input active high reset + + reg strobe_scaled; + wire strobe_clip; + wire [32:0] i_clip, q_clip; + + always @(posedge clk) strobe_scaled <= strobe_unscaled_clip; + + clip_reg #(.bits_in(36), .bits_out(33), .STROBED(1)) clip_i + (.clk(clk), .in(prod_i[35:0]), .strobe_in(strobe_scaled), .out(i_clip), .strobe_out(strobe_clip)); + clip_reg #(.bits_in(36), .bits_out(33), .STROBED(1)) clip_q + (.clk(clk), .in(prod_q[35:0]), .strobe_in(strobe_scaled), .out(q_clip), .strobe_out()); + + round_sd #(.WIDTH_IN(33), .WIDTH_OUT(16)) round_i + (.clk(clk), .reset(rst), .in(i_clip), .strobe_in(strobe_clip), .out(sample[31:16]), .strobe_out(strobe)); + round_sd #(.WIDTH_IN(33), .WIDTH_OUT(16)) round_q + (.clk(clk), .reset(rst), .in(q_clip), .strobe_in(strobe_clip), .out(sample[15:0]), .strobe_out()); + + end // block: old_hb + endgenerate + + + + assign debug = {enable_hb1, enable_hb2, run, strobe, strobe_cic, strobe_hb1, strobe_hb2}; + +endmodule // ddc_chain diff --git a/fpga/usrp3/lib/dsp/duc_chain.v b/fpga/usrp3/lib/dsp/duc_chain.v new file mode 100644 index 000000000..44931318c --- /dev/null +++ b/fpga/usrp3/lib/dsp/duc_chain.v @@ -0,0 +1,244 @@ +// +// Copyright 2011-2013 Ettus Research LLC +// Copyright 2018 Ettus Research, a National Instruments Company +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// + + +//! The USRP digital up-conversion chain + +module duc_chain + #( + parameter BASE = 0, + parameter DSPNO = 0, + parameter WIDTH = 24, + parameter NEW_HB_INTERP = 0, + parameter DEVICE = "7SERIES" + ) + (input clk, input rst, input clr, + input set_stb, input [7:0] set_addr, input [31:0] set_data, + + // To TX frontend + output [WIDTH-1:0] tx_fe_i, + output [WIDTH-1:0] tx_fe_q, + + // From TX control + input [31:0] sample, + input run, + output strobe, + output [31:0] debug + ); + + genvar i; + + + wire [17:0] scale_factor; + wire [31:0] phase_inc; + reg [31:0] phase; + wire [7:0] interp_rate; + wire [3:0] tx_femux_a, tx_femux_b; + wire enable_hb1, enable_hb2; + wire rate_change; + + 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, interp_rate}),.changed(rate_change)); + + // Strobes are all now delayed by 1 cycle for timing reasons + wire strobe_cic_pre, strobe_hb1_pre, strobe_hb2_pre; + reg strobe_cic = 1; + reg strobe_hb1 = 1; + reg strobe_hb2 = 1; + + assign strobe = strobe_hb1; + + cic_strober #(.WIDTH(8)) + cic_strober(.clock(clk),.reset(rst),.enable(run & ~rate_change),.rate(interp_rate), + .strobe_fast(1'b1),.strobe_slow(strobe_cic_pre) ); + cic_strober #(.WIDTH(2)) + hb2_strober(.clock(clk),.reset(rst),.enable(run & ~rate_change),.rate(enable_hb2 ? 2'd2 : 2'd1), + .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'd2 : 2'd1), + .strobe_fast(strobe_hb2_pre),.strobe_slow(strobe_hb1_pre) ); + + always @(posedge clk) strobe_hb1 <= strobe_hb1_pre; + always @(posedge clk) strobe_hb2 <= strobe_hb2_pre; + always @(posedge clk) strobe_cic <= strobe_cic_pre; + + // NCO + always @(posedge clk) + if(rst) + phase <= 0; + else if(~run) + phase <= 0; + else + phase <= phase + phase_inc; + + wire signed [17:0] da, db; + wire signed [35:0] prod_i, prod_q; + + wire [17:0] i_interp, q_interp; + + wire [17:0] hb1_i, hb1_q, hb2_i, hb2_q; + + wire [7:0] cpo = enable_hb2 ? ({interp_rate,1'b0}) : interp_rate; + // 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 + generate + if (NEW_HB_INTERP == 1) begin: new_hb + // First stage of halfband interpolation filters. These run at a max CPO of 2 when CIC is bypassed and HB2 enabled. + hb47_int + #(.WIDTH(18), + .DEVICE(DEVICE)) + hb1_i0 + ( + .clk(clk), + .rst(rst), + .bypass(~enable_hb1), + .stb_in(strobe_hb1), + .data_in({sample[31:16],2'b00}), + .output_rate(cpo), + .stb_out(strobe_hb2), + .data_out(hb1_i) + ); + + hb47_int + #(.WIDTH(18), + .DEVICE(DEVICE)) + hb1_q0 + ( + .clk(clk), + .rst(rst), + .bypass(~enable_hb1), + .stb_in(strobe_hb1), + .data_in({sample[15:0],2'b00}), + .output_rate(cpo), + .stb_out(strobe_hb2), + .data_out(hb1_q) + ); + + // Second stage of halfband interpolation filters. These run at a max CPO of 1 when CIC is bypassed. + hb47_int + #(.WIDTH(18), + .DEVICE(DEVICE)) + hb2_i0 + ( + .clk(clk), + .rst(rst), + .bypass(~enable_hb2), + .stb_in(strobe_hb2), + .data_in(hb1_i), + .output_rate(interp_rate), + .stb_out(strobe_cic), + .data_out(hb2_i) + ); + + hb47_int + #(.WIDTH(18), + .DEVICE(DEVICE)) + hb2_q0 + ( + .clk(clk), + .rst(rst), + .bypass(~enable_hb2), + .stb_in(strobe_hb2), + .data_in(hb1_q), + .output_rate(interp_rate), + .stb_out(strobe_cic), + .data_out(hb2_q) + ); + + end else begin: old_hb + + 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({sample[31:16], 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({sample[15:0], 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), + .output_rate(interp_rate),.stb_out(strobe_cic),.data_out(hb2_i)); + small_hb_int #(.WIDTH(18)) small_hb_interp_q + (.clk(clk),.rst(rst),.bypass(~enable_hb2),.stb_in(strobe_hb2),.data_in(hb1_q), + .output_rate(interp_rate),.stb_out(strobe_cic),.data_out(hb2_q)); + + end // block: old_hb + endgenerate + + 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), + .strobe_in(strobe_cic),.strobe_out(1'd1), + .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), + .strobe_in(strobe_cic),.strobe_out(1'd1), + .signal_in(hb2_q),.signal_out(q_interp)); + + localparam cwidth = WIDTH; // was 18 + localparam zwidth = 24; // was 16 + + wire [cwidth-1:0] da_c, db_c; + // + // Note. No head room has been added to the CORDIC to accomodate gain in excess of the input signals dynamic range. + // The CORDIC has algorithmic gain of 1.647, implementation gain of 0.5 and potential gain associated with rotation of 1.414. + // Thus the CORDIC will overflow when rotating and an input CW with (clipped) effective amplitude of 1.22 is applied. + // + cordic_z24 #(.bitwidth(cwidth)) + cordic(.clock(clk), .reset(rst), .enable(run), + .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() ); + + MULT_MACRO #(.DEVICE(DEVICE), // Target Device: "VIRTEX5", "VIRTEX6", "SPARTAN6","7SERIES" + .LATENCY(1), // Desired clock cycle latency, 0-4 + .WIDTH_A(18), // Multiplier A-input bus width, 1-25 + .WIDTH_B(18)) // Multiplier B-input bus width, 1-18 + mult_i (.P(prod_i), // Multiplier output bus, width determined by WIDTH_P parameter + .A(da_c[cwidth-1:cwidth-18]),// Multiplier input A bus, width determined by WIDTH_A parameter + .B(scale_factor), // Multiplier input B bus, width determined by WIDTH_B parameter + .CE(1'b1), // 1-bit active high input clock enable + .CLK(clk), // 1-bit positive edge clock input + .RST(rst)); // 1-bit input active high reset + + MULT_MACRO #(.DEVICE(DEVICE), // Target Device: "VIRTEX5", "VIRTEX6", "SPARTAN6","7SERIES" + .LATENCY(1), // Desired clock cycle latency, 0-4 + .WIDTH_A(18), // Multiplier A-input bus width, 1-25 + .WIDTH_B(18)) // Multiplier B-input bus width, 1-18 + mult_q (.P(prod_q), // Multiplier output bus, width determined by WIDTH_P parameter + .A(db_c[cwidth-1:cwidth-18]),// Multiplier input A bus, width determined by WIDTH_A parameter + .B(scale_factor), // Multiplier input B bus, width determined by WIDTH_B parameter + .CE(1'b1), // 1-bit active high input clock enable + .CLK(clk), // 1-bit positive edge clock input + .RST(rst)); // 1-bit input active high reset + + + wire [32:0] i_clip, q_clip; + + // Cordic rotation coupled with a saturated input signal can cause overflow + // so we clip here rather than allow a wrap. + clip_reg #(.bits_in(36), .bits_out(33), .STROBED(1)) clip_i + (.clk(clk), .in(prod_i[35:0]), .strobe_in(1'b1), .out(i_clip), .strobe_out()); + clip_reg #(.bits_in(36), .bits_out(33), .STROBED(1)) clip_q + (.clk(clk), .in(prod_q[35:0]), .strobe_in(1'b1), .out(q_clip), .strobe_out()); + + assign tx_fe_i = i_clip[32:33-WIDTH]; + assign tx_fe_q = q_clip[32:33-WIDTH]; + + + // + // Debug + // + assign debug = {strobe_cic, strobe_hb1, strobe_hb2,run}; + +endmodule // duc_chain diff --git a/fpga/usrp3/lib/dsp/hb47_int.v b/fpga/usrp3/lib/dsp/hb47_int.v new file mode 100644 index 000000000..3f69952cc --- /dev/null +++ b/fpga/usrp3/lib/dsp/hb47_int.v @@ -0,0 +1,180 @@ +// +// Copyright 2011-2014 Ettus Research LLC +// Copyright 2018 Ettus Research, a National Instruments Company +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// 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 hb47_int + #(parameter WIDTH=18, + parameter DEVICE="7SERIES") + (input clk, + input rst, + input bypass, + input stb_in, + input [WIDTH-1:0] data_in, + input [7:0] output_rate, + input stb_out, + output reg [WIDTH-1:0] data_out); + + // Input data Pipeline + reg [WIDTH-1:0] data_in_pipe[0:23]; + + reg stb_pipe0, stb_pipe1, stb_pipe2, stb_pipe3, stb_pipe4 ; + reg stb_pipe5, stb_pipe6, stb_pipe7, stb_pipe8, stb_pipe9 ; + wire [WIDTH-1:0] sample_a[0:5], sample_b[0:5]; + wire [17:0] coeff[0:5]; + wire [47:0] accumulator_out[0:5]; + reg [47:0] partial_result_a, partial_result_b; + reg [47:0] result; + + + // Implicit coeff23 of 131071 + wire [17:0] coeff_a[0:5]; + wire [17:0] coeff_b[0:5]; + + assign coeff_a[0] = -62; + assign coeff_b[0] = 194; + assign coeff_a[1] = -440; + assign coeff_b[1] = 855; + assign coeff_a[2] = -1505; + assign coeff_b[2] = 2478; + assign coeff_a[3] = -3900; + assign coeff_b[3] = 5990; + assign coeff_a[4] = -9187; + assign coeff_b[4] = 14632; + assign coeff_a[5] = -26536; + assign coeff_b[5] = 83009; + + genvar i; + + always @(posedge clk) + if (rst) + data_in_pipe[0] <= 18'h0; + else if (stb_in) + data_in_pipe[0] <= data_in; + + generate + for (i=0; i<23; i=i+1) begin: sample_pipeline + always @(posedge clk) if (rst) + data_in_pipe[i+1] <= 0; + else if (stb_in) + data_in_pipe[i+1] <= data_in_pipe[i]; + end + endgenerate + + generate + for (i=0; i<6; i=i+1) begin: filter_core + + assign sample_a[i] = stb_pipe0 ? data_in_pipe[(i*2)] : data_in_pipe[(2*i)+1]; + assign sample_b[i] = stb_pipe0 ? data_in_pipe[23-(i*2)] : data_in_pipe[23-(2*i)-1]; + // Coeffs are 1 pipeline downstream of sample input + assign coeff[i] = stb_pipe1 ? coeff_a[i] : coeff_b[i]; + + add_then_mac + #(.DEVICE(DEVICE)) + add_then_mac_i + ( + .acc(accumulator_out[i]), + .carryin(1'b0), + .ce(1'b1), + .clk(clk), + .b(coeff[i]), + .load(stb_pipe2), + .c(48'h0), + .a(sample_a[i]), + .d(sample_b[i]), + .rst(rst) + ); + + end // block: filter_core + endgenerate + + // + // Dual 3:1 compressors + // + always @(posedge clk) if (stb_pipe5) begin + partial_result_a[47:0] <= accumulator_out[0] + accumulator_out[1] + accumulator_out[2]; + partial_result_b[47:0] <= accumulator_out[3] + accumulator_out[4] + accumulator_out[5]; + end + + // + // Final Result Adder + // + always @(posedge clk) if (stb_pipe6) begin + result[47:0] <= partial_result_a[47:0] + partial_result_b[47:0]; + end + + // + // Now round unneed precision from accumulator result, and clip the unused dynamic range + // + wire [47:17] result_rnd; + round_reg #(.bits_in(48),.bits_out(31)) + final_round (.clk(clk),.in(result[47:0]),.out(result_rnd[47:17]),.err()); + + wire [34:17] result_clip; + clip_reg #(.bits_in(31),.bits_out(18)) final_clip + (.clk(clk),.in(result_rnd[47:17]),.strobe_in(1'b1), .out(result_clip[34:17]), .strobe_out()); + + // + // Data enters the sample pipeline when stb_in is asserted. + // The clock cycle after is phase=0 with pipeline delay=0 + // + always @(posedge clk) + if (rst) begin + stb_pipe0 <= 1'b0; // New sample loaded into sample pipeline, setup on reg a + stb_pipe1 <= 1'b0; // Sample n+0 presented to pre-adder, result to reg ad, coeff_a setup on input reg b + stb_pipe2 <= 1'b0; // Sample n+1 presented to pre-adder, product of sample n+0 and coeff_a setup on reg m + stb_pipe3 <= 1'b0; // product of sample n+1 and coeff_b setup on reg m, previous product loaded into accumulator. + stb_pipe4 <= 1'b0; // Add both products into accumulator + stb_pipe5 <= 1'b0; // Add 3 accumulator values into one partial result + stb_pipe6 <= 1'b0; // Add both partial results into final full precision result. + stb_pipe7 <= 1'b0; // Round result + stb_pipe8 <= 1'b0; // Clip Result + stb_pipe9 <= 1'b0; + + end else begin + stb_pipe0 <= stb_in; // New sample loaded into sample pipeline, setup on reg a + stb_pipe1 <= stb_pipe0; // Sample n+0 presented to pre-adder, result to reg ad, coeff_a setup on input reg b + stb_pipe2 <= stb_pipe1; // Sample n+1 presented to pre-adder, product of sample n+0 and coeff_a setup on reg m + stb_pipe3 <= stb_pipe2; // product of sample n+1 and coeff_b setup on reg m, previous product loaded into accumulator. + stb_pipe4 <= stb_pipe3; // Add both products into accumulator + stb_pipe5 <= stb_pipe4; // Add 3 accumulator values into one partial result + stb_pipe6 <= stb_pipe5; // Add both partial results into final result. + stb_pipe7 <= stb_pipe6; // Round result + stb_pipe8 <= stb_pipe7; // Clip Result + stb_pipe9 <= stb_pipe8; + + end // else: !if(rst) + + // + // Interleave newly interpolated samples (odd taps) with raw input samples (even taps - All zero except center tap) + // Account for differences caused by various CPO settings and the pipeline advancing. + // + always @(posedge clk) + if (bypass) + data_out <= data_in; + else if (stb_in & stb_out) + data_out <= result_clip[34:17]; + else if(stb_out) + case(output_rate) + 1: data_out <= data_in_pipe[16]; // Four input pipeline shifts since we calculated odd taps + 2: data_out <= data_in_pipe[14]; // Three input pipeline shifts since we calculated odd taps + 3,4: data_out <= data_in_pipe[13]; // Two input pipeline shifts since we calculated odd taps + default: data_out <= data_in_pipe[12]; // One input pipeline shift since we calculated odd taps + endcase // case(output_rate) + +endmodule // hb47_int diff --git a/fpga/usrp3/lib/dsp/hb47_int_tb.v b/fpga/usrp3/lib/dsp/hb47_int_tb.v new file mode 100644 index 000000000..501fa682f --- /dev/null +++ b/fpga/usrp3/lib/dsp/hb47_int_tb.v @@ -0,0 +1,136 @@ +// +// Copyright 2015 Ettus Research, a National Instruments Company +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +`timescale 1ns/1ps + +module hb47_int_tb(); + + wire GSR, GTS; + glbl glbl( ); + + reg clk = 0; + reg rst; + reg bypass; + reg run; + + wire stb_in; + reg stb_out; + reg [7:0] cpo; + + reg [17:0] data_in; + + wire [17:0] data_out_dsp48a; + wire [17:0] data_out_dsp48e; + + reg [15:0] freq = 500; + + integer x = 0, y =0; + + + + always #100 clk = ~clk; + + // SPARTAN6 / DSP48A + hb47_int + #(.WIDTH(18), + .DEVICE("SPARTAN6")) + hb47_int_i0 + ( + .clk(clk), + .rst(rst), + .bypass(bypass), + .stb_in(stb_in), + .data_in(data_in), + .output_rate(cpo), + .stb_out(stb_out), + .data_out(data_out_dsp48a) + ); + + // SERIES7 / DSP48E + hb47_int + #(.WIDTH(18), + .DEVICE("7SERIES")) + hb47_int_i1 + ( + .clk(clk), + .rst(rst), + .bypass(bypass), + .stb_in(stb_in), + .data_in(data_in), + .output_rate(cpo), + .stb_out(stb_out), + .data_out(data_out_dsp48e) + ); + + always @(negedge clk) + if (data_out_dsp48a !== data_out_dsp48e) + $display("Output missmatch at %t",$time); + + + + cic_strober #(.WIDTH(2)) + hb1_strober(.clock(clk),.reset(rst),.enable(run),.rate(2'd2), + .strobe_fast(stb_out),.strobe_slow(stb_in) ); + + initial + begin + rst <= 1; + bypass <= 0; + run <= 0; + data_in <= 0; + stb_out <= 1; + cpo <= 1; + + repeat(10) @(posedge clk); + rst <= 0; + run <= 1; + + for (x=0; x<100000; x=x+1) begin + for (y=0; y<10000; y=y+1) + begin + while (stb_in == 1'b0) @(posedge clk); + triangle_wave(freq,data_in); + @(posedge clk); + + end + freq = freq * 2; + end + + $finish; + end // initial begin + + + + + reg signed [18:0] phase_acc = 0; + reg direction = 0; + + + task triangle_wave; + input [15:0] inc; + output [17:0] data_out; + + begin + if (direction) begin + phase_acc = phase_acc - inc; + if (phase_acc < -19'sh20000) begin + direction = 0; + phase_acc = phase_acc + inc; + end + end else begin + phase_acc = phase_acc + inc; + if (phase_acc > 19'sh1ffff) begin + direction = 1; + phase_acc = phase_acc - inc; + end + end + data_out = phase_acc[17:0]; + end + + endtask // triangle_wave + + + +endmodule // hb47_int_tb diff --git a/fpga/usrp3/lib/dsp/hb_dec.v b/fpga/usrp3/lib/dsp/hb_dec.v new file mode 100644 index 000000000..0cae5c460 --- /dev/null +++ b/fpga/usrp3/lib/dsp/hb_dec.v @@ -0,0 +1,202 @@ +// +// Copyright 2011 Ettus Research LLC +// Copyright 2018 Ettus Research, a National Instruments Company +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// NOTE: This module uses Xilinx IP that is not available in Spartan3 and older FPGA's + +// Final halfband decimator +// Implements impulse responses of the form [A 0 B 0 C .. 0 H 0.5 H 0 .. C 0 B 0 A] +// Strobe in cannot come faster than every 2nd clock cycle +// These taps designed by halfgen4 from ldoolittle +// myfilt = round(2^18 * halfgen4(.7/4,8)) + +module hb_dec + #(parameter WIDTH=24, + parameter DEVICE = "SPARTAN6") + (input clk, + input rst, + input bypass, + input run, + input [8:0] cpi, // Clocks per input -- equal to the decimation ratio ahead of this block + input stb_in, + input [WIDTH-1:0] data_in, + output reg stb_out, + output reg [WIDTH-1:0] data_out); + + localparam INTWIDTH = 17; + localparam ACCWIDTH = WIDTH + 3; + + // Round off inputs to 17 bits because of 18 bit multipliers + wire [INTWIDTH-1:0] data_rnd; + wire stb_rnd; + + round_sd #(.WIDTH_IN(WIDTH),.WIDTH_OUT(INTWIDTH)) round_in + (.clk(clk),.reset(rst),.in(data_in),.strobe_in(stb_in),.out(data_rnd),.strobe_out(stb_rnd)); + + // Control + reg [3:0] addr_odd_a, addr_odd_b, addr_odd_c, addr_odd_d; + wire write_odd, write_even, do_mult; + reg odd; + reg [2:0] phase, phase_d1; + reg stb_out_int; + wire clear, do_acc; + assign do_mult = 1; + + always @(posedge clk) + if(rst | ~run) + odd <= 0; + else if(stb_rnd) + odd <= ~odd; + + assign write_odd = stb_rnd & odd; + assign write_even = stb_rnd & ~odd; + + always @(posedge clk) + if(rst | ~run) + phase <= 0; + else if(stb_rnd & odd) + phase <= 1; + else if(phase == 4) + phase <= 0; + else if(phase != 0) + phase <= phase + 1; + + always @(posedge clk) + phase_d1 <= phase; + + reg [15:0] stb_out_pre; + always @(posedge clk) + if(rst) + stb_out_pre <= 0; + else + stb_out_pre <= {stb_out_pre[14:0],(stb_rnd & odd)}; + + always @* + case(phase) + 1 : begin addr_odd_a = 0; addr_odd_b = 15; end + 2 : begin addr_odd_a = 1; addr_odd_b = 14; end + 3 : begin addr_odd_a = 2; addr_odd_b = 13; end + 4 : begin addr_odd_a = 3; addr_odd_b = 12; end + default : begin addr_odd_a = 0; addr_odd_b = 15; end + endcase // case(phase) + + always @* + case(phase) + 1 : begin addr_odd_c = 4; addr_odd_d = 11; end + 2 : begin addr_odd_c = 5; addr_odd_d = 10; end + 3 : begin addr_odd_c = 6; addr_odd_d = 9; end + 4 : begin addr_odd_c = 7; addr_odd_d = 8; end + default : begin addr_odd_c = 4; addr_odd_d = 11; end + endcase // case(phase) + + assign do_acc = |stb_out_pre[6:3]; + assign clear = stb_out_pre[3]; + + // Data + wire [INTWIDTH-1:0] data_odd_a, data_odd_b, data_odd_c, data_odd_d; + reg [INTWIDTH:0] sum1, sum2; // these are 18-bit inputs to mult + reg [WIDTH:0] final_sum; + wire [WIDTH-1:0] final_sum_clip; + reg [17:0] coeff1, coeff2; + wire [35:0] prod1, prod2; + + always @* // Outer coeffs + case(phase_d1) + 1 : coeff1 = -107; + 2 : coeff1 = 445; + 3 : coeff1 = -1271; + 4 : coeff1 = 2959; + default : coeff1 = -107; + endcase // case(phase) + + always @* // Inner coeffs + case(phase_d1) + 1 : coeff2 = -6107; + 2 : coeff2 = 11953; + 3 : coeff2 = -24706; + 4 : coeff2 = 82359; + default : coeff2 = -6107; + endcase // case(phase) + + srl #(.WIDTH(INTWIDTH)) srl_odd_a + (.clk(clk),.rst(rst),.write(write_odd),.in(data_rnd),.addr(addr_odd_a),.out(data_odd_a)); + srl #(.WIDTH(INTWIDTH)) srl_odd_b + (.clk(clk),.rst(rst),.write(write_odd),.in(data_rnd),.addr(addr_odd_b),.out(data_odd_b)); + srl #(.WIDTH(INTWIDTH)) srl_odd_c + (.clk(clk),.rst(rst),.write(write_odd),.in(data_rnd),.addr(addr_odd_c),.out(data_odd_c)); + srl #(.WIDTH(INTWIDTH)) srl_odd_d + (.clk(clk),.rst(rst),.write(write_odd),.in(data_rnd),.addr(addr_odd_d),.out(data_odd_d)); + + always @(posedge clk) sum1 <= {data_odd_a[INTWIDTH-1],data_odd_a} + {data_odd_b[INTWIDTH-1],data_odd_b}; + always @(posedge clk) sum2 <= {data_odd_c[INTWIDTH-1],data_odd_c} + {data_odd_d[INTWIDTH-1],data_odd_d}; + + wire [INTWIDTH-1:0] data_even; + reg [3:0] addr_even; + + always @(posedge clk) + case(cpi) + // 1 is an error + 2 : addr_even <= 9; // Maximum speed (overall decim by 4) + 3, 4, 5, 6, 7 : addr_even <= 8; + default : addr_even <= 7; + endcase // case(cpi) + + srl #(.WIDTH(INTWIDTH)) srl_even + (.clk(clk),.rst(rst),.write(write_even),.in(data_rnd),.addr(addr_even),.out(data_even)); + + + MULT_MACRO #(.DEVICE(DEVICE), // Target Device: "VIRTEX5", "VIRTEX6", "SPARTAN6","7SERIES" + .LATENCY(1), // Desired clock cycle latency, 0-4 + .WIDTH_A(18), // Multiplier A-input bus width, 1-25 + .WIDTH_B(18)) // Multiplier B-input bus width, 1-18 + mult1 (.P(prod1), // Multiplier output bus, width determined by WIDTH_P parameter + .A(coeff1), // Multiplier input A bus, width determined by WIDTH_A parameter + .B(sum1), // Multiplier input B bus, width determined by WIDTH_B parameter + .CE(do_mult), // 1-bit active high input clock enable + .CLK(clk), // 1-bit positive edge clock input + .RST(rst)); // 1-bit input active high reset + + MULT_MACRO #(.DEVICE(DEVICE), // Target Device: "VIRTEX5", "VIRTEX6", "SPARTAN6","7SERIES" + .LATENCY(1), // Desired clock cycle latency, 0-4 + .WIDTH_A(18), // Multiplier A-input bus width, 1-25 + .WIDTH_B(18)) // Multiplier B-input bus width, 1-18 + mult2 (.P(prod2), // Multiplier output bus, width determined by WIDTH_P parameter + .A(coeff2), // Multiplier input A bus, width determined by WIDTH_A parameter + .B(sum2), // Multiplier input B bus, width determined by WIDTH_B parameter + .CE(do_mult), // 1-bit active high input clock enable + .CLK(clk), // 1-bit positive edge clock input + .RST(rst)); // 1-bit input active high reset + + + reg [35:0] sum_of_prod; + always @(posedge clk) sum_of_prod <= prod1 + prod2; // Can't overflow + + wire [ACCWIDTH-1:0] acc_out; + acc #(.IWIDTH(ACCWIDTH-2),.OWIDTH(ACCWIDTH)) + acc (.clk(clk),.clear(clear),.acc(do_acc),.in(sum_of_prod[35:38-ACCWIDTH]),.out(acc_out)); + + wire [ACCWIDTH-1:0] data_even_signext; + + localparam SHIFT_FACTOR = 6; + + sign_extend #(.bits_in(INTWIDTH),.bits_out(ACCWIDTH-SHIFT_FACTOR)) signext_data_even + (.in(data_even),.out(data_even_signext[ACCWIDTH-1:SHIFT_FACTOR])); + assign data_even_signext[SHIFT_FACTOR-1:0] = 0; + + always @(posedge clk) final_sum <= acc_out + data_even_signext; + + clip #(.bits_in(WIDTH+1), .bits_out(WIDTH)) clip (.in(final_sum), .out(final_sum_clip)); + + // Output MUX to allow for bypass + wire selected_stb = bypass ? stb_in : stb_out_pre[8]; + + always @(posedge clk) + begin + stb_out <= selected_stb; + if(selected_stb) + data_out <= bypass ? data_in : final_sum_clip; + end + +endmodule // hb_dec diff --git a/fpga/usrp3/lib/dsp/hb_interp.v b/fpga/usrp3/lib/dsp/hb_interp.v new file mode 100644 index 000000000..6d8ef5174 --- /dev/null +++ b/fpga/usrp3/lib/dsp/hb_interp.v @@ -0,0 +1,168 @@ +// +// Copyright 2011 Ettus Research LLC +// Copyright 2018 Ettus Research, a National Instruments Company +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// + + +// First halfband iterpolator +// Implements impulse responses of the form [A 0 B 0 C .. 0 H 0.5 H 0 .. C 0 B 0 A] +// Strobe in cannot come faster than every 4th clock cycle, +// Strobe out cannot come faster than every 2nd clock cycle + +// These taps designed by halfgen4 from ldoolittle +// myfilt = round(2^18 * halfgen4(.7/4,8)) + +module hb_interp + #(parameter IWIDTH=18, OWIDTH=18, ACCWIDTH=24) + (input clk, + input rst, + input bypass, + input [7:0] cpo, // Clocks per output, must be at least 2 + input stb_in, + input [IWIDTH-1:0] data_in, + input stb_out, + output reg [OWIDTH-1:0] data_out); + + localparam MWIDTH = ACCWIDTH-2; + localparam CWIDTH = 18; + + reg [CWIDTH-1:0] coeff1, coeff2; + reg [3:0] addr_a, addr_b, addr_c, addr_d, addr_e; + wire [IWIDTH-1:0] data_a, data_b, data_c, data_d, data_e, sum1, sum2; + wire [35:0] prod1, prod2; + + reg [2:0] phase, phase_d1, phase_d2, phase_d3, phase_d4, phase_d5; + + always @(posedge clk) + if(rst) + phase <= 0; + else + if(stb_in) + phase <= 1; + else if(phase==4) + phase <= 0; + else if(phase!=0) + phase <= phase + 1; + always @(posedge clk) phase_d1 <= phase; + always @(posedge clk) phase_d2 <= phase_d1; + always @(posedge clk) phase_d3 <= phase_d2; + always @(posedge clk) phase_d4 <= phase_d3; + always @(posedge clk) phase_d5 <= phase_d4; + + srl #(.WIDTH(IWIDTH)) srl_a + (.clk(clk),.rst(rst),.write(stb_in),.in(data_in),.addr(addr_a),.out(data_a)); + srl #(.WIDTH(IWIDTH)) srl_b + (.clk(clk),.rst(rst),.write(stb_in),.in(data_in),.addr(addr_b),.out(data_b)); + srl #(.WIDTH(IWIDTH)) srl_c + (.clk(clk),.rst(rst),.write(stb_in),.in(data_in),.addr(addr_c),.out(data_c)); + srl #(.WIDTH(IWIDTH)) srl_d + (.clk(clk),.rst(rst),.write(stb_in),.in(data_in),.addr(addr_d),.out(data_d)); + srl #(.WIDTH(IWIDTH)) srl_e + (.clk(clk),.rst(rst),.write(stb_in),.in(data_in),.addr(addr_e),.out(data_e)); + + always @* + case(phase) + 1 : begin addr_a = 0; addr_b = 15; end + 2 : begin addr_a = 1; addr_b = 14; end + 3 : begin addr_a = 2; addr_b = 13; end + 4 : begin addr_a = 3; addr_b = 12; end + default : begin addr_a = 0; addr_b = 15; end + endcase // case(phase) + + always @* + case(phase) + 1 : begin addr_c = 4; addr_d = 11; end + 2 : begin addr_c = 5; addr_d = 10; end + 3 : begin addr_c = 6; addr_d = 9; end + 4 : begin addr_c = 7; addr_d = 8; end + default : begin addr_c = 4; addr_d = 11; end + endcase // case(phase) + + always @* + case(cpo) + 2 : addr_e <= 9; + 3,4,5,6,7,8 : addr_e <= 8; + default : addr_e <= 7; // This case works for 256, which = 0 due to overflow outside this block + endcase // case(cpo) + + always @* // Outer coeffs + case(phase_d1) + 1 : coeff1 = -107; + 2 : coeff1 = 445; + 3 : coeff1 = -1271; + 4 : coeff1 = 2959; + default : coeff1 = -107; + endcase // case(phase) + + always @* // Inner coeffs + case(phase_d1) + 1 : coeff2 = -6107; + 2 : coeff2 = 11953; + 3 : coeff2 = -24706; + 4 : coeff2 = 82359; + default : coeff2 = -6107; + endcase // case(phase) + + add2_reg /*_and_round_reg*/ #(.WIDTH(IWIDTH)) add1 (.clk(clk),.in1(data_a),.in2(data_b),.sum(sum1)); + add2_reg /*_and_round_reg*/ #(.WIDTH(IWIDTH)) add2 (.clk(clk),.in1(data_c),.in2(data_d),.sum(sum2)); + // sum1, sum2 available on phase_d1 + + wire do_mult = 1; + MULT18X18S mult1(.C(clk), .CE(do_mult), .R(rst), .P(prod1), .A(coeff1), .B(sum1) ); + MULT18X18S mult2(.C(clk), .CE(do_mult), .R(rst), .P(prod2), .A(coeff2), .B(sum2) ); + // prod1, prod2 available on phase_d2 + + wire [MWIDTH-1:0] sum_of_prod; + + add2_and_round_reg #(.WIDTH(MWIDTH)) + add3 (.clk(clk),.in1(prod1[35:36-MWIDTH]),.in2(prod2[35:36-MWIDTH]),.sum(sum_of_prod)); + // sum_of_prod available on phase_d3 + + wire [ACCWIDTH-1:0] acc_out; + + wire clear = (phase_d3 == 1); + wire do_acc = (phase_d3 != 0); + + acc #(.IWIDTH(MWIDTH),.OWIDTH(ACCWIDTH)) //IJB rst + acc (.clk(clk),.clear(rst|clear),.acc(do_acc),.in(sum_of_prod),.out(acc_out)); + // acc_out available on phase_d4 + + wire [ACCWIDTH-6:0] clipped_acc; + clip #(.bits_in(ACCWIDTH),.bits_out(ACCWIDTH-5)) final_clip(.in(acc_out),.out(clipped_acc)); + + reg [ACCWIDTH-6:0] clipped_reg; + always @(posedge clk) + if (rst) + clipped_reg <= 0; + else if(phase_d4 == 4) + clipped_reg <= clipped_acc; + // clipped_reg available on phase_d5 + + wire [OWIDTH-1:0] data_out_round; + round #(.bits_in(ACCWIDTH-5),.bits_out(OWIDTH)) final_round (.in(clipped_reg),.out(data_out_round)); + + reg odd; + always @(posedge clk) + if(rst) + odd <= 0; + else if(stb_in) + odd <= 0; + else if(stb_out) + odd <= 1; + + always @(posedge clk) + if (rst) + data_out <= 0; + else if(bypass) + data_out <= data_in; + else if(stb_out) + if(odd) + data_out <= data_e; + else + data_out <= data_out_round; + + // data_out available on phase_d6 + +endmodule // hb_interp diff --git a/fpga/usrp3/lib/dsp/mult_add_clip.v b/fpga/usrp3/lib/dsp/mult_add_clip.v new file mode 100644 index 000000000..b1b49af8b --- /dev/null +++ b/fpga/usrp3/lib/dsp/mult_add_clip.v @@ -0,0 +1,260 @@ +// Copyright 2018 Ettus Research, a National Instruments Company +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// Write xilinx DSP48E1 primitive for mult-add-clip (signed) + +`default_nettype none + +module mult_add_clip #( + parameter WIDTH_A=25, // Max 25 + parameter BIN_PT_A=24, + parameter WIDTH_B=18, // Max 18 + parameter BIN_PT_B=17, + parameter WIDTH_C=43, // Max 43 + + // Min (47-WIDTH_C-1)+BIN_PT_A+BIN_PT_B, + // Max WIDTH_C-1+BIN_PT_A+BIN_PT_B + parameter BIN_PT_C=42, + + parameter WIDTH_O=43, // Max 43-(BIN_PT_A+BIN_PT_B-BIN_PT_O) + parameter BIN_PT_O=42, + parameter LATENCY=2 // Maximum is 4 +) ( + input wire clk, + input wire reset, + input wire CE, // Ordinarily set to 1'b1 + input wire [WIDTH_A-1:0] A, + input wire [WIDTH_B-1:0] B, + input wire [WIDTH_C-1:0] C, + output reg [WIDTH_O-1:0] O +); + // DSP operations: + // O = clip(A * B + C) + // + // Mux settings: + // X,Y (01,01) = M + // Z (011) = C + + localparam MREG_IN = (LATENCY >= 1) ? 1 : 0; + localparam CREG_IN = MREG_IN; + localparam PREG_IN = (LATENCY >= 2) ? 1 : 0; + localparam A2REG_IN = (LATENCY >= 3) ? 1 : 0; + localparam A1REG_IN = (LATENCY == 4) ? 1 : 0; + localparam AREG_IN = A1REG_IN + A2REG_IN; + // See OPMODE Control Bits Settings, Table 2-7,2-8,2-9 + localparam ZMUX_C = 3'b011; + localparam YMUX_M = 2'b01; + localparam XMUX_M = 2'b01; + localparam [6:0] OPMODE = {ZMUX_C, YMUX_M, XMUX_M}; + + // A_IN is 25 bits; B_IN is 18 bits. Product M's binary point shifts: + localparam BIN_PT_M = BIN_PT_A+(25-WIDTH_A) + BIN_PT_B+(18-WIDTH_B); + + // Calculate shift for C to align binary point to A*B product (M) + // Determine top and bottom indices of C (in C_IN), normalized to M + // Divide by 2**BIN_PT_C then multiply up by 2**BIN_PT_M + localparam C_TOP = WIDTH_C-1 - BIN_PT_C + BIN_PT_M; + localparam C_BOT = 0 - BIN_PT_C + BIN_PT_M; + // Determine number of sign-extended bits above C_TOP + localparam C_EXT = 47 - C_TOP; + + // P is a 43-bit fixed point number with bin pt BIN_PT_M + // O is extracted from those bits + // Sign extend if more bits to left of bin pt + localparam O_EXT = ((WIDTH_O-BIN_PT_O) > (43-BIN_PT_M)) ? + (WIDTH_O-BIN_PT_O) - (43-BIN_PT_M) : 0; + // If extending, use highest bit of P, else extract bits based on bin pt + localparam P_TOP = (O_EXT > 0) ? 42 : + (42 + (WIDTH_O-BIN_PT_O) - (43-BIN_PT_M)); + // Pad bottom of O if remaining P not enough bits + localparam O_PAD = (WIDTH_O > P_TOP+1) ? (WIDTH_O-P_TOP-1) : 0; + // If padding O, grab lowest bit of P, else determine based on O's width + localparam P_BOT = (O_PAD > 0) ? 0 : (P_TOP+1-WIDTH_O); + + //------------------------------------------------ + // Normalize C input to A*B product's binary point + //------------------------------------------------ + function automatic [47:0] align_c; + input [WIDTH_C-1:0] c; + begin + // Do sign extension + if (C_EXT > 0) begin + align_c[47 -: C_EXT] = {C_EXT{c[WIDTH_C-1]}}; + end + if (C_BOT < 0) begin + // Chop off lower bits of C + align_c[C_TOP:0] = c[WIDTH_C-1:(-C_BOT)]; + end else begin + // Place C and zero pad if necessary + align_c[C_TOP:C_BOT] = c; + if (C_BOT > 0) begin + align_c[C_BOT-1:0] = {C_BOT{1'b0}}; + end + end + end + endfunction + + wire [24:0] A_IN = (WIDTH_A < 25) ? { A, {(25-(WIDTH_A)){1'b0}}} : A; + wire [17:0] B_IN = (WIDTH_B < 18) ? { B, {(18-(WIDTH_B)){1'b0}}} : B; + wire [47:0] C_IN; + wire [47:0] P_OUT; + + //-------------------------------------------------- + // C needs more pipeline registers at higher latency + //-------------------------------------------------- + generate if (AREG_IN > 0) begin + reg [AREG_IN*WIDTH_C-1:0] c_r; + + if (AREG_IN > 1) begin + always @ (posedge clk) + begin + if (CE) begin + c_r <= {c_r[0 +: (AREG_IN-1)*WIDTH_C], C}; + end + end + end else begin + always @ (posedge clk) + begin + if (CE) begin + c_r <= C; + end + end + end + + wire [WIDTH_C-1:0] c_pre = c_r[AREG_IN*WIDTH_C-1 -: WIDTH_C]; + assign C_IN = align_c(c_pre); + end else begin + assign C_IN = align_c(C); + end endgenerate + + //---------------------------------------------- + // Track signs for overflow/underflow processing + //---------------------------------------------- + reg [LATENCY-1:0] mult_sign; + reg [LATENCY-1:0] c_sign; + wire bin_pt_overflow; + wire adder_overflow; + wire [WIDTH_O-1:0] p_extract; + + generate if (LATENCY > 1) begin + always @ (posedge clk) + begin + if (CE) begin + mult_sign <= {mult_sign[0 +: LATENCY-1], A[WIDTH_A-1] ^ B[WIDTH_B-1]}; + c_sign <= {c_sign[0 +: LATENCY-1], C[WIDTH_C-1]}; + end + end + end else begin + always @ (posedge clk) + begin + if (CE) begin + mult_sign <= A[WIDTH_A-1] ^ B[WIDTH_B-1]; + c_sign <= C[WIDTH_C-1]; + end + end + end endgenerate + + assign adder_overflow = (mult_sign[LATENCY-1] == c_sign[LATENCY-1]) && + (P_OUT[42] != c_sign[LATENCY-1]); + + //---------------------------------------------- + // Extract renormalized bits from P_OUT + //---------------------------------------------- + generate + if (P_TOP < 42) begin + assign bin_pt_overflow = (|P_OUT[42:P_TOP]) != (&P_OUT[42:P_TOP]); + end else begin + assign bin_pt_overflow = 1'b0; + end + + if (O_EXT > 0) begin + assign p_extract[WIDTH_O-1 -: O_EXT] = {O_EXT{P_OUT[42]}}; + end + + if (O_PAD > 0) begin + assign p_extract[O_PAD-1:0] = {O_PAD{1'b0}}; + end + endgenerate + + assign p_extract[WIDTH_O-1-O_EXT:O_PAD] = P_OUT[P_TOP:P_BOT]; + + //---------------------------------- + // Clip if underflowed or overflowed + //---------------------------------- + always @ (*) + begin + if (bin_pt_overflow || adder_overflow) begin + O <= {c_sign[LATENCY-1], {WIDTH_O-1{!c_sign[LATENCY-1]}}}; + end else begin + O <= p_extract; + end + end + + + DSP48E1 #( + .ACASCREG(AREG_IN), + .AREG(AREG_IN), + .ADREG(0), + .DREG(0), + .BCASCREG(AREG_IN), + .BREG(AREG_IN), + .MREG(MREG_IN), + .CREG(CREG_IN), + .PREG(PREG_IN) + ) DSP48_inst ( + // Outputs + .ACOUT(), + .BCOUT(), + .CARRYCASCOUT(), + .CARRYOUT(), + .MULTSIGNOUT(), + .OVERFLOW(), + .P(P_OUT), + .PATTERNBDETECT(), + .PATTERNDETECT(), + .PCOUT(), + .UNDERFLOW(), + + // Inputs + .A({5'b0,A_IN}), + .ACIN(30'b0), + .ALUMODE(4'b0000), + .B(B_IN), + .BCIN(18'b0), + .C(C_IN), + .CARRYCASCIN(1'b0), + .CARRYIN(1'b0), + .CARRYINSEL(3'b0), + .CEA1(CE), + .CEA2(CE), + .CEAD(1'b0), + .CEALUMODE(1'b1), + .CEB1(CE), + .CEB2(CE), + .CEC(CE), + .CECARRYIN(CE), + .CECTRL(CE), + .CED(1'b0), + .CEINMODE(CE), + .CEM(CE), + .CEP(CE), + .CLK(clk), + .D({25{1'b1}}), + .INMODE(5'b0), + .MULTSIGNIN(1'b0), + .OPMODE(OPMODE), + .PCIN(48'b0), + .RSTA(reset), + .RSTALLCARRYIN(reset), + .RSTALUMODE(reset), + .RSTB(reset), + .RSTC(reset), + .RSTD(reset), + .RSTCTRL(reset), + .RSTINMODE(reset), + .RSTM(reset), + .RSTP(reset) + ); + +endmodule // mult_add_clip +`default_nettype wire diff --git a/fpga/usrp3/lib/dsp/round.v b/fpga/usrp3/lib/dsp/round.v new file mode 100644 index 000000000..4d3cf5521 --- /dev/null +++ b/fpga/usrp3/lib/dsp/round.v @@ -0,0 +1,49 @@ +// -*- verilog -*- +// +// USRP - Universal Software Radio Peripheral +// +// Copyright (C) 2011 Matt Ettus +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// + +// + +// Rounding "macro" +// Keeps the topmost bits, does proper 2s comp round to zero (unbiased truncation) + +module round + #(parameter bits_in=0, + parameter bits_out=0, + parameter round_to_zero=0, // original behavior + parameter round_to_nearest=1, // lowest noise + parameter trunc=0) // round to negative infinity + (input [bits_in-1:0] in, + output [bits_out-1:0] out, + output [bits_in-bits_out:0] err); + + wire round_corr,round_corr_trunc,round_corr_rtz,round_corr_nearest,round_corr_nearest_safe; + + assign round_corr_trunc = 0; + assign round_corr_rtz = (in[bits_in-1] & |in[bits_in-bits_out-1:0]); + assign round_corr_nearest = in[bits_in-bits_out-1]; + + generate + if(bits_in-bits_out > 1) + assign round_corr_nearest_safe = (~in[bits_in-1] & (&in[bits_in-2:bits_in-bits_out])) ? 1'b0 : + round_corr_nearest; + else + assign round_corr_nearest_safe = round_corr_nearest; + endgenerate + + + assign round_corr = round_to_nearest ? round_corr_nearest_safe : + trunc ? round_corr_trunc : + round_to_zero ? round_corr_rtz : + 0; // default to trunc + + assign out = in[bits_in-1:bits_in-bits_out] + round_corr; + + assign err = in - {out,{(bits_in-bits_out){1'b0}}}; + +endmodule // round diff --git a/fpga/usrp3/lib/dsp/round_reg.v b/fpga/usrp3/lib/dsp/round_reg.v new file mode 100644 index 000000000..d1bc6a848 --- /dev/null +++ b/fpga/usrp3/lib/dsp/round_reg.v @@ -0,0 +1,34 @@ +// -*- verilog -*- +// +// USRP - Universal Software Radio Peripheral +// +// Copyright (C) 2008 Matt Ettus +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// + +// + +// Rounding "macro" +// Keeps the topmost bits, does proper 2s comp rounding (round-to-zero) + +module round_reg + #(parameter bits_in=0, + parameter bits_out=0) + (input clk, + input [bits_in-1:0] in, + output reg [bits_out-1:0] out, + output reg [bits_in-bits_out:0] err); + + wire [bits_out-1:0] temp; + wire [bits_in-bits_out:0] err_temp; + + round #(.bits_in(bits_in),.bits_out(bits_out)) round (.in(in),.out(temp), .err(err_temp)); + + always @(posedge clk) + out <= temp; + + always @(posedge clk) + err <= err_temp; + +endmodule // round_reg diff --git a/fpga/usrp3/lib/dsp/round_sd.v b/fpga/usrp3/lib/dsp/round_sd.v new file mode 100644 index 000000000..37aef53f0 --- /dev/null +++ b/fpga/usrp3/lib/dsp/round_sd.v @@ -0,0 +1,43 @@ +// +// Copyright 2016 Ettus Research +// Copyright 2018 Ettus Research, a National Instruments Company +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// + +module round_sd #( + parameter WIDTH_IN=18, + parameter WIDTH_OUT=16, + parameter DISABLE_SD=0 +)( + input clk, input reset, + input [WIDTH_IN-1:0] in, input strobe_in, + output reg [WIDTH_OUT-1:0] out, output reg strobe_out +); + + localparam ERR_WIDTH = WIDTH_IN - WIDTH_OUT + 1; + + wire [ERR_WIDTH-1:0] err; + wire [WIDTH_IN-1:0] err_ext, sum; + wire [WIDTH_OUT-1:0] out_pre; + wire strobe_pre; + + sign_extend #(.bits_in(ERR_WIDTH),.bits_out(WIDTH_IN)) ext_err (.in(err), .out(err_ext)); + + add2_and_clip_reg #(.WIDTH(WIDTH_IN)) add2_and_clip_reg ( + .clk(clk), .rst(reset), .in1(in), .in2((DISABLE_SD == 0) ? err_ext : {WIDTH_IN{1'b0}}), .strobe_in(strobe_in), .sum(sum), .strobe_out(strobe_pre)); + + round #(.bits_in(WIDTH_IN),.bits_out(WIDTH_OUT)) round_sum (.in(sum), .out(out_pre), .err(err)); + + always @(posedge clk) begin + if (reset) begin + strobe_out <= 1'b0; + end else begin + strobe_out <= strobe_pre; + if (strobe_pre) begin + out <= out_pre; + end + end + end + +endmodule // round_sd diff --git a/fpga/usrp3/lib/dsp/rx_dcoffset.v b/fpga/usrp3/lib/dsp/rx_dcoffset.v new file mode 100644 index 000000000..02950fbd5 --- /dev/null +++ b/fpga/usrp3/lib/dsp/rx_dcoffset.v @@ -0,0 +1,50 @@ +// +// Copyright 2015 Ettus Research LLC +// Copyright 2018 Ettus Research, a National Instruments Company +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// + +module rx_dcoffset + #(parameter WIDTH=16, + parameter ADDR=8'd0, + parameter alpha_shift=20) + (input clk, input rst, + input set_stb, input [7:0] set_addr, input [31:0] set_data, + input in_stb, input [WIDTH-1:0] in, + output out_stb, output [WIDTH-1:0] out); + + wire set_now = set_stb & (ADDR == set_addr); + reg fixed; // uses fixed offset + wire [WIDTH-1:0] fixed_dco; + + localparam int_width = WIDTH + alpha_shift; + reg [int_width-1:0] integrator; + reg integ_in_stb; + wire [WIDTH-1:0] quantized; + + always @(posedge clk) begin + if(rst) + begin + integ_in_stb <= 0; + fixed <= 0; + integrator <= {int_width{1'b0}}; + end + else if(set_now) + begin + fixed <= set_data[31]; + if(set_data[30]) + integrator <= {set_data[29:0],{(int_width-30){1'b0}}}; + end + else if(~fixed & in_stb) + integrator <= integrator + {{(alpha_shift){out[WIDTH-1]}},out}; + integ_in_stb <= in_stb; + end + + round_sd #(.WIDTH_IN(int_width),.WIDTH_OUT(WIDTH)) round_sd + (.clk(clk), .reset(rst), .in(integrator), .strobe_in(integ_in_stb), .out(quantized), .strobe_out()); + + add2_and_clip_reg #(.WIDTH(WIDTH)) add2_and_clip_reg + (.clk(clk), .rst(rst), .in1(in), .in2(-quantized), .strobe_in(in_stb), .sum(out), .strobe_out(out_stb)); + +endmodule // rx_dcoffset diff --git a/fpga/usrp3/lib/dsp/rx_frontend.v b/fpga/usrp3/lib/dsp/rx_frontend.v new file mode 100644 index 000000000..45c701688 --- /dev/null +++ b/fpga/usrp3/lib/dsp/rx_frontend.v @@ -0,0 +1,87 @@ +// +// Copyright 2014 Ettus Research LLC +// Copyright 2018 Ettus Research, a National Instruments Company +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +module rx_frontend + #(parameter BASE = 0, + parameter IQCOMP_EN = 1) + (input clk, input rst, + input set_stb, input [7:0] set_addr, input [31:0] set_data, + + input [15:0] adc_a, input adc_ovf_a, + input [15:0] adc_b, input adc_ovf_b, + + output [23:0] i_out, output [23:0] q_out, + input run, + output [31:0] debug + ); + + reg [15:0] adc_i, adc_q; + wire [23:0] adc_i_ofs, adc_q_ofs; + wire [35:0] corr_i, corr_q; + wire [17:0] mag_corr,phase_corr; + wire swap_iq; + + setting_reg #(.my_addr(BASE), .width(1)) sr_8 + (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr), + .in(set_data),.out(swap_iq),.changed()); + + always @(posedge clk) + if(swap_iq) // Swap + {adc_i,adc_q} <= {adc_b,adc_a}; + else + {adc_i,adc_q} <= {adc_a,adc_b}; + + setting_reg #(.my_addr(BASE+1),.width(18)) sr_1 + (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr), + .in(set_data),.out(mag_corr),.changed()); + + setting_reg #(.my_addr(BASE+2),.width(18)) sr_2 + (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr), + .in(set_data),.out(phase_corr),.changed()); + + rx_dcoffset #(.WIDTH(24),.ADDR(BASE+3)) rx_dcoffset_i + (.clk(clk),.rst(rst),.set_stb(set_stb),.set_addr(set_addr),.set_data(set_data), + .in({adc_i,8'b00}), .in_stb(1'b1), + .out(adc_i_ofs), .out_stb()); + + rx_dcoffset #(.WIDTH(24),.ADDR(BASE+4)) rx_dcoffset_q + (.clk(clk),.rst(rst),.set_stb(set_stb),.set_addr(set_addr),.set_data(set_data), + .in({adc_q,8'b00}), .in_stb(1'b1), + .out(adc_q_ofs), .out_stb()); + + generate + if(IQCOMP_EN == 1) + begin + reg [23:0] adc_i_ofs_dly, adc_q_ofs_dly; + always @(posedge clk) begin + adc_i_ofs_dly <= adc_i_ofs; + adc_q_ofs_dly <= adc_q_ofs; + end + + MULT18X18S mult_mag_corr + (.P(corr_i), .A(adc_i_ofs[23:6]), .B(mag_corr), .C(clk), .CE(1'b1), .R(rst) ); + + MULT18X18S mult_phase_corr + (.P(corr_q), .A(adc_i_ofs[23:6]), .B(phase_corr), .C(clk), .CE(1'b1), .R(rst) ); + + add2_and_clip_reg #(.WIDTH(24)) add_clip_i + (.clk(clk), .rst(rst), + .in1(adc_i_ofs_dly), .in2(corr_i[35:12]), .strobe_in(1'b1), + .sum(i_out), .strobe_out()); + + add2_and_clip_reg #(.WIDTH(24)) add_clip_q + (.clk(clk), .rst(rst), + .in1(adc_q_ofs_dly), .in2(corr_q[35:12]), .strobe_in(1'b1), + .sum(q_out), .strobe_out()); + end // if (IQCOMP_EN == 1) + else + begin + assign i_out = adc_i_ofs; + assign q_out = adc_q_ofs; + end // else: !if(IQCOMP_EN == 1) + endgenerate + +endmodule // rx_frontend diff --git a/fpga/usrp3/lib/dsp/rx_frontend_tb.v b/fpga/usrp3/lib/dsp/rx_frontend_tb.v new file mode 100644 index 000000000..c7e88da11 --- /dev/null +++ b/fpga/usrp3/lib/dsp/rx_frontend_tb.v @@ -0,0 +1,50 @@ +// +// Copyright 2013 Ettus Research, a National Instruments Company +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// + +`timescale 1ns/1ns +module rx_frontend_tb(); + + reg clk, rst; + + initial rst = 1; + initial #1000 rst = 0; + initial clk = 0; + always #5 clk = ~clk; + + initial $dumpfile("rx_frontend_tb.vcd"); + initial $dumpvars(0,rx_frontend_tb); + + reg [15:0] adc_in; + wire [23:0] adc_out; + + always @(posedge clk) + begin + if(adc_in[15]) + $write("-%d,",-adc_in); + else + $write("%d,",adc_in); + if(adc_out[23]) + $write("-%d\n",-adc_out); + else + $write("%d\n",adc_out); + end + + rx_frontend #(.BASE(0), .IQCOMP_EN(1)) rx_frontend + (.clk(clk),.rst(rst), + .set_stb(0),.set_addr(0),.set_data(0), + .adc_a(adc_in), .adc_ovf_a(0), + .adc_b(0), .adc_ovf_b(0), + .i_out(adc_out),.q_out(), + .run(), .debug()); + + always @(posedge clk) + if(rst) + adc_in <= 0; + else + adc_in <= adc_in + 4; + //adc_in <= (($random % 473) + 23)/4; + +endmodule // rx_frontend_tb diff --git a/fpga/usrp3/lib/dsp/sign_extend.v b/fpga/usrp3/lib/dsp/sign_extend.v new file mode 100644 index 000000000..e1c24b717 --- /dev/null +++ b/fpga/usrp3/lib/dsp/sign_extend.v @@ -0,0 +1,25 @@ +// -*- verilog -*- +// +// USRP - Universal Software Radio Peripheral +// +// Copyright (C) 2003 Matt Ettus +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// + +// + + +// Sign extension "macro" +// bits_out should be greater than bits_in + +module sign_extend (in,out); + parameter bits_in=0; // FIXME Quartus insists on a default + parameter bits_out=0; + + input [bits_in-1:0] in; + output [bits_out-1:0] out; + + assign out = {{(bits_out-bits_in){in[bits_in-1]}},in}; + +endmodule diff --git a/fpga/usrp3/lib/dsp/sim/sim_ddc_chain/dc_in_cordic_decim_2/gtk.conf.gtkw b/fpga/usrp3/lib/dsp/sim/sim_ddc_chain/dc_in_cordic_decim_2/gtk.conf.gtkw new file mode 100644 index 000000000..27c2c836e --- /dev/null +++ b/fpga/usrp3/lib/dsp/sim/sim_ddc_chain/dc_in_cordic_decim_2/gtk.conf.gtkw @@ -0,0 +1,64 @@ +[*] +[*] GTKWave Analyzer v3.3.40 (w)1999-2012 BSI +[*] Wed Jul 15 02:18:40 2015 +[*] +[dumpfile] "/disk2/ianb/ettus/fpgadev-b200/fpgadev/usrp3/lib/dsp/sim/sim_ddc_chain/dc_in_cordic_run/waves.vcd" +[dumpfile_mtime] "Wed Jul 15 02:13:19 2015" +[dumpfile_size] 238141440 +[savefile] "/disk2/ianb/ettus/fpgadev-b200/fpgadev/usrp3/lib/dsp/sim/sim_ddc_chain/dc_in_cordic_run/gtk.conf.gtkw" +[timestart] 0 +[size] 2488 1221 +[pos] -1 -1 +*-24.083374 129800000 -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 +[treeopen] ddc_chain_tb. +[treeopen] ddc_chain_tb.dut_i0. +[sst_width] 331 +[signals_width] 280 +[sst_expanded] 1 +[sst_vpaned_height] 370 +@28 +ddc_chain_tb.dut_i0.clk +ddc_chain_tb.dut_i0.rst +ddc_chain_tb.dut_i0.set_stb +@22 +#{ddc_chain_tb.dut_i0.set_addr[7:0]} ddc_chain_tb.dut_i0.set_addr[7] ddc_chain_tb.dut_i0.set_addr[6] ddc_chain_tb.dut_i0.set_addr[5] ddc_chain_tb.dut_i0.set_addr[4] ddc_chain_tb.dut_i0.set_addr[3] ddc_chain_tb.dut_i0.set_addr[2] ddc_chain_tb.dut_i0.set_addr[1] ddc_chain_tb.dut_i0.set_addr[0] +#{ddc_chain_tb.dut_i0.set_data[31:0]} ddc_chain_tb.dut_i0.set_data[31] ddc_chain_tb.dut_i0.set_data[30] ddc_chain_tb.dut_i0.set_data[29] ddc_chain_tb.dut_i0.set_data[28] ddc_chain_tb.dut_i0.set_data[27] ddc_chain_tb.dut_i0.set_data[26] ddc_chain_tb.dut_i0.set_data[25] ddc_chain_tb.dut_i0.set_data[24] ddc_chain_tb.dut_i0.set_data[23] ddc_chain_tb.dut_i0.set_data[22] ddc_chain_tb.dut_i0.set_data[21] ddc_chain_tb.dut_i0.set_data[20] ddc_chain_tb.dut_i0.set_data[19] ddc_chain_tb.dut_i0.set_data[18] ddc_chain_tb.dut_i0.set_data[17] ddc_chain_tb.dut_i0.set_data[16] ddc_chain_tb.dut_i0.set_data[15] ddc_chain_tb.dut_i0.set_data[14] ddc_chain_tb.dut_i0.set_data[13] ddc_chain_tb.dut_i0.set_data[12] ddc_chain_tb.dut_i0.set_data[11] ddc_chain_tb.dut_i0.set_data[10] ddc_chain_tb.dut_i0.set_data[9] ddc_chain_tb.dut_i0.set_data[8] ddc_chain_tb.dut_i0.set_data[7] ddc_chain_tb.dut_i0.set_data[6] ddc_chain_tb.dut_i0.set_data[5] ddc_chain_tb.dut_i0.set_data[4] ddc_chain_tb.dut_i0.set_data[3] ddc_chain_tb.dut_i0.set_data[2] ddc_chain_tb.dut_i0.set_data[1] ddc_chain_tb.dut_i0.set_data[0] +@10420 +#{ddc_chain_tb.dut_i0.rx_fe_i[23:0]} ddc_chain_tb.dut_i0.rx_fe_i[23] ddc_chain_tb.dut_i0.rx_fe_i[22] ddc_chain_tb.dut_i0.rx_fe_i[21] ddc_chain_tb.dut_i0.rx_fe_i[20] ddc_chain_tb.dut_i0.rx_fe_i[19] ddc_chain_tb.dut_i0.rx_fe_i[18] ddc_chain_tb.dut_i0.rx_fe_i[17] ddc_chain_tb.dut_i0.rx_fe_i[16] ddc_chain_tb.dut_i0.rx_fe_i[15] ddc_chain_tb.dut_i0.rx_fe_i[14] ddc_chain_tb.dut_i0.rx_fe_i[13] ddc_chain_tb.dut_i0.rx_fe_i[12] ddc_chain_tb.dut_i0.rx_fe_i[11] ddc_chain_tb.dut_i0.rx_fe_i[10] ddc_chain_tb.dut_i0.rx_fe_i[9] ddc_chain_tb.dut_i0.rx_fe_i[8] ddc_chain_tb.dut_i0.rx_fe_i[7] ddc_chain_tb.dut_i0.rx_fe_i[6] ddc_chain_tb.dut_i0.rx_fe_i[5] ddc_chain_tb.dut_i0.rx_fe_i[4] ddc_chain_tb.dut_i0.rx_fe_i[3] ddc_chain_tb.dut_i0.rx_fe_i[2] ddc_chain_tb.dut_i0.rx_fe_i[1] ddc_chain_tb.dut_i0.rx_fe_i[0] +@20000 +- +@10420 +#{ddc_chain_tb.dut_i0.rx_fe_q[23:0]} ddc_chain_tb.dut_i0.rx_fe_q[23] ddc_chain_tb.dut_i0.rx_fe_q[22] ddc_chain_tb.dut_i0.rx_fe_q[21] ddc_chain_tb.dut_i0.rx_fe_q[20] ddc_chain_tb.dut_i0.rx_fe_q[19] ddc_chain_tb.dut_i0.rx_fe_q[18] ddc_chain_tb.dut_i0.rx_fe_q[17] ddc_chain_tb.dut_i0.rx_fe_q[16] ddc_chain_tb.dut_i0.rx_fe_q[15] ddc_chain_tb.dut_i0.rx_fe_q[14] ddc_chain_tb.dut_i0.rx_fe_q[13] ddc_chain_tb.dut_i0.rx_fe_q[12] ddc_chain_tb.dut_i0.rx_fe_q[11] ddc_chain_tb.dut_i0.rx_fe_q[10] ddc_chain_tb.dut_i0.rx_fe_q[9] ddc_chain_tb.dut_i0.rx_fe_q[8] ddc_chain_tb.dut_i0.rx_fe_q[7] ddc_chain_tb.dut_i0.rx_fe_q[6] ddc_chain_tb.dut_i0.rx_fe_q[5] ddc_chain_tb.dut_i0.rx_fe_q[4] ddc_chain_tb.dut_i0.rx_fe_q[3] ddc_chain_tb.dut_i0.rx_fe_q[2] ddc_chain_tb.dut_i0.rx_fe_q[1] ddc_chain_tb.dut_i0.rx_fe_q[0] +@20000 +- +@10420 +#{ddc_chain_tb.dut_i0.i_cordic_clip[23:0]} ddc_chain_tb.dut_i0.i_cordic_clip[23] ddc_chain_tb.dut_i0.i_cordic_clip[22] ddc_chain_tb.dut_i0.i_cordic_clip[21] ddc_chain_tb.dut_i0.i_cordic_clip[20] ddc_chain_tb.dut_i0.i_cordic_clip[19] ddc_chain_tb.dut_i0.i_cordic_clip[18] ddc_chain_tb.dut_i0.i_cordic_clip[17] ddc_chain_tb.dut_i0.i_cordic_clip[16] ddc_chain_tb.dut_i0.i_cordic_clip[15] ddc_chain_tb.dut_i0.i_cordic_clip[14] ddc_chain_tb.dut_i0.i_cordic_clip[13] ddc_chain_tb.dut_i0.i_cordic_clip[12] ddc_chain_tb.dut_i0.i_cordic_clip[11] ddc_chain_tb.dut_i0.i_cordic_clip[10] ddc_chain_tb.dut_i0.i_cordic_clip[9] ddc_chain_tb.dut_i0.i_cordic_clip[8] ddc_chain_tb.dut_i0.i_cordic_clip[7] ddc_chain_tb.dut_i0.i_cordic_clip[6] ddc_chain_tb.dut_i0.i_cordic_clip[5] ddc_chain_tb.dut_i0.i_cordic_clip[4] ddc_chain_tb.dut_i0.i_cordic_clip[3] ddc_chain_tb.dut_i0.i_cordic_clip[2] ddc_chain_tb.dut_i0.i_cordic_clip[1] ddc_chain_tb.dut_i0.i_cordic_clip[0] +@20000 +- +@10420 +#{ddc_chain_tb.dut_i0.q_cordic_clip[23:0]} ddc_chain_tb.dut_i0.q_cordic_clip[23] ddc_chain_tb.dut_i0.q_cordic_clip[22] ddc_chain_tb.dut_i0.q_cordic_clip[21] ddc_chain_tb.dut_i0.q_cordic_clip[20] ddc_chain_tb.dut_i0.q_cordic_clip[19] ddc_chain_tb.dut_i0.q_cordic_clip[18] ddc_chain_tb.dut_i0.q_cordic_clip[17] ddc_chain_tb.dut_i0.q_cordic_clip[16] ddc_chain_tb.dut_i0.q_cordic_clip[15] ddc_chain_tb.dut_i0.q_cordic_clip[14] ddc_chain_tb.dut_i0.q_cordic_clip[13] ddc_chain_tb.dut_i0.q_cordic_clip[12] ddc_chain_tb.dut_i0.q_cordic_clip[11] ddc_chain_tb.dut_i0.q_cordic_clip[10] ddc_chain_tb.dut_i0.q_cordic_clip[9] ddc_chain_tb.dut_i0.q_cordic_clip[8] ddc_chain_tb.dut_i0.q_cordic_clip[7] ddc_chain_tb.dut_i0.q_cordic_clip[6] ddc_chain_tb.dut_i0.q_cordic_clip[5] ddc_chain_tb.dut_i0.q_cordic_clip[4] ddc_chain_tb.dut_i0.q_cordic_clip[3] ddc_chain_tb.dut_i0.q_cordic_clip[2] ddc_chain_tb.dut_i0.q_cordic_clip[1] ddc_chain_tb.dut_i0.q_cordic_clip[0] +@20000 +- +@10420 +#{ddc_chain_tb.dut_i0.i_cic[23:0]} ddc_chain_tb.dut_i0.i_cic[23] ddc_chain_tb.dut_i0.i_cic[22] ddc_chain_tb.dut_i0.i_cic[21] ddc_chain_tb.dut_i0.i_cic[20] ddc_chain_tb.dut_i0.i_cic[19] ddc_chain_tb.dut_i0.i_cic[18] ddc_chain_tb.dut_i0.i_cic[17] ddc_chain_tb.dut_i0.i_cic[16] ddc_chain_tb.dut_i0.i_cic[15] ddc_chain_tb.dut_i0.i_cic[14] ddc_chain_tb.dut_i0.i_cic[13] ddc_chain_tb.dut_i0.i_cic[12] ddc_chain_tb.dut_i0.i_cic[11] ddc_chain_tb.dut_i0.i_cic[10] ddc_chain_tb.dut_i0.i_cic[9] ddc_chain_tb.dut_i0.i_cic[8] ddc_chain_tb.dut_i0.i_cic[7] ddc_chain_tb.dut_i0.i_cic[6] ddc_chain_tb.dut_i0.i_cic[5] ddc_chain_tb.dut_i0.i_cic[4] ddc_chain_tb.dut_i0.i_cic[3] ddc_chain_tb.dut_i0.i_cic[2] ddc_chain_tb.dut_i0.i_cic[1] ddc_chain_tb.dut_i0.i_cic[0] +@20000 +- +@10420 +#{ddc_chain_tb.dut_i0.q_cic[23:0]} ddc_chain_tb.dut_i0.q_cic[23] ddc_chain_tb.dut_i0.q_cic[22] ddc_chain_tb.dut_i0.q_cic[21] ddc_chain_tb.dut_i0.q_cic[20] ddc_chain_tb.dut_i0.q_cic[19] ddc_chain_tb.dut_i0.q_cic[18] ddc_chain_tb.dut_i0.q_cic[17] ddc_chain_tb.dut_i0.q_cic[16] ddc_chain_tb.dut_i0.q_cic[15] ddc_chain_tb.dut_i0.q_cic[14] ddc_chain_tb.dut_i0.q_cic[13] ddc_chain_tb.dut_i0.q_cic[12] ddc_chain_tb.dut_i0.q_cic[11] ddc_chain_tb.dut_i0.q_cic[10] ddc_chain_tb.dut_i0.q_cic[9] ddc_chain_tb.dut_i0.q_cic[8] ddc_chain_tb.dut_i0.q_cic[7] ddc_chain_tb.dut_i0.q_cic[6] ddc_chain_tb.dut_i0.q_cic[5] ddc_chain_tb.dut_i0.q_cic[4] ddc_chain_tb.dut_i0.q_cic[3] ddc_chain_tb.dut_i0.q_cic[2] ddc_chain_tb.dut_i0.q_cic[1] ddc_chain_tb.dut_i0.q_cic[0] +@20000 +- +@10420 +#{ddc_chain_tb.dut_i0.\new_hb.i_hb1[46:0]} ddc_chain_tb.dut_i0.\new_hb.i_hb1[46] ddc_chain_tb.dut_i0.\new_hb.i_hb1[45] ddc_chain_tb.dut_i0.\new_hb.i_hb1[44] ddc_chain_tb.dut_i0.\new_hb.i_hb1[43] ddc_chain_tb.dut_i0.\new_hb.i_hb1[42] ddc_chain_tb.dut_i0.\new_hb.i_hb1[41] ddc_chain_tb.dut_i0.\new_hb.i_hb1[40] ddc_chain_tb.dut_i0.\new_hb.i_hb1[39] ddc_chain_tb.dut_i0.\new_hb.i_hb1[38] ddc_chain_tb.dut_i0.\new_hb.i_hb1[37] ddc_chain_tb.dut_i0.\new_hb.i_hb1[36] ddc_chain_tb.dut_i0.\new_hb.i_hb1[35] ddc_chain_tb.dut_i0.\new_hb.i_hb1[34] ddc_chain_tb.dut_i0.\new_hb.i_hb1[33] ddc_chain_tb.dut_i0.\new_hb.i_hb1[32] ddc_chain_tb.dut_i0.\new_hb.i_hb1[31] ddc_chain_tb.dut_i0.\new_hb.i_hb1[30] ddc_chain_tb.dut_i0.\new_hb.i_hb1[29] ddc_chain_tb.dut_i0.\new_hb.i_hb1[28] ddc_chain_tb.dut_i0.\new_hb.i_hb1[27] ddc_chain_tb.dut_i0.\new_hb.i_hb1[26] ddc_chain_tb.dut_i0.\new_hb.i_hb1[25] ddc_chain_tb.dut_i0.\new_hb.i_hb1[24] ddc_chain_tb.dut_i0.\new_hb.i_hb1[23] ddc_chain_tb.dut_i0.\new_hb.i_hb1[22] ddc_chain_tb.dut_i0.\new_hb.i_hb1[21] ddc_chain_tb.dut_i0.\new_hb.i_hb1[20] ddc_chain_tb.dut_i0.\new_hb.i_hb1[19] ddc_chain_tb.dut_i0.\new_hb.i_hb1[18] ddc_chain_tb.dut_i0.\new_hb.i_hb1[17] ddc_chain_tb.dut_i0.\new_hb.i_hb1[16] ddc_chain_tb.dut_i0.\new_hb.i_hb1[15] ddc_chain_tb.dut_i0.\new_hb.i_hb1[14] ddc_chain_tb.dut_i0.\new_hb.i_hb1[13] ddc_chain_tb.dut_i0.\new_hb.i_hb1[12] ddc_chain_tb.dut_i0.\new_hb.i_hb1[11] ddc_chain_tb.dut_i0.\new_hb.i_hb1[10] ddc_chain_tb.dut_i0.\new_hb.i_hb1[9] ddc_chain_tb.dut_i0.\new_hb.i_hb1[8] ddc_chain_tb.dut_i0.\new_hb.i_hb1[7] ddc_chain_tb.dut_i0.\new_hb.i_hb1[6] ddc_chain_tb.dut_i0.\new_hb.i_hb1[5] ddc_chain_tb.dut_i0.\new_hb.i_hb1[4] ddc_chain_tb.dut_i0.\new_hb.i_hb1[3] ddc_chain_tb.dut_i0.\new_hb.i_hb1[2] ddc_chain_tb.dut_i0.\new_hb.i_hb1[1] ddc_chain_tb.dut_i0.\new_hb.i_hb1[0] +@20000 +- +@10420 +#{ddc_chain_tb.dut_i0.\new_hb.q_hb1[46:0]} ddc_chain_tb.dut_i0.\new_hb.q_hb1[46] ddc_chain_tb.dut_i0.\new_hb.q_hb1[45] ddc_chain_tb.dut_i0.\new_hb.q_hb1[44] ddc_chain_tb.dut_i0.\new_hb.q_hb1[43] ddc_chain_tb.dut_i0.\new_hb.q_hb1[42] ddc_chain_tb.dut_i0.\new_hb.q_hb1[41] ddc_chain_tb.dut_i0.\new_hb.q_hb1[40] ddc_chain_tb.dut_i0.\new_hb.q_hb1[39] ddc_chain_tb.dut_i0.\new_hb.q_hb1[38] ddc_chain_tb.dut_i0.\new_hb.q_hb1[37] ddc_chain_tb.dut_i0.\new_hb.q_hb1[36] ddc_chain_tb.dut_i0.\new_hb.q_hb1[35] ddc_chain_tb.dut_i0.\new_hb.q_hb1[34] ddc_chain_tb.dut_i0.\new_hb.q_hb1[33] ddc_chain_tb.dut_i0.\new_hb.q_hb1[32] ddc_chain_tb.dut_i0.\new_hb.q_hb1[31] ddc_chain_tb.dut_i0.\new_hb.q_hb1[30] ddc_chain_tb.dut_i0.\new_hb.q_hb1[29] ddc_chain_tb.dut_i0.\new_hb.q_hb1[28] ddc_chain_tb.dut_i0.\new_hb.q_hb1[27] ddc_chain_tb.dut_i0.\new_hb.q_hb1[26] ddc_chain_tb.dut_i0.\new_hb.q_hb1[25] ddc_chain_tb.dut_i0.\new_hb.q_hb1[24] ddc_chain_tb.dut_i0.\new_hb.q_hb1[23] ddc_chain_tb.dut_i0.\new_hb.q_hb1[22] ddc_chain_tb.dut_i0.\new_hb.q_hb1[21] ddc_chain_tb.dut_i0.\new_hb.q_hb1[20] ddc_chain_tb.dut_i0.\new_hb.q_hb1[19] ddc_chain_tb.dut_i0.\new_hb.q_hb1[18] ddc_chain_tb.dut_i0.\new_hb.q_hb1[17] ddc_chain_tb.dut_i0.\new_hb.q_hb1[16] ddc_chain_tb.dut_i0.\new_hb.q_hb1[15] ddc_chain_tb.dut_i0.\new_hb.q_hb1[14] ddc_chain_tb.dut_i0.\new_hb.q_hb1[13] ddc_chain_tb.dut_i0.\new_hb.q_hb1[12] ddc_chain_tb.dut_i0.\new_hb.q_hb1[11] ddc_chain_tb.dut_i0.\new_hb.q_hb1[10] ddc_chain_tb.dut_i0.\new_hb.q_hb1[9] ddc_chain_tb.dut_i0.\new_hb.q_hb1[8] ddc_chain_tb.dut_i0.\new_hb.q_hb1[7] ddc_chain_tb.dut_i0.\new_hb.q_hb1[6] ddc_chain_tb.dut_i0.\new_hb.q_hb1[5] ddc_chain_tb.dut_i0.\new_hb.q_hb1[4] ddc_chain_tb.dut_i0.\new_hb.q_hb1[3] ddc_chain_tb.dut_i0.\new_hb.q_hb1[2] ddc_chain_tb.dut_i0.\new_hb.q_hb1[1] ddc_chain_tb.dut_i0.\new_hb.q_hb1[0] +@20000 +- +@10420 +#{ddc_chain_tb.dut_i0.\new_hb.i_hb2[46:0]} ddc_chain_tb.dut_i0.\new_hb.i_hb2[46] ddc_chain_tb.dut_i0.\new_hb.i_hb2[45] ddc_chain_tb.dut_i0.\new_hb.i_hb2[44] ddc_chain_tb.dut_i0.\new_hb.i_hb2[43] ddc_chain_tb.dut_i0.\new_hb.i_hb2[42] ddc_chain_tb.dut_i0.\new_hb.i_hb2[41] ddc_chain_tb.dut_i0.\new_hb.i_hb2[40] ddc_chain_tb.dut_i0.\new_hb.i_hb2[39] ddc_chain_tb.dut_i0.\new_hb.i_hb2[38] ddc_chain_tb.dut_i0.\new_hb.i_hb2[37] ddc_chain_tb.dut_i0.\new_hb.i_hb2[36] ddc_chain_tb.dut_i0.\new_hb.i_hb2[35] ddc_chain_tb.dut_i0.\new_hb.i_hb2[34] ddc_chain_tb.dut_i0.\new_hb.i_hb2[33] ddc_chain_tb.dut_i0.\new_hb.i_hb2[32] ddc_chain_tb.dut_i0.\new_hb.i_hb2[31] ddc_chain_tb.dut_i0.\new_hb.i_hb2[30] ddc_chain_tb.dut_i0.\new_hb.i_hb2[29] ddc_chain_tb.dut_i0.\new_hb.i_hb2[28] ddc_chain_tb.dut_i0.\new_hb.i_hb2[27] ddc_chain_tb.dut_i0.\new_hb.i_hb2[26] ddc_chain_tb.dut_i0.\new_hb.i_hb2[25] ddc_chain_tb.dut_i0.\new_hb.i_hb2[24] ddc_chain_tb.dut_i0.\new_hb.i_hb2[23] ddc_chain_tb.dut_i0.\new_hb.i_hb2[22] ddc_chain_tb.dut_i0.\new_hb.i_hb2[21] ddc_chain_tb.dut_i0.\new_hb.i_hb2[20] ddc_chain_tb.dut_i0.\new_hb.i_hb2[19] ddc_chain_tb.dut_i0.\new_hb.i_hb2[18] ddc_chain_tb.dut_i0.\new_hb.i_hb2[17] ddc_chain_tb.dut_i0.\new_hb.i_hb2[16] ddc_chain_tb.dut_i0.\new_hb.i_hb2[15] ddc_chain_tb.dut_i0.\new_hb.i_hb2[14] ddc_chain_tb.dut_i0.\new_hb.i_hb2[13] ddc_chain_tb.dut_i0.\new_hb.i_hb2[12] ddc_chain_tb.dut_i0.\new_hb.i_hb2[11] ddc_chain_tb.dut_i0.\new_hb.i_hb2[10] ddc_chain_tb.dut_i0.\new_hb.i_hb2[9] ddc_chain_tb.dut_i0.\new_hb.i_hb2[8] ddc_chain_tb.dut_i0.\new_hb.i_hb2[7] ddc_chain_tb.dut_i0.\new_hb.i_hb2[6] ddc_chain_tb.dut_i0.\new_hb.i_hb2[5] ddc_chain_tb.dut_i0.\new_hb.i_hb2[4] ddc_chain_tb.dut_i0.\new_hb.i_hb2[3] ddc_chain_tb.dut_i0.\new_hb.i_hb2[2] ddc_chain_tb.dut_i0.\new_hb.i_hb2[1] ddc_chain_tb.dut_i0.\new_hb.i_hb2[0] +#{ddc_chain_tb.dut_i0.\new_hb.q_hb2[46:0]} ddc_chain_tb.dut_i0.\new_hb.q_hb2[46] ddc_chain_tb.dut_i0.\new_hb.q_hb2[45] ddc_chain_tb.dut_i0.\new_hb.q_hb2[44] ddc_chain_tb.dut_i0.\new_hb.q_hb2[43] ddc_chain_tb.dut_i0.\new_hb.q_hb2[42] ddc_chain_tb.dut_i0.\new_hb.q_hb2[41] ddc_chain_tb.dut_i0.\new_hb.q_hb2[40] ddc_chain_tb.dut_i0.\new_hb.q_hb2[39] ddc_chain_tb.dut_i0.\new_hb.q_hb2[38] ddc_chain_tb.dut_i0.\new_hb.q_hb2[37] ddc_chain_tb.dut_i0.\new_hb.q_hb2[36] ddc_chain_tb.dut_i0.\new_hb.q_hb2[35] ddc_chain_tb.dut_i0.\new_hb.q_hb2[34] ddc_chain_tb.dut_i0.\new_hb.q_hb2[33] ddc_chain_tb.dut_i0.\new_hb.q_hb2[32] ddc_chain_tb.dut_i0.\new_hb.q_hb2[31] ddc_chain_tb.dut_i0.\new_hb.q_hb2[30] ddc_chain_tb.dut_i0.\new_hb.q_hb2[29] ddc_chain_tb.dut_i0.\new_hb.q_hb2[28] ddc_chain_tb.dut_i0.\new_hb.q_hb2[27] ddc_chain_tb.dut_i0.\new_hb.q_hb2[26] ddc_chain_tb.dut_i0.\new_hb.q_hb2[25] ddc_chain_tb.dut_i0.\new_hb.q_hb2[24] ddc_chain_tb.dut_i0.\new_hb.q_hb2[23] ddc_chain_tb.dut_i0.\new_hb.q_hb2[22] ddc_chain_tb.dut_i0.\new_hb.q_hb2[21] ddc_chain_tb.dut_i0.\new_hb.q_hb2[20] ddc_chain_tb.dut_i0.\new_hb.q_hb2[19] ddc_chain_tb.dut_i0.\new_hb.q_hb2[18] ddc_chain_tb.dut_i0.\new_hb.q_hb2[17] ddc_chain_tb.dut_i0.\new_hb.q_hb2[16] ddc_chain_tb.dut_i0.\new_hb.q_hb2[15] ddc_chain_tb.dut_i0.\new_hb.q_hb2[14] ddc_chain_tb.dut_i0.\new_hb.q_hb2[13] ddc_chain_tb.dut_i0.\new_hb.q_hb2[12] ddc_chain_tb.dut_i0.\new_hb.q_hb2[11] ddc_chain_tb.dut_i0.\new_hb.q_hb2[10] ddc_chain_tb.dut_i0.\new_hb.q_hb2[9] ddc_chain_tb.dut_i0.\new_hb.q_hb2[8] ddc_chain_tb.dut_i0.\new_hb.q_hb2[7] ddc_chain_tb.dut_i0.\new_hb.q_hb2[6] ddc_chain_tb.dut_i0.\new_hb.q_hb2[5] ddc_chain_tb.dut_i0.\new_hb.q_hb2[4] ddc_chain_tb.dut_i0.\new_hb.q_hb2[3] ddc_chain_tb.dut_i0.\new_hb.q_hb2[2] ddc_chain_tb.dut_i0.\new_hb.q_hb2[1] ddc_chain_tb.dut_i0.\new_hb.q_hb2[0] +@20000 +- +[pattern_trace] 1 +[pattern_trace] 0 diff --git a/fpga/usrp3/lib/dsp/sim/sim_ddc_chain/dc_in_cordic_decim_2/simulation_script.v b/fpga/usrp3/lib/dsp/sim/sim_ddc_chain/dc_in_cordic_decim_2/simulation_script.v new file mode 100644 index 000000000..0eeb661da --- /dev/null +++ b/fpga/usrp3/lib/dsp/sim/sim_ddc_chain/dc_in_cordic_decim_2/simulation_script.v @@ -0,0 +1,82 @@ +// +// Copyright 2015 Ettus Research, a National Instruments Company +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// 10MHz master_clock_rate +always #50 clk <= ~clk; + + initial + begin + reset <= 1'b0; + i_in <= 0; + q_in <= 0; + run <= 0; + set_stb <= 0; + set_addr <= 0; + set_data <= 0; + + + @(posedge clk); + // Into Reset... + reset <= 1'b1; + repeat(10) @(posedge clk); + // .. and back out of reset. + reset <= 1'b0; + repeat(10) @(posedge clk); + // Now program DSP configuration via settings regs. + write_setting_bus(SR_DSP_RX_FREQ,42949672); // 100kHz @ 10MHz MCR + // (1 << 15) * std::pow(2, ceil_log2(rate_pow))*2./(1.648*rate_pow) + write_setting_bus(SR_DSP_RX_SCALE_IQ, 39767); // Should include CORDIC and CIC gain compensation. + write_setting_bus(SR_DSP_RX_DECIM, 1<<9|1); // Decim = 2 + write_setting_bus(SR_DSP_RX_MUX, 0); + write_setting_bus(SR_DSP_RX_COEFFS,0); + repeat(10) @(posedge clk); + + // Set complex data inputs to DC unit circle position. + i_in <= 12'h7ff; + q_in <= 12'h0; + run <= 1'b1; + repeat(100) @(posedge clk); + // Set complex data inputs to simulate ADC saturation of front end + i_in <= 12'h7ff; + q_in <= 12'h100; + repeat(1000) @(posedge clk); + i_in <= 12'h7ff; + q_in <= 12'h200; + repeat(1000) @(posedge clk); + i_in <= 12'h7ff; + q_in <= 12'h300; + repeat(1000) @(posedge clk); + i_in <= 12'h7ff; + q_in <= 12'h400; + repeat(1000) @(posedge clk); + i_in <= 12'h7ff; + q_in <= 12'h500; + repeat(1000) @(posedge clk); + i_in <= 12'h7ff; + q_in <= 12'h600; + repeat(1000) @(posedge clk); + i_in <= 12'h7ff; + q_in <= 12'h700; + repeat(1000) @(posedge clk); + i_in <= 12'h7ff; + q_in <= 12'h7FF; + // Now test small signal performance + repeat(1000) @(posedge clk); + i_in <= 12'h001; + q_in <= 12'h000; + repeat(1000) @(posedge clk); + i_in <= 12'h000; + q_in <= 12'h001; + repeat(1000) @(posedge clk); + i_in <= 12'hfff; + q_in <= 12'h000; + repeat(1000) @(posedge clk); + i_in <= 12'h000; + q_in <= 12'hfff; + + repeat(100000) @(posedge clk); + $finish(); + + end // initial begin diff --git a/fpga/usrp3/lib/dsp/sim/sim_ddc_chain/dc_in_cordic_decim_6/gtk.conf.gtkw b/fpga/usrp3/lib/dsp/sim/sim_ddc_chain/dc_in_cordic_decim_6/gtk.conf.gtkw new file mode 100644 index 000000000..27c2c836e --- /dev/null +++ b/fpga/usrp3/lib/dsp/sim/sim_ddc_chain/dc_in_cordic_decim_6/gtk.conf.gtkw @@ -0,0 +1,64 @@ +[*] +[*] GTKWave Analyzer v3.3.40 (w)1999-2012 BSI +[*] Wed Jul 15 02:18:40 2015 +[*] +[dumpfile] "/disk2/ianb/ettus/fpgadev-b200/fpgadev/usrp3/lib/dsp/sim/sim_ddc_chain/dc_in_cordic_run/waves.vcd" +[dumpfile_mtime] "Wed Jul 15 02:13:19 2015" +[dumpfile_size] 238141440 +[savefile] "/disk2/ianb/ettus/fpgadev-b200/fpgadev/usrp3/lib/dsp/sim/sim_ddc_chain/dc_in_cordic_run/gtk.conf.gtkw" +[timestart] 0 +[size] 2488 1221 +[pos] -1 -1 +*-24.083374 129800000 -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 +[treeopen] ddc_chain_tb. +[treeopen] ddc_chain_tb.dut_i0. +[sst_width] 331 +[signals_width] 280 +[sst_expanded] 1 +[sst_vpaned_height] 370 +@28 +ddc_chain_tb.dut_i0.clk +ddc_chain_tb.dut_i0.rst +ddc_chain_tb.dut_i0.set_stb +@22 +#{ddc_chain_tb.dut_i0.set_addr[7:0]} ddc_chain_tb.dut_i0.set_addr[7] ddc_chain_tb.dut_i0.set_addr[6] ddc_chain_tb.dut_i0.set_addr[5] ddc_chain_tb.dut_i0.set_addr[4] ddc_chain_tb.dut_i0.set_addr[3] ddc_chain_tb.dut_i0.set_addr[2] ddc_chain_tb.dut_i0.set_addr[1] ddc_chain_tb.dut_i0.set_addr[0] +#{ddc_chain_tb.dut_i0.set_data[31:0]} ddc_chain_tb.dut_i0.set_data[31] ddc_chain_tb.dut_i0.set_data[30] ddc_chain_tb.dut_i0.set_data[29] ddc_chain_tb.dut_i0.set_data[28] ddc_chain_tb.dut_i0.set_data[27] ddc_chain_tb.dut_i0.set_data[26] ddc_chain_tb.dut_i0.set_data[25] ddc_chain_tb.dut_i0.set_data[24] ddc_chain_tb.dut_i0.set_data[23] ddc_chain_tb.dut_i0.set_data[22] ddc_chain_tb.dut_i0.set_data[21] ddc_chain_tb.dut_i0.set_data[20] ddc_chain_tb.dut_i0.set_data[19] ddc_chain_tb.dut_i0.set_data[18] ddc_chain_tb.dut_i0.set_data[17] ddc_chain_tb.dut_i0.set_data[16] ddc_chain_tb.dut_i0.set_data[15] ddc_chain_tb.dut_i0.set_data[14] ddc_chain_tb.dut_i0.set_data[13] ddc_chain_tb.dut_i0.set_data[12] ddc_chain_tb.dut_i0.set_data[11] ddc_chain_tb.dut_i0.set_data[10] ddc_chain_tb.dut_i0.set_data[9] ddc_chain_tb.dut_i0.set_data[8] ddc_chain_tb.dut_i0.set_data[7] ddc_chain_tb.dut_i0.set_data[6] ddc_chain_tb.dut_i0.set_data[5] ddc_chain_tb.dut_i0.set_data[4] ddc_chain_tb.dut_i0.set_data[3] ddc_chain_tb.dut_i0.set_data[2] ddc_chain_tb.dut_i0.set_data[1] ddc_chain_tb.dut_i0.set_data[0] +@10420 +#{ddc_chain_tb.dut_i0.rx_fe_i[23:0]} ddc_chain_tb.dut_i0.rx_fe_i[23] ddc_chain_tb.dut_i0.rx_fe_i[22] ddc_chain_tb.dut_i0.rx_fe_i[21] ddc_chain_tb.dut_i0.rx_fe_i[20] ddc_chain_tb.dut_i0.rx_fe_i[19] ddc_chain_tb.dut_i0.rx_fe_i[18] ddc_chain_tb.dut_i0.rx_fe_i[17] ddc_chain_tb.dut_i0.rx_fe_i[16] ddc_chain_tb.dut_i0.rx_fe_i[15] ddc_chain_tb.dut_i0.rx_fe_i[14] ddc_chain_tb.dut_i0.rx_fe_i[13] ddc_chain_tb.dut_i0.rx_fe_i[12] ddc_chain_tb.dut_i0.rx_fe_i[11] ddc_chain_tb.dut_i0.rx_fe_i[10] ddc_chain_tb.dut_i0.rx_fe_i[9] ddc_chain_tb.dut_i0.rx_fe_i[8] ddc_chain_tb.dut_i0.rx_fe_i[7] ddc_chain_tb.dut_i0.rx_fe_i[6] ddc_chain_tb.dut_i0.rx_fe_i[5] ddc_chain_tb.dut_i0.rx_fe_i[4] ddc_chain_tb.dut_i0.rx_fe_i[3] ddc_chain_tb.dut_i0.rx_fe_i[2] ddc_chain_tb.dut_i0.rx_fe_i[1] ddc_chain_tb.dut_i0.rx_fe_i[0] +@20000 +- +@10420 +#{ddc_chain_tb.dut_i0.rx_fe_q[23:0]} ddc_chain_tb.dut_i0.rx_fe_q[23] ddc_chain_tb.dut_i0.rx_fe_q[22] ddc_chain_tb.dut_i0.rx_fe_q[21] ddc_chain_tb.dut_i0.rx_fe_q[20] ddc_chain_tb.dut_i0.rx_fe_q[19] ddc_chain_tb.dut_i0.rx_fe_q[18] ddc_chain_tb.dut_i0.rx_fe_q[17] ddc_chain_tb.dut_i0.rx_fe_q[16] ddc_chain_tb.dut_i0.rx_fe_q[15] ddc_chain_tb.dut_i0.rx_fe_q[14] ddc_chain_tb.dut_i0.rx_fe_q[13] ddc_chain_tb.dut_i0.rx_fe_q[12] ddc_chain_tb.dut_i0.rx_fe_q[11] ddc_chain_tb.dut_i0.rx_fe_q[10] ddc_chain_tb.dut_i0.rx_fe_q[9] ddc_chain_tb.dut_i0.rx_fe_q[8] ddc_chain_tb.dut_i0.rx_fe_q[7] ddc_chain_tb.dut_i0.rx_fe_q[6] ddc_chain_tb.dut_i0.rx_fe_q[5] ddc_chain_tb.dut_i0.rx_fe_q[4] ddc_chain_tb.dut_i0.rx_fe_q[3] ddc_chain_tb.dut_i0.rx_fe_q[2] ddc_chain_tb.dut_i0.rx_fe_q[1] ddc_chain_tb.dut_i0.rx_fe_q[0] +@20000 +- +@10420 +#{ddc_chain_tb.dut_i0.i_cordic_clip[23:0]} ddc_chain_tb.dut_i0.i_cordic_clip[23] ddc_chain_tb.dut_i0.i_cordic_clip[22] ddc_chain_tb.dut_i0.i_cordic_clip[21] ddc_chain_tb.dut_i0.i_cordic_clip[20] ddc_chain_tb.dut_i0.i_cordic_clip[19] ddc_chain_tb.dut_i0.i_cordic_clip[18] ddc_chain_tb.dut_i0.i_cordic_clip[17] ddc_chain_tb.dut_i0.i_cordic_clip[16] ddc_chain_tb.dut_i0.i_cordic_clip[15] ddc_chain_tb.dut_i0.i_cordic_clip[14] ddc_chain_tb.dut_i0.i_cordic_clip[13] ddc_chain_tb.dut_i0.i_cordic_clip[12] ddc_chain_tb.dut_i0.i_cordic_clip[11] ddc_chain_tb.dut_i0.i_cordic_clip[10] ddc_chain_tb.dut_i0.i_cordic_clip[9] ddc_chain_tb.dut_i0.i_cordic_clip[8] ddc_chain_tb.dut_i0.i_cordic_clip[7] ddc_chain_tb.dut_i0.i_cordic_clip[6] ddc_chain_tb.dut_i0.i_cordic_clip[5] ddc_chain_tb.dut_i0.i_cordic_clip[4] ddc_chain_tb.dut_i0.i_cordic_clip[3] ddc_chain_tb.dut_i0.i_cordic_clip[2] ddc_chain_tb.dut_i0.i_cordic_clip[1] ddc_chain_tb.dut_i0.i_cordic_clip[0] +@20000 +- +@10420 +#{ddc_chain_tb.dut_i0.q_cordic_clip[23:0]} ddc_chain_tb.dut_i0.q_cordic_clip[23] ddc_chain_tb.dut_i0.q_cordic_clip[22] ddc_chain_tb.dut_i0.q_cordic_clip[21] ddc_chain_tb.dut_i0.q_cordic_clip[20] ddc_chain_tb.dut_i0.q_cordic_clip[19] ddc_chain_tb.dut_i0.q_cordic_clip[18] ddc_chain_tb.dut_i0.q_cordic_clip[17] ddc_chain_tb.dut_i0.q_cordic_clip[16] ddc_chain_tb.dut_i0.q_cordic_clip[15] ddc_chain_tb.dut_i0.q_cordic_clip[14] ddc_chain_tb.dut_i0.q_cordic_clip[13] ddc_chain_tb.dut_i0.q_cordic_clip[12] ddc_chain_tb.dut_i0.q_cordic_clip[11] ddc_chain_tb.dut_i0.q_cordic_clip[10] ddc_chain_tb.dut_i0.q_cordic_clip[9] ddc_chain_tb.dut_i0.q_cordic_clip[8] ddc_chain_tb.dut_i0.q_cordic_clip[7] ddc_chain_tb.dut_i0.q_cordic_clip[6] ddc_chain_tb.dut_i0.q_cordic_clip[5] ddc_chain_tb.dut_i0.q_cordic_clip[4] ddc_chain_tb.dut_i0.q_cordic_clip[3] ddc_chain_tb.dut_i0.q_cordic_clip[2] ddc_chain_tb.dut_i0.q_cordic_clip[1] ddc_chain_tb.dut_i0.q_cordic_clip[0] +@20000 +- +@10420 +#{ddc_chain_tb.dut_i0.i_cic[23:0]} ddc_chain_tb.dut_i0.i_cic[23] ddc_chain_tb.dut_i0.i_cic[22] ddc_chain_tb.dut_i0.i_cic[21] ddc_chain_tb.dut_i0.i_cic[20] ddc_chain_tb.dut_i0.i_cic[19] ddc_chain_tb.dut_i0.i_cic[18] ddc_chain_tb.dut_i0.i_cic[17] ddc_chain_tb.dut_i0.i_cic[16] ddc_chain_tb.dut_i0.i_cic[15] ddc_chain_tb.dut_i0.i_cic[14] ddc_chain_tb.dut_i0.i_cic[13] ddc_chain_tb.dut_i0.i_cic[12] ddc_chain_tb.dut_i0.i_cic[11] ddc_chain_tb.dut_i0.i_cic[10] ddc_chain_tb.dut_i0.i_cic[9] ddc_chain_tb.dut_i0.i_cic[8] ddc_chain_tb.dut_i0.i_cic[7] ddc_chain_tb.dut_i0.i_cic[6] ddc_chain_tb.dut_i0.i_cic[5] ddc_chain_tb.dut_i0.i_cic[4] ddc_chain_tb.dut_i0.i_cic[3] ddc_chain_tb.dut_i0.i_cic[2] ddc_chain_tb.dut_i0.i_cic[1] ddc_chain_tb.dut_i0.i_cic[0] +@20000 +- +@10420 +#{ddc_chain_tb.dut_i0.q_cic[23:0]} ddc_chain_tb.dut_i0.q_cic[23] ddc_chain_tb.dut_i0.q_cic[22] ddc_chain_tb.dut_i0.q_cic[21] ddc_chain_tb.dut_i0.q_cic[20] ddc_chain_tb.dut_i0.q_cic[19] ddc_chain_tb.dut_i0.q_cic[18] ddc_chain_tb.dut_i0.q_cic[17] ddc_chain_tb.dut_i0.q_cic[16] ddc_chain_tb.dut_i0.q_cic[15] ddc_chain_tb.dut_i0.q_cic[14] ddc_chain_tb.dut_i0.q_cic[13] ddc_chain_tb.dut_i0.q_cic[12] ddc_chain_tb.dut_i0.q_cic[11] ddc_chain_tb.dut_i0.q_cic[10] ddc_chain_tb.dut_i0.q_cic[9] ddc_chain_tb.dut_i0.q_cic[8] ddc_chain_tb.dut_i0.q_cic[7] ddc_chain_tb.dut_i0.q_cic[6] ddc_chain_tb.dut_i0.q_cic[5] ddc_chain_tb.dut_i0.q_cic[4] ddc_chain_tb.dut_i0.q_cic[3] ddc_chain_tb.dut_i0.q_cic[2] ddc_chain_tb.dut_i0.q_cic[1] ddc_chain_tb.dut_i0.q_cic[0] +@20000 +- +@10420 +#{ddc_chain_tb.dut_i0.\new_hb.i_hb1[46:0]} ddc_chain_tb.dut_i0.\new_hb.i_hb1[46] ddc_chain_tb.dut_i0.\new_hb.i_hb1[45] ddc_chain_tb.dut_i0.\new_hb.i_hb1[44] ddc_chain_tb.dut_i0.\new_hb.i_hb1[43] ddc_chain_tb.dut_i0.\new_hb.i_hb1[42] ddc_chain_tb.dut_i0.\new_hb.i_hb1[41] ddc_chain_tb.dut_i0.\new_hb.i_hb1[40] ddc_chain_tb.dut_i0.\new_hb.i_hb1[39] ddc_chain_tb.dut_i0.\new_hb.i_hb1[38] ddc_chain_tb.dut_i0.\new_hb.i_hb1[37] ddc_chain_tb.dut_i0.\new_hb.i_hb1[36] ddc_chain_tb.dut_i0.\new_hb.i_hb1[35] ddc_chain_tb.dut_i0.\new_hb.i_hb1[34] ddc_chain_tb.dut_i0.\new_hb.i_hb1[33] ddc_chain_tb.dut_i0.\new_hb.i_hb1[32] ddc_chain_tb.dut_i0.\new_hb.i_hb1[31] ddc_chain_tb.dut_i0.\new_hb.i_hb1[30] ddc_chain_tb.dut_i0.\new_hb.i_hb1[29] ddc_chain_tb.dut_i0.\new_hb.i_hb1[28] ddc_chain_tb.dut_i0.\new_hb.i_hb1[27] ddc_chain_tb.dut_i0.\new_hb.i_hb1[26] ddc_chain_tb.dut_i0.\new_hb.i_hb1[25] ddc_chain_tb.dut_i0.\new_hb.i_hb1[24] ddc_chain_tb.dut_i0.\new_hb.i_hb1[23] ddc_chain_tb.dut_i0.\new_hb.i_hb1[22] ddc_chain_tb.dut_i0.\new_hb.i_hb1[21] ddc_chain_tb.dut_i0.\new_hb.i_hb1[20] ddc_chain_tb.dut_i0.\new_hb.i_hb1[19] ddc_chain_tb.dut_i0.\new_hb.i_hb1[18] ddc_chain_tb.dut_i0.\new_hb.i_hb1[17] ddc_chain_tb.dut_i0.\new_hb.i_hb1[16] ddc_chain_tb.dut_i0.\new_hb.i_hb1[15] ddc_chain_tb.dut_i0.\new_hb.i_hb1[14] ddc_chain_tb.dut_i0.\new_hb.i_hb1[13] ddc_chain_tb.dut_i0.\new_hb.i_hb1[12] ddc_chain_tb.dut_i0.\new_hb.i_hb1[11] ddc_chain_tb.dut_i0.\new_hb.i_hb1[10] ddc_chain_tb.dut_i0.\new_hb.i_hb1[9] ddc_chain_tb.dut_i0.\new_hb.i_hb1[8] ddc_chain_tb.dut_i0.\new_hb.i_hb1[7] ddc_chain_tb.dut_i0.\new_hb.i_hb1[6] ddc_chain_tb.dut_i0.\new_hb.i_hb1[5] ddc_chain_tb.dut_i0.\new_hb.i_hb1[4] ddc_chain_tb.dut_i0.\new_hb.i_hb1[3] ddc_chain_tb.dut_i0.\new_hb.i_hb1[2] ddc_chain_tb.dut_i0.\new_hb.i_hb1[1] ddc_chain_tb.dut_i0.\new_hb.i_hb1[0] +@20000 +- +@10420 +#{ddc_chain_tb.dut_i0.\new_hb.q_hb1[46:0]} ddc_chain_tb.dut_i0.\new_hb.q_hb1[46] ddc_chain_tb.dut_i0.\new_hb.q_hb1[45] ddc_chain_tb.dut_i0.\new_hb.q_hb1[44] ddc_chain_tb.dut_i0.\new_hb.q_hb1[43] ddc_chain_tb.dut_i0.\new_hb.q_hb1[42] ddc_chain_tb.dut_i0.\new_hb.q_hb1[41] ddc_chain_tb.dut_i0.\new_hb.q_hb1[40] ddc_chain_tb.dut_i0.\new_hb.q_hb1[39] ddc_chain_tb.dut_i0.\new_hb.q_hb1[38] ddc_chain_tb.dut_i0.\new_hb.q_hb1[37] ddc_chain_tb.dut_i0.\new_hb.q_hb1[36] ddc_chain_tb.dut_i0.\new_hb.q_hb1[35] ddc_chain_tb.dut_i0.\new_hb.q_hb1[34] ddc_chain_tb.dut_i0.\new_hb.q_hb1[33] ddc_chain_tb.dut_i0.\new_hb.q_hb1[32] ddc_chain_tb.dut_i0.\new_hb.q_hb1[31] ddc_chain_tb.dut_i0.\new_hb.q_hb1[30] ddc_chain_tb.dut_i0.\new_hb.q_hb1[29] ddc_chain_tb.dut_i0.\new_hb.q_hb1[28] ddc_chain_tb.dut_i0.\new_hb.q_hb1[27] ddc_chain_tb.dut_i0.\new_hb.q_hb1[26] ddc_chain_tb.dut_i0.\new_hb.q_hb1[25] ddc_chain_tb.dut_i0.\new_hb.q_hb1[24] ddc_chain_tb.dut_i0.\new_hb.q_hb1[23] ddc_chain_tb.dut_i0.\new_hb.q_hb1[22] ddc_chain_tb.dut_i0.\new_hb.q_hb1[21] ddc_chain_tb.dut_i0.\new_hb.q_hb1[20] ddc_chain_tb.dut_i0.\new_hb.q_hb1[19] ddc_chain_tb.dut_i0.\new_hb.q_hb1[18] ddc_chain_tb.dut_i0.\new_hb.q_hb1[17] ddc_chain_tb.dut_i0.\new_hb.q_hb1[16] ddc_chain_tb.dut_i0.\new_hb.q_hb1[15] ddc_chain_tb.dut_i0.\new_hb.q_hb1[14] ddc_chain_tb.dut_i0.\new_hb.q_hb1[13] ddc_chain_tb.dut_i0.\new_hb.q_hb1[12] ddc_chain_tb.dut_i0.\new_hb.q_hb1[11] ddc_chain_tb.dut_i0.\new_hb.q_hb1[10] ddc_chain_tb.dut_i0.\new_hb.q_hb1[9] ddc_chain_tb.dut_i0.\new_hb.q_hb1[8] ddc_chain_tb.dut_i0.\new_hb.q_hb1[7] ddc_chain_tb.dut_i0.\new_hb.q_hb1[6] ddc_chain_tb.dut_i0.\new_hb.q_hb1[5] ddc_chain_tb.dut_i0.\new_hb.q_hb1[4] ddc_chain_tb.dut_i0.\new_hb.q_hb1[3] ddc_chain_tb.dut_i0.\new_hb.q_hb1[2] ddc_chain_tb.dut_i0.\new_hb.q_hb1[1] ddc_chain_tb.dut_i0.\new_hb.q_hb1[0] +@20000 +- +@10420 +#{ddc_chain_tb.dut_i0.\new_hb.i_hb2[46:0]} ddc_chain_tb.dut_i0.\new_hb.i_hb2[46] ddc_chain_tb.dut_i0.\new_hb.i_hb2[45] ddc_chain_tb.dut_i0.\new_hb.i_hb2[44] ddc_chain_tb.dut_i0.\new_hb.i_hb2[43] ddc_chain_tb.dut_i0.\new_hb.i_hb2[42] ddc_chain_tb.dut_i0.\new_hb.i_hb2[41] ddc_chain_tb.dut_i0.\new_hb.i_hb2[40] ddc_chain_tb.dut_i0.\new_hb.i_hb2[39] ddc_chain_tb.dut_i0.\new_hb.i_hb2[38] ddc_chain_tb.dut_i0.\new_hb.i_hb2[37] ddc_chain_tb.dut_i0.\new_hb.i_hb2[36] ddc_chain_tb.dut_i0.\new_hb.i_hb2[35] ddc_chain_tb.dut_i0.\new_hb.i_hb2[34] ddc_chain_tb.dut_i0.\new_hb.i_hb2[33] ddc_chain_tb.dut_i0.\new_hb.i_hb2[32] ddc_chain_tb.dut_i0.\new_hb.i_hb2[31] ddc_chain_tb.dut_i0.\new_hb.i_hb2[30] ddc_chain_tb.dut_i0.\new_hb.i_hb2[29] ddc_chain_tb.dut_i0.\new_hb.i_hb2[28] ddc_chain_tb.dut_i0.\new_hb.i_hb2[27] ddc_chain_tb.dut_i0.\new_hb.i_hb2[26] ddc_chain_tb.dut_i0.\new_hb.i_hb2[25] ddc_chain_tb.dut_i0.\new_hb.i_hb2[24] ddc_chain_tb.dut_i0.\new_hb.i_hb2[23] ddc_chain_tb.dut_i0.\new_hb.i_hb2[22] ddc_chain_tb.dut_i0.\new_hb.i_hb2[21] ddc_chain_tb.dut_i0.\new_hb.i_hb2[20] ddc_chain_tb.dut_i0.\new_hb.i_hb2[19] ddc_chain_tb.dut_i0.\new_hb.i_hb2[18] ddc_chain_tb.dut_i0.\new_hb.i_hb2[17] ddc_chain_tb.dut_i0.\new_hb.i_hb2[16] ddc_chain_tb.dut_i0.\new_hb.i_hb2[15] ddc_chain_tb.dut_i0.\new_hb.i_hb2[14] ddc_chain_tb.dut_i0.\new_hb.i_hb2[13] ddc_chain_tb.dut_i0.\new_hb.i_hb2[12] ddc_chain_tb.dut_i0.\new_hb.i_hb2[11] ddc_chain_tb.dut_i0.\new_hb.i_hb2[10] ddc_chain_tb.dut_i0.\new_hb.i_hb2[9] ddc_chain_tb.dut_i0.\new_hb.i_hb2[8] ddc_chain_tb.dut_i0.\new_hb.i_hb2[7] ddc_chain_tb.dut_i0.\new_hb.i_hb2[6] ddc_chain_tb.dut_i0.\new_hb.i_hb2[5] ddc_chain_tb.dut_i0.\new_hb.i_hb2[4] ddc_chain_tb.dut_i0.\new_hb.i_hb2[3] ddc_chain_tb.dut_i0.\new_hb.i_hb2[2] ddc_chain_tb.dut_i0.\new_hb.i_hb2[1] ddc_chain_tb.dut_i0.\new_hb.i_hb2[0] +#{ddc_chain_tb.dut_i0.\new_hb.q_hb2[46:0]} ddc_chain_tb.dut_i0.\new_hb.q_hb2[46] ddc_chain_tb.dut_i0.\new_hb.q_hb2[45] ddc_chain_tb.dut_i0.\new_hb.q_hb2[44] ddc_chain_tb.dut_i0.\new_hb.q_hb2[43] ddc_chain_tb.dut_i0.\new_hb.q_hb2[42] ddc_chain_tb.dut_i0.\new_hb.q_hb2[41] ddc_chain_tb.dut_i0.\new_hb.q_hb2[40] ddc_chain_tb.dut_i0.\new_hb.q_hb2[39] ddc_chain_tb.dut_i0.\new_hb.q_hb2[38] ddc_chain_tb.dut_i0.\new_hb.q_hb2[37] ddc_chain_tb.dut_i0.\new_hb.q_hb2[36] ddc_chain_tb.dut_i0.\new_hb.q_hb2[35] ddc_chain_tb.dut_i0.\new_hb.q_hb2[34] ddc_chain_tb.dut_i0.\new_hb.q_hb2[33] ddc_chain_tb.dut_i0.\new_hb.q_hb2[32] ddc_chain_tb.dut_i0.\new_hb.q_hb2[31] ddc_chain_tb.dut_i0.\new_hb.q_hb2[30] ddc_chain_tb.dut_i0.\new_hb.q_hb2[29] ddc_chain_tb.dut_i0.\new_hb.q_hb2[28] ddc_chain_tb.dut_i0.\new_hb.q_hb2[27] ddc_chain_tb.dut_i0.\new_hb.q_hb2[26] ddc_chain_tb.dut_i0.\new_hb.q_hb2[25] ddc_chain_tb.dut_i0.\new_hb.q_hb2[24] ddc_chain_tb.dut_i0.\new_hb.q_hb2[23] ddc_chain_tb.dut_i0.\new_hb.q_hb2[22] ddc_chain_tb.dut_i0.\new_hb.q_hb2[21] ddc_chain_tb.dut_i0.\new_hb.q_hb2[20] ddc_chain_tb.dut_i0.\new_hb.q_hb2[19] ddc_chain_tb.dut_i0.\new_hb.q_hb2[18] ddc_chain_tb.dut_i0.\new_hb.q_hb2[17] ddc_chain_tb.dut_i0.\new_hb.q_hb2[16] ddc_chain_tb.dut_i0.\new_hb.q_hb2[15] ddc_chain_tb.dut_i0.\new_hb.q_hb2[14] ddc_chain_tb.dut_i0.\new_hb.q_hb2[13] ddc_chain_tb.dut_i0.\new_hb.q_hb2[12] ddc_chain_tb.dut_i0.\new_hb.q_hb2[11] ddc_chain_tb.dut_i0.\new_hb.q_hb2[10] ddc_chain_tb.dut_i0.\new_hb.q_hb2[9] ddc_chain_tb.dut_i0.\new_hb.q_hb2[8] ddc_chain_tb.dut_i0.\new_hb.q_hb2[7] ddc_chain_tb.dut_i0.\new_hb.q_hb2[6] ddc_chain_tb.dut_i0.\new_hb.q_hb2[5] ddc_chain_tb.dut_i0.\new_hb.q_hb2[4] ddc_chain_tb.dut_i0.\new_hb.q_hb2[3] ddc_chain_tb.dut_i0.\new_hb.q_hb2[2] ddc_chain_tb.dut_i0.\new_hb.q_hb2[1] ddc_chain_tb.dut_i0.\new_hb.q_hb2[0] +@20000 +- +[pattern_trace] 1 +[pattern_trace] 0 diff --git a/fpga/usrp3/lib/dsp/sim/sim_ddc_chain/dc_in_cordic_decim_6/simulation_script.v b/fpga/usrp3/lib/dsp/sim/sim_ddc_chain/dc_in_cordic_decim_6/simulation_script.v new file mode 100644 index 000000000..091162a5a --- /dev/null +++ b/fpga/usrp3/lib/dsp/sim/sim_ddc_chain/dc_in_cordic_decim_6/simulation_script.v @@ -0,0 +1,83 @@ +// +// Copyright 2015 Ettus Research, a National Instruments Company +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// 10MHz master_clock_rate +always #50 clk <= ~clk; + + initial + begin + reset <= 1'b0; + i_in <= 0; + q_in <= 0; + run <= 0; + set_stb <= 0; + set_addr <= 0; + set_data <= 0; + + + @(posedge clk); + // Into Reset... + reset <= 1'b1; + repeat(10) @(posedge clk); + // .. and back out of reset. + reset <= 1'b0; + repeat(10) @(posedge clk); + // Now program DSP configuration via settings regs. + write_setting_bus(SR_DSP_RX_FREQ,42949672); // 100kHz @ 10MHz MCR + write_setting_bus(SR_DSP_RX_SCALE_IQ, 62842); // Should include CORDIC and CIC gain compensation. + // write_setting_bus(SR_DSP_RX_SCALE_IQ, ((1<<16) * 1.647 * 0.5 * 1.22)); // Should include CORDIC and CIC gain compensation. + write_setting_bus(SR_DSP_RX_DECIM, 1<<9|3); // Decim = 6 + write_setting_bus(SR_DSP_RX_MUX, 0); + write_setting_bus(SR_DSP_RX_COEFFS,0); + repeat(10) @(posedge clk); + + // Set complex data inputs to DC unit circle position. + i_in <= 12'h7ff; + q_in <= 12'h0; + run <= 1'b1; + repeat(100) @(posedge clk); + // Set complex data inputs to simulate ADC saturation of front end + i_in <= 12'h7ff; + q_in <= 12'h100; + repeat(1000) @(posedge clk); + i_in <= 12'h7ff; + q_in <= 12'h200; + repeat(1000) @(posedge clk); + i_in <= 12'h7ff; + q_in <= 12'h300; + repeat(1000) @(posedge clk); + i_in <= 12'h7ff; + q_in <= 12'h400; + repeat(1000) @(posedge clk); + i_in <= 12'h7ff; + q_in <= 12'h500; + repeat(1000) @(posedge clk); + i_in <= 12'h7ff; + q_in <= 12'h600; + repeat(1000) @(posedge clk); + i_in <= 12'h7ff; + q_in <= 12'h700; + repeat(1000) @(posedge clk); + i_in <= 12'h7ff; + q_in <= 12'h7FF; + // Now test small signal performance + repeat(1000) @(posedge clk); + i_in <= 12'h001; + q_in <= 12'h000; + repeat(1000) @(posedge clk); + i_in <= 12'h000; + q_in <= 12'h001; + repeat(1000) @(posedge clk); + i_in <= 12'hfff; + q_in <= 12'h000; + repeat(1000) @(posedge clk); + i_in <= 12'h000; + q_in <= 12'hfff; + + + repeat(100000) @(posedge clk); + $finish(); + + end // initial begin diff --git a/fpga/usrp3/lib/dsp/sim/sim_ddc_chain/ddc_chain_tb.v b/fpga/usrp3/lib/dsp/sim/sim_ddc_chain/ddc_chain_tb.v new file mode 100644 index 000000000..76f0db300 --- /dev/null +++ b/fpga/usrp3/lib/dsp/sim/sim_ddc_chain/ddc_chain_tb.v @@ -0,0 +1,94 @@ +// +// Copyright 2015 Ettus Research, a National Instruments Company +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +`timescale 1ns/1ps + +module ddc_chain_tb(); + + initial $dumpfile("waves.vcd"); + initial $dumpvars(2,ddc_chain_tb.dut_i0); + + + // Need these declarations to use the task libarary. +`ifndef CHDR_IN_NUMBER + `define CHDR_IN_NUMBER 1 +`endif +`ifndef CHDR_OUT_NUMBER + `define CHDR_OUT_NUMBER 1 +`endif + + reg [63:0] data_in[`CHDR_IN_NUMBER-1:0]; + reg last_in[`CHDR_IN_NUMBER-1:0]; + reg valid_in[`CHDR_IN_NUMBER-1:0]; + wire ready_in[`CHDR_IN_NUMBER-1:0]; + wire [63:0] data_out[`CHDR_OUT_NUMBER-1:0]; + wire last_out[`CHDR_OUT_NUMBER-1:0]; + wire valid_out[`CHDR_OUT_NUMBER-1:0]; + reg ready_out[`CHDR_OUT_NUMBER-1:0]; + // + +`include "../../../../../sim/radio_setting_regs.v" +`include "../../../../../sim/task_library.v" + + localparam DSPNO = 0; + localparam WIDTH = 24; + localparam NEW_HB_DECIM = 1; + localparam DEVICE = "SPARTAN6"; + + reg clk = 0; + reg reset; + + reg set_stb; + reg [7:0] set_addr; + reg [31:0] set_data; + + wire [WIDTH-1:0] rx_fe_i, rx_fe_q; + wire [31:0] sample; + reg run; + wire strobe; + + reg [11:0] i_in, q_in; + + assign rx_fe_i = {i_in,12'h0}; + assign rx_fe_q = {q_in,12'h0}; + + // + // DUT + // + ddc_chain + #( + .BASE(SR_RX_DSP), + .DSPNO(DSPNO), + .WIDTH(WIDTH), + .NEW_HB_DECIM(NEW_HB_DECIM), + .DEVICE("SPARTAN6") + ) + dut_i0 ( + .clk(clk), + .rst(reset), + .clr(1'b0), + .set_stb(set_stb), + .set_addr(set_addr), + .set_data(set_data), + + // From RX frontend + .rx_fe_i(rx_fe_i), + .rx_fe_q(rx_fe_q), + + // To RX control + .sample(sample), + .run(run), + .strobe(strobe), + .debug() + ); + + + + // + // Include testbench + // +`include "simulation_script.v" + +endmodule // diff --git a/fpga/usrp3/lib/dsp/sim/sim_ddc_chain/run_isim b/fpga/usrp3/lib/dsp/sim/sim_ddc_chain/run_isim new file mode 100755 index 000000000..4beb08ed3 --- /dev/null +++ b/fpga/usrp3/lib/dsp/sim/sim_ddc_chain/run_isim @@ -0,0 +1,18 @@ +rm -rf fuse* *.exe isim +vlogcomp -work work ${XILINX}/verilog/src/glbl.v +vlogcomp -work work --sourcelibext .v \ + --sourcelibdir ../../.. \ + --sourcelibdir ../../../../control \ + --sourcelibdir ../../../../../top/b200/coregen_dsp \ + --sourcelibdir ../../../../../top/b200/coregen \ + --sourcelibdir ${XILINX}/verilog/src/unimacro \ + ../ddc_chain_tb.v + + + +fuse work.ddc_chain_tb work.glbl -L unisims_ver -L xilinxcorelib_ver -o testbench.exe + +# run the simulation script +./testbench.exe #-gui #-tclbatch simcmds.tcl + + diff --git a/fpga/usrp3/lib/dsp/small_hb_dec.v b/fpga/usrp3/lib/dsp/small_hb_dec.v new file mode 100644 index 000000000..25a635bc1 --- /dev/null +++ b/fpga/usrp3/lib/dsp/small_hb_dec.v @@ -0,0 +1,139 @@ +// +// Copyright 2011 Ettus Research LLC +// Copyright 2018 Ettus Research, a National Instruments Company +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// + +// NOTE: This module uses Xilinx IP that is not available in Spartan3 and older FPGA's + +// Short halfband decimator (intended to be followed by another stage) +// Implements impulse responses of the form [A 0 B 0.5 B 0 A] +// +// These taps designed by halfgen4 from ldoolittle: +// 2 * 131072 * halfgen4(.75/8,2) +module small_hb_dec + #(parameter WIDTH=18, + parameter DEVICE = "SPARTAN6") + (input clk, + input rst, + input bypass, + input run, + input stb_in, + input [WIDTH-1:0] data_in, + output reg stb_out, + output reg [WIDTH-1:0] data_out); + + // Round off inputs to 17 bits because of 18 bit multipliers + localparam INTWIDTH = 17; + wire [INTWIDTH-1:0] data_rnd; + wire stb_rnd; + + round_sd #(.WIDTH_IN(WIDTH),.WIDTH_OUT(INTWIDTH)) round_in + (.clk(clk),.reset(rst),.in(data_in),.strobe_in(stb_in),.out(data_rnd),.strobe_out(stb_rnd)); + + + reg stb_rnd_d1; + reg [INTWIDTH-1:0] data_rnd_d1; + always @(posedge clk) stb_rnd_d1 <= stb_rnd; + always @(posedge clk) data_rnd_d1 <= data_rnd; + + wire go; + reg phase, go_d1, go_d2, go_d3, go_d4; + always @(posedge clk) + if(rst | ~run) + phase <= 0; + else if(stb_rnd_d1) + phase <= ~phase; + assign go = stb_rnd_d1 & phase; + always @(posedge clk) + if(rst | ~run) + begin + go_d1 <= 0; + go_d2 <= 0; + go_d3 <= 0; + go_d4 <= 0; + end + else + begin + go_d1 <= go; + go_d2 <= go_d1; + go_d3 <= go_d2; + go_d4 <= go_d3; + end + + wire [17:0] coeff_a = -10690; + wire [17:0] coeff_b = 75809; + + reg [INTWIDTH-1:0] d1, d2, d3, d4 , d5, d6; + always @(posedge clk) + if(stb_rnd_d1 | rst) + begin + d1 <= data_rnd_d1; + d2 <= d1; + d3 <= d2; + d4 <= d3; + d5 <= d4; + d6 <= d5; + end + + reg [17:0] sum_a, sum_b, middle, middle_d1; + + always @(posedge clk) + if(go) + begin + sum_a <= {data_rnd_d1[INTWIDTH-1],data_rnd_d1} + {d6[INTWIDTH-1],d6}; + sum_b <= {d2[INTWIDTH-1],d2} + {d4[INTWIDTH-1],d4}; + //middle <= {d3[INTWIDTH-1],d3}; + middle <= {d3,1'b0}; + end + + always @(posedge clk) + if(go_d1) + middle_d1 <= middle; + + wire [17:0] sum = go_d1 ? sum_b : sum_a; + wire [17:0] coeff = go_d1 ? coeff_b : coeff_a; + wire [35:0] prod; + + MULT_MACRO #(.DEVICE(DEVICE), // Target Device: "VIRTEX5", "VIRTEX6", "SPARTAN6","7SERIES" + .LATENCY(1), // Desired clock cycle latency, 0-4 + .WIDTH_A(18), // Multiplier A-input bus width, 1-25 + .WIDTH_B(18)) // Multiplier B-input bus width, 1-18 + mult (.P(prod), // Multiplier output bus, width determined by WIDTH_P parameter + .A(coeff), // Multiplier input A bus, width determined by WIDTH_A parameter + .B(sum), // Multiplier input B bus, width determined by WIDTH_B parameter + .CE(go_d1 | go_d2), // 1-bit active high input clock enable + .CLK(clk), // 1-bit positive edge clock input + .RST(rst)); // 1-bit input active high reset + + localparam ACCWIDTH = 30; + reg [ACCWIDTH-1:0] accum; + + always @(posedge clk) + if(rst) + accum <= 0; + else if(go_d2) + accum <= {middle_d1[17],middle_d1[17],middle_d1,{(16+ACCWIDTH-36){1'b0}}} + {prod[35:36-ACCWIDTH]}; + else if(go_d3) + accum <= accum + {prod[35:36-ACCWIDTH]}; + + wire [WIDTH:0] accum_rnd; + wire [WIDTH-1:0] accum_rnd_clip; + + wire stb_round; + + round_sd #(.WIDTH_IN(ACCWIDTH),.WIDTH_OUT(WIDTH+1)) round_acc + (.clk(clk), .reset(rst), .in(accum), .strobe_in(go_d4), .out(accum_rnd), .strobe_out(stb_round)); + + clip #(.bits_in(WIDTH+1),.bits_out(WIDTH)) clip (.in(accum_rnd), .out(accum_rnd_clip)); + + // Output + always @(posedge clk) + begin + stb_out <= bypass ? stb_in : stb_round; + data_out <= bypass ? data_in : accum_rnd_clip; + end + + +endmodule // small_hb_dec diff --git a/fpga/usrp3/lib/dsp/small_hb_int.v b/fpga/usrp3/lib/dsp/small_hb_int.v new file mode 100644 index 000000000..e34b34eb5 --- /dev/null +++ b/fpga/usrp3/lib/dsp/small_hb_int.v @@ -0,0 +1,102 @@ +// +// Copyright 2011 Ettus Research LLC +// Copyright 2018 Ettus Research, a National Instruments Company +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// + + +// Short halfband decimator (intended to be followed by another stage) +// Implements impulse responses of the form [A 0 B 0.5 B 0 A] +// +// These taps designed by halfgen4 from ldoolittle: +// 2 * 131072 * halfgen4(.75/8,2) + +module small_hb_int + #(parameter WIDTH=18) + (input clk, + input rst, + input bypass, + input stb_in, + input [WIDTH-1:0] data_in, + input [7:0] output_rate, + input stb_out, + output reg [WIDTH-1:0] data_out); + + + reg [WIDTH-1:0] d1, d2, d3, d4, d5, d6; + + localparam MWIDTH = 36; + wire [MWIDTH-1:0] prod; + + reg [6:0] stbin_d; + + always @(posedge clk) + stbin_d <= {stbin_d[5:0],stb_in}; + + always @(posedge clk) + if (rst) + begin + d1 <= 0; + d2 <= 0; + d3 <= 0; + d4 <= 0; + d5 <= 0; + d6 <= 0; + end + else if(stb_in) + begin + d1 <= data_in; + d2 <= d1; + d3 <= d2; + d4 <= d3; + d5 <= d4; + d6 <= d5; + end + + wire [WIDTH-1:0] sum_outer, sum_inner; + add2_and_round_reg #(.WIDTH(WIDTH)) add_outer (.clk(clk),.in1(d1),.in2(d4),.sum(sum_outer)); + add2_and_round_reg #(.WIDTH(WIDTH)) add_inner (.clk(clk),.in1(d2),.in2(d3),.sum(sum_inner)); + + wire [17:0] coeff_outer = -10690; + wire [17:0] coeff_inner = 75809; + + MULT18X18S mult(.C(clk), .CE(1), .R(rst), .P(prod), .A(stbin_d[1] ? coeff_outer : coeff_inner), + .B(stbin_d[1] ? sum_outer : sum_inner) ); + + wire [MWIDTH:0] accum; + acc #(.IWIDTH(MWIDTH),.OWIDTH(MWIDTH+1)) + acc (.clk(clk),.clear(stbin_d[2]),.acc(|stbin_d[3:2]),.in(prod),.out(accum)); + + wire [WIDTH+2:0] accum_rnd; + round_reg #(.bits_in(MWIDTH+1),.bits_out(WIDTH+3)) + final_round (.clk(clk),.in(accum),.out(accum_rnd)); + + wire [WIDTH-1:0] clipped; + clip_reg #(.bits_in(WIDTH+3),.bits_out(WIDTH)) final_clip + (.clk(clk),.in(accum_rnd),.strobe_in(1'b1), .out(clipped)); + + reg [WIDTH-1:0] saved, saved_d3; + always @(posedge clk) + if(stbin_d[6]) + saved <= clipped; + + always @(posedge clk) + if(stbin_d[3]) + saved_d3 <= d3; + + always @(posedge clk) + if(bypass) + data_out <= data_in; + else if(stb_in & stb_out) + case(output_rate) + 1 : data_out <= d6; + 2 : data_out <= d4; + 3, 4, 5, 6, 7 : data_out <= d3; + default : data_out <= d2; + endcase // case(output_rate) + else if(stb_out) + data_out <= saved; + +endmodule // small_hb_int + diff --git a/fpga/usrp3/lib/dsp/srl.v b/fpga/usrp3/lib/dsp/srl.v new file mode 100644 index 000000000..9bea98a09 --- /dev/null +++ b/fpga/usrp3/lib/dsp/srl.v @@ -0,0 +1,30 @@ +// +// Copyright 2011 Ettus Research LLC +// Copyright 2018 Ettus Research, a National Instruments Company +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// + + + +module srl + #(parameter WIDTH=18) + (input clk, + input rst, + input write, + input [WIDTH-1:0] in, + input [3:0] addr, + output [WIDTH-1:0] out); + + genvar i; + generate + for (i=0;i<WIDTH;i=i+1) + begin : gen_srl + SRL16E + srl16e(.Q(out[i]), + .A0(addr[0]),.A1(addr[1]),.A2(addr[2]),.A3(addr[3]), + .CE(write|rst),.CLK(clk),.D(in[i])); + end + endgenerate + +endmodule // srl diff --git a/fpga/usrp3/lib/dsp/tx_frontend.v b/fpga/usrp3/lib/dsp/tx_frontend.v new file mode 100644 index 000000000..5484b80d4 --- /dev/null +++ b/fpga/usrp3/lib/dsp/tx_frontend.v @@ -0,0 +1,108 @@ +// +// Copyright 2014 Ettus Research, a National Instruments Company +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// + +module tx_frontend + #(parameter BASE=0, + parameter WIDTH_OUT=16, + parameter IQCOMP_EN=1) + (input clk, input rst, + input set_stb, input [7:0] set_addr, input [31:0] set_data, + input [23:0] tx_i, input [23:0] tx_q, input run, + output reg [WIDTH_OUT-1:0] dac_a, output reg [WIDTH_OUT-1:0] dac_b + ); + + // IQ balance --> DC offset --> rounding --> mux + + wire [23:0] i_dco, q_dco, i_ofs, q_ofs; + wire [WIDTH_OUT-1:0] i_final, q_final; + wire [7:0] mux_ctrl; + wire [35:0] corr_i, corr_q; + wire [23:0] i_bal, q_bal; + wire [17:0] mag_corr, phase_corr; + + setting_reg #(.my_addr(BASE+0), .width(24)) sr_0 + (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr), + .in(set_data),.out(i_dco),.changed()); + + setting_reg #(.my_addr(BASE+1), .width(24)) sr_1 + (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr), + .in(set_data),.out(q_dco),.changed()); + + setting_reg #(.my_addr(BASE+2),.width(18)) sr_2 + (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr), + .in(set_data),.out(mag_corr),.changed()); + + setting_reg #(.my_addr(BASE+3),.width(18)) sr_3 + (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr), + .in(set_data),.out(phase_corr),.changed()); + + setting_reg #(.my_addr(BASE+4), .width(8)) sr_4 + (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr), + .in(set_data),.out(mux_ctrl),.changed()); + + generate + if(IQCOMP_EN==1) + begin + reg [23:0] tx_i_dly, tx_q_dly; + always @(posedge clk) begin + tx_i_dly <= tx_i; + tx_q_dly <= tx_q; + end + + // IQ Balance + MULT18X18S mult_mag_corr + (.P(corr_i), .A(tx_i[23:6]), .B(mag_corr), .C(clk), .CE(1), .R(rst) ); + + MULT18X18S mult_phase_corr + (.P(corr_q), .A(tx_i[23:6]), .B(phase_corr), .C(clk), .CE(1), .R(rst) ); + + add2_and_clip_reg #(.WIDTH(24)) add_clip_i + (.clk(clk), .rst(rst), + .in1(tx_i_dly), .in2(corr_i[35:12]), .strobe_in(1'b1), + .sum(i_bal), .strobe_out()); + + add2_and_clip_reg #(.WIDTH(24)) add_clip_q + (.clk(clk), .rst(rst), + .in1(tx_q_dly), .in2(corr_q[35:12]), .strobe_in(1'b1), + .sum(q_bal), .strobe_out()); + end // if (IQCOMP_EN==1) + else + begin + assign i_bal = tx_i; + assign q_bal = tx_q; + end // else: !if(IQCOMP_EN==1) + endgenerate + + // DC Offset + add2_and_clip_reg #(.WIDTH(24)) add_dco_i + (.clk(clk), .rst(rst), .in1(i_dco), .in2(i_bal), .strobe_in(1'b1), .sum(i_ofs), .strobe_out()); + + add2_and_clip_reg #(.WIDTH(24)) add_dco_q + (.clk(clk), .rst(rst), .in1(q_dco), .in2(q_bal), .strobe_in(1'b1), .sum(q_ofs), .strobe_out()); + + // Rounding + round_sd #(.WIDTH_IN(24),.WIDTH_OUT(WIDTH_OUT)) round_i + (.clk(clk), .reset(rst), .in(i_ofs),.strobe_in(1'b1), .out(i_final), .strobe_out()); + + round_sd #(.WIDTH_IN(24),.WIDTH_OUT(WIDTH_OUT)) round_q + (.clk(clk), .reset(rst), .in(q_ofs),.strobe_in(1'b1), .out(q_final), .strobe_out()); + + // Mux + always @(posedge clk) + case(mux_ctrl[3:0]) + 0 : dac_a <= i_final; + 1 : dac_a <= q_final; + default : dac_a <= 0; + endcase // case (mux_ctrl[3:0]) + + always @(posedge clk) + case(mux_ctrl[7:4]) + 0 : dac_b <= i_final; + 1 : dac_b <= q_final; + default : dac_b <= 0; + endcase // case (mux_ctrl[7:4]) + +endmodule // tx_frontend diff --git a/fpga/usrp3/lib/dsp/variable_delay_line.v b/fpga/usrp3/lib/dsp/variable_delay_line.v new file mode 100644 index 000000000..ccef6172f --- /dev/null +++ b/fpga/usrp3/lib/dsp/variable_delay_line.v @@ -0,0 +1,144 @@ +// +// Copyright 2018 Ettus Research, A National Instruments Company +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Module: variable_delay_line +// Description: +// This module implements a variable length delay line. It can be used +// in filter implementation where the delay is either variable and/or +// longer than a few flip-flops +// +// Parameters: +// - WIDTH: Width of data_in and data_out +// - DYNAMIC_DELAY: Is the delay variable (configurable at runtime) +// - DEPTH: The depth of the delay line. Must be greater than 2. +// The output delay can be between 0 and DEPTH-1. +// If DYNAMIC_DELAY==0, then this is the static delay +// - DEFAULT_DATA: Data to output if time post-delay is negative +// - OUT_REG: Add an output register. This adds a cycle of latency +// - DEVICE: FPGA device family +// Signals: +// - data_in : Input sample value +// - stb_in : Is input sample valid? +// - delay : Delay value for output (Must be between 0 and DEPTH-1) +// - data_out : Output sample value. data_out is updated 1 clock +// cycle (2 if OUT_REG == 1) after assertion of delay +// + +module variable_delay_line #( + parameter WIDTH = 18, + parameter DEPTH = 256, + parameter DYNAMIC_DELAY = 0, + parameter [WIDTH-1:0] DEFAULT_DATA = 0, + parameter OUT_REG = 0, + parameter DEVICE = "7SERIES" +) ( + input wire clk, + input wire clk_en, + input wire reset, + input wire [WIDTH-1:0] data_in, + input wire stb_in, + input wire [$clog2(DEPTH)-1:0] delay, + output wire [WIDTH-1:0] data_out +); + //FIXME: Change to localparam when Vivado doesn't freak out + // about the use of clog2. + parameter ADDR_W = $clog2(DEPTH+1); + localparam DATA_W = WIDTH; + + //----------------------------------------------------------- + // RAM State Machine: FIFO write, random access read + //----------------------------------------------------------- + wire w_en; + wire [DATA_W-1:0] r_data, w_data; + wire [ADDR_W-1:0] r_addr; + reg [ADDR_W-1:0] w_addr = {ADDR_W{1'b0}}, occupied = {ADDR_W{1'b0}}; + reg [1:0] use_default = 2'b11; + + // FIFO write, random access read + always @(posedge clk) begin + if (reset) begin + w_addr <= {ADDR_W{1'b0}}; + occupied <= {ADDR_W{1'b0}}; + end else if (w_en) begin + w_addr <= w_addr + 1'b1; + if (occupied != DEPTH) begin + occupied <= occupied + 1'b1; + end + end + end + + // Logic to handle negative delays + always @(posedge clk) begin + if (reset) begin + use_default <= 2'b11; + end else if (clk_en && (occupied != 0)) begin + use_default <= {use_default[0], (r_addr >= occupied ? 1'b1 : 1'b0)}; + end + end + + assign w_en = stb_in & clk_en; + assign w_data = data_in; + assign r_addr = (DYNAMIC_DELAY == 0) ? DEPTH : delay; + assign data_out = use_default[OUT_REG] ? DEFAULT_DATA : r_data; + + //----------------------------------------------------------- + // Delay Line RAM Implementation + //----------------------------------------------------------- + // Use a delay line implementation based on the depth. + // The DEVICE parameter is passed in but SPARTAN6, + // 7Series, Ultrascale and Ultrascale+ have the same + // MACROs for SRLs so we don't use the param quite yet. + + genvar i; + generate + if (ADDR_W == 4 || ADDR_W == 5) begin + // SRLs don't have an output register to instantiate + // that plus the pipeline register manually + wire [DATA_W-1:0] r_data_srl; + reg [DATA_W-1:0] r_data_shreg[0:1]; + always @(posedge clk) begin + if (clk_en) + {r_data_shreg[1], r_data_shreg[0]} <= {r_data_shreg[0], r_data_srl}; + end + assign r_data = r_data_shreg[OUT_REG]; + + for (i = 0; i < DATA_W; i = i + 1) begin: bits + // Pick SRL based on address width + if (ADDR_W == 4) begin + SRL16E #( + .INIT(16'h0000), .IS_CLK_INVERTED(1'b0) + ) srl16e_i ( + .CLK(clk), .CE(w_en), + .D(w_data[i]), + .A0(r_addr[0]),.A1(r_addr[1]),.A2(r_addr[2]),.A3(r_addr[3]), + .Q(r_data_srl[i]) + ); + end else begin + SRLC32E #( + .INIT(32'h00000000), .IS_CLK_INVERTED(1'b0) + ) srlc32e_i ( + .CLK(clk), .CE(w_en), + .D(w_data[i]), + .A(r_addr), + .Q(r_data_srl[i]), .Q31() + ); + end + end + end else begin + // For ADDR_W < 4, the RAM should ideally get + // synthesized down to flip-flops. + ram_2port #( + .DWIDTH (DATA_W), .AWIDTH(ADDR_W), + .RW_MODE("NO-CHANGE"), .OUT_REG(OUT_REG) + ) ram_i ( + .clka (clk), .ena(clk_en), .wea(w_en), + .addra(w_addr), .dia(w_data), .doa(), + .clkb (clk), .enb(clk_en), .web(1'b0), + .addrb(w_addr - r_addr - 1), .dib(), .dob(r_data) + ); + end + endgenerate + +endmodule // delay_line
\ No newline at end of file |