FC2カウンター FPGAの部屋 2019年09月10日
FC2ブログ

FPGAやCPLDの話題やFPGA用のツールの話題などです。 マニアックです。 日記も書きます。

FPGAの部屋

FPGAの部屋の有用と思われるコンテンツのまとめサイトを作りました。Xilinx ISEの初心者の方には、FPGAリテラシーおよびチュートリアルのページをお勧めいたします。

2つのAXI4 Stream 入力データを演算してAXI4 Stream 出力1

以前、”2つのHLSストリームを同時に入力して演算してHLSストリーム出力2”でDATAFLOW 指示子を使って、2 つのHLS Stream 入力を同時に受け取ることができた。
しかし、その方法は大げさというかソースコードが分かりにくくなるため、普通の C ソースコードで、2つのAXI4 Stream 入力からデータを受け取る方法を見つけたので、書いておく。

s_squares_axis.cpp のコンセプトは、user == 1 だったら、AXI4 Stream 入力を止めて、2 つのAXI4 Steam 入力が共に user == 1 になることを待つということだ。
それでは、s_squares_axis.cpp を貼っておく。

#include <ap_int.h>
#include <hls_stream.h>
#include <ap_axi_sdata.h>

int s_squares_axis(hls::stream<ap_axis<8,1,1,1> >& x,
    hls::stream<ap_axis<8,1,1,1> >& y, hls::stream<ap_axis<32,1,1,1> >& result){
#pragma HLS INTERFACE s_axilite port=return
#pragma HLS INTERFACE axis register both port=result
#pragma HLS INTERFACE axis register both port=y
#pragma HLS INTERFACE axis register both port=x
    ap_axis<8,1,1,1> xt;
    ap_axis<8,1,1,1> yt;
    ap_axis<32,1,1,1> rlt;

    xt.user = 0; yt.user = 0;
    Loop1 : while(!(xt.user==1 && yt.user==1)){
#pragma HLS PIPELINE II=1
    // user が 1になった時にフレームがスタートする
#pragma HLS LOOP_TRIPCOUNT min=1 max=1 avg=1
        if(xt.user == 0)
            x >> xt;
        if(yt.user == 0)
            y >> yt;
    }

    Loop2 : for(int i=0; i<10; i++){
#pragma HLS PIPELINE II=1
        if(i != 0){
            x >> xt; y >> yt;
        }
        rlt.data = xt.data*xt.data + yt.data*yt.data;
        if(i == 0)
            rlt.user = 1;
        else
            rlt.user = 0;
        if(i==9)
            rlt.last = 1;
        else
            rlt.last = 0;
        result << rlt;
    }
    return(0);
}


なお、いつもの do{ } while( ); 文を使用すると、PIPELINE 指示子の II を 1 にしても、ループを 1 回回るのに 2 クロックかかってしまう。 do{ } while( ); 文を使用すると、ストリーム用のパイプから入力した user 信号をそのクロックで処理する必要があるから、1 クロックで処理することができなくなってしまうのだろう? while() 文を使用すると、現在のクロックでストリーム用のパイプから入力した user 信号は次のクロックで評価することができるので、ループを 1 回回るのに 1 クロックで済むのだと思う。
このように、ソフトウェアとしてではなく、ハードウェアとして、ソースコードを書く必要がある。

次に、テストベンチの s_squares_axis_tb.cpp を示す。

#include <ap_int.h>
#include <hls_stream.h>
#include <ap_axi_sdata.h>

int s_squares_axis(hls::stream<ap_axis<8,1,1,1> >& x,
    hls::stream<ap_axis<8,1,1,1> >& y, hls::stream<ap_axis<32,1,1,1> >& result);

int main(){
    using namespace std;
    hls::stream<ap_axis<8,1,1,1> > x;
    hls::stream<ap_axis<8,1,1,1> > y;
    hls::stream<ap_axis<32,1,1,1> > result;
    ap_axis<8,1,1,1> xt;
    ap_axis<8,1,1,1> yt;
    ap_axis<32,1,1,1> rlt;

    for(int i=0; i<5; i++){ // dummy data
        xt.user = 0; yt.user = 0;
        xt.data = i; yt.data = i;
        x << xt;
        if(i>2)
            y << yt;
    }
    for(int i=0; i<10; i++){
        xt.data = i; yt.data = i+1;
        if(i == 0){
            xt.user = 1; yt.user = 1;
        }else{
            xt.user = 0; yt.user = 0;
        }
        if(i == 9){
            xt.last = 1; yt.last = 1;
        }else{
            xt.last = 0; yt.last = 0;
        }
        x << xt; y << yt;
    }
    s_squares_axis(x, y, result);

    cout << endl;
    cout << "result" << endl;
    for(int i=0; i<10; i++){
        result >> rlt;
        cout << "i = " << i << " result = " << rlt.data << " user = "
                << rlt.user << " last = " << rlt.last << endl;
    }
    cout << endl;
    return(0);
}


AXI4 Stream の x パイプでは、5 つのダミーデータを入れてあるが、y パイプでは、2 つになっている。これで、本体のデータを正常に受けることができれば成功だ。

s_squares_axis2 プロジェクトを示す。
s_squares_axis_1_190910.png

C シミュレーションを行った。問題ないようだ。
s_squares_axis_2_190910.png
  1. 2019年09月10日 05:08 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0