FC2カウンター FPGAの部屋 AXI4-Stream インターフェースの最終出力層3(出力フォーマットの変更 )
FC2ブログ

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

FPGAの部屋

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

AXI4-Stream インターフェースの最終出力層3(出力フォーマットの変更 )

AXI4-Stream インターフェースの最終出力層2(C シミュレーション、C コードの合成、C/RTL 協調シミュレーション、Export RTL )”の続き。

前回は、AXI4-Stream インターフェースの最終出力層のC シミュレーション、C コードの合成、C/RTL 協調シミュレーション、Export RTLを行った。今回は、出力フォーマットを変更したので、もう一度、それらをやり直す。

出力フォーマットは、ビット精度は異なるのだが、”カーブ、直線用白線間走行用畳み込みニューラルネットワーク13(AXI4 Stream版CNN IP 1)”のフォーマットに合わせることにした。

まずは、output_layer.h から貼っておく。

// output_layer.h
// 2018/03/11 by marsee
// 2018/03/12 : 出力フォーマットを変更
//

#ifndef __OUTPUT_LAYER_H__
#define __OUTPUT_LAYER_H__
#include <ap_fixed.h>

template<int W, int I, int U, int TI, int TD>
    struct ap_fixed1_axis{
        struct data {
            ap_fixed<W,I,AP_TRN,AP_WRAP> data0;
        } data;
        ap_uint<(W+7)/8> keep;
        ap_uint<(W+7)/8> strb;
        ap_uint<U>       user;
        ap_uint<1>       last;
        ap_uint<TI>      id;
        ap_uint<TD>      dest;
    };

template<int U, int TI, int TD>
    struct float1_axis{
        struct data {
            float data0;
        } data;
        ap_uint<1> keep;
        ap_uint<1> strb;
        ap_uint<U>       user;
        ap_uint<1>       last;
        ap_uint<TI>      id;
        ap_uint<TD>      dest;
    };

#define NUMBER_OF_OUTPUT_LAYER 3

typedef struct {
    ap_fixed<12,7,AP_TRN,AP_WRAP> data [NUMBER_OF_OUTPUT_LAYER];
} mdata_type;

typedef struct {
    float data [NUMBER_OF_OUTPUT_LAYER];
} fmdata_type;

typedef ap_fixed<12,7,AP_TRN,AP_WRAP> out_affine_type;

typedef ap_uint<2> output_type;
#endif


次に、output_layer.cpp を貼っておく。

// output_layer.cpp
// 2018/03/11 by marsee
// 2018/03/12 : 出力フォーマットを変更
//

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

#include "output_layer.h"

int output_layer(hls::stream<ap_fixed1_axis<12,7,1,1,1> >& ins, output_type& output,
        out_affine_type dot2[NUMBER_OF_OUTPUT_LAYER]){
#pragma HLS ARRAY_PARTITION variable=dot2 complete dim=1
#pragma HLS INTERFACE s_axilite port=output
#pragma HLS INTERFACE s_axilite port=dot2
#pragma HLS INTERFACE s_axilite port=return
#pragma HLS INTERFACE axis register both port=ins

    ap_fixed1_axis<12,7,1,1,1> stdata;
    mdata_type af2;
    int max_num;
    out_affine_type max_val;

    Loop1: do {
#pragma HLS LOOP_TRIPCOUNT min=1 max=1 avg=1
    // user が 1になった時にフレームがスタートする
        ins >> stdata;
    } while(stdata.user == 0);

    Loop2: for(int i=0; i<NUMBER_OF_OUTPUT_LAYER; i++){
#pragma HLS PIPELINE II=1
        if(i != 0)    // 最初の入力はすでに入力されている
            ins >> stdata;    // AXI4-Stream からの入力

        af2.data[i] = stdata.data.data0;
    }

    max_val = 0;
    Loop3: for(int i=0; i<NUMBER_OF_OUTPUT_LAYER; i++){
#pragma HLS UNROLL
        dot2[i] = af2.data[i];
        if(i == 0){
            max_val = af2.data[0];
            max_num = 0;
        } else if (max_val < af2.data[i]){
            max_val = af2.data[i];
            max_num = i;
        }
    }

    output = output_type(max_num);

    return(0);
}


output_layer_tb.cpp を貼っておく。

// output_layer_tb.cpp
// 2018/03/12 by marsee
// 2018/03/12 : 出力フォーマットを変更
//

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <ap_int.h>
#include <hls_stream.h>
#include <iostream>
#include <fstream>
#include <iomanip>
#include <math.h>
#include <ap_axi_sdata.h>
#include <hls_video.h>

