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
578 lines
22 KiB
Systemverilog
578 lines
22 KiB
Systemverilog
//
|
|
// Copyright 2025 Ettus Research, a National Instruments Brand
|
|
//
|
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
|
//
|
|
// Module: fft_packetize
|
|
//
|
|
// Description:
|
|
//
|
|
// This module converts the packets from the RFNoC shell's AXI-stream data
|
|
// interface into packets to be consumed by the FFT logic. It works in
|
|
// collaboration with the fft_depacketize module, which does the reverse.
|
|
// Relevant information about the burst and number of FFTs is passed along
|
|
// using side-band AXI-stream buses (o_info and o_symbol) to the depacketizer.
|
|
//
|
|
// This module takes into account any cyclic prefix removal being performed
|
|
// by the FFT block to ensure the data is packetized for the FFT logic
|
|
// appropriately.
|
|
//
|
|
// The RFNoC packet from the NoC shell is input onto the i_noc bus. The
|
|
// repacketized FFT data, resized to the requested symbol size, is output on
|
|
// the o_fft bus.
|
|
//
|
|
// The cyclic prefix length to be removed for each symbol is input on the
|
|
// i_cp_rem bus. A copy of the cyclic prefix length that was input is then
|
|
// stored in a FIFO to be output onto the o_cp_rem bus for use by downstream
|
|
// FFT logic, where the actual removal is performed. The cyclic prefix to be
|
|
// used must be set on the i_cp_rem_tdata input at the time the associated
|
|
// symbol begins to be received because it will not wait for i_cp_rem_tvalid.
|
|
// In the case where no cyclic prefix was provided by the user, it is assumed
|
|
// that the logic driving this input will give it a reasonable default (e.g.,
|
|
// a prefix length of 0).
|
|
//
|
|
// If the last sample of the input burst does not coincide with the end of a
|
|
// symbol, then data will be inserted, so that the FFT block does not end a
|
|
// burst in the middle of an FFT transfer. This may result in extra data
|
|
// being output at the end of a burst, and the values of the final FFT/IFFT
|
|
// will be corrupted in an unpredictable way. So, users should always input
|
|
// full symbols into the FFT block.
|
|
//
|
|
// Timestamps are also supported. The timestamp from the first packet of the
|
|
// burst input into i_noc is captured by this module and passed to the
|
|
// fft_depacketize module via the o_info bus. See the fft_depacketize module
|
|
// for details of how timestamps are generated for output packets.
|
|
//
|
|
// This module also supports multiple synchronized channels by setting
|
|
// NUM_CHAN to a number greater than 1. In this case, all the sideband
|
|
// signals are assumed to be shared by all channels (tvalid, tready, tkeep,
|
|
// tlength, ttimestamp, etc.) but the tdata field is NUM_CHAN times wider to
|
|
// accommodate the data from the other channels.
|
|
//
|
|
// The minimum FFT size supported by this module is the next power of two
|
|
// that's greater than or equal to 2*NIPC, due to the pipeline delay of
|
|
// calculating when we've reached the end of the packet.
|
|
//
|
|
// The incoming RFNoC packets and the cyclic prefix length must both be a
|
|
// multiple of NIPC. Trailing data (i.e., when TKEEP is not all ones) is only
|
|
// allowed on the last transfer of a burst.
|
|
//
|
|
// Parameters:
|
|
//
|
|
// ITEM_W : Item size (or sample size) in bits for the FFT/IFFT
|
|
// core.
|
|
// NIPC : Number of items per clock cycle. Each word is
|
|
// NIPC*ITEM_W bits wide. It must be a power of 2.
|
|
// NUM_CHAN : Number of parallel channels sharing the sideband
|
|
// information.
|
|
// EN_CP_REMOVAL : Indicates whether to support cyclic prefix removal.
|
|
// MAX_PKT_SIZE_LOG2 : Maximum packet payload size in items, expressed as
|
|
// a log base 2. In other words, the maximum packet
|
|
// size is 2**PKT_SIZE_LOG items.
|
|
// MAX_FFT_SIZE_LOG2 : Maximum FFT size in items, expressed as a log base
|
|
// 2. In other words, the maximum FFT size is
|
|
// 2**MAX_FFT_SIZE_LOG2 items.
|
|
// DATA_FIFO_SIZE_LOG2 : Depth of the internal FIFO that stores output data
|
|
// to o_fft, expressed as a log base 2. In other
|
|
// words, the FIFO size is 2**DATA_FIFO_SIZE_LOG2
|
|
// items for each channel. This can be used to provide
|
|
// additional buffering, if needed. Set to -1 to
|
|
// remove the FIFO.
|
|
// CP_FIFO_SIZE_LOG2 : Depth of the internal FIFO that stores cyclic
|
|
// prefix lengths, expressed as a log base 2. In other
|
|
// words, the FIFO size is 2**CP_FIFO_SIZE_LOG2
|
|
// lengths deep. This FIFO is used to pass i_cp_rem to
|
|
// o_cp_rem and must be deep enough to account for the
|
|
// maximum number of FFT operations that are in flight
|
|
// at one time.
|
|
// BURST_FIFO_SIZE_LOG2 : Depth of the internal FIFO that stores burst
|
|
// information, expressed as a log base 2. In other
|
|
// words, the FIFO size is 2**BURST_FIFO_SIZE_LOG2
|
|
// bursts deep. This FIFO stores information about
|
|
// each burst and must be deep enough to account for
|
|
// the maximum number of bursts that are in flight at
|
|
// one time.
|
|
// SYMB_FIFO_SIZE_LOG2 : Depth of the internal FIFO that stores symbol
|
|
// information, expressed as a log base 2. In other
|
|
// words, the FIFO size is 2**SYMB_FIFO_SIZE_LOG2
|
|
// symbols deep. This FIFO is used to store
|
|
// information about each symbol and must be deep
|
|
// enough to account for the maximum number of FFT
|
|
// operations that are in flight at one time.
|
|
//
|
|
|
|
`default_nettype none
|
|
|
|
|
|
module fft_packetize
|
|
import rfnoc_chdr_utils_pkg::*;
|
|
import fft_packetize_pkg::*;
|
|
#(
|
|
int ITEM_W = 32,
|
|
int NIPC = 1,
|
|
int NUM_CHAN = 1,
|
|
bit EN_CP_REMOVAL = 1'b1,
|
|
int MAX_PKT_SIZE_LOG2 = 11,
|
|
int MAX_FFT_SIZE_LOG2 = 10,
|
|
int DATA_FIFO_SIZE_LOG2 = -1,
|
|
int CP_FIFO_SIZE_LOG2 = 5,
|
|
int BURST_FIFO_SIZE_LOG2 = 5,
|
|
int SYMB_FIFO_SIZE_LOG2 = 5,
|
|
|
|
// Internal constants
|
|
localparam int DATA_W = NUM_CHAN * ITEM_W * NIPC,
|
|
localparam int KEEP_W = NIPC,
|
|
localparam int PKT_SIZE_W = MAX_PKT_SIZE_LOG2 + 1,
|
|
localparam int FFT_SIZE_W = MAX_FFT_SIZE_LOG2 + 1,
|
|
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,
|
|
|
|
input wire [ FFT_SIZE_LOG2_W-1:0] fft_size_log2,
|
|
|
|
// Input from cyclic prefix removal list
|
|
input wire [ CP_LEN_W-1:0] i_cp_rem_tdata,
|
|
input wire i_cp_rem_tvalid,
|
|
output logic i_cp_rem_tready,
|
|
|
|
// Output to cyclic prefix removal logic
|
|
output logic [ CP_LEN_W-1:0] o_cp_rem_tdata,
|
|
output logic o_cp_rem_tvalid,
|
|
input wire o_cp_rem_tready,
|
|
|
|
// Input from NoC Shell
|
|
input wire [ DATA_W-1:0] i_noc_tdata,
|
|
input wire [ KEEP_W-1:0] i_noc_tkeep,
|
|
input wire i_noc_tlast,
|
|
input wire i_noc_tvalid,
|
|
output logic i_noc_tready,
|
|
input wire [CHDR_TIMESTAMP_W-1:0] i_noc_ttimestamp,
|
|
input wire i_noc_thas_time,
|
|
input wire [ CHDR_LENGTH_W-1:0] i_noc_tlength,
|
|
input wire i_noc_teov,
|
|
input wire i_noc_teob,
|
|
|
|
// Output to FFT core
|
|
output logic [ DATA_W-1:0] o_fft_tdata,
|
|
output logic [ KEEP_W-1:0] o_fft_tkeep,
|
|
output logic o_fft_tlast,
|
|
output logic o_fft_tvalid,
|
|
input wire o_fft_tready,
|
|
|
|
// Information about each burst (packet size in items, timestamp), going to
|
|
// the depacketizer.
|
|
output burst_info_t o_burst_tdata,
|
|
output logic o_burst_tvalid,
|
|
input wire o_burst_tready,
|
|
|
|
// Information about each symbol (whether it is the last of a burst), going
|
|
// to the depacketizer.
|
|
output symbol_info_t o_symbol_tdata,
|
|
output logic o_symbol_tvalid,
|
|
input wire o_symbol_tready
|
|
);
|
|
|
|
// Make sure NIPC is a power of 2
|
|
if (NIPC != 2**$clog2(NIPC)) begin : gen_nipc_assertion
|
|
$error("NIPC must be a power of 2");
|
|
end
|
|
|
|
// Create a mask to remove unused bits
|
|
localparam logic [ CP_LEN_W-1:0] CP_LEN_MASK = $clog2(NIPC);
|
|
localparam logic [PKT_SIZE_W-1:0] PKT_SIZE_MASK = $clog2(NIPC);
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// FFT Size Register
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
// We assume the fft_size input is set well in advance of any data being
|
|
// received and that it does not change during a burst. This means that we
|
|
// can tolerate a few cycles of delay on these registers.
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
logic [FFT_SIZE_W-1:0] fft_size;
|
|
|
|
always_ff @(posedge clk) begin
|
|
fft_size <= 1 << fft_size_log2;
|
|
end
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// State Machine
|
|
//---------------------------------------------------------------------------
|
|
|
|
typedef enum logic [1:0] {
|
|
WAIT_BURST_ST,
|
|
GET_PREFIX_ST,
|
|
PASS_SYMBOL_ST,
|
|
FINISH_SYMBOL_ST
|
|
} state_t;
|
|
|
|
state_t state = WAIT_BURST_ST;
|
|
|
|
// Burst information
|
|
logic [CHDR_TIMESTAMP_W-1:0] timestamp;
|
|
logic has_time;
|
|
logic [ PKT_SIZE_W-1:0] pkt_size; // Packet size in items
|
|
logic burst_wr_stb = 1'b0; // Info write strobe
|
|
|
|
// Symbol size (IFFT data + cyclic prefix)
|
|
logic [FFT_SIZE_W-1:0] symbol_size;
|
|
logic prefix_wr_stb = 1'b0; // Write strobe
|
|
|
|
// Symbol information
|
|
logic last_symbol; // Last symbol of burst
|
|
logic symbol_wr_stb = 1'b0; // Write strobe
|
|
|
|
// Counter to track how much of current symbol we've output
|
|
logic [FFT_SIZE_W-1:0] item_count = NIPC;
|
|
|
|
// Indicates we're on the last sample/item of the symbol
|
|
logic symbol_tlast;
|
|
|
|
// Data FIFO inputs
|
|
logic [DATA_W-1:0] i_fft_tdata;
|
|
logic [KEEP_W-1:0] i_fft_tkeep;
|
|
logic i_fft_tlast;
|
|
logic i_fft_tvalid;
|
|
logic i_fft_tready;
|
|
|
|
// Cyclic prefix removal length FIFO inputs
|
|
logic [CP_LEN_W-1:0] cp_rem_fifo_tdata;
|
|
logic cp_rem_fifo_tvalid;
|
|
logic cp_rem_fifo_tready;
|
|
|
|
// Burst information FIFO inputs
|
|
burst_info_t burst_fifo_tdata;
|
|
logic burst_fifo_tvalid;
|
|
logic burst_fifo_tready;
|
|
|
|
// Symbol information FIFO inputs
|
|
symbol_info_t symbol_fifo_tdata;
|
|
logic symbol_fifo_tvalid;
|
|
logic symbol_fifo_tready;
|
|
|
|
always_ff @(posedge clk) begin
|
|
burst_wr_stb <= 1'b0;
|
|
prefix_wr_stb <= 1'b0;
|
|
symbol_wr_stb <= 1'b0;
|
|
|
|
unique case (state)
|
|
WAIT_BURST_ST : begin
|
|
// Grab the packet and FFT size for this burst
|
|
item_count <= 2*NIPC; // Account for one cycle of delay, plus one for tlast
|
|
symbol_tlast <= 1'b0;
|
|
timestamp <= i_noc_ttimestamp;
|
|
has_time <= i_noc_thas_time;
|
|
pkt_size <= (i_noc_tlength / (ITEM_W/8)) & ~PKT_SIZE_MASK;
|
|
|
|
// We wait until we have a new packet and the downstream info FIFOs
|
|
// have room to accept another entry (CP removal length, burst info,
|
|
// and symbol info).
|
|
if (i_noc_tvalid && cp_rem_fifo_tready && burst_fifo_tready && symbol_fifo_tready) begin
|
|
//synthesis translate_off
|
|
assert (i_noc_tlength % (NIPC * ITEM_W/8) == 0) else
|
|
$error("fft_packetize: Input packet length is not a multiple of NIPC");
|
|
//synthesis translate_on
|
|
burst_wr_stb <= 1'b1;
|
|
if (EN_CP_REMOVAL) begin
|
|
state <= GET_PREFIX_ST;
|
|
end else begin
|
|
symbol_size <= fft_size;
|
|
state <= PASS_SYMBOL_ST;
|
|
end
|
|
end
|
|
end
|
|
|
|
GET_PREFIX_ST : begin
|
|
// Get the cyclic prefix length for this the next symbol. We assume it
|
|
// is always valid because it defaults to the desired default value.
|
|
item_count <= 2*NIPC;
|
|
symbol_tlast <= 1'b0;
|
|
|
|
// Wait until there's room in the downstream FIFOs for the next symbol
|
|
if (symbol_fifo_tready && cp_rem_fifo_tready) begin
|
|
// Symbol size only changes when CP removal is enabled
|
|
if (EN_CP_REMOVAL) begin
|
|
symbol_size <= fft_size + (i_cp_rem_tdata & ~CP_LEN_MASK);
|
|
end
|
|
prefix_wr_stb <= 1'b1;
|
|
state <= PASS_SYMBOL_ST;
|
|
end
|
|
end
|
|
|
|
PASS_SYMBOL_ST : begin
|
|
// Pass the symbol through
|
|
if (i_fft_tvalid && i_fft_tready) begin
|
|
item_count <= item_count + NIPC;
|
|
symbol_tlast <= (item_count >= symbol_size);
|
|
|
|
if (symbol_tlast) begin
|
|
symbol_wr_stb <= 1'b1;
|
|
if (i_noc_tlast && i_noc_teob) begin
|
|
// All done! Wait for the next burst.
|
|
last_symbol <= 1'b1;
|
|
state <= WAIT_BURST_ST;
|
|
end else begin
|
|
last_symbol <= 1'b0;
|
|
// Finished the symbol. Figure out the length of the next one.
|
|
state <= GET_PREFIX_ST;
|
|
end
|
|
end else if (i_noc_tlast && i_noc_teob) begin
|
|
// We've reached the end of the burst, but we haven't finished the
|
|
// current symbol.
|
|
state <= FINISH_SYMBOL_ST;
|
|
end else begin
|
|
; // Let the next item/sample pass through
|
|
end
|
|
end
|
|
end
|
|
|
|
FINISH_SYMBOL_ST : begin
|
|
// Push through enough data to finish the symbol, so that the
|
|
// downstream FFT logic doesn't get left in a bad state.
|
|
last_symbol <= 1'b1;
|
|
if (i_fft_tvalid && i_fft_tready) begin
|
|
item_count <= item_count + NIPC;
|
|
symbol_tlast <= (item_count >= symbol_size);
|
|
|
|
if (symbol_tlast) begin
|
|
// All done! Wait for the next burst.
|
|
symbol_wr_stb <= 1'b1;
|
|
state <= WAIT_BURST_ST;
|
|
end
|
|
end
|
|
end
|
|
endcase
|
|
|
|
if (rst) begin
|
|
state <= WAIT_BURST_ST;
|
|
prefix_wr_stb <= 1'b0;
|
|
timestamp <= 'X;
|
|
has_time <= 'X;
|
|
pkt_size <= 'X;
|
|
burst_wr_stb <= 1'b0;
|
|
symbol_size <= 'X;
|
|
item_count <= 'X;
|
|
symbol_tlast <= 'X;
|
|
symbol_wr_stb <= 1'b0;
|
|
last_symbol <= 'X;
|
|
end
|
|
end
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Data Pass-through Logic
|
|
//---------------------------------------------------------------------------
|
|
|
|
always_comb begin
|
|
i_fft_tdata = i_noc_tdata;
|
|
i_fft_tkeep = {KEEP_W{1'b1}};
|
|
i_fft_tlast = symbol_tlast;
|
|
|
|
unique case (state)
|
|
WAIT_BURST_ST : begin
|
|
i_fft_tvalid = 1'b0;
|
|
i_noc_tready = 1'b0;
|
|
end
|
|
|
|
GET_PREFIX_ST : begin
|
|
i_fft_tvalid = 1'b0;
|
|
i_noc_tready = 1'b0;
|
|
end
|
|
|
|
PASS_SYMBOL_ST : begin
|
|
// Pass the next item/sample through
|
|
i_fft_tvalid = i_noc_tvalid;
|
|
i_noc_tready = i_fft_tready;
|
|
end
|
|
|
|
FINISH_SYMBOL_ST : begin
|
|
// Flush the data through the FFT
|
|
i_fft_tvalid = 1'b1;
|
|
i_noc_tready = 1'b0;
|
|
end
|
|
endcase
|
|
end
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Output Data FIFO
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
// This FIFO is required to handle the worst-case scenario in which the user
|
|
// wants small FFTs and large packets. In the case where the FFT size equals
|
|
// the packet size, this FIFO is not required.
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
if (DATA_FIFO_SIZE_LOG2 > -1) begin : gen_output_fifo
|
|
axi_fifo #(
|
|
.WIDTH(1 + KEEP_W + DATA_W ),
|
|
.SIZE (DATA_FIFO_SIZE_LOG2 - $clog2(NIPC))
|
|
) axi_fifo_i (
|
|
.clk (clk ),
|
|
.reset (rst ),
|
|
.clear (1'b0 ),
|
|
.i_tdata ({i_fft_tlast, i_fft_tkeep, i_fft_tdata}),
|
|
.i_tvalid(i_fft_tvalid ),
|
|
.i_tready(i_fft_tready ),
|
|
.o_tdata ({o_fft_tlast, o_fft_tkeep, o_fft_tdata}),
|
|
.o_tvalid(o_fft_tvalid ),
|
|
.o_tready(o_fft_tready ),
|
|
.space ( ),
|
|
.occupied( )
|
|
);
|
|
end else begin : gen_no_output_fifo
|
|
assign o_fft_tdata = i_fft_tdata;
|
|
assign o_fft_tkeep = i_fft_tkeep;
|
|
assign o_fft_tlast = i_fft_tlast;
|
|
assign o_fft_tvalid = i_fft_tvalid;
|
|
assign i_fft_tready = o_fft_tready;
|
|
end
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Cyclic Prefix Pass-through Logic
|
|
//---------------------------------------------------------------------------
|
|
|
|
if (EN_CP_REMOVAL) begin : gen_cp_rem_pass_through
|
|
logic [15:0] cp_rem_fifo_space;
|
|
|
|
assign i_cp_rem_tready = prefix_wr_stb;
|
|
assign cp_rem_fifo_tdata = i_cp_rem_tdata & ~CP_LEN_MASK; // Clear the unused bits
|
|
assign cp_rem_fifo_tvalid = prefix_wr_stb;
|
|
|
|
axi_fifo #(
|
|
.WIDTH(CP_LEN_W ),
|
|
.SIZE (CP_FIFO_SIZE_LOG2)
|
|
) axis_fifo_cp_length (
|
|
.clk (clk ),
|
|
.reset (rst ),
|
|
.clear (1'b0 ),
|
|
.i_tdata (cp_rem_fifo_tdata ),
|
|
.i_tvalid(cp_rem_fifo_tvalid),
|
|
.i_tready(cp_rem_fifo_tready),
|
|
.o_tdata (o_cp_rem_tdata ),
|
|
.o_tvalid(o_cp_rem_tvalid ),
|
|
.o_tready(o_cp_rem_tready ),
|
|
.space (cp_rem_fifo_space ),
|
|
.occupied( )
|
|
);
|
|
|
|
// The CP removal length FIFO should be large enough to hold all the
|
|
// symbols that are in flight. Filling up might be an indication that it's
|
|
// sized too small.
|
|
//synthesis translate_off
|
|
logic cp_rem_fifo_empty_prev = 0;
|
|
always_ff @(posedge clk) begin
|
|
cp_rem_fifo_empty_prev <= (cp_rem_fifo_space == 0);
|
|
if (!cp_rem_fifo_empty_prev && cp_rem_fifo_space == 0) begin
|
|
$warning("CP removal FIFO has filled");
|
|
end
|
|
end
|
|
//synthesis translate_on
|
|
end else begin : gen_no_cp_rem_pass_through
|
|
assign cp_rem_fifo_tready = 1'b1;
|
|
assign i_cp_rem_tready = 1'b1;
|
|
assign o_cp_rem_tdata = '0;
|
|
assign o_cp_rem_tvalid = 1'b0;
|
|
end
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Burst Info Logic
|
|
//---------------------------------------------------------------------------
|
|
|
|
logic [15:0] burst_fifo_space;
|
|
|
|
assign burst_fifo_tdata = '{ timestamp, has_time, pkt_size & ~PKT_SIZE_MASK};
|
|
assign burst_fifo_tvalid = burst_wr_stb;
|
|
|
|
axi_fifo #(
|
|
.WIDTH(BURST_INFO_W ),
|
|
.SIZE (BURST_FIFO_SIZE_LOG2)
|
|
) axis_fifo_burst (
|
|
.clk (clk ),
|
|
.reset (rst ),
|
|
.clear (1'b0 ),
|
|
.i_tdata (burst_fifo_tdata ),
|
|
.i_tvalid(burst_fifo_tvalid),
|
|
.i_tready(burst_fifo_tready),
|
|
.o_tdata (o_burst_tdata ),
|
|
.o_tvalid(o_burst_tvalid ),
|
|
.o_tready(o_burst_tready ),
|
|
.space (burst_fifo_space ),
|
|
.occupied( )
|
|
);
|
|
|
|
// The burst information FIFO should be large enough to hold all the
|
|
// bursts that are in flight. Filling up might be an indication that it's
|
|
// sized too small.
|
|
//synthesis translate_off
|
|
logic burst_fifo_empty_prev = 0;
|
|
always_ff @(posedge clk) begin
|
|
burst_fifo_empty_prev <= (burst_fifo_space == 0);
|
|
if (!burst_fifo_empty_prev && burst_fifo_space == 0) begin
|
|
$warning("Burst info FIFO has filled");
|
|
end
|
|
end
|
|
//synthesis translate_on
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Symbol Information FIFO
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
// This FIFO is used to store the information about the the symbols that have
|
|
// been input to the FFT block. Each element in the FIFO corresponds to one
|
|
// symbol. If the data bit is 0, then the corresponding symbol is not the
|
|
// last symbol of the burst. If the data bit is 1, then it is the last symbol
|
|
// of the burst.
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
logic [15:0] o_symbol_space;
|
|
|
|
assign symbol_fifo_tdata.last = last_symbol;
|
|
assign symbol_fifo_tvalid = symbol_wr_stb;
|
|
|
|
axi_fifo #(
|
|
.WIDTH(SYMBOL_INFO_W ),
|
|
.SIZE (SYMB_FIFO_SIZE_LOG2)
|
|
) axis_fifo_symb (
|
|
.clk (clk ),
|
|
.reset (rst ),
|
|
.clear (1'b0 ),
|
|
.i_tdata (symbol_fifo_tdata ),
|
|
.i_tvalid(symbol_fifo_tvalid),
|
|
.i_tready(symbol_fifo_tready),
|
|
.o_tdata (o_symbol_tdata ),
|
|
.o_tvalid(o_symbol_tvalid ),
|
|
.o_tready(o_symbol_tready ),
|
|
.space (o_symbol_space ),
|
|
.occupied( )
|
|
);
|
|
|
|
// The symbol information FIFO should be large enough to hold all the
|
|
// symbols that are in flight. Filling up might be an indication that it's
|
|
// sized too small.
|
|
//synthesis translate_off
|
|
logic symbol_fifo_empty_prev = 0;
|
|
always_ff @(posedge clk) begin
|
|
symbol_fifo_empty_prev <= (o_symbol_space == 0);
|
|
if (!symbol_fifo_empty_prev && o_symbol_space == 0) begin
|
|
$warning("Symbol info FIFO has filled");
|
|
end
|
|
end
|
|
//synthesis translate_on
|
|
|
|
endmodule : fft_packetize
|
|
|
|
|
|
`default_nettype wire
|