This replaces the legacy RFNoC FFT block with a new one of the same name that includes a superset of the original features. New features include cyclic prefix insertion or removal and FFT sizes up to 64k. Original-commit: 25fffb006755b2e91f0138eb4af3ab9e16b8690c
166 lines
6.2 KiB
Systemverilog
166 lines
6.2 KiB
Systemverilog
//
|
|
// Copyright 2024 Ettus Research, a National Instruments Brand
|
|
//
|
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
|
//
|
|
// Module: xfft_config_pkg
|
|
//
|
|
// Description:
|
|
//
|
|
// This package helps helps build and interpret the s_axis_config_tdata bus
|
|
// used to configure the Xilinx FFT core. The bus changes depending on the
|
|
// parameters of the IP. See the Xilinx Fast Fourier Transform product guide
|
|
// (PG109) for details. You can verify the values for a specific
|
|
// configuration by clicking the Implementation tab in the Vivado IP
|
|
// customization GUI.
|
|
//
|
|
|
|
|
|
package xfft_config_pkg;
|
|
|
|
// Set to 1 if cyclic prefix is enabled on the Xilinx IP. Set to 0 otherwise.
|
|
localparam bit CP_ENABLE = 0;
|
|
|
|
localparam int MAX_W = 256;
|
|
|
|
// Returns the width of the SCAL_SCH field of the config_tdata bus.
|
|
function automatic int fft_scale_w(int max_fft_size_log2);
|
|
// max_fft_size_log2 rounded up to the nearest multiple of 2
|
|
return ((max_fft_size_log2+1) / 2) * 2;
|
|
endfunction
|
|
|
|
// Returns the FFT scale value needed to get the default 1/N scaling for a
|
|
// given FFT size.
|
|
function automatic int fft_scale_default(int size_log2);
|
|
// Should be [ 10 10 ... 10] if N is a power of 4 (size_log2 is even)
|
|
// Should be [ 01 10 ... 10] if N is not a power of 4 (size log2 is odd)
|
|
int scale;
|
|
for (int i = 0; i < (size_log2+1)/2; i++) begin
|
|
scale[i*2 +: 2] = i == size_log2/2 ? 2'b01: 2'b10;
|
|
end
|
|
return scale;
|
|
endfunction
|
|
|
|
// Returns the width of the FWD_INV field of the config_tdata bus.
|
|
function automatic int fft_fwd_inv_w(int max_fft_size_log2);
|
|
return 1;
|
|
endfunction
|
|
|
|
// Returns the width of the CP_LEN field of the config_tdata bus.
|
|
function automatic int fft_cp_len_w(int max_fft_size_log2);
|
|
if (CP_ENABLE) begin
|
|
// Always the same as NFFT if present
|
|
return max_fft_size_log2;
|
|
end else begin
|
|
return 0;
|
|
end
|
|
endfunction
|
|
|
|
// Returns the width of the NFFT field of the config_tdata bus.
|
|
function automatic int fft_nfft_w(int max_fft_size_log2);
|
|
return 5;
|
|
endfunction
|
|
|
|
// Returns the LSB position of the SCAL_SCH field of the config_tdata bus.
|
|
function automatic int fft_scale_pos(int max_fft_size_log2);
|
|
return fft_fwd_inv_pos(max_fft_size_log2) + 1;
|
|
endfunction
|
|
|
|
// Returns the LSB position of the FWD_INV field of the config_tdata bus.
|
|
function automatic int fft_fwd_inv_pos(int max_fft_size_log2);
|
|
if (CP_ENABLE) begin
|
|
if (fft_cp_len_pos(max_fft_size_log2) + fft_cp_len_w(max_fft_size_log2) > 16)
|
|
return 24;
|
|
else
|
|
return 16;
|
|
end else begin
|
|
return 8;
|
|
end
|
|
endfunction
|
|
|
|
// Returns the LSB position of the CP_LEN field of the config_tdata bus.
|
|
function automatic int fft_cp_len_pos(int max_fft_size_log2);
|
|
return 8;
|
|
endfunction
|
|
|
|
// Returns the LSB position of the NFFT field of the config_tdata bus.
|
|
function automatic int fft_nfft_pos(int max_fft_size_log2);
|
|
return 0;
|
|
endfunction
|
|
|
|
// Returns the width of the config_tdata bus.
|
|
function automatic int fft_config_w(int max_fft_size_log2);
|
|
// It's the length needed to hold SCALE_SCH rounded up to the nearest byte
|
|
return ((fft_scale_w(max_fft_size_log2) + fft_scale_pos(max_fft_size_log2) + 7) / 8) * 8;
|
|
endfunction
|
|
|
|
// Generates a mask of all ones that is num_bits wide.
|
|
function automatic logic [MAX_W-1:0] mask(int num_bits);
|
|
logic [MAX_W-1:0] bits;
|
|
bits = (1 << num_bits) - 1;
|
|
return bits;
|
|
endfunction
|
|
|
|
// Builds the config_tdata value from the provided settings.
|
|
function automatic bit [MAX_W-1:0] build_fft_config(
|
|
int max_fft_size_log2,
|
|
int scale_sch,
|
|
bit fwd_inv,
|
|
int nfft,
|
|
int cp_len = 0
|
|
);
|
|
bit [MAX_W-1:0] cfg;
|
|
assert (max_fft_size_log2 >= 4 && max_fft_size_log2 <= 16) else
|
|
$fatal(1, "This FFT size is not yet supported");
|
|
assert (!CP_ENABLE || cp_len == 0) else
|
|
$fatal(1, "Cyclic prefix must be 0 if not in use");
|
|
cfg =
|
|
((scale_sch & mask(fft_scale_w (max_fft_size_log2))) << fft_scale_pos (max_fft_size_log2)) |
|
|
((fwd_inv & mask(fft_fwd_inv_w(max_fft_size_log2))) << fft_fwd_inv_pos(max_fft_size_log2)) |
|
|
((cp_len & mask(fft_cp_len_w (max_fft_size_log2))) << fft_cp_len_pos (max_fft_size_log2)) |
|
|
((nfft & mask(fft_nfft_w (max_fft_size_log2))) << fft_nfft_pos (max_fft_size_log2));
|
|
return cfg;
|
|
endfunction
|
|
|
|
|
|
//synthesis translate_off
|
|
|
|
// Takes as input the config_tdata bus and prints the settings encoding on it.
|
|
function automatic void print_fft_config(int max_fft_size_log2, logic [MAX_W-1:0] cfg);
|
|
int scale_sch, fwd_inv, cp_len, nfft;
|
|
|
|
scale_sch = (cfg >> fft_scale_pos (max_fft_size_log2)) & mask(fft_scale_w (max_fft_size_log2));
|
|
fwd_inv = (cfg >> fft_fwd_inv_pos(max_fft_size_log2)) & mask(fft_fwd_inv_w(max_fft_size_log2));
|
|
cp_len = (cfg >> fft_cp_len_pos (max_fft_size_log2)) & mask(fft_cp_len_w (max_fft_size_log2));
|
|
nfft = (cfg >> fft_nfft_pos (max_fft_size_log2)) & mask(fft_nfft_w (max_fft_size_log2));
|
|
|
|
$display("SCALE_SCH_0 : 0b%0b", scale_sch);
|
|
$display("FWD_INV_0 : %0d", fwd_inv);
|
|
if (CP_ENABLE) $display("CP_LEN : %0d", cp_len);
|
|
$display("NFFT : %0d", nfft);
|
|
endfunction
|
|
|
|
// The output of this function should match what's shown in the
|
|
// Implementation Details tab of the Xilinx Fast Fourier Transform IP
|
|
// generation wizard.
|
|
function automatic void print_fft_config_fields(int max_fft_size_log2);
|
|
$display("SCALE_SCH_0(%0d:%0d) bit%0d",
|
|
fft_scale_w(max_fft_size_log2) + fft_scale_pos(max_fft_size_log2) - 1,
|
|
fft_scale_pos(max_fft_size_log2), fft_scale_w(max_fft_size_log2));
|
|
$display("FWD_INV_0(%0d:%0d) bit%0d",
|
|
fft_fwd_inv_w(max_fft_size_log2) + fft_fwd_inv_pos(max_fft_size_log2) - 1,
|
|
fft_fwd_inv_pos(max_fft_size_log2), fft_fwd_inv_w(max_fft_size_log2));
|
|
if (CP_ENABLE) begin
|
|
$display("CP_LEN(%0d:%0d) uint%0d",
|
|
fft_cp_len_w(max_fft_size_log2) + fft_cp_len_pos(max_fft_size_log2) - 1,
|
|
fft_cp_len_pos(max_fft_size_log2), fft_cp_len_w(max_fft_size_log2));
|
|
end
|
|
$display("NFFT(%0d:%0d) uint%0d",
|
|
fft_nfft_w(max_fft_size_log2) + fft_nfft_pos(max_fft_size_log2) - 1,
|
|
fft_nfft_pos(max_fft_size_log2), fft_nfft_w(max_fft_size_log2));
|
|
endfunction
|
|
|
|
//synthesis translate_on
|
|
|
|
endpackage : xfft_config_pkg
|