This adds additional tests to the testbench to cover register reads and basic IFFT functionaltiy. Original-commit: 9157e11795f3ca86dae2ee930e60a79470d1447f
523 lines
22 KiB
Verilog
523 lines
22 KiB
Verilog
//
|
|
// Copyright 2019 Ettus Research, a National Instruments Company
|
|
//
|
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
|
//
|
|
// Module: rfnoc_block_fft
|
|
//
|
|
// Description: An FFT block for RFNoC.
|
|
//
|
|
// Parameters:
|
|
//
|
|
// THIS_PORTID : Control crossbar port to which this block is connected
|
|
// CHDR_W : AXIS CHDR interface data width
|
|
// MTU : Maximum transmission unit (i.e., maximum packet size) in
|
|
// CHDR words is 2**MTU.
|
|
// EN_MAGNITUDE_OUT : CORDIC based magnitude calculation
|
|
// EN_MAGNITUDE_APPROX_OUT : Multipler-less, lower resource usage
|
|
// EN_MAGNITUDE_SQ_OUT : Magnitude squared
|
|
// EN_FFT_SHIFT : Center zero frequency bin
|
|
//
|
|
|
|
module rfnoc_block_fft #(
|
|
parameter THIS_PORTID = 0,
|
|
parameter CHDR_W = 64,
|
|
parameter MTU = 10,
|
|
|
|
parameter EN_MAGNITUDE_OUT = 0,
|
|
parameter EN_MAGNITUDE_APPROX_OUT = 1,
|
|
parameter EN_MAGNITUDE_SQ_OUT = 1,
|
|
parameter EN_FFT_SHIFT = 1
|
|
)
|
|
(
|
|
//---------------------------------------------------------------------------
|
|
// AXIS CHDR Port
|
|
//---------------------------------------------------------------------------
|
|
|
|
input wire rfnoc_chdr_clk,
|
|
input wire ce_clk,
|
|
|
|
// CHDR inputs from framework
|
|
input wire [CHDR_W-1:0] s_rfnoc_chdr_tdata,
|
|
input wire s_rfnoc_chdr_tlast,
|
|
input wire s_rfnoc_chdr_tvalid,
|
|
output wire s_rfnoc_chdr_tready,
|
|
|
|
// CHDR outputs to framework
|
|
output wire [CHDR_W-1:0] m_rfnoc_chdr_tdata,
|
|
output wire m_rfnoc_chdr_tlast,
|
|
output wire m_rfnoc_chdr_tvalid,
|
|
input wire m_rfnoc_chdr_tready,
|
|
|
|
// Backend interface
|
|
input wire [511:0] rfnoc_core_config,
|
|
output wire [511:0] rfnoc_core_status,
|
|
|
|
//---------------------------------------------------------------------------
|
|
// AXIS CTRL Port
|
|
//---------------------------------------------------------------------------
|
|
|
|
input wire rfnoc_ctrl_clk,
|
|
|
|
// CTRL port requests from framework
|
|
input wire [31:0] s_rfnoc_ctrl_tdata,
|
|
input wire s_rfnoc_ctrl_tlast,
|
|
input wire s_rfnoc_ctrl_tvalid,
|
|
output wire s_rfnoc_ctrl_tready,
|
|
|
|
// CTRL port requests to framework
|
|
output wire [31:0] m_rfnoc_ctrl_tdata,
|
|
output wire m_rfnoc_ctrl_tlast,
|
|
output wire m_rfnoc_ctrl_tvalid,
|
|
input wire m_rfnoc_ctrl_tready
|
|
);
|
|
|
|
// These are the only supported values for now
|
|
localparam ITEM_W = 32;
|
|
localparam NIPC = 1;
|
|
|
|
`include "../../core/rfnoc_axis_ctrl_utils.vh"
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Signal Declarations
|
|
//---------------------------------------------------------------------------
|
|
|
|
wire ctrlport_req_wr;
|
|
wire ctrlport_req_rd;
|
|
wire [19:0] ctrlport_req_addr;
|
|
wire [31:0] ctrlport_req_data;
|
|
wire ctrlport_resp_ack;
|
|
wire [31:0] ctrlport_resp_data;
|
|
|
|
wire [ITEM_W-1:0] axis_to_fft_tdata;
|
|
wire axis_to_fft_tlast;
|
|
wire axis_to_fft_tvalid;
|
|
wire axis_to_fft_tready;
|
|
|
|
wire [ITEM_W-1:0] axis_from_fft_tdata;
|
|
wire axis_from_fft_tlast;
|
|
wire axis_from_fft_tvalid;
|
|
wire axis_from_fft_tready;
|
|
|
|
wire [CHDR_W-1:0] m_axis_context_tdata;
|
|
wire [ 3:0] m_axis_context_tuser;
|
|
wire [ 0:0] m_axis_context_tlast;
|
|
wire [ 0:0] m_axis_context_tvalid;
|
|
wire [ 0:0] m_axis_context_tready;
|
|
|
|
wire [CHDR_W-1:0] s_axis_context_tdata;
|
|
wire [ 3:0] s_axis_context_tuser;
|
|
wire [ 0:0] s_axis_context_tlast;
|
|
wire [ 0:0] s_axis_context_tvalid;
|
|
wire [ 0:0] s_axis_context_tready;
|
|
|
|
wire ce_rst;
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// NoC Shell
|
|
//---------------------------------------------------------------------------
|
|
|
|
noc_shell_fft #(
|
|
.THIS_PORTID (THIS_PORTID),
|
|
.CHDR_W (CHDR_W ),
|
|
.MTU (MTU )
|
|
) noc_shell_fft_i (
|
|
.rfnoc_chdr_clk (rfnoc_chdr_clk ),
|
|
.rfnoc_ctrl_clk (rfnoc_ctrl_clk ),
|
|
.ce_clk (ce_clk ),
|
|
.rfnoc_chdr_rst ( ),
|
|
.rfnoc_ctrl_rst ( ),
|
|
.ce_rst (ce_rst ),
|
|
.rfnoc_core_config (rfnoc_core_config ),
|
|
.rfnoc_core_status (rfnoc_core_status ),
|
|
.s_rfnoc_chdr_tdata (s_rfnoc_chdr_tdata ),
|
|
.s_rfnoc_chdr_tlast (s_rfnoc_chdr_tlast ),
|
|
.s_rfnoc_chdr_tvalid (s_rfnoc_chdr_tvalid ),
|
|
.s_rfnoc_chdr_tready (s_rfnoc_chdr_tready ),
|
|
.m_rfnoc_chdr_tdata (m_rfnoc_chdr_tdata ),
|
|
.m_rfnoc_chdr_tlast (m_rfnoc_chdr_tlast ),
|
|
.m_rfnoc_chdr_tvalid (m_rfnoc_chdr_tvalid ),
|
|
.m_rfnoc_chdr_tready (m_rfnoc_chdr_tready ),
|
|
.s_rfnoc_ctrl_tdata (s_rfnoc_ctrl_tdata ),
|
|
.s_rfnoc_ctrl_tlast (s_rfnoc_ctrl_tlast ),
|
|
.s_rfnoc_ctrl_tvalid (s_rfnoc_ctrl_tvalid ),
|
|
.s_rfnoc_ctrl_tready (s_rfnoc_ctrl_tready ),
|
|
.m_rfnoc_ctrl_tdata (m_rfnoc_ctrl_tdata ),
|
|
.m_rfnoc_ctrl_tlast (m_rfnoc_ctrl_tlast ),
|
|
.m_rfnoc_ctrl_tvalid (m_rfnoc_ctrl_tvalid ),
|
|
.m_rfnoc_ctrl_tready (m_rfnoc_ctrl_tready ),
|
|
.ctrlport_clk ( ),
|
|
.ctrlport_rst ( ),
|
|
.m_ctrlport_req_wr (ctrlport_req_wr ),
|
|
.m_ctrlport_req_rd (ctrlport_req_rd ),
|
|
.m_ctrlport_req_addr (ctrlport_req_addr ),
|
|
.m_ctrlport_req_data (ctrlport_req_data ),
|
|
.m_ctrlport_resp_ack (ctrlport_resp_ack ),
|
|
.m_ctrlport_resp_data (ctrlport_resp_data ),
|
|
.axis_data_clk ( ),
|
|
.axis_data_rst ( ),
|
|
.m_in_0_payload_tdata (axis_to_fft_tdata ),
|
|
.m_in_0_payload_tkeep ( ),
|
|
.m_in_0_payload_tlast (axis_to_fft_tlast ),
|
|
.m_in_0_payload_tvalid (axis_to_fft_tvalid ),
|
|
.m_in_0_payload_tready (axis_to_fft_tready ),
|
|
.m_in_0_context_tdata (m_axis_context_tdata ),
|
|
.m_in_0_context_tuser (m_axis_context_tuser ),
|
|
.m_in_0_context_tlast (m_axis_context_tlast ),
|
|
.m_in_0_context_tvalid (m_axis_context_tvalid),
|
|
.m_in_0_context_tready (m_axis_context_tready),
|
|
.s_out_0_payload_tdata (axis_from_fft_tdata ),
|
|
.s_out_0_payload_tkeep ({1*NIPC{1'b1}} ),
|
|
.s_out_0_payload_tlast (axis_from_fft_tlast ),
|
|
.s_out_0_payload_tvalid (axis_from_fft_tvalid ),
|
|
.s_out_0_payload_tready (axis_from_fft_tready ),
|
|
.s_out_0_context_tdata (s_axis_context_tdata ),
|
|
.s_out_0_context_tuser (s_axis_context_tuser ),
|
|
.s_out_0_context_tlast (s_axis_context_tlast ),
|
|
.s_out_0_context_tvalid (s_axis_context_tvalid),
|
|
.s_out_0_context_tready (s_axis_context_tready)
|
|
);
|
|
|
|
// The input packets are the same configuration as the output packets, so
|
|
// just use the header information for each incoming to create the header for
|
|
// each outgoing packet. This is done by connecting m_axis_context to
|
|
// directly to s_axis_context.
|
|
assign s_axis_context_tdata = m_axis_context_tdata;
|
|
assign s_axis_context_tuser = m_axis_context_tuser;
|
|
assign s_axis_context_tlast = m_axis_context_tlast;
|
|
assign s_axis_context_tvalid = m_axis_context_tvalid;
|
|
assign m_axis_context_tready = s_axis_context_tready;
|
|
|
|
wire [ 8-1:0] set_addr;
|
|
wire [32-1:0] set_data;
|
|
wire set_stb;
|
|
wire [ 8-1:0] rb_addr;
|
|
reg [64-1:0] rb_data;
|
|
|
|
ctrlport_to_settings_bus # (
|
|
.NUM_PORTS (1)
|
|
) ctrlport_to_settings_bus_i (
|
|
.ctrlport_clk (ce_clk),
|
|
.ctrlport_rst (ce_rst),
|
|
.s_ctrlport_req_wr (ctrlport_req_wr),
|
|
.s_ctrlport_req_rd (ctrlport_req_rd),
|
|
.s_ctrlport_req_addr (ctrlport_req_addr),
|
|
.s_ctrlport_req_data (ctrlport_req_data),
|
|
.s_ctrlport_req_has_time (1'b0),
|
|
.s_ctrlport_req_time (64'b0),
|
|
.s_ctrlport_resp_ack (ctrlport_resp_ack),
|
|
.s_ctrlport_resp_data (ctrlport_resp_data),
|
|
.set_data (set_data),
|
|
.set_addr (set_addr),
|
|
.set_stb (set_stb),
|
|
.set_time (),
|
|
.set_has_time (),
|
|
.rb_stb (1'b1),
|
|
.rb_addr (rb_addr),
|
|
.rb_data (rb_data));
|
|
|
|
localparam MAX_FFT_SIZE_LOG2 = 11;
|
|
|
|
localparam [31:0] SR_FFT_RESET = 131;
|
|
localparam [31:0] SR_FFT_SIZE_LOG2 = 132;
|
|
localparam [31:0] SR_MAGNITUDE_OUT = 133;
|
|
localparam [31:0] SR_FFT_DIRECTION = 134;
|
|
localparam [31:0] SR_FFT_SCALING = 135;
|
|
localparam [31:0] SR_FFT_SHIFT_CONFIG = 136;
|
|
|
|
localparam RB_FFT_RESET = 0;
|
|
localparam RB_MAGNITUDE_OUT = 1;
|
|
localparam RB_FFT_SIZE_LOG2 = 2;
|
|
localparam RB_FFT_DIRECTION = 3;
|
|
localparam RB_FFT_SCALING = 4;
|
|
localparam RB_FFT_SHIFT_CONFIG = 5;
|
|
|
|
// FFT Output
|
|
localparam [1:0] COMPLEX_OUT = 0;
|
|
localparam [1:0] MAG_OUT = 1;
|
|
localparam [1:0] MAG_SQ_OUT = 2;
|
|
|
|
// FFT Direction
|
|
localparam [0:0] FFT_REVERSE = 0;
|
|
localparam [0:0] FFT_FORWARD = 1;
|
|
|
|
wire [1:0] magnitude_out;
|
|
wire [31:0] fft_data_o_tdata;
|
|
wire fft_data_o_tlast;
|
|
wire fft_data_o_tvalid;
|
|
wire fft_data_o_tready;
|
|
wire [15:0] fft_data_o_tuser;
|
|
wire [31:0] fft_shift_o_tdata;
|
|
wire fft_shift_o_tlast;
|
|
wire fft_shift_o_tvalid;
|
|
wire fft_shift_o_tready;
|
|
wire [31:0] fft_mag_i_tdata, fft_mag_o_tdata, fft_mag_o_tdata_int;
|
|
wire fft_mag_i_tlast, fft_mag_o_tlast;
|
|
wire fft_mag_i_tvalid, fft_mag_o_tvalid;
|
|
wire fft_mag_i_tready, fft_mag_o_tready;
|
|
wire [31:0] fft_mag_sq_i_tdata, fft_mag_sq_o_tdata;
|
|
wire fft_mag_sq_i_tlast, fft_mag_sq_o_tlast;
|
|
wire fft_mag_sq_i_tvalid, fft_mag_sq_o_tvalid;
|
|
wire fft_mag_sq_i_tready, fft_mag_sq_o_tready;
|
|
wire [31:0] fft_mag_round_i_tdata, fft_mag_round_o_tdata;
|
|
wire fft_mag_round_i_tlast, fft_mag_round_o_tlast;
|
|
wire fft_mag_round_i_tvalid, fft_mag_round_o_tvalid;
|
|
wire fft_mag_round_i_tready, fft_mag_round_o_tready;
|
|
|
|
// Settings Registers
|
|
wire fft_reset;
|
|
setting_reg #(
|
|
.my_addr(SR_FFT_RESET), .awidth(8), .width(1))
|
|
sr_fft_reset (
|
|
.clk(ce_clk), .rst(ce_rst),
|
|
.strobe(set_stb), .addr(set_addr), .in(set_data), .out(fft_reset), .changed());
|
|
|
|
// Two instances of FFT size register, one for FFT core and one for FFT shift
|
|
localparam DEFAULT_FFT_SIZE = 8; // 256
|
|
wire [7:0] fft_size_log2_tdata ,fft_core_size_log2_tdata;
|
|
wire fft_size_log2_tvalid, fft_core_size_log2_tvalid, fft_size_log2_tready, fft_core_size_log2_tready;
|
|
axi_setting_reg #(
|
|
.ADDR(SR_FFT_SIZE_LOG2), .AWIDTH(8), .WIDTH(8), .DATA_AT_RESET(DEFAULT_FFT_SIZE), .VALID_AT_RESET(1))
|
|
sr_fft_size_log2 (
|
|
.clk(ce_clk), .reset(ce_rst),
|
|
.set_stb(set_stb), .set_addr(set_addr), .set_data(set_data),
|
|
.o_tdata(fft_size_log2_tdata), .o_tlast(), .o_tvalid(fft_size_log2_tvalid), .o_tready(fft_size_log2_tready));
|
|
|
|
axi_setting_reg #(
|
|
.ADDR(SR_FFT_SIZE_LOG2), .AWIDTH(8), .WIDTH(8), .DATA_AT_RESET(DEFAULT_FFT_SIZE), .VALID_AT_RESET(1))
|
|
sr_fft_size_log2_2 (
|
|
.clk(ce_clk), .reset(ce_rst),
|
|
.set_stb(set_stb), .set_addr(set_addr), .set_data(set_data),
|
|
.o_tdata(fft_core_size_log2_tdata), .o_tlast(), .o_tvalid(fft_core_size_log2_tvalid), .o_tready(fft_core_size_log2_tready));
|
|
|
|
localparam DEFAULT_FFT_DIRECTION = FFT_FORWARD;
|
|
wire fft_direction_tdata;
|
|
wire fft_direction_tvalid, fft_direction_tready;
|
|
axi_setting_reg #(
|
|
.ADDR(SR_FFT_DIRECTION), .AWIDTH(8), .WIDTH(1), .DATA_AT_RESET(DEFAULT_FFT_DIRECTION), .VALID_AT_RESET(1))
|
|
sr_fft_direction (
|
|
.clk(ce_clk), .reset(ce_rst),
|
|
.set_stb(set_stb), .set_addr(set_addr), .set_data(set_data),
|
|
.o_tdata(fft_direction_tdata), .o_tlast(), .o_tvalid(fft_direction_tvalid), .o_tready(fft_direction_tready));
|
|
|
|
localparam [11:0] DEFAULT_FFT_SCALING = 12'b011010101010; // Conservative 1/N scaling
|
|
wire [11:0] fft_scaling_tdata;
|
|
wire fft_scaling_tvalid, fft_scaling_tready;
|
|
axi_setting_reg #(
|
|
.ADDR(SR_FFT_SCALING), .AWIDTH(8), .WIDTH(12), .DATA_AT_RESET(DEFAULT_FFT_SCALING), .VALID_AT_RESET(1))
|
|
sr_fft_scaling (
|
|
.clk(ce_clk), .reset(ce_rst),
|
|
.set_stb(set_stb), .set_addr(set_addr), .set_data(set_data),
|
|
.o_tdata(fft_scaling_tdata), .o_tlast(), .o_tvalid(fft_scaling_tvalid), .o_tready(fft_scaling_tready));
|
|
|
|
wire [1:0] fft_shift_config_tdata;
|
|
wire fft_shift_config_tvalid, fft_shift_config_tready;
|
|
axi_setting_reg #(
|
|
.ADDR(SR_FFT_SHIFT_CONFIG), .AWIDTH(8), .WIDTH(2))
|
|
sr_fft_shift_config (
|
|
.clk(ce_clk), .reset(ce_rst),
|
|
.set_stb(set_stb), .set_addr(set_addr), .set_data(set_data),
|
|
.o_tdata(fft_shift_config_tdata), .o_tlast(), .o_tvalid(fft_shift_config_tvalid), .o_tready(fft_shift_config_tready));
|
|
|
|
// Synchronize writing configuration to the FFT core
|
|
reg fft_config_ready;
|
|
wire fft_config_write = fft_config_ready & axis_to_fft_tvalid & axis_to_fft_tready;
|
|
always @(posedge ce_clk) begin
|
|
if (ce_rst | fft_reset) begin
|
|
fft_config_ready <= 1'b1;
|
|
end else begin
|
|
if (fft_config_write) begin
|
|
fft_config_ready <= 1'b0;
|
|
end else if (axis_to_fft_tlast) begin
|
|
fft_config_ready <= 1'b1;
|
|
end
|
|
end
|
|
end
|
|
|
|
wire [23:0] fft_config_tdata = {3'd0, fft_scaling_tdata, fft_direction_tdata, fft_core_size_log2_tdata};
|
|
wire fft_config_tvalid = fft_config_write & (fft_scaling_tvalid | fft_direction_tvalid | fft_core_size_log2_tvalid);
|
|
wire fft_config_tready;
|
|
assign fft_core_size_log2_tready = fft_config_tready & fft_config_write;
|
|
assign fft_direction_tready = fft_config_tready & fft_config_write;
|
|
assign fft_scaling_tready = fft_config_tready & fft_config_write;
|
|
axi_fft inst_axi_fft (
|
|
.aclk(ce_clk), .aresetn(~(fft_reset)),
|
|
.s_axis_data_tvalid(axis_to_fft_tvalid),
|
|
.s_axis_data_tready(axis_to_fft_tready),
|
|
.s_axis_data_tlast(axis_to_fft_tlast),
|
|
.s_axis_data_tdata({axis_to_fft_tdata[15:0],axis_to_fft_tdata[31:16]}),
|
|
.m_axis_data_tvalid(fft_data_o_tvalid),
|
|
.m_axis_data_tready(fft_data_o_tready),
|
|
.m_axis_data_tlast(fft_data_o_tlast),
|
|
.m_axis_data_tdata({fft_data_o_tdata[15:0],fft_data_o_tdata[31:16]}),
|
|
.m_axis_data_tuser(fft_data_o_tuser), // FFT index
|
|
.s_axis_config_tdata(fft_config_tdata),
|
|
.s_axis_config_tvalid(fft_config_tvalid),
|
|
.s_axis_config_tready(fft_config_tready),
|
|
.event_frame_started(),
|
|
.event_tlast_unexpected(),
|
|
.event_tlast_missing(),
|
|
.event_status_channel_halt(),
|
|
.event_data_in_channel_halt(),
|
|
.event_data_out_channel_halt());
|
|
|
|
// Mux control signals
|
|
assign fft_shift_o_tready = (magnitude_out == MAG_OUT) ? fft_mag_i_tready :
|
|
(magnitude_out == MAG_SQ_OUT) ? fft_mag_sq_i_tready : axis_from_fft_tready;
|
|
assign fft_mag_i_tvalid = (magnitude_out == MAG_OUT) ? fft_shift_o_tvalid : 1'b0;
|
|
assign fft_mag_i_tlast = (magnitude_out == MAG_OUT) ? fft_shift_o_tlast : 1'b0;
|
|
assign fft_mag_i_tdata = fft_shift_o_tdata;
|
|
assign fft_mag_o_tready = (magnitude_out == MAG_OUT) ? fft_mag_round_i_tready : 1'b0;
|
|
assign fft_mag_sq_i_tvalid = (magnitude_out == MAG_SQ_OUT) ? fft_shift_o_tvalid : 1'b0;
|
|
assign fft_mag_sq_i_tlast = (magnitude_out == MAG_SQ_OUT) ? fft_shift_o_tlast : 1'b0;
|
|
assign fft_mag_sq_i_tdata = fft_shift_o_tdata;
|
|
assign fft_mag_sq_o_tready = (magnitude_out == MAG_SQ_OUT) ? fft_mag_round_i_tready : 1'b0;
|
|
assign fft_mag_round_i_tvalid = (magnitude_out == MAG_OUT) ? fft_mag_o_tvalid :
|
|
(magnitude_out == MAG_SQ_OUT) ? fft_mag_sq_o_tvalid : 1'b0;
|
|
assign fft_mag_round_i_tlast = (magnitude_out == MAG_OUT) ? fft_mag_o_tlast :
|
|
(magnitude_out == MAG_SQ_OUT) ? fft_mag_sq_o_tlast : 1'b0;
|
|
assign fft_mag_round_i_tdata = (magnitude_out == MAG_OUT) ? fft_mag_o_tdata : fft_mag_sq_o_tdata;
|
|
assign fft_mag_round_o_tready = axis_from_fft_tready;
|
|
assign axis_from_fft_tvalid = (magnitude_out == MAG_OUT | magnitude_out == MAG_SQ_OUT) ? fft_mag_round_o_tvalid : fft_shift_o_tvalid;
|
|
assign axis_from_fft_tlast = (magnitude_out == MAG_OUT | magnitude_out == MAG_SQ_OUT) ? fft_mag_round_o_tlast : fft_shift_o_tlast;
|
|
assign axis_from_fft_tdata = (magnitude_out == MAG_OUT | magnitude_out == MAG_SQ_OUT) ? fft_mag_round_o_tdata : fft_shift_o_tdata;
|
|
|
|
// Conditionally synth magnitude / magnitude^2 logic
|
|
generate
|
|
if (EN_MAGNITUDE_OUT | EN_MAGNITUDE_APPROX_OUT | EN_MAGNITUDE_SQ_OUT) begin : generate_magnitude_out
|
|
setting_reg #(
|
|
.my_addr(SR_MAGNITUDE_OUT), .awidth(8), .width(2))
|
|
sr_magnitude_out (
|
|
.clk(ce_clk), .rst(ce_rst),
|
|
.strobe(set_stb), .addr(set_addr), .in(set_data), .out(magnitude_out), .changed());
|
|
end else begin : generate_magnitude_out_else
|
|
// Magnitude calculation logic not included, so always bypass
|
|
assign magnitude_out = 2'd0;
|
|
end
|
|
|
|
if (EN_FFT_SHIFT) begin : generate_fft_shift
|
|
fft_shift #(
|
|
.MAX_FFT_SIZE_LOG2(MAX_FFT_SIZE_LOG2),
|
|
.WIDTH(32))
|
|
inst_fft_shift (
|
|
.clk(ce_clk), .reset(ce_rst | fft_reset),
|
|
.config_tdata(fft_shift_config_tdata),
|
|
.config_tvalid(fft_shift_config_tvalid),
|
|
.config_tready(fft_shift_config_tready),
|
|
.fft_size_log2_tdata(fft_size_log2_tdata[$clog2(MAX_FFT_SIZE_LOG2)-1:0]),
|
|
.fft_size_log2_tvalid(fft_size_log2_tvalid),
|
|
.fft_size_log2_tready(fft_size_log2_tready),
|
|
.i_tdata(fft_data_o_tdata),
|
|
.i_tlast(fft_data_o_tlast),
|
|
.i_tvalid(fft_data_o_tvalid),
|
|
.i_tready(fft_data_o_tready),
|
|
.i_tuser(fft_data_o_tuser[MAX_FFT_SIZE_LOG2-1:0]),
|
|
.o_tdata(fft_shift_o_tdata),
|
|
.o_tlast(fft_shift_o_tlast),
|
|
.o_tvalid(fft_shift_o_tvalid),
|
|
.o_tready(fft_shift_o_tready));
|
|
end
|
|
else begin : generate_fft_shift_else
|
|
assign fft_shift_o_tdata = fft_data_o_tdata;
|
|
assign fft_shift_o_tlast = fft_data_o_tlast;
|
|
assign fft_shift_o_tvalid = fft_data_o_tvalid;
|
|
assign fft_data_o_tready = fft_shift_o_tready;
|
|
end
|
|
|
|
// More accurate magnitude calculation takes precedence if enabled
|
|
if (EN_MAGNITUDE_OUT) begin : generate_complex_to_magphase
|
|
complex_to_magphase
|
|
inst_complex_to_magphase (
|
|
.aclk(ce_clk), .aresetn(~(ce_rst | fft_reset)),
|
|
.s_axis_cartesian_tvalid(fft_mag_i_tvalid),
|
|
.s_axis_cartesian_tlast(fft_mag_i_tlast),
|
|
.s_axis_cartesian_tready(fft_mag_i_tready),
|
|
.s_axis_cartesian_tdata(fft_mag_i_tdata),
|
|
.m_axis_dout_tvalid(fft_mag_o_tvalid),
|
|
.m_axis_dout_tlast(fft_mag_o_tlast),
|
|
.m_axis_dout_tdata(fft_mag_o_tdata_int),
|
|
.m_axis_dout_tready(fft_mag_o_tready));
|
|
assign fft_mag_o_tdata = {1'b0, fft_mag_o_tdata_int[15:0], 15'd0};
|
|
end
|
|
else if (EN_MAGNITUDE_APPROX_OUT) begin : generate_complex_to_mag_approx
|
|
complex_to_mag_approx
|
|
inst_complex_to_mag_approx (
|
|
.clk(ce_clk), .reset(ce_rst | fft_reset), .clear(1'b0),
|
|
.i_tvalid(fft_mag_i_tvalid),
|
|
.i_tlast(fft_mag_i_tlast),
|
|
.i_tready(fft_mag_i_tready),
|
|
.i_tdata(fft_mag_i_tdata),
|
|
.o_tvalid(fft_mag_o_tvalid),
|
|
.o_tlast(fft_mag_o_tlast),
|
|
.o_tready(fft_mag_o_tready),
|
|
.o_tdata(fft_mag_o_tdata_int[15:0]));
|
|
assign fft_mag_o_tdata = {1'b0, fft_mag_o_tdata_int[15:0], 15'd0};
|
|
end
|
|
else begin : generate_complex_to_mag_approx_else
|
|
assign fft_mag_o_tdata = fft_mag_i_tdata;
|
|
assign fft_mag_o_tlast = fft_mag_i_tlast;
|
|
assign fft_mag_o_tvalid = fft_mag_i_tvalid;
|
|
assign fft_mag_i_tready = fft_mag_o_tready;
|
|
end
|
|
|
|
if (EN_MAGNITUDE_SQ_OUT) begin : generate_complex_to_magsq
|
|
complex_to_magsq
|
|
inst_complex_to_magsq (
|
|
.clk(ce_clk), .reset(ce_rst | fft_reset), .clear(1'b0),
|
|
.i_tvalid(fft_mag_sq_i_tvalid),
|
|
.i_tlast(fft_mag_sq_i_tlast),
|
|
.i_tready(fft_mag_sq_i_tready),
|
|
.i_tdata(fft_mag_sq_i_tdata),
|
|
.o_tvalid(fft_mag_sq_o_tvalid),
|
|
.o_tlast(fft_mag_sq_o_tlast),
|
|
.o_tready(fft_mag_sq_o_tready),
|
|
.o_tdata(fft_mag_sq_o_tdata));
|
|
end
|
|
else begin : generate_complex_to_magsq_else
|
|
assign fft_mag_sq_o_tdata = fft_mag_sq_i_tdata;
|
|
assign fft_mag_sq_o_tlast = fft_mag_sq_i_tlast;
|
|
assign fft_mag_sq_o_tvalid = fft_mag_sq_i_tvalid;
|
|
assign fft_mag_sq_i_tready = fft_mag_sq_o_tready;
|
|
end
|
|
|
|
// Convert to SC16
|
|
if (EN_MAGNITUDE_OUT | EN_MAGNITUDE_APPROX_OUT | EN_MAGNITUDE_SQ_OUT) begin : generate_axi_round_and_clip
|
|
axi_round_and_clip #(
|
|
.WIDTH_IN(32),
|
|
.WIDTH_OUT(16),
|
|
.CLIP_BITS(1))
|
|
inst_axi_round_and_clip (
|
|
.clk(ce_clk), .reset(ce_rst | fft_reset),
|
|
.i_tdata(fft_mag_round_i_tdata),
|
|
.i_tlast(fft_mag_round_i_tlast),
|
|
.i_tvalid(fft_mag_round_i_tvalid),
|
|
.i_tready(fft_mag_round_i_tready),
|
|
.o_tdata(fft_mag_round_o_tdata[31:16]),
|
|
.o_tlast(fft_mag_round_o_tlast),
|
|
.o_tvalid(fft_mag_round_o_tvalid),
|
|
.o_tready(fft_mag_round_o_tready));
|
|
assign fft_mag_round_o_tdata[15:0] = {16{16'd0}};
|
|
end
|
|
else begin : generate_axi_round_and_clip_else
|
|
assign fft_mag_round_o_tdata = fft_mag_round_i_tdata;
|
|
assign fft_mag_round_o_tlast = fft_mag_round_i_tlast;
|
|
assign fft_mag_round_o_tvalid = fft_mag_round_i_tvalid;
|
|
assign fft_mag_round_i_tready = fft_mag_round_o_tready;
|
|
end
|
|
endgenerate
|
|
|
|
// Readback registers
|
|
always @*
|
|
case(rb_addr)
|
|
RB_FFT_RESET : rb_data <= {63'd0, fft_reset};
|
|
RB_MAGNITUDE_OUT : rb_data <= {62'd0, magnitude_out};
|
|
RB_FFT_SIZE_LOG2 : rb_data <= {fft_size_log2_tdata};
|
|
RB_FFT_DIRECTION : rb_data <= {63'd0, fft_direction_tdata};
|
|
RB_FFT_SCALING : rb_data <= {52'd0, fft_scaling_tdata};
|
|
RB_FFT_SHIFT_CONFIG : rb_data <= {62'd0, fft_shift_config_tdata};
|
|
default : rb_data <= 64'h0BADC0DE0BADC0DE;
|
|
endcase
|
|
|
|
endmodule
|