diff options
author | Martin Braun <martin.braun@ettus.com> | 2020-01-23 16:10:22 -0800 |
---|---|---|
committer | Martin Braun <martin.braun@ettus.com> | 2020-01-28 09:35:36 -0800 |
commit | bafa9d95453387814ef25e6b6256ba8db2df612f (patch) | |
tree | 39ba24b5b67072d354775272e687796bb511848d /fpga/usrp3/lib/dsp | |
parent | 3075b981503002df3115d5f1d0b97d2619ba30f2 (diff) | |
download | uhd-bafa9d95453387814ef25e6b6256ba8db2df612f.tar.gz uhd-bafa9d95453387814ef25e6b6256ba8db2df612f.tar.bz2 uhd-bafa9d95453387814ef25e6b6256ba8db2df612f.zip |
Merge FPGA repository back into UHD repository
The FPGA codebase was removed from the UHD repository in 2014 to reduce
the size of the repository. However, over the last half-decade, the
split between the repositories has proven more burdensome than it has
been helpful. By merging the FPGA code back, it will be possible to
create atomic commits that touch both FPGA and UHD codebases. Continuous
integration testing is also simplified by merging the repositories,
because it was previously difficult to automatically derive the correct
UHD branch when testing a feature branch on the FPGA repository.
This commit also updates the license files and paths therein.
We are therefore merging the repositories again. Future development for
FPGA code will happen in the same repository as the UHD host code and
MPM code.
== Original Codebase and Rebasing ==
The original FPGA repository will be hosted for the foreseeable future
at its original local location: https://github.com/EttusResearch/fpga/
It can be used for bisecting, reference, and a more detailed history.
The final commit from said repository to be merged here is
05003794e2da61cabf64dd278c45685a7abad7ec. This commit is tagged as
v4.0.0.0-pre-uhd-merge.
If you have changes in the FPGA repository that you want to rebase onto
the UHD repository, simply run the following commands:
- Create a directory to store patches (this should be an empty
directory):
mkdir ~/patches
- Now make sure that your FPGA codebase is based on the same state as
the code that was merged:
cd src/fpga # Or wherever your FPGA code is stored
git rebase v4.0.0.0-pre-uhd-merge
Note: The rebase command may look slightly different depending on what
exactly you're trying to rebase.
- Create a patch set for your changes versus v4.0.0.0-pre-uhd-merge:
git format-patch v4.0.0.0-pre-uhd-merge -o ~/patches
Note: Make sure that only patches are stored in your output directory.
It should otherwise be empty. Make sure that you picked the correct
range of commits, and only commits you wanted to rebase were exported
as patch files.
- Go to the UHD repository and apply the patches:
cd src/uhd # Or wherever your UHD repository is stored
git am --directory fpga ~/patches/*
rm -rf ~/patches # This is for cleanup
== Contributors ==
The following people have contributed mainly to these files (this list
is not complete):
Co-authored-by: Alex Williams <alex.williams@ni.com>
Co-authored-by: Andrej Rode <andrej.rode@ettus.com>
Co-authored-by: Ashish Chaudhari <ashish@ettus.com>
Co-authored-by: Ben Hilburn <ben.hilburn@ettus.com>
Co-authored-by: Ciro Nishiguchi <ciro.nishiguchi@ni.com>
Co-authored-by: Daniel Jepson <daniel.jepson@ni.com>
Co-authored-by: Derek Kozel <derek.kozel@ettus.com>
Co-authored-by: EJ Kreinar <ej@he360.com>
Co-authored-by: Humberto Jimenez <humberto.jimenez@ni.com>
Co-authored-by: Ian Buckley <ian.buckley@gmail.com>
Co-authored-by: Jörg Hofrichter <joerg.hofrichter@ni.com>
Co-authored-by: Jon Kiser <jon.kiser@ni.com>
Co-authored-by: Josh Blum <josh@joshknows.com>
Co-authored-by: Jonathon Pendlum <jonathan.pendlum@ettus.com>
Co-authored-by: Martin Braun <martin.braun@ettus.com>
Co-authored-by: Matt Ettus <matt@ettus.com>
Co-authored-by: Michael West <michael.west@ettus.com>
Co-authored-by: Moritz Fischer <moritz.fischer@ettus.com>
Co-authored-by: Nick Foster <nick@ettus.com>
Co-authored-by: Nicolas Cuervo <nicolas.cuervo@ettus.com>
Co-authored-by: Paul Butler <paul.butler@ni.com>
Co-authored-by: Paul David <paul.david@ettus.com>
Co-authored-by: Ryan Marlow <ryan.marlow@ettus.com>
Co-authored-by: Sugandha Gupta <sugandha.gupta@ettus.com>
Co-authored-by: Sylvain Munaut <tnt@246tNt.com>
Co-authored-by: Trung Tran <trung.tran@ettus.com>
Co-authored-by: Vidush Vishwanath <vidush.vishwanath@ettus.com>
Co-authored-by: Wade Fife <wade.fife@ettus.com>
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 |