#include "output_layer.h"
#include "affine_layer2_output.h"

int output_layer(hls::stream<ap_fixed1_axis<12,7,1,1,1> >& ins, output_type& output,
        out_affine_type dot2[NUMBER_OF_OUTPUT_LAYER]);

int output_layer_soft(hls::stream<float1_axis<1,1,1> >& ins, output_type& output,
        float dot2[NUMBER_OF_OUTPUT_LAYER]);

int main(){
    using namespace std;

    hls::stream<ap_fixed1_axis<12,7,1,1,1> > ins;
    hls::stream<float1_axis<1,1,1> > ins_soft;

    ap_fixed1_axis<12,7,1,1,1> pix;
    float1_axis<1,1,1> fpix;
    output_type out, out_soft;
    out_affine_type dot2[NUMBER_OF_OUTPUT_LAYER];
    float fdot2[NUMBER_OF_OUTPUT_LAYER];

    // ins に入力データを用意する
    for(int i=0; i<5; i++){    // dummy data
        pix.user = 0;
        pix.data.data0 = (out_affine_type)i;
        ins << pix;
        fpix.user = 0;
        fpix.data.data0 = (float)i;
        ins_soft << fpix;
    }

    // 1 画面分のデータを ins、ins_soft に入力する
    for(int i=0; i < NUMBER_OF_OUTPUT_LAYER; i++){
        pix.data.data0 = affine2_out[i];
        fpix.data.data0 = affine2_fout[i];

        if (i == 0){    // 最初のデータの時に TUSER を 1 にする
            pix.user = 1;
            fpix.user = 1;
        } else {
            pix.user = 0;
            fpix.user = 0;
        }

        if (i == NUMBER_OF_OUTPUT_LAYER-1){ // 行の最後でTLASTをアサートする
            pix.last = 1;
            fpix.last = 1;
        } else {
            pix.last = 0;
            fpix.last = 0;
        }

        ins << pix;
        ins_soft << fpix;
    }

    output_layer(ins, out, dot2);
    output_layer_soft(ins_soft, out_soft, fdot2);

    // out と out_soft を比較する
    cout << "out" << " = " << int(out) << " out_soft" " = " << int(out_soft) << endl;
    for(int i=0; i<NUMBER_OF_OUTPUT_LAYER; i++){
        cout << "dot2[" << i << "] = " << float(dot2[i]) << " fdot2[" << i << "] = " << fdot2[i] << endl;
    }
    if(out != out_soft){
        cout << "error: out" << " = " << int(out) << " out_soft" " = " << int(out_soft) << endl;
        //return(1);
    }

    return(0);
}

int output_layer_soft(hls::stream<float1_axis<1,1,1> >& ins, output_type& output,
        float dot2[NUMBER_OF_OUTPUT_LAYER]){

    float1_axis<1,1,1> stdata;
    fmdata_type af2;
    int max_num;
    float max_val;

    Loop1: do {
    // user が 1になった時にフレームがスタートする
        ins >> stdata;
    } while(stdata.user == 0);

    Loop2: for(int i=0; i<NUMBER_OF_OUTPUT_LAYER; i++){
        if(i != 0)    // 最初の入力はすでに入力されている
            ins >> stdata;    // AXI4-Stream からの入力

        af2.data[i] = stdata.data.data0;
    }

    max_val = 0;
    Loop3: for(int i=0; i<NUMBER_OF_OUTPUT_LAYER; i++){
        dot2[i] = af2.data[i];
        if(i == 0){
            max_val = af2.data[0];
            max_num = 0;
        } else if (max_val < af2.data[i]){
            max_val = af2.data[i];
            max_num = i;
        }
    }

    output = output_type(max_num);

    return(0);
}


output_layer プロジェクトを示す。
output_layer_8_180313.png

C シミュレーションを行った。結果を示す。
output_layer_14_180417.png

C コードの合成を行った。結果を示す。
output_layer_10_180313.png

やはり、FF とLUT のリソース使用量が増えている。

C/RTL 協調シミュレーションを行った。結果を示す。
output_layer_11_180313.png

C/RTL 協調シミュレーションの波形を示す。
output_layer_13_180313.png

Export RTL を行った。結果を示す。
なお、Vivado synthesis, place and route にチェックを入れてある。
output_layer_12_180313.png
  1. 2018年03月14日 04:57 |
  2. DNN
  3. | トラックバック:0
  4. | コメント:0

コメント

コメントの投稿


管理者にだけ表示を許可する

トラックバック URL
http://marsee101.blog19.fc2.com/tb.php/4106-ed758a04
この記事にトラックバックする(FC2ブログユーザー)