diff options
Diffstat (limited to 'fpga/usrp3/lib/rfnoc/complex_to_mag_approx.v')
-rw-r--r-- | fpga/usrp3/lib/rfnoc/complex_to_mag_approx.v | 136 |
1 files changed, 136 insertions, 0 deletions
diff --git a/fpga/usrp3/lib/rfnoc/complex_to_mag_approx.v b/fpga/usrp3/lib/rfnoc/complex_to_mag_approx.v new file mode 100644 index 000000000..7455afcad --- /dev/null +++ b/fpga/usrp3/lib/rfnoc/complex_to_mag_approx.v @@ -0,0 +1,136 @@ +// +// Copyright 2014 Ettus Research LLC +// Copyright 2018 Ettus Research, a National Instruments Company +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Fast magnitude approximation. +// +// ALPHA_DENOM & BETA_DENOM should be a power of 2 +// Multiplierless if ALPHA_NUM & BETA_NUM are 1 +// +// Mag ~= Alpha * max(|I|, |Q|) + Beta * min(|I|, |Q|) +// +// (table taken from http://www.dspguru.com/dsp/tricks/magnitude-estimator) +// ========================================= +// Alpha Beta Avg Err RMS Peak +// (linear) (dB) (dB) +// ----------------------------------------- +// 1, 1/2 -0.086775 -20.7 -18.6 +// 1, 1/4 0.006456 -27.6 -18.7 +// 1, 11/32 -0.028505 -28.0 -24.8 +// 1, 3/8 -0.040159 -26.4 -23.4 +// 15/16, 15/32 -0.018851 -29.2 -24.1 +// 15/16, 1/2 -0.030505 -26.9 -24.1 +// 31/32, 11/32 -0.000371 -31.6 -22.9 +// 31/32, 3/8 -0.012024 -31.4 -26.1 +// 61/64, 3/8 0.002043 -32.5 -24.3 +// 61/64, 13/32 0.009611 -31.8 -26.6 +// ========================================= +// +// Input: Complex, Output: Unsigned Int + +`ifndef LOG2 +`define LOG2(N) ( \ + N < 2 ? 0 : \ + N < 4 ? 1 : \ + N < 8 ? 2 : \ + N < 16 ? 3 : \ + N < 32 ? 4 : \ + N < 64 ? 5 : \ + N < 128 ? 6 : \ + N < 256 ? 7 : \ + N < 512 ? 8 : \ + N < 1024 ? 9 : \ + 10) +`endif + +module complex_to_mag_approx #( + parameter ALPHA_NUM = 1, + parameter ALPHA_DENOM = 1, + parameter BETA_NUM = 1, + parameter BETA_DENOM = 4, + parameter LATENCY = 3, // 0, 1, 2, or 3 + parameter SAMP_WIDTH = 16) +( + input clk, input reset, input clear, + input [2*SAMP_WIDTH-1:0] i_tdata, input i_tlast, input i_tvalid, output i_tready, + output [SAMP_WIDTH-1:0] o_tdata, output o_tlast, output o_tvalid, input o_tready +); + + wire [2*SAMP_WIDTH-1:0] pipeline_i_tdata[0:2], pipeline_o_tdata[0:2]; + wire [2:0] pipeline_i_tvalid, pipeline_i_tlast, pipeline_i_tready; + wire [2:0] pipeline_o_tvalid, pipeline_o_tlast, pipeline_o_tready; + wire signed [SAMP_WIDTH-1:0] i, q, max, max_int, min, min_int; + wire [SAMP_WIDTH-1:0] i_abs, q_abs, i_abs_int, q_abs_int, mag; + + + // Absolute value + assign i = i_tdata[2*SAMP_WIDTH-1:SAMP_WIDTH]; + assign q = i_tdata[SAMP_WIDTH-1:0]; + assign i_abs_int = i[SAMP_WIDTH-1] ? (~i + 1'b1) : i; + assign q_abs_int = q[SAMP_WIDTH-1] ? (~q + 1'b1) : q; + + + // First stage pipeline + assign pipeline_i_tdata[0] = {i_abs_int,q_abs_int}; + assign pipeline_i_tlast[0] = i_tlast; + assign pipeline_i_tvalid[0] = i_tvalid; + assign pipeline_o_tready[0] = pipeline_i_tready[1]; + + axi_fifo_flop #(.WIDTH(SAMP_WIDTH*2+1)) + pipeline0_axi_fifo_flop ( + .clk(clk), .reset(reset), .clear(clear), + .i_tdata({pipeline_i_tlast[0],pipeline_i_tdata[0]}), .i_tvalid(pipeline_i_tvalid[0]), .i_tready(pipeline_i_tready[0]), + .o_tdata({pipeline_o_tlast[0],pipeline_o_tdata[0]}), .o_tvalid(pipeline_o_tvalid[0]), .o_tready(pipeline_o_tready[0])); + + + // Max & Min + assign i_abs = (LATENCY == 3) ? pipeline_o_tdata[0][2*SAMP_WIDTH-1:SAMP_WIDTH] : i_abs; + assign q_abs = (LATENCY == 3) ? pipeline_o_tdata[0][SAMP_WIDTH-1:0] : q_abs; + assign max_int = (i_abs > q_abs) ? i_abs : q_abs; + assign min_int = (i_abs > q_abs) ? q_abs : i_abs; + + + // Second stage pipeline + assign pipeline_i_tdata[1] = {max_int,min_int}; + assign pipeline_i_tlast[1] = (LATENCY == 2) ? i_tlast : pipeline_o_tlast[0]; + assign pipeline_i_tvalid[1] = (LATENCY == 2) ? i_tvalid : pipeline_o_tvalid[0]; + assign pipeline_o_tready[1] = pipeline_i_tready[2]; + + axi_fifo_flop #(.WIDTH(SAMP_WIDTH*2+1)) + pipeline1_axi_fifo_flop ( + .clk(clk), .reset(reset), .clear(clear), + .i_tdata({pipeline_i_tlast[1],pipeline_i_tdata[1]}), .i_tvalid(pipeline_i_tvalid[1]), .i_tready(pipeline_i_tready[1]), + .o_tdata({pipeline_o_tlast[1],pipeline_o_tdata[1]}), .o_tvalid(pipeline_o_tvalid[1]), .o_tready(pipeline_o_tready[1])); + + + // Magnitude Approx + assign max = (LATENCY >= 2) ? pipeline_o_tdata[1][2*SAMP_WIDTH-1:SAMP_WIDTH] : max_int; + assign min = (LATENCY >= 2) ? pipeline_o_tdata[1][SAMP_WIDTH-1:0] : min_int; + assign mag = ALPHA_NUM * {{`LOG2(ALPHA_DENOM){1'b0}},max[SAMP_WIDTH-1:`LOG2(ALPHA_DENOM)]} + + BETA_NUM * {{`LOG2( BETA_DENOM){1'b0}},min[SAMP_WIDTH-1:`LOG2( BETA_DENOM)]}; + + + // Third stage pipeline + assign pipeline_i_tdata[2][SAMP_WIDTH-1:0] = mag; + assign pipeline_i_tlast[2] = (LATENCY == 1) ? i_tlast : pipeline_o_tlast[1]; + assign pipeline_i_tvalid[2] = (LATENCY == 1) ? i_tvalid : pipeline_o_tvalid[1]; + assign pipeline_o_tready[2] = o_tready; + + axi_fifo_flop #(.WIDTH(SAMP_WIDTH+1)) + pipeline2_axi_fifo_flop ( + .clk(clk), .reset(reset), .clear(clear), + .i_tdata({pipeline_i_tlast[2],pipeline_i_tdata[2][SAMP_WIDTH-1:0]}), .i_tvalid(pipeline_i_tvalid[2]), .i_tready(pipeline_i_tready[2]), + .o_tdata({pipeline_o_tlast[2],pipeline_o_tdata[2][SAMP_WIDTH-1:0]}), .o_tvalid(pipeline_o_tvalid[2]), .o_tready(pipeline_o_tready[2])); + + + // Output based on LATENCY mux + assign o_tdata = (LATENCY == 0) ? mag : pipeline_o_tdata[2][SAMP_WIDTH-1:0]; + assign o_tlast = (LATENCY == 0) ? i_tlast : pipeline_o_tlast[2]; + assign o_tvalid = (LATENCY == 0) ? i_tvalid : pipeline_o_tvalid[2]; + assign i_tready = (LATENCY == 0) ? o_tready : + (LATENCY == 1) ? pipeline_i_tready[2] : + (LATENCY == 2) ? pipeline_i_tready[1] : pipeline_i_tready[0]; + +endmodule
\ No newline at end of file |