FC2カウンター FPGAの部屋 Vitis HLS 2022.2 の新機能を確かめる2(performance プラグマ2)
fc2ブログ

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

FPGAの部屋

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

Vitis HLS 2022.2 の新機能を確かめる2(performance プラグマ2)

Vitis HLS 2022.2 の新機能を確かめる1(performance プラグマ)”の続き。

What’s New in the Vitis HLS Tool 2022.2 – Key Feature Enhancements”を参考に、Vitis HLS 2022.2 の新機能を確かめてみようということで、前回は、 performance プラグマについて調査した。今回は、 performance プラグマの続きをやってみる。

performance プラグマを入れた場合は、C コードの合成を行った時の Synthesis Summary Report の Pragma Report に次の記述があった。

Cannot apply performance pragma target_ti=800 cycles for loop 'LOOP_Y' in function 'sobel_axis_RGB24'. The target requires a pipeline II less than the minimal achievable II of 4 determined by the number of conflicting accesses on local memory 'tmp.i.i47' (4 per iteration), the number of conflicting accesses on local memory 'tmp.i.i29' (4 per iteration), the number of conflicting accesses on local memory 'tmp.i.i192' (4 per iteration)


Vitis_HLS_2022_2_17_221128.png

performance プラグマを正しく評価したいということで、”What’s New in the Vitis HLS Tool 2022.2 – Key Feature Enhancements”の例と同じように、ループの回数を固定にして、sobel_axis_RGB24 関数を書き換えた。なお、パフォーマンスに関わるプラグマはコメントアウトした。

// sobel_axis_RGB24.cpp
// 2022/03/20 by marsee
// Up to HD resolution
// 2022/03/23 : Added keep and strb
// 2022/03/26 : axi_vdma と axi dma 用に分けた
// 2022/11/27 : perfomance プラグマを追加
// 2022/11/28 : row_size を 600、col_size を 800 に固定した

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

#include "sobel_axis_RGB24.h"

ap_int<32> sobel_fil(ap_int<32> h_or_v, ap_int<32> x0y0, ap_int<32> x1y0, ap_int<32> x2y0, ap_int<32> x0y1,
        ap_int<32> x1y1, ap_int<32> x2y1, ap_int<32> x0y2, ap_int<32> x1y2, ap_int<32> x2y2);
ap_int<32> conv_rbg2y(ap_int<32> rbg);
ap_int<32> square_root8(ap_int<32> val);

#define row_size 600
#define col_size 800

int sobel_axis_RGB24(hls::stream<ap_axiu<24,1,1,1> >& ins,
        hls::stream<ap_axiu<24,1,1,1> >& outs, int32_t function){
#pragma HLS INTERFACE mode=s_axilite port=function
#pragma HLS INTERFACE mode=axis register_mode=both port=outs register
#pragma HLS INTERFACE mode=axis register_mode=both port=ins register
#pragma HLS INTERFACE mode=s_axilite port=return

    ap_axiu<24,1,1,1> pix;
    ap_axiu<24,1,1,1> sobel;
    ap_int<32> sobel_val, sobel_h_val, sobel_v_val;

    ap_int<32> line_buf[2][1920]; // Up to HD resolution
//#pragma HLS array_partition variable=line_buf block factor=2 dim=1

    ap_int<32> pix_mat[3][3];
//#pragma HLS array_partition variable=pix_mat complete

    LOOP_WAIT_USER : do {   // user が 1になった時にフレームがスタートする
#pragma HLS LOOP_TRIPCOUNT min=1 max=1 avg=1
        ins >> pix;
        if(function==ORG_IMGwAxiDma || function==SOBELwAxiDma)
            break;
    } while(pix.user == 0);

    LOOP_Y: for(int y=0; y<row_size; y++){
#pragma HLS LOOP_TRIPCOUNT avg=600 max=600 min=600
//#pragma HLS performance target_ti=800
        LOOP_X: for(int x=0; x<col_size; x++){
#pragma HLS LOOP_TRIPCOUNT avg=800 max=800 min=800
//#pragma HLS PIPELINE II=1
            if (!(x==0 && y==0))    // 最初の入力はすでに入力されている
                ins >> pix; // AXI4-Stream からの入力

            LOOP_PIX_MAT_K: for(int k=0; k<3; k++){
                LOOP_PIX_MAT_M: for(int m=0; m<2; m++){
                    pix_mat[k][m] = pix_mat[k][m+1];
                }
            }
            pix_mat[0][2] = line_buf[0][x];
            pix_mat[1][2] = line_buf[1][x];
            ap_int<32> y_val = conv_rbg2y(pix.data);
            pix_mat[2][2] = y_val;

            line_buf[0][x] = line_buf[1][x];    // 行の入れ替え
            line_buf[1][x] = y_val;

            sobel_h_val = sobel_fil(HORIZONTAL, pix_mat[0][0], pix_mat[0][1], pix_mat[0][2],
                                                pix_mat[1][0], pix_mat[1][1], pix_mat[1][2],
                                                pix_mat[2][0], pix_mat[2][1], pix_mat[2][2]);
            sobel_v_val = sobel_fil(VERTICAL,   pix_mat[0][0], pix_mat[0][1], pix_mat[0][2],
                                                pix_mat[1][0], pix_mat[1][1], pix_mat[1][2],
                                                pix_mat[2][0], pix_mat[2][1], pix_mat[2][2]);
            sobel_val = square_root8(sobel_h_val*sobel_h_val + sobel_v_val*sobel_v_val);
            sobel.data = (sobel_val<<16)+(sobel_val<<8)+sobel_val;

            if(x<2 || y<2)
                sobel.data = 0;

            if(function==ORG_IMGwAxiVdma || function == SOBELwAxiVdma){
                if(x==0 && y==0) // 最初のピクセル
                    sobel.user = 1;
                else
                    sobel.user = 0;
                if(x == (col_size-1)) // 行の最後
                    sobel.last = 1;
                else
                    sobel.last = 0;
            }else{
                sobel.user = 0;
                sobel.last = pix.last;
            }
            sobel.keep = 0x7;
            sobel.strb = 0x7;
            if(function==SOBELwAxiVdma || function==SOBELwAxiDma)
                outs << sobel;
            else
                outs << pix;
        }
    }
    return(0);
}

