FC2カウンター FPGAの部屋 AXI4 Stream 出力にAXI4 Stream スイッチ付きのDMA Read IP を Vitis HLS 2021.2 で作成 1
fc2ブログ

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

FPGAの部屋

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

AXI4 Stream 出力にAXI4 Stream スイッチ付きのDMA Read IP を Vitis HLS 2021.2 で作成 1

Vitis HLS 2021.2 で”AXI4 Stream 出力にAXI4 Stream スイッチ付きのDMA Read IP 1”をやってみることにした。これをやるのは Vitis HLS と Vivado HLS の違いを比べたいという欲求と Vitis Vision Library の AXI4-Stream 入出力の xf_median_blur IP を実機でテストしたいからだ。

最初にソースコードの DMA2axis2st.cpp を貼っておく。
Vivado HLS のコードに比べて、PIPELINE 指示子が抜けているが、これは、Vitis HLS が自動的に PIPELINE してくれるからだ。
(2022/01/26 :追記) ブロックレベルのインターフェースを AXI4-Lite インターフェースにするのを忘れていたので、プラグマを追加した。それに応じて、結果が変更されることに注意。

// DMA2axis2st.cpp
// for Vitis HLS 2021.2
// 2022/01/21 by marsee
//

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

int DMA2axis2st(ap_int<32> *in, int sel, int x_size, int y_size,
    hls::stream<ap_axis<32,1,1,1> >& outs0, hls::stream<ap_axis<32,1,1,1> >& outs1){
#pragma HLS INTERFACE mode=s_axilite port=return
#pragma HLS INTERFACE mode=axis register_mode=both port=outs1 register
#pragma HLS INTERFACE mode=axis register_mode=both port=outs0 register
#pragma HLS INTERFACE mode=s_axilite port=y_size
#pragma HLS INTERFACE mode=s_axilite port=x_size
#pragma HLS INTERFACE mode=s_axilite port=sel
#pragma HLS INTERFACE mode=m_axi depth=480000 port=in

    ap_axis<32,1,1,1> out_val;

    for(int y=0; y<y_size; y++){
#pragma HLS LOOP_TRIPCOUNT min=600 max=600 avg=600
        for(int x=0; x<x_size; x++){
#pragma HLS LOOP_TRIPCOUNT min=800 max=800 avg=800
            out_val.data = in[y*x_size+x];
            if(x==0 && y==0)
                out_val.user = 1;
            else
                out_val.user = 0;
            if(x == x_size-1)
                out_val.last = 1;
            else
                out_val.last = 0;
            if(sel == 0)
                outs0 << out_val;
            else
                outs1 << out_val;
        }
    }
    return(0);
}


テストベンチの DMA2axis2st_tb.cpp を貼っておく。

// DMA2axis2st_tb.cpp
// for Vitis HLS 2021.2
// 2022/01/21 by marsee
//

#include <ap_int.h>
#include <hls_stream.h>
#include <ap_axi_sdata.h>
#include <iostream>
#include "opencv2/opencv.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgcodecs/imgcodecs.hpp"

#include "pict_data.h"

#define Y_SIZE  600
#define X_SIZE  800

char OUTPUT_PICT_FILE0[] = "test0.jpg";
char OUTPUT_PICT_FILE1[] = "test1.jpg";

int DMA2axis2st(ap_int<32> *in, int sel, int x_size, int y_size,
    hls::stream<ap_axis<32,1,1,1> >& outs0, hls::stream<ap_axis<32,1,1,1> >& outs1);

