cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
w-w-j
Visitor
Visitor
7,336 Views
Registered: ‎04-04-2017

HLS FFT (fft_single example) ap_fifo problem in larger AXI Streaming project(HLS 2016.4)

Jump to solution

 Hi everyone,

 

I am having a problem with using the HLS fft_single example project(HLS 2016.4) and was wondering if some kind soul can help me out. The core issue I am having is that the fft_single example that uses ap_fifo interface does not work in my hls::stream top_level_function. I should probably mention that my solution compiles with 0 errors, but does not output anything on my Zedboard(using printfs). I am using an AXI DMA and have verified everything to be correct (ie HLS project works happily in Zedboard without FFT function) so it is certain that there is an issue with how I am using the fft_single project. 

 

To simplify things, I will show 3 code extracts - fft_top.h, fft_top.cpp and mainFile.cpp(top level function in which I call fft_top). fft_top.h and fft_top.cpp is mostly unchanged. I am using a scaled FFT, 1024-points, 16 bit input.

 

My question is this -> How do I use fft_single example as a subfunction in a larger AXI Streaming project?

 

fft_top.h (from fft_single Vivado HLS example)

 

#ifndef FFT_TOP_H_
#define FFT_TOP_H_

#include "ap_fixed.h"
#include "hls_fft.h"

// configurable params
const char FFT_INPUT_WIDTH                     = 16;            
const char FFT_OUTPUT_WIDTH                    = FFT_INPUT_WIDTH;
const char FFT_CONFIG_WIDTH                    = 16;
const char FFT_NFFT_MAX                        = 10;
const int  FFT_LENGTH                          = 1 << FFT_NFFT_MAX;


#include <complex>
using namespace std;

struct config1 : hls::ip_fft::params_t {
    static const unsigned ordering_opt = hls::ip_fft::natural_order;

    static const unsigned config_width = FFT_CONFIG_WIDTH;

    static const unsigned arch_opt =  hls::ip_fft::pipelined_streaming_io;      
    static const unsigned complex_mult_type = hls::ip_fft::use_mults_resources; 
    static const unsigned butterfly_type = hls::ip_fft::use_xtremedsp_slices;   
    static const unsigned input_width = FFT_INPUT_WIDTH;    
    static const unsigned output_width = FFT_OUTPUT_WIDTH;  
};

typedef hls::ip_fft::config_t<config1> config_t;
typedef hls::ip_fft::status_t<config1> status_t;

typedef ap_fixed<FFT_INPUT_WIDTH,1> data_in_t;
typedef ap_fixed<FFT_OUTPUT_WIDTH,FFT_OUTPUT_WIDTH-FFT_INPUT_WIDTH+1> data_out_t;
typedef std::complex<data_in_t> cmpxDataIn;
typedef std::complex<data_out_t> cmpxDataOut;

void dummy_proc_fe(
    bool direction,
    config_t* config,
    cmpxDataIn in[FFT_LENGTH],
    cmpxDataIn out[FFT_LENGTH]);

void dummy_proc_be(
    status_t* status_in,
    bool* ovflo,
    cmpxDataOut in[FFT_LENGTH],
    cmpxDataOut out[FFT_LENGTH]);

void fft_top(
    cmpxDataIn in[FFT_LENGTH],
    cmpxDataOut out[FFT_LENGTH]);

#endif

 

fft_top.cpp (unchanged)

 

#include "fft_top.h"

void dummy_proc_fe(
    bool direction,
    config_t* config,
    cmpxDataIn in[FFT_LENGTH],
    cmpxDataIn out[FFT_LENGTH])
{
    int i;
    config->setDir(direction);
    config->setSch(0x2AB);
    for (i=0; i< FFT_LENGTH; i++)
        out[i] = in[i];
}

void dummy_proc_be(
    status_t* status_in,
    bool* ovflo,
    cmpxDataOut in[FFT_LENGTH],
    cmpxDataOut out[FFT_LENGTH])
{
    int i;
    for (i=0; i< FFT_LENGTH; i++)
        out[i] = in[i];
    *ovflo = status_in->getOvflo() & 0x1;
}

void fft_top(
    bool direction,
    complex<data_in_t> in[FFT_LENGTH],
    complex<data_out_t> out[FFT_LENGTH],
    bool* ovflo)
{
#pragma HLS interface ap_hs port=direction
#pragma HLS interface ap_fifo depth=1 port=ovflo
#pragma HLS interface ap_fifo depth=FFT_LENGTH port=in,out
#pragma HLS data_pack variable=in
#pragma HLS data_pack variable=out
#pragma HLS dataflow

    complex<data_in_t> xn[FFT_LENGTH];
    complex<data_out_t> xk[FFT_LENGTH];
    config_t fft_config;
    status_t fft_status;

    dummy_proc_fe(direction, &fft_config, in, xn);
    // FFT IP
    hls::fft<config1>(xn, xk, &fft_status, &fft_config);
    dummy_proc_be(&fft_status, ovflo, xk, out);
}

 

mainFile.cpp ( top level function is my_top_level_function )

 

Summary : My inputs and outputs are defined as AXI streaming interfaces. I am defining extra ap_fifo interfaces so I can interact with HLS FFT. Not sure if my approach is right, any guidance would be much appreciated. 

 

static cmpxDataIn inputArray[FFT_LENGTH];
static cmpxDataIn inputToFFTStub[FFT_LENGTH];
static cmpxDataIn outputOfFFTStub[FFT_LENGTH];
bool directionStub = 1;
bool ovfloStub;


