aboutsummaryrefslogtreecommitdiffstats
path: root/fpga/usrp3/lib/rfnoc/complex_to_mag_approx.v
diff options
context:
space:
mode:
Diffstat (limited to 'fpga/usrp3/lib/rfnoc/complex_to_mag_approx.v')
-rw-r--r--fpga/usrp3/lib/rfnoc/complex_to_mag_approx.v136
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