FC2カウンター FPGAの部屋 2022年01月24日
fc2ブログ

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

FPGAの部屋

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

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

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

最初にソースコードの axis2DMA2st.cpp を貼っておく。
(2022/01/25:修正)リソースを食いすぎたので、stdint.h をインクルードして、引数の定義を変更した。

// axis2DMA2st.cpp
// for Vitis HLS 2021.2
// 2022/01/24 by marsee
//

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

int axis2DMA2st(hls::stream<ap_axis<32,1,1,1> >& ins0, hls::stream<ap_axis<32,1,1,1> >& ins1,
    ap_uint<1> sel,  int32_t x_size, int32_t y_size, ap_int<32> *out){
#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=axis register_mode=both port=ins1 register
#pragma HLS INTERFACE mode=axis register_mode=both port=ins0 register
#pragma HLS INTERFACE s_axilite port=return
#pragma HLS INTERFACE m_axi depth=480000 port=out offset=slave
    ap_axis<32,1,1,1> val;

    Loop1 : do {    // user が 1 になった時にスタート
#pragma HLS LOOP_TRIPCOUNT min=1 max=1 avg=1
        if(sel == 0)
            ins0 >> val;
        else
            ins1 >> val;
    } while(val.user == 0);

    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
            if(!(y==0 && x==0)){
                if(sel == 0)
                    ins0 >> val;
                else
                    ins1 >> val;
            }
            out[y*x_size+x] = val.data;
        }
    }

    return(0);
}


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

// axis2DMA2st_tb.cpp
// for Vitis HLS 2021.2
// 2022/01/24 by marsee
//

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

#include "pict_data.h"

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

int axis2DMA2st(hls::stream<ap_axis<32,1,1,1> >& ins0, hls::stream<ap_axis<32,1,1,1> >& ins1,
    ap_uint<1> sel,  int32_t x_size, int32_t y_size, ap_int<32> *out);

int main(){
    hls::stream<ap_axis<32,1,1,1> > ins0;
    hls::stream<ap_axis<32,1,1,1> > ins1;
    ap_axis<32,1,1,1> axisp;
    ap_int<32> *wr_pict0, *wr_pict1;

    for(int y=0; y<Y_SIZE; y++){
        for(int x=0; x<X_SIZE; x++){
            axisp.data = (ap_int<32>)pict_file_array[y][x][0] | ((ap_int<32>)pict_file_array[y][x][1])<<8 | ((ap_int<32>)pict_file_array[y][x][2])<<16;

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

            if(x == X_SIZE-1)
                axisp.last = 1;
            else
                axisp.last = 0;

            ins0 << axisp;
            ins1 << axisp;
        }
    }

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

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

    axis2DMA2st(ins0, ins1, 0, X_SIZE, Y_SIZE, wr_pict0);

    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++){
            ap_int<32> data = wr_pict0[y*X_SIZE+x];
            cv::Vec3b pixel;
            pixel[0] = data & 0xff; // blue
            pixel[1] = (data >> 8) & 0xff; // green
            pixel[2] = (data >> 16) & 0xff; // red
            dst_vec3b(y,x) = pixel;
        }
    }

    cv::imwrite(OUTPUT_PICT_FILE0, img);

    axis2DMA2st(ins0, ins1, 1, X_SIZE, Y_SIZE, wr_pict1);

    for (int y=0; y<Y_SIZE; y++){
        for (int x=0; x<X_SIZE; x++){
            ap_int<32> data = wr_pict1[y*X_SIZE+x];
            cv::Vec3b pixel;
            pixel[0] = data & 0xff; // blue
            pixel[1] = (data >> 8) & 0xff; // green
            pixel[2] = (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 を axis2DMA2st プロジェクトのディレクトリにコピー&ペーストした。

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

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

-I/usr/local/include

を設定した。

Linker Flags に

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

を設定した。
Vitis_Vision2_95_220124.png

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

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

axis2DMA2st/solution1/csim/build ディレクトリを見ると画像ファイルの test0.jpg と test1.jpg が生成されている。
Vitis_Vision2_97_220124.png
  1. 2022年01月24日 04:30 |
  2. Vitis HLS
  3. | トラックバック:0
  4. | コメント:0