FC2カウンター FPGAの部屋 ZynqBerryZero で HDMI にラプラシアン・フィルタ画像を出力する6(Vitis HLS で青と緑を反転)
fc2ブログ

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

FPGAの部屋

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

ZynqBerryZero で HDMI にラプラシアン・フィルタ画像を出力する6(Vitis HLS で青と緑を反転)

ZynqBerryZero で HDMI にラプラシアン・フィルタ画像を出力する5(デバック 編)”の続き。

ZynqBerryZero 用のラプラシアン・フィルタを Vitis HLS 2020.2 で実装してみようということで、前回は、 実機確認を行ったところ、画像が真っ赤だった原因を追求するということで、カラーパターンを表示させたところ、青と緑が反転しているということが分かった。今回は、青と緑を反転するために、AXI4-Stream インターフェースで青と緑を反転する IP を Vitis HLS 2020.2 で作成する。

Vitis HLS 2020.2 で赤、緑、青を反転することができる汎用 IP を作成する。
AXI4 Lite インターフェースでレジスタを設定して、反転する色を決定するのでもよいのだが、今回は、色を決め打ちで define 指定して、 IP の起動も自動で起動するようにブロック・レベルのインターフェースに ap_ctrl_none を使用する。

Vitis HLS 2020.2 で reverse_rgb プロジェクトを作成した。
プロジェクトを作成する時に、 Part として、 xc7z010clg225-1 を指定した。
ZynqBerryZero_160_201216.png

C シミュレーションを行った。
青と緑だけビット反転して、赤はそのままということが分かる。
ZynqBerryZero_161_201216.png

ZynqBerryZero_162_201216.png

C コードの合成を行った。
ZynqBerryZero_163_201217.png
ZynqBerryZero_164_201217.png

C/RTL 協調シミュレーションを行った。
ZynqBerryZero_165_201217.png

480010 クロックと性能は良いようだ。

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

outs_TVALID や ins_TREADY もほとんど 1 でスループットが最大になっているのが分かる。

次に、ブロック・レベルのインターフェースを ap_ctrl_hs から ap_ctrl_none に変更した。
なぜ、 ap_ctrl_hs でやっていたかと言うと、 ap_ctrl_none では、 C/RTL 協調シミュレーションが実行できないからだ。
再度、 C コードの合成をを行った。
ZynqBerryZero_168_201217.png
ZynqBerryZero_169_201217.png

ap_ctrl が ap_ctrl_none になっただけで、ほとんど変更は無い。

Export RTL を行った。
ZynqBerryZero_170_201217.png

問題無さそうだ。

solution1/impl には export.zip, solution1/impl/ip には、 xilinx_com_hls_reverse_rgb_1_0.zip が生成されていた。
ZynqBerryZero_171_201217.png

reverse_rgb.h を貼っておく。

// reverse_rgb.h
// 2020/12/16 by marsee
//

#ifndef __REVERSE_RGB_H__
#define __REVERSE_RGB_H__

#define HORIZONTAL_PIXEL_WIDTH 800
#define VERTICAL_PIXEL_WIDTH 600

#define REVERSE_RED  false
#define REVERSE_GREEN true
#define REVERSE_BLUE  true

#endif


reverse_rgb.cpp を貼っておく。

// reverse_rgb.cpp
// 2020/12/16 by marsee
// data format: 8'd0, Red[8:0], Green[8], Blue[8]
//

#include <stdio.h>
#include <string.h>
#include <ap_int.h>
#include <hls_stream.h>
#include <ap_axi_sdata.h>
#include "reverse_rgb.h"

int reverse_rgb(hls::stream<ap_axis<32,1,1,1> >& ins, hls::stream<ap_axis<32,1,1,1> >& outs){
#pragma HLS INTERFACE axis register_mode=both register port=outs
#pragma HLS INTERFACE axis register_mode=both register port=ins
//#pragma HLS INTERFACE ap_ctrl_hs port=return
#pragma HLS INTERFACE ap_ctrl_none port=return
    ap_axis<32,1,1,1> pix, rev_pix;

    LOOP_WAIT: do{ // wait if user signal = 1
#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 PIPELINE II=1
            if (!(x==0 && y==0))    // The first input has already been entered
                ins >> pix; // Input from AXI4-Stream

            if(REVERSE_RED == true)
                rev_pix.data = (~pix.data) & 0xff0000;
            else
                rev_pix.data = pix.data & 0xff0000;
            if(REVERSE_GREEN == true)
                rev_pix.data |= (~pix.data) & 0xff00;
            else
                rev_pix.data |= pix.data & 0xff00;
            if(REVERSE_BLUE == true)
                rev_pix.data |= (~pix.data) & 0xff;
            else
                rev_pix.data |= pix.data & 0xff;

            rev_pix.user = pix.user;
            rev_pix.last = pix.last;
            outs << rev_pix;
        }
    }
    return(0);
}


