FC2カウンター FPGAの部屋 Vivado HLS でRGB2HSV IPを作る1(UNROLL指示子による性能向上)

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

FPGAの部屋

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

Vivado HLS でRGB2HSV IPを作る1(UNROLL指示子による性能向上)

Vivado HLS 2016.2 で、RGB2HSV IP を作ろうと思う。

Vivado HLS で rgb2hsv プロジェクトを作成した。
rgb2hsv_1_161007.png

まずは、rgb2hsv.cpp を作成して、C コードの合成を行った。
なお、内側の for ループには、「#pragma HLS PIPELINE II=1」を書いてある。
rgb2hsv_2_161007.png

その結果は、Estimated が 15.52 ns でTarget を満たしていない。Latency も 5760002 で 1 ピクセルに 12 クロックかかっている。
C コードの合成の途中でのレポートを示す。遅延を積算していくと、15.5 ns になるようだ。

WARNING: [SCHED 204-21] Estimated clock period (15.5ns) exceeds the target (target clock period: 10ns, clock uncertainty: 1.25ns, effective delay budget: 8.75ns).
WARNING: [SCHED 204-21] The critical path consists of the following:
    multiplexor before 'phi' operation ('pix.data.V') with incoming values : ('tmp.data.V', rgb2hsv/rgb2hsv.cpp:23) ('tmp.data.V', rgb2hsv/rgb2hsv.cpp:30) ('hsv', rgb2hsv/rgb2hsv.cpp:79) (1.57 ns)
    'phi' operation ('pix.data.V') with incoming values : ('tmp.data.V', rgb2hsv/rgb2hsv.cpp:23) ('tmp.data.V', rgb2hsv/rgb2hsv.cpp:30) ('hsv', rgb2hsv/rgb2hsv.cpp:79) (0 ns)
    'partselect' operation ('min', rgb2hsv/rgb2hsv.cpp:34) (0 ns)
    'icmp' operation ('tmp_8', rgb2hsv/rgb2hsv.cpp:40) (2 ns)
    'or' operation ('or_cond2', rgb2hsv/rgb2hsv.cpp:40) (1.37 ns)
    'or' operation ('sel_tmp2_demorgan', rgb2hsv/rgb2hsv.cpp:37) (1.37 ns)
    'select' operation ('sel_tmp', rgb2hsv/rgb2hsv.cpp:37) (1.37 ns)
    'select' operation ('sel_tmp1', rgb2hsv/rgb2hsv.cpp:48) (1.37 ns)
    'select' operation ('min_5', rgb2hsv/rgb2hsv.cpp:37) (1.37 ns)
    'sub' operation ('tmp_10', rgb2hsv/rgb2hsv.cpp:68) (1.72 ns)
    'sdiv' operation ('tmp_11', rgb2hsv/rgb2hsv.cpp:68) (3.38 ns)


いろいろと指示子を試してみたが、なかなかうまく行かなかった。
昨日、UNROLL指示子の並列数を説明していたのを思い出して、内側の for ループを 2 並列にしてみた。そうすれば、遅延しても、2 クロックに1度データが出れば良いのではないだろうか?
使用する指示子は「#pragma HLS UNROLL factor=2」だ。factor=2 が 2 並列を表す。
rgb2hsv_3_161007.png

C コードの合成の結果を示す。
rgb2hsv_4_161007.png

Estimated は 8.47 ns で Target の範囲内で収まった。Latency も 1 ピクセルで 1 データを処理できる値だ。うまく行ったのではあるが、リソースは倍になってしまった。

rgb2hsv.h を貼っておく。

// rgb2hsv.h
// 2016/10/06 by marsee
//

#ifndef __RGB2HSV_H__
#define __RGB2HSV_H__

#define HORIZONTAL_PIXEL_WIDTH    800
#define VERTICAL_PIXEL_WIDTH    600

//#define HORIZONTAL_PIXEL_WIDTH    64
//#define VERTICAL_PIXEL_WIDTH    48

#define ALL_PIXEL_VALUE    (HORIZONTAL_PIXEL_WIDTH*VERTICAL_PIXEL_WIDTH)

#endif


rgb2hsv.cpp を貼っておく。まだ、シミュレーションしていないので、正しいかどうか?はまだわからない。それに、小数点以下がない整数でとりあえず作ったので、固定小数点演算にする必要があるだろう。
2016/10/14 追記:このC ソースコードは間違っています。

// rgb2hsv.cpp
// 2016/10/06 by marsee
//

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

#include "rgb2hsv.h"

int rgb2hsv(hls::stream<ap_axis<32,1,1,1> >& ins, hls::stream<ap_axis<32,1,1,1> >& outs){
#pragma HLS INTERFACE axis port=outs
#pragma HLS INTERFACE axis port=ins
    ap_axis<32,1,1,1> pix;
    int r, g, b;
    int h, s, v;
    int max, min;
    int hsv;
    int offset;

#pragma HLS LOOP_TRIPCOUNT min=1 max=1 avg=1
    {
        ins >> pix;
    }while(pix.user == 0);

    loop_y: for(int y=0; y<VERTICAL_PIXEL_WIDTH; y++){
        loop_x: for(int x=0; x<HORIZONTAL_PIXEL_WIDTH; x++){
#pragma HLS UNROLL factor=2
#pragma HLS PIPELINE II=1
            if(!(x==0 && y==0))    // 最初の入力はすでに入力されている
                ins >> pix;    // AXI4-Stream からの入力

            b = pix.data & 0xff;
            g = (pix.data>>8) & 0xff;
            r = (pix.data>>16) & 0xff;

            // h と max, min を求める
            if(r==g && g==b && r==b){
                max = r;
                min = r;
            }else if(r>=g && r>=b){
                max = r;
                if(g>=b)
                    min = b;
                else
                    min = g;

                offset = 0;
            }else if(g>=r && g>=b){
                max = g;
                if(r>=b)
                    min = b;
                else
                    min = r;

                offset = 120;
            }else// b が最大
                max = b;
                if(r>=g)
                    min = g;
                else
                    min = b;

                offset = 240;
            }
            if(max-min == 0)
                h = 0;
            else
                h = 60 * ((g-b)/(max-min)) + offset;
            if(h < 0)
                h += 360;

            if(max == 0)
                s = 0;
            else
                s = (max - min)/max * 255;

            v = max;

            hsv = (h&0xff)<<16 + (s&0xff)<<8 + (v&0xff);

            pix.data = hsv;

            if (x==0 && y==0// 最初のデータでは、TUSERをアサートする
                pix.user = 1;
            else
                pix.user = 0;

            if (x == (HORIZONTAL_PIXEL_WIDTH-1))    // 行の最後で TLAST をアサートする
                pix.last = 1;
            else
                pix.last = 0;

            outs << pix;
        }
    }

    return(0);
}

  1. 2016年10月08日 03:51 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

コメント

コメントの投稿


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

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