FC2カウンター FPGAの部屋 hls::LineBufferとhls::Windowでラプラシアンフィルタを実装する5

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

FPGAの部屋

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

hls::LineBufferとhls::Windowでラプラシアンフィルタを実装する5

hls::LineBufferとhls::Windowでラプラシアンフィルタを実装する4”の続き。

前回は、列の処理と、行の処理の2重 for ループの内側の行の処理の for ループに 最初の行のピクセルを処理する時は、if 文で1ライン分 memcpy() で Read して、行の最後のピクセルを処理した後で、if 文で1ライン分のピクセルを memcpy() でWrite する。
今回は、単純にmemcpy() を内側の for ループの外に置くことにする。

下に今回の lap_filter_axim() のみのC++ソースコードを示す。

int lap_filter_axim(volatile int *cam_fb, volatile int *lap_fb)
{
    #pragma HLS INTERFACE s_axilite port=return

#pragma HLS INTERFACE m_axi depth=3072 port=cam_fb offset=slave bundle=cam_fb
#pragma HLS INTERFACE m_axi depth=3072 port=lap_fb offset=slave bundle=lap_fb

    hls::LineBuffer<2, HORIZONTAL_PIXEL_WIDTH, int> linebuf;
    hls::Window<33int> mbuf;
    int x, y;
    int val;
    int gray_pix;
    int i, j;
    const int lap_weight[3][3] = {{-1, -1, -1},{-18, -1},{-1, -1, -1}};
#pragma HLS ARRAY_PARTITION variable=lap_weight complete dim=0
    int read_line[HORIZONTAL_PIXEL_WIDTH];
    int write_line[HORIZONTAL_PIXEL_WIDTH];

    // RGB値をY(輝度成分)のみに変換し、ラプラシアンフィルタを掛けた。
    for (y=0; y<VERTICAL_PIXEL_WIDTH; y++){
        // 1 行 Read
        memcpy(read_line, (const int*)&cam_fb[y*(HORIZONTAL_PIXEL_WIDTH)], (HORIZONTAL_PIXEL_WIDTH)*sizeof(int));
        for (x=0; x<HORIZONTAL_PIXEL_WIDTH; x++){
            mbuf.shift_left();  // mbuf の列を1ビット左シフト
            //mbuf.insert_left(colbuf); // mbuf の列に colbuf[] を代入
            mbuf.insert(linebuf(1,x), 22);
            mbuf.insert(linebuf(0,x), 12);
            gray_pix = conv_rgb2y(read_line[x]);
            mbuf.insert(gray_pix, 02);

            // LineBuffer の更新
            linebuf.shift_down(x);
            linebuf.insert_bottom(gray_pix, x);

            // ラプラシアンフィルタの演算
            for (j=0, val=0; j<3; j++){
                for (i=0; i<3; i++){
                    val += lap_weight[j][i] * mbuf(2-j,i);
                }
            }
            if (val<0// 飽和演算
                val = 0;
            else if (val>255)
                val = 255;

            // ラプラシアンフィルタ・データの書き込み
            if (x>1 && y>1)
                write_line[x] = (val<<16)+(val<<8)+val ;
            else
                // x<2 || y<2 の場合はピクセルデータがまだ揃っていないので0にする
                write_line[x] = 0;
            // printf("x = %d  y = %d", x, y);
        }
        memcpy((void *)&lap_fb[y*(HORIZONTAL_PIXEL_WIDTH)], (const int*)write_line, (HORIZONTAL_PIXEL_WIDTH)*sizeof(int));
     }
     return(0);
}


前回よりも、単純なコードになっている。

これをC++コードの合成を行った。結果を下に示す。
LineBuffer_Window_42_160320.png

LineBuffer_Window_43_160320.png

246721 クロックかかっているので、前回とそう違いはない。使用リソースも違いはあまり無い。

Analysis 表示にしてみた。
LineBuffer_Window_44_160320.png
C22 ステートまでだった。

リソース表示にしてみた。
LineBuffer_Window_45_160320.png

C/RTL コシミュレーションを行った。
LineBuffer_Window_46_160320.png

C/RTL コシミュレーション波形を示す。
LineBuffer_Window_47_160320.png
2.47 ms 程度かかっている。

拡大してみた。
LineBuffer_Window_48_160320.png
1行ラプラシアンフィルタ処理を行うための経過時間を知るために、Read 間隔を測ってみたところ、51.54 us だった。

次に、内側の for ループに PIPELINE II=1 のディレクティブを追加した。
LineBuffer_Window_49_160320.png

C++コードの合成を行った。結果を下に示す。
LineBuffer_Window_50_160320.png

LineBuffer_Window_51_160320.png

Latency は 10513 クロックになって、20倍程度速くなった。使用リソースはPIPELINEディレクティブを追加する前よりもむしろ少なくなった。これは良い。

C/RTL コシミュレーションを行った。
LineBuffer_Window_52_160320.png

Latencyは 11203 クロックだった。高位合成時よりも、それほど増えていない。

C/RTL コシミュレーション波形を示す。
LineBuffer_Window_53_160320.png
終了までに 113 us 程度になった。

LineBuffer_Window_54_160320.png
Read 間隔は、 2.33 us だった。

最後に、内側の for ループに追加した PIPELINE ディレクティブを削除して、外側の for ループに PIPELINE II=1 ディレクティブを追加した。
LineBuffer_Window_55_160320.png

C++コードの合成を行った。結果を下に示す。
LineBuffer_Window_56_160320.png
Latency は、3092 クロックだった。これだと、1クロックあたり 1 ピクセルの処理を行えている。

使用リソースを示す。
LineBuffer_Window_57_160320.png
DSP48E を 81 %、FF を 38 %、LUT を 85 % 使用している。これは使用リソースを使いすぎている。これでは、ラプラシアンフィルタだけしかZYBO に入らなくなってしまう。Latency は最高に良いが、選択できない感じだ。

Analysis 表示にしてみた。
LineBuffer_Window_58_160320.png
なんと C83 まである。

リソース表示にした。
LineBuffer_Window_59_160320.png

C/RTL コシミュレーションを行った。
LineBuffer_Window_62_160320.png
Latency は、3733 クロックだった。高位合成結果よりもLatency が増えたが、1クロック、1ピクセル出力を維持できているようだ。

C/RTL コシミュレーション波形を示す。
LineBuffer_Window_63_160320.png
37.8 us で終了している。

拡大してみた。
LineBuffer_Window_64_160320.png
Read 間隔は、770 ns だった。見ると、Read と Write が重なっていた。

現在は 64 x 48 ピクセルのラプラシアンフィルタを合成しているので、800 x 600 ピクセルに変更し、このPIPELINE ディレクティブでやってみたが、合成に長時間かかっても合成できなかった。たぶん行の処理を展開してしまっているのだろう?
もし、800 x 600 画面を 1行の Read 間隔の 770 ns で処理できるとしたら、770 ns / 64 pixel x 800 x 600 = 5.775 ms かかる計算になる。
  1. 2016年03月21日 05:01 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

コメント

コメントの投稿


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

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