diff options
Diffstat (limited to 'fpga/usrp3/lib/rfnoc/cic_interpolate.v')
-rw-r--r-- | fpga/usrp3/lib/rfnoc/cic_interpolate.v | 132 |
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 |