Top Level Definition and main Function - 2023.1 English

Vitis Libraries

Release Date
2023-12-20
Version
2023.1 English

Following section lists a complete example test that uses 2-D fixed point SSR FFT L1 module. The header file named top_2d_fft_test.hpp listed below provides definition of most of the template parameters and data types used in test and also the declaration of top level function top_fft2d that will be synthesized.

#ifndef _TOP_2D_FFT_TEST_H_
#define _TOP_2D_FFT_TEST_H_
#ifndef __SYNTHESIS__
#include <iostream>
#endif
#include "vt_fft.hpp"
#ifndef __SYNTHESIS__
#include <iostream>
#endif
using namespace xf::dsp::fft;
typedef ap_fixed<27, 8> T_innerData;
typedef std::complex<T_innerData> T_elemType;
const int k_memWidthBits = 512;
const int k_memWidth = k_memWidthBits / (sizeof(std::complex<T_innerData>) * 8);
const int k_fftKernelRadix = 4;
const int k_numOfKernels = k_memWidth / (k_fftKernelRadix);
const int k_fftKernelSize = 16;
typedef float T_innerFloat;
typedef std::complex<T_innerFloat> T_compleFloat;
const int k_numRows = k_fftKernelSize;
const int k_numCols = k_fftKernelSize;
const int k_rowInstanceIDOffset = 40000;
const int k_colInstanceIDOffset = 80000;
const int k_totalWideSamples = k_fftKernelSize * k_fftKernelSize / k_memWidth;
struct FFTParams : ssr_fft_default_params {
    static const int N = k_fftKernelSize;
    static const int R = k_fftKernelRadix;
    static const scaling_mode_enum scaling_mode = SSR_FFT_NO_SCALING;

    static const transform_direction_enum transform_direction = FORWARD_TRANSFORM;
};
struct FFTParams2 : ssr_fft_default_params {
    static const int N = k_fftKernelSize;
    static const int R = k_fftKernelRadix;
    static const scaling_mode_enum scaling_mode = SSR_FFT_NO_SCALING;

    static const transform_direction_enum transform_direction = FORWARD_TRANSFORM;
};

typedef FFTIOTypes<FFTParams, T_elemType>::T_outType T_outType_row;
typedef FFTIOTypes<FFTParams2, T_outType_row>::T_outType T_outType;

typedef WideTypeDefs<k_memWidth, T_elemType>::WideIFType MemWideIFTypeIn;
typedef WideTypeDefs<k_memWidth, T_elemType>::WideIFStreamType MemWideIFStreamTypeIn;

typedef WideTypeDefs<k_memWidth, T_outType>::WideIFType MemWideIFTypeOut;
typedef WideTypeDefs<k_memWidth, T_outType>::WideIFStreamType MemWideIFStreamTypeOut;

void top_fft2d(MemWideIFStreamTypeIn& p_inStream, MemWideIFStreamTypeOut& p_outStream);
#endif

Following .cpp file named top_2d_fft_test.cpp defines top level function which essentially calls fft2d from Vitis FFT library.