reverse_rgb_tb.cpp を貼っておく。

// reverse_rgb_tb.cpp
// 2020/12/16 by marsee
//

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ap_int.h>
#include <hls_stream.h>
#include <iostream>
#include <fstream>
#include <ap_axi_sdata.h>
#include "reverse_rgb.h"

int reverse_rgb(hls::stream<ap_axis<32,1,1,1> >& ins, hls::stream<ap_axis<32,1,1,1> >& outs);
int reverse_rgb_soft(hls::stream<ap_axis<32,1,1,1> >& ins, hls::stream<ap_axis<32,1,1,1> >& outs);

int main(){
    using namespace std;

    hls::stream<ap_axis<32,1,1,1> > ins;
    hls::stream<ap_axis<32,1,1,1> > ins_soft;
    hls::stream<ap_axis<32,1,1,1> > outs;
    hls::stream<ap_axis<32,1,1,1> > outs_soft;
    ap_axis<32,1,1,1> pix;
    ap_axis<32,1,1,1> vals;
    ap_axis<32,1,1,1> vals_soft;
    int xy;

    // Prepare input data in ins and ins_soft
    for(int i=0; i<5; i++){ // dummy data
        pix.user = 0;
        pix.last = 0;
        pix.data = i;
        ins << pix;
        ins_soft << pix;
    }
    for(int y=0; y<VERTICAL_PIXEL_WIDTH; y++){
        for(int x=0; x<HORIZONTAL_PIXEL_WIDTH; x++){
            xy = x*(y+1);
            pix.data = xy & 0xffffff;

            if(y==0 && x==0)
                pix.user = 1;
            else
                pix.user = 0;

            if(x == HORIZONTAL_PIXEL_WIDTH-1)
                pix.last = 1;
            else
                pix.last = 0;

            ins << pix;
            ins_soft << pix;
        }
    }

    reverse_rgb(ins, outs);
    reverse_rgb_soft(ins_soft, outs_soft);

    // Checking hardware and software values
    cout << endl;
    cout << "outs" << endl;
    for(int y=0; y<VERTICAL_PIXEL_WIDTH; y++){
        for(int x=0; x<HORIZONTAL_PIXEL_WIDTH; x++){
            outs >> vals;
            outs_soft >> vals_soft;
            ap_int<32> val = vals.data;
            ap_int<32> val_soft = vals_soft.data;
            if(val != val_soft){
                printf("ERROR HW and SW results mismatch x = %ld, y = %ld, HW = %x, SW = %x\n", x, y, (int)val, (int)val_soft);
                return(1);
            }
            printf("x = %ld, y = %ld, xy = %x, HW = %x, SW = %x\n", x, y, (x*(y+1)&0xffffff), (int)val, (int)val_soft);
        }
    }
    cout << "Success HW and SW results match" << endl;
    cout << endl;

    return(0);
}

int reverse_rgb_soft(hls::stream<ap_axis<32,1,1,1> >& ins, hls::stream<ap_axis<32,1,1,1> >& outs){
    ap_axis<32,1,1,1> pix, rev_pix;

    do{ // wait if user signal = 1
        ins >> pix;
    } while(pix.user == 0);

    for(int y=0; y<VERTICAL_PIXEL_WIDTH; y++){
        for(int x=0; x<HORIZONTAL_PIXEL_WIDTH; x++){
            if (!(x==0 && y==0))    // The first input has already been entered
                ins >> pix; // Input from AXI4-Stream

            if(REVERSE_RED == true)
                rev_pix.data = (~pix.data) & 0xff0000;
            else
                rev_pix.data = pix.data & 0xff0000;
            if(REVERSE_GREEN == true)
                rev_pix.data |= (~pix.data) & 0xff00;
            else
                rev_pix.data |= pix.data & 0xff00;
            if(REVERSE_BLUE == true)
                rev_pix.data |= (~pix.data) & 0xff;
            else
                rev_pix.data |= pix.data & 0xff;

            rev_pix.user = pix.user;
            rev_pix.last = pix.last;
            outs << rev_pix;
        }
    }
    return(0);
}

  1. 2020年12月17日 05:00 |
  2. ZynqBerryZero
  3. | トラックバック:0
  4. | コメント:0

コメント

コメントの投稿


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

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