File: fft_pipeline.sv

package info (click to toggle)
uhd 4.9.0.0%2Bds1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 184,180 kB
  • sloc: cpp: 262,887; python: 112,011; ansic: 102,670; vhdl: 57,031; tcl: 19,924; xml: 8,581; makefile: 3,028; sh: 2,812; pascal: 230; javascript: 120; csh: 94; asm: 20; perl: 11
file content (442 lines) | stat: -rw-r--r-- 17,156 bytes parent folder | download
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
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
//
// Copyright 2024 Ettus Research, a National Instruments Brand
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// Module: fft_pipeline
//
// Description:
//
//   The module contains all FFT processing for a single channel, including
//   cyclic prefix removal, cyclic prefix insertion, FFT/IFFT, and logic to
//   change the output order of the FFT data.
//
//   The data is input on the data input (i_t*) and output on the data output
//   (o_t*) ports. There must be one FFT/IFFT per packet, plus cyclic-prefix to
//   be removed, if applicable.
//
//   The "global FFT settings" are treated as fixed values that won't change
//   for the duration of a single FFT/IFFT. These should only be updated when
//   everything is idle and there is no data in flight.
//
//   The fft_config_t* input contains the per-FFT settings for the Xilinx FFT
//   core and you should write once per FFT.
//
//   The cp_rem_t* and cp_ins_t* are the cyclic prefix removal and insertion
//   lengths. You should write one length per FFT/IFFT.
//
// Parameters:
//
//   MAX_FFT_SIZE_LOG2 : Set to the log base 2 of the maximum FFT size to be
//                       supported. For example, a value of 14 means the
//                       maximum FFT size is 2**14 = 4096.
//   EN_CONFIG_FIFO    : When 1, the fft_config_tdata AXI-Stream input is used
//                       in order to allow a unique configuration per FFT
//                       operation. If EN_CONFIG_FIFO is 0, then the fft_config
//                       input is used instead and it is assumed to be static
//                       for the duration of the FFT operation and must only
//                       change while the module is idle.
//   EN_CP_REMOVAL     : Controls whether to include the cyclic prefix removal
//                       logic.
//   EN_CP_INSERTION   : Controls whether to include the cyclic prefix
//                       insertion logic. If included, EN_FFT_ORDER must be 1.
//   EN_FFT_ORDER      : Set to 1 to add the optional FFT reorder core. Set to
//                       0 to remove it and save resources. Removing it also
//                       disable CP insertion.
//   EN_MAGNITUDE      : Set to 1 to add the magnitude output calculation core.
//                       Set to 0 to remove it and save resources.
//   EN_MAGNITUDE_SQ   : Set to 1 to add the magnitude squared output
//                       calculation core. Set to 0 to remove it and save
//                       resources.
//   USE_APPROX_MAG    : Control which magnitude calculation to use. Set to 1
//                       to use a simpler circuit that gives pretty good
//                       results in order to save resources. Set to 0 to use
//                       the CORDIC IP to calculate the magnitude.
//