int main(){
    hls::stream<ap_axis<32,1,1,1> > outs0;
    hls::stream<ap_axis<32,1,1,1> > outs1;
    ap_axis<32,1,1,1> axisp;
    ap_int<32> *rd_pict;

    if((rd_pict =(ap_int<32> *)malloc(sizeof(ap_int<32>) * (X_SIZE * Y_SIZE))) == NULL){
        fprintf(stderr, "Can't allocate rd_pict memory\n");
        exit(1);
    }

    for(int y=0; y<Y_SIZE; y++){
        for(int x=0; x<X_SIZE; x++){
            rd_pict[y*X_SIZE+x] = (int)(pict_file_array[y][x][0]) | ((int)(pict_file_array[y][x][1])<<8) | ((int)(pict_file_array[y][x][2]) <<16);
        }
    }

    DMA2axis2st(rd_pict, 0, X_SIZE, Y_SIZE, outs0, outs1);

    cv::Mat img(Y_SIZE, X_SIZE, CV_8UC3);
    cv::Mat_<cv::Vec3b> dst_vec3b = cv::Mat_<cv::Vec3b>(img);
    for (int y=0; y<Y_SIZE; y++){
        for (int x=0; x<X_SIZE; x++){
            outs0 >> axisp;
            cv::Vec3b pixel;
            pixel[0] = axisp.data & 0xff; // blue
            pixel[1] = (axisp.data >> 8) & 0xff; // green
            pixel[2] = (axisp.data >> 16) & 0xff; // red
            dst_vec3b(y,x) = pixel;
        }
    }

    cv::imwrite(OUTPUT_PICT_FILE0, img);

    DMA2axis2st(rd_pict, 1, X_SIZE, Y_SIZE, outs0, outs1);

    for (int y=0; y<Y_SIZE; y++){
        for (int x=0; x<X_SIZE; x++){
            outs1 >> axisp;
            cv::Vec3b pixel;
            pixel[0] = axisp.data & 0xff; // blue
            pixel[1] = (axisp.data >> 8) & 0xff; // green
            pixel[2] = (axisp.data >> 16) & 0xff; // red
            dst_vec3b(y,x) = pixel;
        }
    }

    cv::imwrite(OUTPUT_PICT_FILE1, img);

    return(0);
}


他に使用するファイルは、画像ファイルを変換した C のヘッダ・ファイルの pict_data.h だ。

Vitis HLS 2021.2 で ZYBO Z7-20 用の DMA2axis2st プロジェクトを作成した。
画像ファイルを変換した C のヘッダ・ファイルの pict_data.h を DMA2axis2st プロジェクトのディレクトリにコピー&ペーストした。
Vitis_Vision2_81_220121.png

Vitis HLS 2021.2 の DMA2axis2st プロジェクトを示す。
Vitis_Vision2_82_220121.png

Vitis HLS 2021.2 の Project メニューから Project Settings... を選択して、設定を行う。
Project Settings (DMA2axis2st) ダイアログが開く。
左のウインドウで Simulation をクリックする。
DMA2axis2st_tb.cpp の CFLAGS を設定する。(設定方法は、Edit CFLAGS... ボタンをクリックする)
DMA2axis2st_tb.cpp の CFLAGS に

-I/usr/local/include

を設定した。

Linker Flags に

-L/usr/local/lib -lopencv_core -lopencv_imgcodecs -lopencv_imgproc

を設定した。
Vitis_Vision2_83_220121.png

ZYBO Z7-20 を使用するので、64 ビットアドレスの DMA を禁止して、 32 ビットアドレスの DMA にする。
Vitis HLS の Solution メニューから Solution Settings... を選択する。
Solution Settings (solution1) ダイアログが開く。
config_interface を展開して、m_axi_addr64 の Value のチェックボックスのチェックを外した。
Vitis_Vision2_86_220123.png

C シミュレーションを行った。
Vitis_Vision2_84_220121.png

test0.jpg と test1.jpg が生成されていた。
Vitis_Vision2_85_220121.png

DMA2axis2st/solution1/csim/build ディレクトリを見ると test0.jpg と test1.jpg がちゃんと画像ファイルになっていることが分かった。
  1. 2022年01月22日 04:45 |
  2. Vitis HLS
  3. | トラックバック:0
  4. | コメント:0

コメント

コメントの投稿


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

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