// RBGからYへの変換
// RBGのフォーマットは、{R(8bits), G(8bits), B(8bits)}, 1pixel = 32bits
// 輝度信号Yのみに変換する。変換式は、Y =  0.299R + 0.587G + 0.114B
// "YUVフォーマット及び YUV<->RGB変換"を参考にした。http://vision.kuee.kyoto-u.ac.jp/~hiroaki/firewire/yuv.html
// 2013/09/27 : float を止めて、すべてint にした
ap_int<32> conv_rbg2y(ap_int<32> rbg){
    ap_int<32> r, g, b, y_f;
    ap_int<32> y;

    b = rbg & 0xff;
    g = (rbg>>8) & 0xff;
    r = (rbg>>16) & 0xff;

    y_f = 77*r + 150*g + 29*b; //y_f = 0.299*r + 0.587*g + 0.114*b;の係数に256倍した
    y = y_f >> 8; // 256で割る

    return(y);
}

// sobel filter
// HORZONTAL
// x0y0 x1y0 x2y0  1  2  1
// x0y1 x1y1 x2y1  0  0  0
// x0y2 x1y2 x2y2 -1 -2 -1
// VERTICAL
// x0y0 x1y0 x2y0  1  0 -1
// x0y1 x1y1 x2y1  2  0 -2
// x0y2 x1y2 x2y2  1  0 -1
ap_int<32> sobel_fil(ap_int<32> h_or_v, ap_int<32> x0y0, ap_int<32> x1y0, ap_int<32> x2y0, ap_int<32> x0y1,
        ap_int<32> x1y1, ap_int<32> x2y1, ap_int<32> x0y2, ap_int<32> x1y2, ap_int<32> x2y2){
    ap_int<32> y;

    if(h_or_v == HORIZONTAL){
        y = x0y0 + 2*x1y0 + x2y0 - x0y2 - 2*x1y2 - x2y2;
    } else {
        y = x0y0 - x2y0 + 2*x0y1 - 2*x2y1 + x0y2 - x2y2;
    }
    if(y<0)
        y = -y;
        //y = 0;
    else if(y>255) // 8 bits
        y = 255;
    return(y);
}

// square_root8
// 8 bit幅のsquare_rootを求める
ap_int<32> square_root8(ap_int<32> val){
    ap_int<32> temp = 0;
    ap_int<32> square;

    for(int i=7; i>=0; --i){
        temp += (1 << i);
        square = temp * temp;

        if(square > val){
            temp -= (1 << i);
        }
    }

    return(temp);
}


このソースコードで C コードの合成を行った。
結果を示す。
Vitis_HLS_2022_2_18_221128.png

1 クロックで 1 ピクセル処理をパフォーマンスに関するプラグマなしの状態で達成できてしまった。
Vitis HLS も進化しているのだね。
このソースコードは、ハードウエアを想定しているコードなので、想定していないコードで試す必要があるようだ。

C/RTL 協調シミュレーションを行ったが、問題なく 1 クロックで 1 ピクセル処理をパフォーマンスに関するプラグマなしの状態で達成できている。
Vitis_HLS_2022_2_19_221128.png
  1. 2022年11月28日 04:56 |
  2. Vitis HLS
  3. | トラックバック:0
  4. | コメント:0

コメント

コメントの投稿


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

トラックバック URL
https://marsee101.blog.fc2.com/tb.php/5777-aa15296f
この記事にトラックバックする(FC2ブログユーザー)