Files
b210-k7-fpga/lib/rfnoc/blocks/rfnoc_block_fft/fft_pipeline_wrapper.sv
T
Wade Fife 6b19ec030c fpga: rfnoc: fft: Support multiple samples per cycle
This adds the NIPC parameter, which configures support for processing
multiple items or samples per clock cycle. With this enabled, the FFT
block can process at rates higher than 250 MSPS, such as 500 MSPS and
beyond.


Original-commit: fc76aa940e121fe1f85a3513f6d90df4667338cf
2025-03-07 12:39:34 -06:00

311 lines
11 KiB
Systemverilog

//
// Copyright 2024 Ettus Research, a National Instruments Brand
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// Module: fft_pipeline_wrapper
//
// Description:
//
// This module takes a multiple-item-per-cycle data stream and splits the
// processing of packets across multiple FFT instances, each processing a
// single item/sample per cycle.
//
// See fft_pipeline for documentation of the fft_pipeline parameters and
// ports. To avoid duplication, it is not repeated here.
//
// Parameters:
//
// NIPC : Items/samples per cycle on the input/output data port (i_t*, o_t*d)
//
`default_nettype none
module fft_pipeline_wrapper
import xfft_config_pkg::*;
#(
int NIPC = 1,
// Parameters for fft_pipeline
int MAX_FFT_SIZE_LOG2 = 12,
bit EN_CONFIG_FIFO = 0,
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 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 [NIPC*DATA_W-1:0] i_tdata,
input wire i_tlast,
input wire i_tvalid,
output wire i_tready,
// Data Output Packets
output wire [NIPC*DATA_W-1:0] o_tdata,
output wire o_tlast,
output wire o_tvalid,
input wire o_tready
);
`include "usrp_utils.svh"
if (NIPC == 1) begin : gen_one_spc
fft_pipeline #(
.MAX_FFT_SIZE_LOG2(MAX_FFT_SIZE_LOG2),
.EN_CONFIG_FIFO (EN_CONFIG_FIFO ),
.EN_CP_REMOVAL (EN_CP_REMOVAL ),
.EN_CP_INSERTION (EN_CP_INSERTION ),
.EN_FFT_ORDER (EN_FFT_ORDER ),
.EN_MAGNITUDE (EN_MAGNITUDE ),
.EN_MAGNITUDE_SQ (EN_MAGNITUDE_SQ ),
.USE_APPROX_MAG (USE_APPROX_MAG )
) fft_pipeline_i (
.clk (clk ),
.rst (rst ),
.fft_order (fft_order ),
.magnitude (magnitude ),
.fft_config (fft_config ),
.fft_size_log2 (fft_size_log2 ),
.fft_config_tdata (fft_config_tdata ),
.fft_config_tvalid (fft_config_tvalid ),
.fft_config_tready (fft_config_tready ),
.cp_rem_tdata (cp_rem_tdata ),
.cp_rem_tvalid (cp_rem_tvalid ),
.cp_rem_tready (cp_rem_tready ),
.cp_ins_tdata (cp_ins_tdata ),
.cp_ins_tvalid (cp_ins_tvalid ),
.cp_ins_tready (cp_ins_tready ),
.event_fft_overflow(event_fft_overflow),
.i_tdata (i_tdata ),
.i_tlast (i_tlast ),
.i_tvalid (i_tvalid ),
.i_tready (i_tready ),
.o_tdata (o_tdata ),
.o_tlast (o_tlast ),
.o_tvalid (o_tvalid ),
.o_tready (o_tready )
);
end else begin : gen_multi_spc
logic [FFT_CONFIG_W-1:0] fft_config_split_tdata [NIPC];
logic fft_config_split_tvalid[NIPC];
logic fft_config_split_tready[NIPC];
logic [CP_LEN_W-1:0] cp_rem_split_tdata [NIPC];
logic cp_rem_split_tvalid [NIPC];
logic cp_rem_split_tready [NIPC];
logic [CP_LEN_W-1:0] cp_ins_split_tdata [NIPC];
logic cp_ins_split_tvalid [NIPC];
logic cp_ins_split_tready [NIPC];
logic [DATA_W-1:0] i_split_tdata [NIPC];
logic i_split_tlast [NIPC];
logic i_split_tvalid [NIPC];
logic i_split_tready [NIPC];
logic [DATA_W-1:0] o_split_tdata [NIPC];
logic o_split_tlast [NIPC];
logic o_split_tvalid [NIPC];
logic o_split_tready [NIPC];
logic [NIPC-1:0] event_fft_overflow_split;
if (EN_CONFIG_FIFO) begin : gen_config_fifo_split
axis_load_split #(
.IN_DATA_W (FFT_CONFIG_W),
.IN_FIFO_SIZE (1 ),
.OUT_DATA_W (FFT_CONFIG_W),
.OUT_FIFO_SIZE(1 ),
.OUT_NUM_PORTS(NIPC )
) axis_load_split_fft_config (
.clk (clk ),
.rst (rst ),
.i_tdata (fft_config_tdata ),
.i_tuser ('0 ),
.i_tlast (1'b1 ),
.i_tvalid(fft_config_tvalid ),
.i_tready(fft_config_tready ),
.o_tdata (fft_config_split_tdata ),
.o_tuser ( ),
.o_tlast ( ),
.o_tvalid(fft_config_split_tvalid),
.o_tready(fft_config_split_tready)
);
end else begin : gen_no_config_fifo_split
assign fft_config_tready = 1'b1;
for (genvar idx=0; idx < NIPC; idx++) begin : gen_assign
assign fft_config_split_tvalid[idx] = 1'b0;
end
end
axis_load_split #(
.IN_DATA_W (CP_LEN_W),
.IN_FIFO_SIZE (1 ),
.OUT_DATA_W (CP_LEN_W),
.OUT_FIFO_SIZE(1 ),
.OUT_NUM_PORTS(NIPC )
) axis_load_split_cp_rem (
.clk (clk ),
.rst (rst ),
.i_tdata (cp_rem_tdata ),
.i_tuser ('0 ),
.i_tlast (1'b1 ),
.i_tvalid(cp_rem_tvalid ),
.i_tready(cp_rem_tready ),
.o_tdata (cp_rem_split_tdata ),
.o_tuser ( ),
.o_tlast ( ),
.o_tvalid(cp_rem_split_tvalid),
.o_tready(cp_rem_split_tready)
);
axis_load_split #(
.IN_DATA_W (CP_LEN_W),
.IN_FIFO_SIZE (1 ),
.OUT_DATA_W (CP_LEN_W),
.OUT_FIFO_SIZE(1 ),
.OUT_NUM_PORTS(NIPC )
) axis_load_split_cp_ins (
.clk (clk ),
.rst (rst ),
.i_tdata (cp_ins_tdata ),
.i_tuser ('0 ),
.i_tlast (1'b1 ),
.i_tvalid(cp_ins_tvalid ),
.i_tready(cp_ins_tready ),
.o_tdata (cp_ins_split_tdata ),
.o_tuser ( ),
.o_tlast ( ),
.o_tvalid(cp_ins_split_tvalid),
.o_tready(cp_ins_split_tready)
);
axis_load_split #(
.IN_DATA_W (NIPC*DATA_W ),
.IN_FIFO_SIZE (1 ),
.OUT_DATA_W (DATA_W ),
.OUT_FIFO_SIZE(MAX_FFT_SIZE_LOG2),
.OUT_NUM_PORTS(NIPC ),
.USER_W (1 )
) axis_load_split_data (
.clk (clk ),
.rst (rst ),
.i_tdata (i_tdata ),
.i_tuser ('0 ),
.i_tlast (i_tlast ),
.i_tvalid(i_tvalid ),
.i_tready(i_tready ),
.o_tdata (i_split_tdata ),
.o_tuser ( ),
.o_tlast (i_split_tlast ),
.o_tvalid(i_split_tvalid),
.o_tready(i_split_tready)
);
for (genvar samp_i = 0; samp_i < NIPC; samp_i++) begin : gen_pipelines
fft_pipeline #(
.MAX_FFT_SIZE_LOG2(MAX_FFT_SIZE_LOG2),
.EN_CONFIG_FIFO (EN_CONFIG_FIFO ),
.EN_CP_REMOVAL (EN_CP_REMOVAL ),
.EN_CP_INSERTION (EN_CP_INSERTION ),
.EN_FFT_ORDER (EN_FFT_ORDER ),
.EN_MAGNITUDE (EN_MAGNITUDE ),
.EN_MAGNITUDE_SQ (EN_MAGNITUDE_SQ ),
.USE_APPROX_MAG (USE_APPROX_MAG )
) fft_pipeline_i (
.clk (clk ),
.rst (rst ),
.fft_order (fft_order ),
.magnitude (magnitude ),
.fft_size_log2 (fft_size_log2 ),
.fft_config (fft_config ),
.fft_config_tdata (fft_config_split_tdata [samp_i]),
.fft_config_tvalid (fft_config_split_tvalid [samp_i]),
.fft_config_tready (fft_config_split_tready [samp_i]),
.cp_rem_tdata (cp_rem_split_tdata [samp_i]),
.cp_rem_tvalid (cp_rem_split_tvalid [samp_i]),
.cp_rem_tready (cp_rem_split_tready [samp_i]),
.cp_ins_tdata (cp_ins_split_tdata [samp_i]),
.cp_ins_tvalid (cp_ins_split_tvalid [samp_i]),
.cp_ins_tready (cp_ins_split_tready [samp_i]),
.event_fft_overflow(event_fft_overflow_split[samp_i]),
.i_tdata (i_split_tdata [samp_i]),
.i_tlast (i_split_tlast [samp_i]),
.i_tvalid (i_split_tvalid [samp_i]),
.i_tready (i_split_tready [samp_i]),
.o_tdata (o_split_tdata [samp_i]),
.o_tlast (o_split_tlast [samp_i]),
.o_tvalid (o_split_tvalid [samp_i]),
.o_tready (o_split_tready [samp_i])
);
end
axis_load_merge #(
.IN_DATA_W (DATA_W ),
.IN_FIFO_SIZE (MAX_FFT_SIZE_LOG2),
.IN_NUM_PORTS (NIPC ),
.OUT_DATA_W (NIPC*DATA_W ),
.OUT_FIFO_SIZE(1 ),
.USER_W (1 )
) axis_load_merge_data (
.clk (clk ),
.rst (rst ),
.i_tdata (o_split_tdata ),
.i_tuser ( ),
.i_tlast (o_split_tlast ),
.i_tvalid(o_split_tvalid),
.i_tready(o_split_tready),
.o_tdata (o_tdata ),
.o_tuser ( ),
.o_tlast (o_tlast ),
.o_tvalid(o_tvalid ),
.o_tready(o_tready )
);
assign event_fft_overflow = |event_fft_overflow_split;
end
endmodule : fft_pipeline_wrapper
`default_nettype wire