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
|