#include "top_2d_fft_test.hpp"
void top_fft2d(MemWideIFStreamTypeIn& p_inStream, MemWideIFStreamTypeOut& p_outStream) {
#ifdef _DEBUG_TYPES
    T_outType_row T_outType_row_temp;
    T_outType T_outType_temp;
    MemWideIFTypeIn MemWideIFTypeIn_temp;
    MemWideIFTypeOut MemWideIFTypeOut_temp;
#endif

#pragma HLS INLINE
#pragma HLS DATA_PACK variable = p_inStream
#pragma HLS DATA_PACK variable = p_outStream
#pragma HLS interface ap_ctrl_none port = return

#ifndef __SYNTHESIS__
    std::cout << "================================================================================" << std::endl;
    std::cout << "-------------------Calling 2D SSR FFT Kernel with Parameters--------------------" << std::endl;
    std::cout << "================================================================================" << std::endl;
    std::cout << "    The Main Memory Width (no. complex<ap_fixed>)   : " << k_memWidth << std::endl;
    std::cout << "    The Size of 1D Row Kernel                    : " << FFTParams::N << std::endl;
    std::cout << "    The SSR for 1D Row Kernel                    : " << FFTParams::R << std::endl;
    std::cout << "    The Transform Direction for Row Kernel       : "
              << ((FFTParams::transform_direction == FORWARD_TRANSFORM) ? "Forward" : "Reverse");
    std::cout << std::endl;

    std::cout << "    The Size of 1D Column Kernel                 : " << FFTParams2::N << std::endl;
    std::cout << "    The SSR for 1D Row Kernel                    : " << FFTParams2::R << std::endl;
    std::cout << "    The Transform Direction for Row Kernel       : "
              << ((FFTParams2::transform_direction == FORWARD_TRANSFORM) ? "Forward" : "Reverse");
    std::cout << std::endl;

    std::cout << "    The Row Instance ID Offset                   : " << k_rowInstanceIDOffset << std::endl;
    std::cout << "    The Column Instance ID Offset                : " << k_colInstanceIDOffset << std::endl;

    std::cout << "    Number of 1D Kernels Used Row/Col wise       : " << k_numOfKernels << std::endl;
    std::cout << "    The Total Number of 1D Kernels Used(row+col) : " << 2 * k_numOfKernels << std::endl;
    std::cout << "================================================================================" << std::endl;

#endif
    fft2d<k_memWidth, k_fftKernelSize, k_fftKernelSize, k_numOfKernels, FFTParams, FFTParams2, k_rowInstanceIDOffset,
          k_colInstanceIDOffset, T_elemType>(p_inStream, p_outStream);
}

The main function is defined as follows which runs an impulse test:

#define TEST_2D_FFT_
#ifdef TEST_2D_FFT_
#ifndef __SYNTHESIS__
#define _DEBUG_TYPES
#endif
#include <math.h>
#include <string>
#include <assert.h>
#include <stdio.h>
#include "top_2d_fft_test.hpp"
#include "mVerificationUtlityFunctions.hpp"
#include "vitis_fft/hls_ssr_fft_2d_modeling_utilities.hpp"
#include "vt_fft.hpp"

int main(int argc, char** argv) {
    // 2d input matrix
    T_elemType l_inMat[k_fftKernelSize][k_fftKernelSize];
    T_outType l_outMat[k_fftKernelSize][k_fftKernelSize];
    T_outType l_data2d_golden[k_fftKernelSize][k_fftKernelSize];

    // init input matrix with real part only impulse
    for (int r = 0; r < k_fftKernelSize; ++r) {
        for (int c = 0; c < k_fftKernelSize; ++c) {
            if (r == 0 && c == 0)
                l_inMat[r][c] = T_compleFloat(1, 0);
            else
                l_inMat[r][c] = T_compleFloat(0, 0);
        }
    }
    // Wide Stream for reading and streaming a 2-d matrix
    MemWideIFStreamTypeIn l_matToStream("matrixToStreaming");
    MemWideIFStreamTypeOut fftOutputStream("fftOutputStream");
    // Pass same data stream multiple times to measure the II correctly
    for (int runs = 0; runs < 5; ++runs) {
        stream2DMatrix<k_fftKernelSize, k_fftKernelSize, k_memWidth, T_elemType, MemWideIFTypeIn>(l_inMat,
                                                                                                  l_matToStream);
        top_fft2d(l_matToStream, fftOutputStream);

        printMatStream<k_fftKernelSize, k_fftKernelSize, k_memWidth, MemWideIFTypeOut>(
            fftOutputStream, "2D SSR FFT Output Natural Order...");
        streamToMatrix<k_fftKernelSize, k_fftKernelSize, k_memWidth, T_outType>(fftOutputStream, l_outMat);
    } // runs loop

    T_outType golden_result = T_elemType(1, 0);
    for (int r = 0; r < k_fftKernelSize; ++r) {
        for (int c = 0; c < k_fftKernelSize; ++c) {
            if (golden_result != l_outMat[r][c]) return 1;
        }
    }

    std::cout << "================================================================" << std::endl;
    std::cout << "---------------------Impulse test Passed Successfully." << std::endl;
    std::cout << "================================================================" << std::endl;
    return 0;
}
#endif