`default_nettype none


module fft_pipeline
  import xfft_config_pkg::*;
#(
  int MAX_FFT_SIZE_LOG2 = 12,
  bit EN_CONFIG_FIFO    = 1,
  bit EN_CP_REMOVAL     = 1,
  bit EN_CP_INSERTION   = 1,
  bit EN_FFT_ORDER      = 1,
  bit EN_MAGNITUDE      = 1,
  bit EN_MAGNITUDE_SQ   = 1,
  bit USE_APPROX_MAG    = 1,

  localparam int FFT_CONFIG_W    = fft_config_w(MAX_FFT_SIZE_LOG2),
  localparam int DATA_W          = 32,
  localparam int FFT_SIZE_LOG2_W = $clog2(MAX_FFT_SIZE_LOG2+1),
  localparam int CP_LEN_W        = MAX_FFT_SIZE_LOG2
) (
  input  wire clk,
  input  wire rst,

  // Global FFT settings
  input  wire [                1:0] fft_order,
  input  wire [                1:0] magnitude,
  input  wire [FFT_SIZE_LOG2_W-1:0] fft_size_log2,
  input  wire [   FFT_CONFIG_W-1:0] fft_config,

  // FFT IP Configuration
  input  wire [FFT_CONFIG_W-1:0] fft_config_tdata,
  input  wire                    fft_config_tvalid,
  output wire                    fft_config_tready,

  // CP Removal Length
  input  wire [CP_LEN_W-1:0] cp_rem_tdata,
  input  wire                cp_rem_tvalid,
  output wire                cp_rem_tready,

  // CP Insertion Length
  input  wire [CP_LEN_W-1:0] cp_ins_tdata,
  input  wire                cp_ins_tvalid,
  output reg                 cp_ins_tready,

  // FFT Event Monitoring
  output wire event_fft_overflow,

  // Data Input Packets
  input  wire [DATA_W-1:0] i_tdata,
  input  wire              i_tlast,
  input  wire              i_tvalid,
  output wire              i_tready,

  // Data Output Packets
  output wire [DATA_W-1:0] o_tdata,
  output wire              o_tlast,
  output wire              o_tvalid,
  input  wire              o_tready
);

  //---------------------------------------------------------------------------
  // Input FIFOs
  //---------------------------------------------------------------------------

  logic [FFT_CONFIG_W-1:0] fft_config_fifo_tdata;
  logic                    fft_config_fifo_tvalid;
  logic                    fft_config_fifo_tready;

  logic [    CP_LEN_W-1:0] cp_rem_fifo_tdata;
  logic                    cp_rem_fifo_tvalid;
  logic                    cp_rem_fifo_tready;

  logic [    CP_LEN_W-1:0] cp_ins_fifo_tdata;
  logic                    cp_ins_fifo_tvalid;
  logic                    cp_ins_fifo_tready;

  logic [DATA_W-1:0] fft_fifo_tdata;
  logic              fft_fifo_tlast;
  logic              fft_fifo_tvalid;
  logic              fft_fifo_tready;

  if (EN_CONFIG_FIFO) begin : gen_config_fifo
    axi_fifo #(
      .WIDTH(FFT_CONFIG_W),
      .SIZE (1           )
    ) axi_fifo_fft_config (
      .clk     (clk                   ),
      .reset   (rst                   ),
      .clear   (1'b0                  ),
      .i_tdata (fft_config_tdata      ),
      .i_tvalid(fft_config_tvalid     ),
      .i_tready(fft_config_tready     ),
      .o_tdata (fft_config_fifo_tdata ),
      .o_tvalid(fft_config_fifo_tvalid),
      .o_tready(fft_config_fifo_tready),
      .space   (                      ),
      .occupied(                      )
    );
  end else begin : gen_no_config_fifo
    assign fft_config_tready = 1'b1;
  end

  if (EN_CP_REMOVAL) begin : gen_cp_rem_fifo
    axi_fifo #(
      .WIDTH(CP_LEN_W),
      .SIZE (1       )
    ) axi_fifo_cp_rem (
      .clk     (clk               ),
      .reset   (rst               ),
      .clear   (1'b0              ),
      .i_tdata (cp_rem_tdata      ),
      .i_tvalid(cp_rem_tvalid     ),
      .i_tready(cp_rem_tready     ),
      .o_tdata (cp_rem_fifo_tdata ),
      .o_tvalid(cp_rem_fifo_tvalid),
      .o_tready(cp_rem_fifo_tready),
      .space   (                  ),
      .occupied(                  )
    );
  end else begin : gen_no_cp_remo_fifo
    assign cp_rem_tready      = 1'b1;
    assign cp_rem_fifo_tdata  = '0;
    assign cp_rem_fifo_tvalid = 1'b1;
  end

  if (EN_CP_INSERTION) begin : gen_cp_ins_fifo
    axi_fifo #(
      .WIDTH(CP_LEN_W),
      .SIZE (1       )
    ) axi_fifo_cp_ins (
      .clk     (clk               ),
      .reset   (rst               ),
      .clear   (1'b0              ),
      .i_tdata (cp_ins_tdata      ),
      .i_tvalid(cp_ins_tvalid     ),
      .i_tready(cp_ins_tready     ),
      .o_tdata (cp_ins_fifo_tdata ),
      .o_tvalid(cp_ins_fifo_tvalid),
      .o_tready(cp_ins_fifo_tready),
      .space   (                  ),
      .occupied(                  )
    );
  end else begin : gen_no_cp_ins_fifo
    assign cp_ins_tready      = 1'b1;
    assign cp_ins_fifo_tdata  = '0;
    assign cp_ins_fifo_tvalid = 1'b1;
  end

  axi_fifo #(
    .WIDTH(1+DATA_W),
    .SIZE (1       )
  ) axi_fifo_fft (
    .clk     (clk                             ),
    .reset   (rst                             ),
    .clear   (1'b0                            ),
    .i_tdata ({i_tlast, i_tdata}              ),
    .i_tvalid(i_tvalid                        ),
    .i_tready(i_tready                        ),
    .o_tdata ({fft_fifo_tlast, fft_fifo_tdata}),
    .o_tvalid(fft_fifo_tvalid                 ),
    .o_tready(fft_fifo_tready                 ),
    .space   (                                ),
    .occupied(                                )
  );


  //---------------------------------------------------------------------------
  // Cyclic Prefix Removal
  //---------------------------------------------------------------------------

  logic [31:0] cp_rem_out_tdata;
  logic        cp_rem_out_tlast;
  logic        cp_rem_out_tvalid;
  logic        cp_rem_out_tready;

  if (EN_CP_REMOVAL) begin : gen_cp_removal
    cp_removal #(
      .CP_LEN_W (CP_LEN_W  ),
      .DATA_W   (DATA_W    )
    ) cp_removal_i (
      .clk          (clk               ),
      .rst          (rst               ),
      .cp_len_tdata (cp_rem_fifo_tdata ),
      .cp_len_tvalid(cp_rem_fifo_tvalid),
      .cp_len_tready(cp_rem_fifo_tready),
      .i_tdata      (fft_fifo_tdata    ),
      .i_tlast      (fft_fifo_tlast    ),
      .i_tvalid     (fft_fifo_tvalid   ),
      .i_tready     (fft_fifo_tready   ),
      .o_tdata      (cp_rem_out_tdata  ),
      .o_tlast      (cp_rem_out_tlast  ),
      .o_tvalid     (cp_rem_out_tvalid ),
      .o_tready     (cp_rem_out_tready )
    );
  end else begin : gen_no_cp_removal
    assign cp_rem_out_tdata  = fft_fifo_tdata;
    assign cp_rem_out_tlast  = fft_fifo_tlast;
    assign cp_rem_out_tvalid = fft_fifo_tvalid;
    assign fft_fifo_tready   = cp_rem_out_tready;
  end


  //---------------------------------------------------------------------------
  // XFFT Configuration Handling
  //---------------------------------------------------------------------------

  logic [31:0] fft_in_tdata;
  logic        fft_in_tlast;
  logic        fft_in_tvalid;
  logic        fft_in_tready;

  logic [FFT_CONFIG_W-1:0] fft_config_core_tdata;
  logic                    fft_config_core_tvalid;
  logic                    fft_config_core_tready;

  // Create a register that indicates the first word transfer of packet
  // (analogous to TLAST).
  logic fft_in_tfirst = 1'b1;

  always_ff @(posedge clk) begin
    if (rst) begin
      fft_in_tfirst <= 1'b1;
    end else if (fft_in_tvalid && fft_in_tready) begin
      fft_in_tfirst <= fft_in_tlast;
    end
  end

  always_comb begin
    if (EN_CONFIG_FIFO) begin
      // In FIFO mode we require one configuration write for each FFT/IFFT
      // packet that is input. This mode was used when the XFFT IP handled the
      // CP insertion but was no longer needed when the CP insertion was moved
      // to the reorder block. We keep it in the design in case we want to use
      // a mode that requires this again in the future.

      // Only pass FFT data from cp_rem_out to fft_in when the configuration
      // FIFO has a configuration for us.
      fft_in_tdata      = cp_rem_out_tdata;
      fft_in_tlast      = cp_rem_out_tlast;
      fft_in_tvalid     = cp_rem_out_tvalid && fft_config_fifo_tvalid;
      cp_rem_out_tready = fft_in_tready     && fft_config_fifo_tvalid;

      // Pass configuration from the fft_config_fifo to fft_config_core. Write
      // the configuration when the first sample is input into the FFT core and
      // pop the configuration off the configuration FIFO when the last sample
      // is input into the FFT core.
      fft_config_core_tdata  = fft_config_fifo_tdata;
      fft_config_core_tvalid = fft_in_tvalid && fft_in_tready && fft_in_tfirst;
      fft_config_fifo_tready = fft_in_tvalid && fft_in_tready && fft_in_tlast;

    end else begin
      // In non-FIFO mode we use whatever configuration value is on the
      // fft_config input.

      // Pass FFT data from cp_rem_out to fft_in
      fft_in_tdata      = cp_rem_out_tdata;
      fft_in_tlast      = cp_rem_out_tlast;
      fft_in_tvalid     = cp_rem_out_tvalid;
      cp_rem_out_tready = fft_in_tready;

      // Write the configuration when the first sample is input into the FFT
      // core.
      fft_config_core_tdata  = fft_config;
      fft_config_core_tvalid = fft_in_tvalid && fft_in_tready && fft_in_tfirst;
      fft_config_fifo_tready = 1'b1;
    end
  end

  //synthesis translate_off
  always_ff @(posedge clk) begin
    if (fft_config_core_tvalid && !fft_config_core_tready) begin
      $error("FFT configuration was not accepted by the XFFT core");
    end
  end
  //synthesis translate_on


  //---------------------------------------------------------------------------
  // FFT IP Core
  //---------------------------------------------------------------------------

  logic [31:0] fft_out_tdata;
  logic        fft_out_tlast;
  logic        fft_out_tvalid;
  logic        fft_out_tready;

  logic event_tlast_unexpected;
  logic event_tlast_missing;

  xfft_wrapper #(
    .MAX_FFT_SIZE_LOG2(MAX_FFT_SIZE_LOG2)
  ) xfft_wrapper_i (
    .aclk                       (clk                                          ),
    .aresetn                    (~rst                                         ),
    .s_axis_config_tdata        (fft_config_core_tdata                        ),
    .s_axis_config_tvalid       (fft_config_core_tvalid                       ),
    .s_axis_config_tready       (fft_config_core_tready                       ),
    .s_axis_data_tdata          ({ fft_in_tdata[15:0], fft_in_tdata[31:16] }  ),
    .s_axis_data_tlast          (fft_in_tlast                                 ),
    .s_axis_data_tvalid         (fft_in_tvalid                                ),
    .s_axis_data_tready         (fft_in_tready                                ),
    .m_axis_data_tdata          ({ fft_out_tdata[15:0], fft_out_tdata[31:16] }),
    .m_axis_data_tuser          (                                             ),
    .m_axis_data_tlast          (fft_out_tlast                                ),
    .m_axis_data_tvalid         (fft_out_tvalid                               ),
    .m_axis_data_tready         (fft_out_tready                               ),
    .m_axis_status_tdata        (                                             ),
    .m_axis_status_tvalid       (                                             ),
    .m_axis_status_tready       (1'b1                                         ),
    .event_frame_started        (                                             ),
    .event_tlast_unexpected     (event_tlast_unexpected                       ),
    .event_tlast_missing        (event_tlast_missing                          ),
    .event_fft_overflow         (event_fft_overflow                           ),
    .event_status_channel_halt  (                                             ),
    .event_data_in_channel_halt (                                             ),
    .event_data_out_channel_halt(                                             )
  );

  //synthesis translate_off
  always_ff @(posedge clk) begin
    // The packets are not being correctly sized if we get an unexpected or missing TLAST.
    assert (event_tlast_unexpected != 1'b1) else $error("FFT TLAST unexpected");
    assert (event_tlast_missing    != 1'b1) else $error("FFT TLAST missing");
    // Overflow can occur depending on the scaling settings and input data.
    assert (event_fft_overflow     != 1'b1) else $warning("FFT overflow");
  end
  //synthesis translate_on


  //---------------------------------------------------------------------------
  // Magnitude and Data Order Post-Processing
  //---------------------------------------------------------------------------

  if (EN_FFT_ORDER || EN_MAGNITUDE || EN_MAGNITUDE_SQ) begin : gen_fft_post_processing
    logic [  DATA_W-1:0] pp_in_tdata;
    logic [CP_LEN_W-1:0] pp_in_tuser;
    logic                pp_in_tlast;
    logic                pp_in_tvalid;
    logic                pp_in_tready;

    // Only transfer data when both the data and CP FIFOs have their data
    // available.
    assign pp_in_tdata    = fft_out_tdata;
    assign pp_in_tuser    = cp_ins_fifo_tdata;
    assign pp_in_tlast    = fft_out_tlast;
    assign pp_in_tvalid   = fft_out_tvalid && cp_ins_fifo_tvalid;
    assign fft_out_tready = pp_in_tready   && cp_ins_fifo_tvalid;

    // Pop the CP off the FIFO at the end of the packet
    assign cp_ins_fifo_tready = pp_in_tready && pp_in_tvalid && pp_in_tlast;

    fft_post_processing #(
      .EN_FFT_ORDER     (EN_FFT_ORDER     ),
      .EN_CP_INSERTION  (EN_CP_INSERTION  ),
      .EN_MAGNITUDE     (EN_MAGNITUDE     ),
      .EN_MAGNITUDE_SQ  (EN_MAGNITUDE_SQ  ),
      .USE_APPROX_MAG   (USE_APPROX_MAG   ),
      .MAX_FFT_SIZE_LOG2(MAX_FFT_SIZE_LOG2)
    ) fft_post_processing_i (
      .clk          (clk          ),
      .rst          (rst          ),
      .fft_order_sel(fft_order    ),
      .magnitude_sel(magnitude    ),
      .fft_size_log2(fft_size_log2),
      .s_axis_tdata (pp_in_tdata  ),
      .s_axis_tuser (pp_in_tuser  ),
      .s_axis_tlast (pp_in_tlast  ),
      .s_axis_tvalid(pp_in_tvalid ),
      .s_axis_tready(pp_in_tready ),
      .m_axis_tdata (o_tdata      ),
      .m_axis_tlast (o_tlast      ),
      .m_axis_tvalid(o_tvalid     ),
      .m_axis_tready(o_tready     )
    );
  end else begin : gen_no_fft_post_processing
    assign cp_ins_fifo_tready = 1'b1;
    assign o_tdata            = fft_out_tdata;
    assign o_tlast            = fft_out_tlast;
    assign o_tvalid           = fft_out_tvalid;
    assign fft_out_tready     = o_tready;
  end

endmodule : fft_pipeline


`default_nettype wire