1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
|
//
// Copyright 2015 Ettus Research LLC
//
// General complex invert algorithm:
// 1 1 a - bi a - bi a bi
// ------ = ------ * ------ = ----------- = --------- - ---------
// a + bi a + bi a - bi a^2 + b^2 a^2 + b^2 a^2 + b^2
//
module complex_invert
(
input clk, input reset, input clear,
input [31:0] i_tdata, input i_tlast, input i_tvalid, output i_tready,
output [31:0] o_tdata, output o_tlast, output o_tvalid, input o_tready);
wire [15:0] a_tdata;
wire [31:0] a_tdata_int;
wire a_tlast;
wire a_tvalid;
wire a_tready;
wire [15:0] b_tdata;
wire [31:0] b_tdata_int;
wire b_tlast;
wire b_tvalid;
wire b_tready;
wire [31:0] a_b_tdata;
wire a_b_tlast;
wire a_b_tvalid;
wire a_b_tready;
// Replicate input data into three streams with FIFOing to account for varying latency on the paths
split_stream_fifo #(
.WIDTH(32),
.ACTIVE_MASK(4'b0111),
.FIFO_SIZE(5))
input_split_stream_fifo0 (
.clk(clk), .reset(reset), .clear(clear),
.i_tdata(i_tdata), .i_tlast(i_tlast), .i_tvalid(i_tvalid), .i_tready(i_tready),
.o0_tdata(a_tdata_int), .o0_tlast(a_tlast), .o0_tvalid(a_tvalid), .o0_tready(a_tready),
.o1_tdata(b_tdata_int), .o1_tlast(b_tlast), .o1_tvalid(b_tvalid), .o1_tready(b_tready),
.o2_tdata(a_b_tdata), .o2_tlast(a_b_tlast), .o2_tvalid(a_b_tvalid), .o2_tready(a_b_tready),
.o3_tdata(), .o3_tlast(), .o3_tvalid(), .o3_tready(1'b0));
assign a_tdata = a_tdata_int[31:16];
assign b_tdata = b_tdata_int[15:0];
wire [31:0] a2_plus_b2_tdata;
wire a2_plus_b2_tlast;
wire a2_plus_b2_tvalid;
wire a2_plus_b2_tready;
// a^2 + b^2
complex_to_magsq
a2_p_b2_complex_to_magsq (
.clk(clk), .reset(reset), .clear(clear),
.i_tdata(a_b_tdata), .i_tlast(a_b_tlast), .i_tvalid(a_b_tvalid), .i_tready(a_b_tready),
.o_tdata(a2_plus_b2_tdata), .o_tlast(a2_plus_b2_tlast), .o_tvalid(a2_plus_b2_tvalid), .o_tready(a2_plus_b2_tready));
wire [31:0] a2_plus_b2_0_tdata;
wire a2_plus_b2_0_tlast;
wire a2_plus_b2_0_tvalid;
wire a2_plus_b2_0_tready;
wire [31:0] a2_plus_b2_1_tdata;
wire a2_plus_b2_1_tlast;
wire a2_plus_b2_1_tvalid;
wire a2_plus_b2_1_tready;
// Replicate two a^2 + b^2 streams for dividers
split_stream_fifo #(
.WIDTH(32),
.ACTIVE_MASK(4'b0011),
.FIFO_SIZE(5))
input_split_stream_fifo1 (
.clk(clk), .reset(reset), .clear(clear),
.i_tdata(a2_plus_b2_tdata), .i_tlast(a2_plus_b2_tlast), .i_tvalid(a2_plus_b2_tvalid), .i_tready(a2_plus_b2_tready),
.o0_tdata(a2_plus_b2_0_tdata), .o0_tlast(a2_plus_b2_0_tlast), .o0_tvalid(a2_plus_b2_0_tvalid), .o0_tready(a2_plus_b2_0_tready),
.o1_tdata(a2_plus_b2_1_tdata), .o1_tlast(a2_plus_b2_1_tlast), .o1_tvalid(a2_plus_b2_1_tvalid), .o1_tready(a2_plus_b2_1_tready),
.o2_tdata(), .o2_tlast(), .o2_tvalid(), .o2_tready(1'b0),
.o3_tdata(), .o3_tlast(), .o3_tvalid(), .o3_tready(1'b0));
wire div_by_zero_a;
wire [47:0] a_div_a2_plus_b2_tdata_int; // signed bit, 15 integer bits, fraction sign bit, 31 fraction
wire [47:0] a_div_a2_plus_b2_tdata = div_by_zero_a ? 48'd0 : a_div_a2_plus_b2_tdata_int;
wire a_div_a2_plus_b2_tlast;
wire a_div_a2_plus_b2_tvalid;
wire a_div_a2_plus_b2_tready;
// a
// ---------
// a^2 + b^2
// Warning: Divider does not sign extend fractional part into the integer part, although we throw away the integer
// part so this issue does not affect our design.
divide_int16_int32
a_div_a2_plus_b2_divider (
.aclk(clk), .aresetn(~reset),
.s_axis_divisor_tdata(a2_plus_b2_0_tdata), .s_axis_divisor_tlast(a2_plus_b2_0_tlast), .s_axis_divisor_tvalid(a2_plus_b2_0_tvalid), .s_axis_divisor_tready(a2_plus_b2_0_tready),
.s_axis_dividend_tdata(a_tdata), .s_axis_dividend_tlast(a_tlast), .s_axis_dividend_tvalid(a_tvalid), .s_axis_dividend_tready(a_tready),
.m_axis_dout_tdata(a_div_a2_plus_b2_tdata_int), .m_axis_dout_tlast(a_div_a2_plus_b2_tlast), .m_axis_dout_tvalid(a_div_a2_plus_b2_tvalid), .m_axis_dout_tready(a_div_a2_plus_b2_tready),
.m_axis_dout_tuser(div_by_zero_a));
wire [15:0] neg_b_tdata;
wire neg_b_tlast;
wire neg_b_tvalid;
wire neg_b_tready;
wire [15:0] neg_b = (b_tdata == -16'sd32768) ? 16'sd32767 : (~b_tdata + 1'b1);
// Negate b
axi_fifo_flop #(.WIDTH(17))
neg_b_axi_fifo_flop (
.clk(clk), .reset(reset), .clear(clear),
.i_tdata({b_tlast,neg_b}), .i_tvalid(b_tvalid), .i_tready(b_tready),
.o_tdata({neg_b_tlast,neg_b_tdata}), .o_tvalid(neg_b_tvalid), .o_tready(neg_b_tready),
.space(), .occupied());
wire div_by_zero_b;
wire [47:0] neg_b_div_a2_plus_b2_tdata_int;
wire [47:0] neg_b_div_a2_plus_b2_tdata = div_by_zero_b ? 48'd0 : neg_b_div_a2_plus_b2_tdata_int;
wire neg_b_div_a2_plus_b2_tlast;
wire neg_b_div_a2_plus_b2_tvalid;
wire neg_b_div_a2_plus_b2_tready;
// bi
// ---------
// a^2 + b^2
divide_int16_int32
neg_b_div_a2_plus_b2_divider (
.aclk(clk), .aresetn(~reset),
.s_axis_divisor_tdata(a2_plus_b2_1_tdata), .s_axis_divisor_tlast(a2_plus_b2_1_tlast), .s_axis_divisor_tvalid(a2_plus_b2_1_tvalid), .s_axis_divisor_tready(a2_plus_b2_1_tready),
.s_axis_dividend_tdata(neg_b_tdata), .s_axis_dividend_tlast(neg_b_tlast), .s_axis_dividend_tvalid(neg_b_tvalid), .s_axis_dividend_tready(neg_b_tready),
.m_axis_dout_tdata(neg_b_div_a2_plus_b2_tdata_int), .m_axis_dout_tlast(neg_b_div_a2_plus_b2_tlast), .m_axis_dout_tvalid(neg_b_div_a2_plus_b2_tvalid), .m_axis_dout_tready(neg_b_div_a2_plus_b2_tready),
.m_axis_dout_tuser(div_by_zero_b));
// Throw away integer part as the result will always be a fraction due to a^2 + b^2 > a (or b)
wire [63:0] one_div_a_plus_bi_tdata = {a_div_a2_plus_b2_tdata[31:0],neg_b_div_a2_plus_b2_tdata[31:0]};
wire one_div_a_plus_bi_tlast;
wire one_div_a_plus_bi_tvalid;
wire one_div_a_plus_bi_tready;
// Join into one word
axi_join #(
.INPUTS(2))
inst_axi_join (
.i_tlast({a_div_a2_plus_b2_tlast,neg_b_div_a2_plus_b2_tlast}), .i_tvalid({a_div_a2_plus_b2_tvalid,neg_b_div_a2_plus_b2_tvalid}), .i_tready({a_div_a2_plus_b2_tready,neg_b_div_a2_plus_b2_tready}),
.o_tlast(one_div_a_plus_bi_tlast), .o_tvalid(one_div_a_plus_bi_tvalid), .o_tready(one_div_a_plus_bi_tready));
// Truncate to a complex int16
axi_round_and_clip_complex #(
.WIDTH_IN(32),
.WIDTH_OUT(16),
.CLIP_BITS(11), // Calibrated value
.FIFOSIZE())
inst_axi_round_and_clip_complex (
.clk(clk), .reset(reset),
.i_tdata(one_div_a_plus_bi_tdata), .i_tlast(one_div_a_plus_bi_tlast), .i_tvalid(one_div_a_plus_bi_tvalid), .i_tready(one_div_a_plus_bi_tready),
.o_tdata(o_tdata), .o_tlast(o_tlast), .o_tvalid(o_tvalid), .o_tready(o_tready));
endmodule
|