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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
|
//
// Copyright 2018 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// DDS frequency shift with complex multiply
module dds_freq_tune #(
parameter WIDTH = 24,
parameter PHASE_WIDTH = 24,
parameter SIN_COS_WIDTH = 16,
parameter OUTPUT_WIDTH = 24
)(
input clk,
input reset,
input eob,
input rate_changed,
input [15:0] dds_input_fifo_occupied,
/* IQ input */
input [WIDTH*2-1:0] s_axis_din_tdata,
input s_axis_din_tlast,
input s_axis_din_tvalid,
output s_axis_din_tready,
/* Phase input from NCO */
input [PHASE_WIDTH-1:0] s_axis_phase_tdata,
input s_axis_phase_tlast,
input s_axis_phase_tvalid,
output s_axis_phase_tready,
/* IQ output */
output [OUTPUT_WIDTH*2-1:0] m_axis_dout_tdata,
output m_axis_dout_tlast,
output m_axis_dout_tvalid,
input m_axis_dout_tready,
//debug signals
output [2:0] state_out,
output phase_valid_hold_out,
output [7:0] phase_invalid_wait_count_out,
output reset_dds_out,
output m_axis_dds_tlast_out,
output m_axis_dds_tvalid_out,
output m_axis_dds_tready_out,
output [SIN_COS_WIDTH*2-1:0] m_axis_dds_tdata_out //[31:16] = sin|q [15:0] cos|i
);
//wires for dds output
wire m_axis_dds_tlast;
wire m_axis_dds_tvalid;
wire m_axis_dds_tready;
wire [SIN_COS_WIDTH*2-1:0] m_axis_dds_tdata; //[31:16] = sin|q [15:0] cos|i
reg reset_reg;
reg phase_valid_hold;
reg [7:0] phase_invalid_wait_count;
reg [2:0] state;
reg reset_dds = 1'b1; // Init DDS resets to 1, since simulation model
reg reset_dds_reg = 1'b1; // requires reset at time 0 to avoid failure.
reg phase_ready_wait;
wire s_axis_phase_tready_dds;
//when we're holding valid, make ready low so no new data comes in.
assign s_axis_phase_tready = s_axis_phase_tready_dds & ~phase_valid_hold;
localparam INIT = 3'b000;
localparam VALID = 3'b001;
localparam WAIT = 3'b010;
localparam HOLD_VALID = 3'b011;
//reset needs to be 2 clk cycles minimum for Xilinx DDS IP
always @(posedge clk) begin
reset_reg <= reset;
reset_dds_reg <= reset_dds;
end
//some logic to reset the dds when data is goes from valid to not valid
//also holds valid high until the pipeline has passed tlast through.
always @(posedge clk) begin
if(reset) begin
state <= INIT;
phase_valid_hold <= 1'b0;
phase_invalid_wait_count <= 16'h00;
reset_dds <= 1'b0;
end
else begin
case(state)
INIT: begin//init case
phase_valid_hold <= 1'b0;
phase_invalid_wait_count <= 16'h0000;
reset_dds <= 1'b0;
if(s_axis_phase_tvalid) begin
state <= VALID;
end
end
VALID: begin //valid data
if(~s_axis_phase_tvalid) begin
state <= WAIT;
end
end
WAIT: begin //wait until we either get valid data or don't
if(m_axis_dds_tready) begin //only increment when the downstream can accept data.
phase_invalid_wait_count <= phase_invalid_wait_count + 4'b1;
end
if(s_axis_phase_tvalid) begin //if we get valid data shortly after, then don't push data through and reset
state <= INIT;
end else begin
if(eob | (phase_invalid_wait_count >= 16'h40) | rate_changed ) begin //if a valid never comes, aka eob
state <= HOLD_VALID;
end
end
end
HOLD_VALID: begin//hold valid to finish pipeline. Apparently the dds IP won't empty without additional valids.
phase_valid_hold <= 1'b1;
// Wait for input FIFO to be empty
if (~s_axis_din_tvalid) begin
state <= INIT;
reset_dds <= 1'b1;
end
end
endcase
end
end
//dds to generate sin/cos data from phase
dds_sin_cos_lut_only dds_inst (
.aclk(clk), // input wire aclk
.aresetn(~(reset | reset_reg | reset_dds | reset_dds_reg)), // input wire aresetn active low rst
.s_axis_phase_tvalid(s_axis_phase_tvalid | phase_valid_hold), // input wire s_axis_phase_tvalid
.s_axis_phase_tready(s_axis_phase_tready_dds), // output wire s_axis_phase_tready
.s_axis_phase_tlast(s_axis_phase_tlast), //tlast
.s_axis_phase_tdata(s_axis_phase_tdata), // input wire [23 : 0] s_axis_phase_tdata
.m_axis_data_tvalid(m_axis_dds_tvalid), // output wire m_axis_data_tvalid
.m_axis_data_tready(m_axis_dds_tready), // input wire m_axis_data_tready
.m_axis_data_tlast(m_axis_dds_tlast), // input wire m_axis_data_tready
.m_axis_data_tdata(m_axis_dds_tdata) // output wire [31 : 0] m_axis_data_tdata
);
wire [WIDTH*2-1:0] mult_in_a_tdata;
wire mult_in_a_tvalid;
wire mult_in_a_tready;
wire mult_in_a_tlast;
wire [SIN_COS_WIDTH*2-1:0] mult_in_b_tdata;
wire mult_in_b_tvalid;
wire mult_in_b_tready;
wire mult_in_b_tlast; //no connect
wire [2*32-1:0] mult_out_tdata;
wire mult_out_tvalid;
wire mult_out_tready;
wire mult_out_tlast;
axi_sync #(
.SIZE(2),
.WIDTH_VEC({SIN_COS_WIDTH*2, WIDTH*2}),
.FIFO_SIZE(0))
axi_sync (
.clk(clk), .reset(reset), .clear(),
.i_tdata({m_axis_dds_tdata,s_axis_din_tdata}),
.i_tlast({m_axis_dds_tlast,s_axis_din_tlast}),
.i_tvalid({m_axis_dds_tvalid,s_axis_din_tvalid}),
.i_tready({m_axis_dds_tready,s_axis_din_tready}),
.o_tdata({mult_in_b_tdata,mult_in_a_tdata}),
.o_tlast({mult_in_b_tlast,mult_in_a_tlast}),
.o_tvalid({mult_in_b_tvalid,mult_in_a_tvalid}),
.o_tready({mult_in_b_tready,mult_in_a_tready}));
//a = input i/q data stream 48 bit i/q lower bits i, upper bits q
//b = output of dds 32 bit cos/sin. lower cos, upper sin
complex_multiplier_dds complex_mult_inst (
.aclk(clk), // input wire aclk
.aresetn(~(reset | reset_reg)), // input wire aresetn
.s_axis_a_tvalid(mult_in_a_tvalid), // input wire s_axis_a_tvalid
.s_axis_a_tready(mult_in_a_tready), // output wire s_axis_a_tready
.s_axis_a_tlast(mult_in_a_tlast), // input wire s_axis_a_tlast
.s_axis_a_tdata({mult_in_a_tdata}), // input wire [47 : 0] s_axis_a_tdata
.s_axis_b_tvalid(mult_in_b_tvalid), // input wire s_axis_b_tvalid
.s_axis_b_tready(mult_in_b_tready), // output wire s_axis_b_tready
.s_axis_b_tlast(mult_in_b_tlast), // output wire s_axis_b_tlast
.s_axis_b_tdata(mult_in_b_tdata), // input wire [31 : 0] s_axis_b_tdata
.m_axis_dout_tvalid(mult_out_tvalid), // output wire m_axis_dout_tvalid
.m_axis_dout_tready(mult_out_tready), // input wire m_axis_dout_tready
.m_axis_dout_tlast(mult_out_tlast), // output wire m_axis_dout_tlast
.m_axis_dout_tdata(mult_out_tdata) // output wire [63 : 0] m_axis_dout_tdata
);
axi_round_complex #(
.WIDTH_IN(32),
.WIDTH_OUT(OUTPUT_WIDTH))
axi_round_complex_inst (
.clk(clk),
.reset(reset | reset_reg),
.i_tdata(mult_out_tdata),
.i_tlast(mult_out_tlast),
.i_tvalid(mult_out_tvalid),
.i_tready(mult_out_tready),
.o_tdata(m_axis_dout_tdata),
.o_tlast(m_axis_dout_tlast),
.o_tvalid(m_axis_dout_tvalid),
.o_tready(m_axis_dout_tready));
//debug
assign state_out = state;
assign phase_valid_hold_out = phase_valid_hold;
assign phase_invalid_wait_count_out = phase_invalid_wait_count;
assign reset_dds_out = reset_dds;
assign m_axis_dds_tlast_out = m_axis_dds_tlast;
assign m_axis_dds_tvalid_out = m_axis_dds_tvalid;
assign m_axis_dds_tready_out = m_axis_dds_tready;
assign m_axis_dds_tdata_out = m_axis_dds_tdata;
endmodule
|