aboutsummaryrefslogtreecommitdiffstats
path: root/fpga/usrp3/lib/rfnoc/cic_interpolate.v
diff options
context:
space:
mode:
Diffstat (limited to 'fpga/usrp3/lib/rfnoc/cic_interpolate.v')
-rw-r--r--fpga/usrp3/lib/rfnoc/cic_interpolate.v132
1 files changed, 132 insertions, 0 deletions
diff --git a/fpga/usrp3/lib/rfnoc/cic_interpolate.v b/fpga/usrp3/lib/rfnoc/cic_interpolate.v
new file mode 100644
index 000000000..d59e973fc
--- /dev/null
+++ b/fpga/usrp3/lib/rfnoc/cic_interpolate.v
@@ -0,0 +1,132 @@
+//
+// Copyright 2016 Ettus Research
+// Copyright 2018 Ettus Research, a National Instruments Company
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+
+module cic_interpolate #(
+ parameter WIDTH = 16,
+ parameter N = 4,
+ parameter MAX_RATE = 128
+)(
+ input clk,
+ input reset,
+ input rate_stb,
+ input [$clog2(MAX_RATE+1)-1:0] rate, // +1 due to $clog2() rounding
+ input strobe_in,
+ output reg strobe_out,
+ input [WIDTH-1:0] signal_in,
+ output reg [WIDTH-1:0] signal_out
+);
+
+ wire [WIDTH+$clog2(MAX_RATE**(N-1))-1:0] signal_in_ext;
+ reg [WIDTH+$clog2(MAX_RATE**(N-1))-1:0] integrator [0:N-1];
+ reg [WIDTH+$clog2(MAX_RATE**(N-1))-1:0] differentiator [0:N-1];
+ reg [WIDTH+$clog2(MAX_RATE**(N-1))-1:0] pipeline [0:N-1];
+ reg [WIDTH+$clog2(MAX_RATE**(N-1))-1:0] sampler;
+
+ reg [N-1:0] strobe_diff;
+ reg [N-1:0] strobe_integ;
+ reg strobe_sampler;
+
+ integer i;
+
+ sign_extend #(WIDTH,WIDTH+$clog2(MAX_RATE**(N-1))) ext_input (.in(signal_in),.out(signal_in_ext));
+
+ // Differentiate
+ always @(posedge clk) begin
+ if (reset) begin
+ strobe_diff <= 'd0;
+ for (i = 0; i < N; i = i + 1) begin
+ differentiator[i] <= 0;
+ pipeline[i] <= 0;
+ end
+ end else begin
+ strobe_diff <= {strobe_diff[N-2:0], strobe_in};
+ if (strobe_in) begin
+ differentiator[0] <= signal_in_ext;
+ pipeline[0] <= signal_in_ext - differentiator[0];
+ end
+ for (i = 1; i < N; i = i + 1) begin
+ if (strobe_diff[i-1]) begin
+ differentiator[i] <= pipeline[i-1];
+ pipeline[i] <= pipeline[i-1] - differentiator[i];
+ end
+ end
+ end
+ end
+
+ // Strober
+ reg [$clog2(MAX_RATE+1)-1:0] counter;
+ wire strobe_out_int;
+
+ always @(posedge clk) begin
+ if (reset | rate_stb) begin
+ counter <= rate;
+ end else if (strobe_diff[N-1]) begin
+ counter <= rate - 1;
+ end else begin
+ if (counter == 0) begin
+ counter <= rate;
+ end else if (counter < rate) begin
+ counter <= counter - 1;
+ end
+ end
+ end
+
+ assign strobe_out_int = (counter < rate) & ~rate_stb;
+
+ // Integrate
+ always @(posedge clk) begin
+ if (reset) begin
+ strobe_sampler <= 1'b0;
+ strobe_integ <= 'd0;
+ for (i = 0; i < N; i = i + 1) begin
+ integrator[i] <= 0;
+ end
+ end else begin
+ strobe_sampler <= strobe_diff[N-1];
+ if (strobe_diff[N-1]) begin
+ sampler <= pipeline[N-1];
+ end
+ strobe_integ <= {strobe_integ[N-2:0],strobe_out_int};
+ if (strobe_sampler) begin
+ integrator[0] <= integrator[0] + sampler;
+ end
+ for (i = 1; i < N; i = i + 1) begin
+ if (strobe_integ[i-1]) begin
+ integrator[i] <= integrator[i] + integrator[i-1];
+ end
+ end
+ end
+ end
+
+ genvar l;
+ wire [WIDTH-1:0] signal_out_shifted[0:MAX_RATE];
+ wire signal_out_shifted_strobe[0:MAX_RATE];
+ generate
+ for (l = 0; l <= MAX_RATE; l = l + 1) begin
+ axi_round #(
+ .WIDTH_IN((l == 0 || l == 1) ? WIDTH : $clog2(l**(N-1))+WIDTH),
+ .WIDTH_OUT(WIDTH))
+ axi_round (
+ .clk(clk), .reset(reset),
+ .i_tdata((l == 0 || l == 1) ? integrator[N-1][WIDTH-1:0] : integrator[N-1][$clog2(l**(N-1))+WIDTH-1:0]),
+ .i_tlast(1'b0), .i_tvalid(strobe_integ[N-1]), .i_tready(),
+ .o_tdata(signal_out_shifted[l]), .o_tlast(), .o_tvalid(signal_out_shifted_strobe[l]), .o_tready(1'b1));
+ end
+ endgenerate
+
+ // Output register
+ always @(posedge clk) begin
+ if (reset) begin
+ strobe_out <= 1'b0;
+ signal_out <= 'd0;
+ end else begin
+ strobe_out <= signal_out_shifted_strobe[0]; // Any of the strobes will work here
+ signal_out <= signal_out_shifted[rate];
+ end
+ end
+
+endmodule