ストリーミング インターフェイス使用した FFT 関数 - 2023.2 日本語

Vitis 高位合成ユーザー ガイド (UG1399)

Document ID
UG1399
Release Date
2023-12-18
Version
2023.2 日本語

ストリーミング インターフェイスを使用する FFT 関数は、次のように HLS 名前空間で定義されます。

  template <typename PARAM_T>
  void fft(hls::stream<complex<float or ap_fixed>> &xn_s,
           hls::stream<complex<float or ap_fixed >> &xk_s,
           hls::stream<ip_fft::status_t<CONFIG_T>> &status_s,
           hls::stream<ip_fft::config_t<CONFIG_T>> &config_s);

これは、次のように呼び出すことができます。

hls::fft<STATIC_PARAM> (
INPUT_DATA_STREAM,
OUTPUT_DATA_STREAM,
OUTPUT_STATUS_STREAM,
INPUT_RUN_TIME_CONFIGURATION_STREAM);

STATIC_PARAM は、FFT のスタティック パラメーターを定義するスタティック パラメーター指定構造体です。

すべての入力および出力は、hls::stream<> として関数に供給されます。最終的なインプリメンテーションでは、FFT RTL ブロックのポートは AXI4-Stream ポートとしてインプリメントされます。

重要: set_directive_dataflow または #pragma HLS dataflow を使用してデータフロー領域でストリーミング FFT 関数を常に使用する必要があります。FFT は、パイプラインされた領域では使用できません。特に、データを処理せずに FFT が停止するクロック サイクルを回避することで、パフォーマンスの優れた演算が必要な場合は、次のようにする必要があります。
  • FFT を含むデザイン階層全体、および FFT より上位の階層は、データフロー領域か、dataflow-in-loop のみを含む関数のいずれかである必要があります。
  • 協調シミュレーションのデッドロック検出 で説明するように、すべての FIFO には、協調シミュレーションでブロッキングを避けるのに十分な深さが必要です。
  • 階層構造のすべてのデータフロー プロセスに含めるのは、次のものだけです。
    • rewind オプションを使用したパイプライン
    • または、rewind オプションを使用したパイプライン処理済みループ

入力データおよび出力データ ストリームのデータ型は、float または ap_fixed です。

void fft_top(
    bool direction,
    complex<data_in_t> in[FFT_LENGTH],
    complex<data_out_t> out[FFT_LENGTH],
    bool &ovflo)
{
    #pragma HLS dataflow
    hls::stream<complex<data_in_t>> in_fft; 
    hls::stream<complex<data_out_t>> out_fft; 
    hls::stream<config_t> fft_config;
    hls::stream<status_t> fft_status;

    // convert inputs to hls::stream<> and generates fft_config stream based on input arguments   
    proc_fe(direction, fft_config, in, in_fft);
    // FFT IP
    hls::fft<config1>(in_fft, out_fft, fft_status, fft_config);
    // convert fft result to outputs data type and sets output ovflo according to fft_status stream
    proc_be(fft_status, ovflo, out_fft, out);
}

固定小数点型を使用する場合は、Vitis HLS 任意精度型 ap_fixed を使用する必要があります。

#include "ap_fixed.h"
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;
#include <complex>
typedef complex<data_in_t> cmpxData;
typedef complex<data_out_t> cmpxDataOut;

どちらの場合でも、FFT のパラメーターを同じ正しいデータ サイズに指定する必要があります。浮動小数点型の場合、データ幅は常に 32 ビットで、その他のサイズを指定しても無効と判断されます。

ストリームと配列の比較

次の表に、FFT IP の配列の例とストリームの使用例を示します。どちらの場合も、データフロー階層は最上位まで広がっており、順次コード (データフロー領域や dataflow-in-loop 関数ではないコード) はなく、copy-in ループと copy-out ループは rewind でパイプライン処理されています。

ヒント: 各例の最上位関数には、一貫性のために配列インターフェイスを使用していますが、hls::stream<> や STREAM プラグマまたは指示子を使用するように変更しても、同じ効果があります。
表 1. FFT の引数
配列引数を使用した FFT hls::stream<> 引数を指定した FFT
#include "fft_top.h"
 
void 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++)
 #pragma HLS pipeline II=1 rewind
 out[i] = in[i];
}
 
void 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++)
 #pragma HLS pipeline II=1 rewind
 out[i] = in[i];
 *ovflo = status_in->getOvflo() & 0x1;
}
 
// TOP function
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;
 
 // convert inputs to arrays and generates fft_config 
 // based on input arguments 
 proc_fe(direction, &fft_config, in, xn);
 // FFT IP
 hls::fft<config1>(xn, xk, &fft_status, &fft_config);
 // convert fft results to outputs data type and 
 // sets output ovflo according to fft_status
 proc_be(&fft_status, ovflo, xk, out);
}
#include "fft_top.h"
 
void proc_fe(
 bool direction,
 hls::stream<config_t> &config_s, 
 cmpxDataIn in[FFT_LENGTH],
 hls::stream<cmpxDataIn> &out_s)
{
 int i; 
 config_t config;
 config.setDir(direction);
 config.setSch(0x2AB);
 config_s.write(config);
 for (i=0; i< FFT_LENGTH; i++) {
 #pragma HLS pipeline II=1 rewind
 out_s.write(in[i]);
 }
}
 
void proc_be(
 hls::stream<status_t> &status_in_s, 
 bool &ovflo,
 hls::stream<cmpxDataOut> &in_s,
 cmpxDataOut out[FFT_LENGTH])
{
 int i; 
 for (i=0; i< FFT_LENGTH; i++) {
 #pragma HLS pipeline II=1 rewind
 out[i] = in_s.read();
 }
 status_t status_in = status_in_s.read();
 ovflo = status_in.getOvflo() & 0x1;
}
 
// TOP function
void fft_top(
 bool direction,
 complex<data_in_t> in[FFT_LENGTH],
 complex<data_out_t> out[FFT_LENGTH],
 bool &ovflo)
{
#pragma HLS dataflow
 hls::stream<complex<data_in_t>> xn;
 hls::stream<complex<data_out_t>> xk;
 hls::stream<config_t> fft_config;
 hls::stream<status_t> fft_status;
 // convert inputs to hls::stream<> 
 // and generates fft_config stream based on input arguments 
 proc_fe(direction, fft_config, in, xn);
 // FFT IP
 hls::fft<config1>(xn, xk, fft_status, fft_config);
 // convert fft result to outputs data type 
 // and sets output ovflo according to fft_status stream
 proc_be(fft_status, ovflo, xk, out);
}