void my_top_level_function(hls::stream<custom_axis> &inputStreak, hls::stream<custom_axis> &outputStream){
#pragma HLS INTERFACE axis port=outStream
#pragma HLS INTERFACE axis port=inStream

// NOTES : I defined these pragmas to match the fft_top function, not sure if it is the correct approach
#pragma HLS interface ap_hs port=directionStub
#pragma HLS interface ap_fifo depth=1 port=ovfloStub
#pragma HLS interface ap_fifo depth=FFT_LENGTH port=inputToFFTStub,outputOfFFTStub

    // NOTES : I just read from AXI Stream, scale the data to (+1,-1) and store it in an array
    // this works fine
    for(int i = 0 ;i < FFT_LENGTH ; i++){
            masterArray[i] = inStream.read();
        	float tempValue =  ((float)masterArray[i].data / (float)256);       // scaling FFT input to (+1,-1) range
            inputArray[i].real() = (data_in_t)tempValue;
            inputArray[i].imag() = 0;       
    }

    // NOTES : Have no idea if all this is correct at all, it just compiles fine...

    // similar to dummy_proc_be and dummy_proc_fe, I am transferring data from inputArray to inputToFFTStub
    // inputToFFTStub is a ap_fifo interface
    for(int i=0;i<FFT_LENGTH;i++){
    	inputToFFTStub[i].real() = inputArray[i].real();
    	inputToFFTStub[i].imag() = inputArray[i].imag();
    }

    fft_top(directionStub,inputToFFTStub,outputOfFFTStub,&ovfloStub);

    // similar to dummy_proc_be and dummy_proc_fe, getting data from ap_fifo outputOfFFTStub into another static array for further processing
    for(int i=0;i<FFT_LENGTH;i++){
    	outputOfFFT[i].real() = outputOfFFTStub[i].real();
    	outputOfFFT[i].imag() = outputOfFFTStub[i].imag();
    }

    // additional processing, sending the data down via AXI Stream, works fine
    outputStream.write(_some_data_of_outputOfFFT_here);
}

 

C/RTL simulation messages before being stuck

 

Warning: WARNING: SCLR is not implemented in this block to try and improve timing - may affect behaviour!
Time: 0 ps  Iteration: 0
////////////////////////////////////////////////////////////////////////////////////
// Inter-Transaction Progress: Completed Transaction / Total Transaction
// Intra-Transaction Progress: Measured Latency / Latency Estimation * 100%
//
// RTL Simulation : "Inter-Transaction Progress" ["Intra-Transaction Progress"] @ "Simulation Time"
////////////////////////////////////////////////////////////////////////////////////
// RTL Simulation : 0 / 1 [0.00%] @ "125000"

 

 

Like I said at the start, the project compiles fine, C simulation works, C/RTL simulation hangs. When I export the RTL into my Vivado project and run it on a Zedboard(viewed using printf statements), there is no output. AXI DMA and other stuff I am using are 100% verified to be working so the problem definitely lies in FFT.

 

 

My question is this -> How do I use fft_single example as a subfunction in a larger AXI Streaming project?

 

Appreciate the help!

 

 

0 Kudos
1 Solution

Accepted Solutions
w-w-j
Visitor
Visitor
10,515 Views
Registered: ‎04-04-2017

Figured it out. Surprising how things start to work just as you are about to give up...

 

Turns out my code actually works. You just need to change the pragmas above :

 

 

From 

 

 

// old pragma
#pragma HLS interface ap_hs port=directionStub
#pragma HLS interface ap_fifo depth=1 port=ovfloStub
#pragma HLS interface ap_fifo depth=FFT_LENGTH port=inputToFFTStub,outputOfFFTStub

 

 

To

 

 

// new pragma
#pragma HLS interface ap_fifo depth=FFT_LENGTH port=inputToFFTStub,outputOfFFTStub

 

 

Everything else is the same. This allows the fft_single Vivado HLS example to be called as a subfunction in your AXI streaming design. 

 

I think it's pretty important that you have a separate outputOfFFTStub static array as they are modelled as an ap_fifo (ie read or write but not both). inputToFFTStub is not necessary in the above example, inputToFFT works fine(in order accesses).

 

 

Feel free to add on to this post. I'm just glad I solve this after 2 days of messing around :)

 

View solution in original post

2 Replies
w-w-j
Visitor
Visitor
10,516 Views
Registered: ‎04-04-2017

Figured it out. Surprising how things start to work just as you are about to give up...

 

Turns out my code actually works. You just need to change the pragmas above :

 

 

From 

 

 

// old pragma
#pragma HLS interface ap_hs port=directionStub
#pragma HLS interface ap_fifo depth=1 port=ovfloStub
#pragma HLS interface ap_fifo depth=FFT_LENGTH port=inputToFFTStub,outputOfFFTStub

 

 

To

 

 

// new pragma
#pragma HLS interface ap_fifo depth=FFT_LENGTH port=inputToFFTStub,outputOfFFTStub

 

 

Everything else is the same. This allows the fft_single Vivado HLS example to be called as a subfunction in your AXI streaming design. 

 

I think it's pretty important that you have a separate outputOfFFTStub static array as they are modelled as an ap_fifo (ie read or write but not both). inputToFFTStub is not necessary in the above example, inputToFFT works fine(in order accesses).

 

 

Feel free to add on to this post. I'm just glad I solve this after 2 days of messing around :)

 

View solution in original post

jkk@ms3e.dk
Visitor
Visitor
6,420 Views
Registered: ‎02-23-2016

Hi,

 

I am facing exactly the same problem, however, I cannot solve the problem by changing the pragmas. Did you do other changes to make this work?

0 Kudos