<acronym id="s8ci2"><small id="s8ci2"></small></acronym>
<rt id="s8ci2"></rt><rt id="s8ci2"><optgroup id="s8ci2"></optgroup></rt>
<acronym id="s8ci2"></acronym>
<acronym id="s8ci2"><center id="s8ci2"></center></acronym>
0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

Vitis初探—1.將設計從SDSoC/Vivado HLS遷移到Vitis上的教程

電子設計 ? 來源:lulugay ? 作者:lulugay ? 2022-07-25 17:45 ? 次閱讀

〇、前言

2020.11.25日,Xilinx更新了Vitis2020.2版本。正好之前報名里Xilinx的自適應計算挑戰賽,比賽要求使用Vitis平臺進行開發,所以今天趁著新版本發布把我之前參加DAC-SDC的項目SkrSkr遷移到Vitis平臺上。之前聽過一些介紹說Vitis將SDAccel和SDSoC合并到了一起,并使用OpenCL語言,所以在項目遷移之前我還是有點打怵的,但是經過一天的嘗試基本搞定了。整個流程走下來感覺Vitis跟SDSoC換湯不換藥,只是調用加速器的方式稍有變化,整體的設計思想還是一致的。下面就進入正題,如何一步一步將設計從SDSoC/Vivado HLS遷移到Vitis平臺。

一、環境準備

1.安裝Vitis,此處省略

2. 安裝zcu104的platform
下載zcu104的base platform
https://www.xilinx.com/support/download/index.html/content/xilinx/en/dow...下載ZCU104 Base 2020.2以及ZYNQMP common image
將ZCU104 Base 2020.2解壓到/tools/Xilinx/Vitis/2020.2/platforms/(Vitis的默認安裝目錄)

3. 準備sysroot
將ZYNQMP common image解壓到任意位置,并將rootfs.tar.gz進一步解壓

mkdir sysroot
tar -xvf rootfs.tar.gz -C sysroot

文件內容如下所示

├── bl31.elf
├── boot.scr
├── Image
├── README.txt
├── rootfs.ext4
├── rootfs.manifest
├── rootfs.tar.gz
├── sdk.sh
├── sysroot
└── u-boot.elf

二、創建工程

o4YBAGAKIy-AUecNAAEEEY9TnBc290.png

pIYBAGAKI3yAPs0bAAIYnKTwNDQ934.png

pIYBAGAKI7yADLCQAAJ1-1-W444821.png

pIYBAGAKI_2AEdpTAAGh4cjT3Tw502.png

sysroot,rootfs,kernel image指向剛才解壓出來的那些文件

o4YBAGAKJD2AbWjWAAIP61LziE8764.png

然后選擇空工程,至此新工程創建完畢
SkrSkr/Develop/C下邊的5個文件導入

.
├── main.cpp
├── SkyNet.cpp
├── SkyNet.h
├── transform.cpp
└── utils.cpp

將SkyNet.cpp和SkyNet.h復制到SkyNet_kernels/src下,將main.cpp, SkyNet.h, transform.cpp, utils.cpp復制到SkyNet/src下,如圖所示

o4YBAGAKJHyAZPbXAAE1jJEYnbw154.png

SkyNet/src下存放的是Host端代碼,而SkyNet_kernels/src下存放的是FPGA端代碼,二者在編譯的時候是獨立的。對比之前Vivado HLS的開發流程,SkyNet_kernels/src下放的就是Vivado HLS工程里的文件,但是沒有testbench,而SkyNet/src放的就是綜合出來比特流之后在SDK里開發應用程序的文件。(SDSoC好用就好用在將SDK的應用程序代碼跟Vivado HLS里的testbench合并,邏輯上很直觀。Vitis這么搞純粹是為了上層使用OpenCL,個人認為是倒退。但是好處是不會像SDSoC稍微修改一點代碼就可能導致整個工程重新編譯一遍)

三、修改源代碼
1. 修改SkyNet.cpp
SkyNet.cpp的設計基本不用動,唯一需要修改的就是接口定義

void SkyNet(ADT4* img, ADT32* fm, WDT32* weight, BDT16* biasm)
{
#pragma HLS INTERFACE m_axi depth=204800 port=img    offset=slave bundle=fm
#pragma HLS INTERFACE m_axi depth=628115 port=fm     offset=slave bundle=fm
#pragma HLS INTERFACE m_axi depth=13792  port=weight offset=slave bundle=wt
#pragma HLS INTERFACE m_axi depth=432    port=biasm  offset=slave bundle=bm
#pragma HLS INTERFACE s_axilite register port=return

#pragma HLS ALLOCATION instances=PWCONV1x1		limit=1 function
#pragma HLS ALLOCATION instances=DWCONV3x3	   	limit=1 function

將接口定義刪掉即可

void SkyNet(ADT4* img, ADT32* fm, WDT32* weight, BDT16* biasm)
{
#pragma HLS ALLOCATION instances=PWCONV1x1		limit=1 function
#pragma HLS ALLOCATION instances=DWCONV3x3	   	limit=1 function

2. 修改SkyNet/src/SkyNet.h
kernel端的SkyNet.h無需修改,但是Host端因為要用OpenCL來調用加速器,因此需要在頭文件中加入相關代碼(就是從案例vadd中復制過來的)

#ifndef SKYNET_H
#define SKYNET_H
#pragma once

#define CL_HPP_CL_1_2_DEFAULT_BUILD
#define CL_HPP_TARGET_OPENCL_VERSION 120
#define CL_HPP_MINIMUM_OPENCL_VERSION 120
#define CL_HPP_ENABLE_PROGRAM_CONSTRUCTION_FROM_ARRAY_COMPATIBILITY 1

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include "ap_int.h"

3.修改SkyNet/src/SkyNet.cpp
這部分改動比較大,主要就是要用OpenCL的方式加載Kernel,分配內存,還是以vadd的案例作為參照。

1. 首先把加載kernel部分代碼全盤復制過來

int main(int argc, char* argv[]) {
    if(argc != 2) {
        std::cout << "Usage: " << argv[0] <<" "<< std::endl;
        return EXIT_FAILURE;
    }

    char* xclbinFilename = argv[1];

    std::vector devices;
    cl::Device device;
    std::vector platforms;
    bool found_device = false;

    cl::Platform::get(&platforms);
    for(size_t i = 0; (i < platforms.size() ) & (found_device == false) ;i++){
        cl::Platform platform = platforms[i];
        std::string platformName = platform.getInfo();
        if ( platformName == "Xilinx"){
            devices.clear();
            platform.getDevices(CL_DEVICE_TYPE_ACCELERATOR, &devices);
        if (devices.size()){
            device = devices[0];
            found_device = true;
            break;
        }
        }
    }
    if (found_device == false){
       std::cout << "Error: Unable to find Target Device "
           << device.getInfo() << std::endl;
       return EXIT_FAILURE;
    }

    // Creating Context and Command Queue for selected device
    cl::Context context(device);
    cl::CommandQueue q(context, device, CL_QUEUE_PROFILING_ENABLE);

    // Load xclbin
    std::cout << "Loading: '" << xclbinFilename << "'/n";
    std::ifstream bin_file(xclbinFilename, std::ifstream::binary);
    bin_file.seekg (0, bin_file.end);
    unsigned n_b = bin_file.tellg();
    bin_file.seekg (0, bin_file.beg);
    char *buf = new char [n_b];
    bin_file.read(buf, n_b);

    // Creating Program from Binary File
    cl::Program::Binaries bins;
    bins.push_back({buf,n_b});
    devices.resize(1);
    cl::Program program(context, devices, bins);

2. 聲明kernel

cl::Kernel krnl_SkyNet(program,"SkyNet");

3. 分配kernel端內存cl::buffer
在SDSoC中我們要給權重、特征圖等buffer分配連續內存地址,

	img = (ADT4*)sds_alloc(4*160*320*sizeof(ADT4));
	weight = (WDT32*)sds_alloc(441344*sizeof(WDT));
	biasm = (BDT16*)sds_alloc(432*sizeof(BDT16));
	fm = (ADT32*)sds_alloc(32*fm_all*sizeof(ADT));

在PYNQ框架中我們用xlnk分配連續內存地址

	img    = xlnk.cma_array(shape=[4,160,320,4], dtype=np.uint8)
	fm     = xlnk.cma_array(shape=(628115*32), dtype=np.uint8)
	weight = xlnk.cma_array(shape=(220672),  dtype=np.int16)
	biasm  = xlnk.cma_array(shape=(432*16),  dtype=np.int16)

其中img和weight對于加速器來說是只讀不寫,但是biasm和fm既讀又寫,這一點在SDSoC和PYNQ中都無需刻意區分,但是在OpenCL需要額外注意。

cl::Buffer(按照我的理解)是在DDR中給kernel(FPGA)端分配一段內存,

	cl::Buffer buffer_img(context, CL_MEM_READ_ONLY, 160*320*sizeof(ADT16));
	cl::Buffer buffer_fm(context, CL_MEM_READ_WRITE, 32*fm_all*sizeof(ADT));
    cl::Buffer buffer_wt(context, CL_MEM_READ_ONLY, 441344*sizeof(WDT));
    cl::Buffer buffer_bm(context, CL_MEM_READ_WRITE, 432*sizeof(BDT16));

所以其讀寫是從kernel端看的,加速器中對img只是讀沒有寫,所以在聲明cl::Buffer時用CL_MEM_READ_ONLY,而fm和biasm既有讀又有寫,所以用CL_MEM_READ_WRITE。

4. 配置加速器
在PYNQ框架里我們要把加速器各個端口對應對物理地址傳給加速器

	SkyNet = overlay.SkyNet
	SkyNet.write(0x10, img.physical_address)
	SkyNet.write(0x1c, fm.physical_address)
	SkyNet.write(0x28, weight.physical_address)
	SkyNet.write(0x34, biasm.physical_address)

在SDSoC中這個步驟工具會自動生成相應的代碼,但是在OpenCL中需要手動指定,需要注意參數的順序要跟function的順序一致。

    //set the kernel Arguments
    int narg=0;
    krnl_SkyNet.setArg(narg++,buffer_img);
    krnl_SkyNet.setArg(narg++,buffer_fm);
    krnl_SkyNet.setArg(narg++,buffer_wt);
    krnl_SkyNet.setArg(narg++,buffer_bm);

5.分 配Host端內存
在PYNQ框架中我們并不能直接訪問屬于加速器的內存片段,因此在Host端都是操作numpy數組,然后將numpy數組的數據復制到屬于加速器的內存片段

parameter = np.fromfile("SkyNet.bin", dtype=np.int16)
np.copyto(weight, parameter[0:220672])# 從numpy數組復制到加速器內存
np.copyto(biasm[0:428*16], parameter[220672:])
print("Parameters loading done")
bbox_origin = np.empty(64, dtype=np.int16)
bbox  = np.zeros((4,4),dtype=np.float32)
result= open('predict.txt','w+')
batch_buff  = None
image = np.zeros((4,160,320,4),np.uint8)
image_buff  = np.zeros((4,160,320,4),np.uint8)
...
np.copyto(bbox_origin, biasm[428*16:])# 從加速器內存復制到numpy數組
...

再次強調一下在SDSoC中不區分Host端內存和Kernel端內存

	img = (ADT4*)sds_alloc(4*160*320*sizeof(ADT4));
	weight = (WDT32*)sds_alloc(441344*sizeof(WDT));
	biasm = (BDT16*)sds_alloc(432*sizeof(BDT16));
	fm = (ADT32*)sds_alloc(32*fm_all*sizeof(ADT));

在OpenCL中要將Kernel端內存映射到Host端內存

    ADT32* img = (ADT32*) q.enqueueMapBuffer (buffer_img , CL_TRUE , CL_MAP_WRITE , 0, 160*320*sizeof(ADT32));
    ADT32* ofm_blob32 = (ADT32*) q.enqueueMapBuffer (buffer_fm , CL_TRUE , CL_MAP_READ | CL_MAP_WRITE , 0, fm_all*sizeof(ADT32));
    WDT32* weight = (WDT32*) q.enqueueMapBuffer (buffer_wt , CL_TRUE , CL_MAP_WRITE , 0, 441344*sizeof(WDT));
    BDT16* biasm = (BDT16*) q.enqueueMapBuffer (buffer_bm , CL_TRUE , CL_MAP_READ | CL_MAP_WRITE , 0, 432*sizeof(BDT16));

需要說明的是此時對讀寫是從Host端開過來的,所以與Kernel端配置反過來。

6. 啟動加速器

在PYNQ里我們用如下代碼控制加速器啟動與停止

        SkyNet.write(0x00, 1)
        isready = SkyNet.read(0x00)
        while( isready == 1 ):
            isready = SkyNet.read(0x00)

在OpenCL中對應的代碼稍微復雜一點點,如下所示

    q.enqueueMigrateMemObjects({buffer_img,buffer_wt},0/* 0 means from Host*/);
    q.enqueueTask(krnl_SkyNet);
    q.enqueueMigrateMemObjects({buffer_fm,buffer_bm},CL_MIGRATE_MEM_OBJECT_HOST);
    q.finish();

在這里又一次出現了對內存的配置,q.enqueueMigrateMemObjects的用法我不是非常清楚,但是大概意思就是CL_MIGRATE_MEM_OBJECT_HOST選項表示Host在啟動加速器之后還得回去接收數據,而0就不用。加速器運行完后邊的數據處理跟SDSoC里是完全一致的。

7. 回收內存

	q.enqueueUnmapMemObject(buffer_img, img);
    q.enqueueUnmapMemObject(buffer_fm, ofm_blob32);
    q.enqueueUnmapMemObject(buffer_wt, weight);
	q.enqueueUnmapMemObject(buffer_bm, biasm);
    q.finish();

四、編譯工程
1. 選擇硬件函數
現在的工程并沒有選擇硬件函數加速

pIYBAGAKJL6AO0bIAAPWtkFQwDI888.png

點擊Hardware Functions里的藍色按鈕將SkyNet添加為硬件函數,并勾選Max Memory Ports。

pIYBAGAKJQSALReVAAPi53SiwyY151.png

2. 編譯工程
將Activation build configuration改為Hardware,點擊左側的菜單欄SkyNet_system,然后點擊小錘子,整個工程就開始編譯了。在R7 3700X上大概20分鐘就能編譯完成。

pIYBAGAKJUyAVtLTAAZnAJPyAvs998.png

SkyNet文件夾存放Host端調用加速器的代碼,SkyNet_kernels文件夾存放FPGA端的加速器代碼,但是加速器端代碼還只是代碼,并不是一個比特流,SkyNet_system_hw_link文件夾用來存放Vivado工程,生成的比特流就在這個文件夾下。編譯完畢我們可以在SkyNet_system_hw_link找到Vivado工程

o4YBAGAKJcSAPAnUAAC1-uhegmY736.png

打開看一下block diagram,可以發現勾選Max Memory Ports生效了,加速器總共生成了4個M_AXI接口,如果不勾選Max Memory Ports那么四個接口就會bundle到一起,影響加速器的傳輸性能。

pIYBAGAKJjCAW1H7AActhpgzM8U114.png

五、上板測試
1. 燒寫SD卡
在編譯好的工程下我們可以看到如下文件

pIYBAGAKJweALXUSAAFdFr_abPo952.png

我們把sd_card.img文件復制到windows電腦上燒寫進SD卡,具體怎么燒寫之前的博文中有提到,在此不再重復

2. 準備文件
用Mobaxterm登錄板子,默認用戶名和密碼都是root。將SkyNet,init.sh,binary_container_1.xclbin以及SkrSkr/Develop/C/blob和SkrSkr/Develop/C/weight復制到/home/root下,如圖所示

pIYBAGAKJ0eAbPDFAAHVW2QlAYA239.png

配置一下xrt環境

./init.sh

然后就可以開始測試啦

至此移植工作全部結束。目前的linux系統是Vitis自動生成的(其實應該是Petalinux構建出來的),可用性很差,后邊會嘗試把Vitis跟PYNQ結合,將Vitis生成的可執行文件放在PYNQ提供的運行環境下執行。

審核編輯 黃昊宇


聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • SDSoC
    +關注

    關注

    0

    文章

    24

    瀏覽量

    12170
  • Vitis
    +關注

    關注

    0

    文章

    144

    瀏覽量

    7189
收藏 人收藏

    評論

    相關推薦

    Vitis2023.2使用之—— classic Vitis IDE

    AMD官網下載全系統安裝包,或下載網頁版安裝包,安裝好vitis全套組件。打開vivado建一個測試工程編譯好后,在tcl命令輸入框子輸入命令 vitis –classic 即可打開傳統的GUI界面
    發表于 03-24 16:15

    Vitis2023.2使用之—— updata to Vitis Unified IDE

    一章聊了一下vitis2023.2怎樣使用classic Vitis IDE,這章我們來說一說基于classic Vitis IDE的工程怎么樣更新到新版本的
    發表于 03-24 17:14

    FPGA高層次綜合HLSVitis HLS知識庫簡析

    ,Vivado 2019.1之前(包括),HLS工具叫Vivado HLS,之后為了統一將HLS集成到V
    發表于 09-07 15:21

    使用Vitis HLS創建屬于自己的IP相關資料分享

    。HLS 采用 C 和 C++ 描述并將它們轉換為自定義硬件 IP,完成后我們就可以在 Vivado 項目中使用該IP。Vitis HLS創建一個新的
    發表于 09-09 16:45

    vitisvivado有什么區別和聯系呢?

    vitisvivado有什么區別和聯系呢
    發表于 10-16 07:55

    將SDAccel項目遷移到Vitis 2019.2的技巧

    Vitis 2019.2 使用 gcc 編譯 C 語言源代碼,使用 Vivado HLS 編譯與 SDAccel 流匹配的加速內核。此外,Vitis 也使用與 SDAccel 相同的目
    的頭像 發表于 06-28 10:05 ?2084次閱讀
    將SDAccel項目<b class='flag-5'>遷移到</b><b class='flag-5'>Vitis</b> 2019.2的技巧

    Vivado HLSVitis HLS 兩者之間有什么區別

    Vitis HLS下,一個Solution的Flow Target可以是Vivado IP Flow Target,也可以是VitisKernel Flow Target,如下圖所示。前者最終導出來
    的頭像 發表于 11-05 17:43 ?3.8w次閱讀

    Vitis初探1.將設計從SDSoC/Vivado HLS遷移到Vitis

    本文介紹如何一步一步將設計從SDSoC/Vivado HLS遷移到Vitis平臺。
    發表于 01-31 08:12 ?8次下載
    <b class='flag-5'>Vitis</b><b class='flag-5'>初探</b>—<b class='flag-5'>1.</b><b class='flag-5'>將設</b>計從<b class='flag-5'>SDSoC</b>/<b class='flag-5'>Vivado</b> <b class='flag-5'>HLS</b><b class='flag-5'>遷移到</b><b class='flag-5'>Vitis</b>上

    基于Vitis HLS的加速圖像處理

    使用Vivado / Vitis工具提供預安裝的OpenCV版本。盡管Vitis_hls編譯Vision庫不需要OpenCV,但是用戶測試驗證使用時OpenCV。
    的頭像 發表于 02-16 16:21 ?2128次閱讀
    基于<b class='flag-5'>Vitis</b> <b class='flag-5'>HLS</b>的加速圖像處理

    Vitis HLS工具簡介及設計流程

    Vitis HLS 是一種高層次綜合工具,支持將 C、C++ 和 OpenCL 函數硬連線到器件邏輯互連結構和 RAM/DSP 塊上。Vitis HLS 可在
    的頭像 發表于 05-25 09:43 ?2047次閱讀

    Vitis HLS前端現已全面開源

    Vitis HLS 工具能夠將 C++ 和 OpenCL 功能部署到器件的邏輯結構和 RAM/DSP 塊上。在 GitHub 上提供 Vitis HLS 前端為研究人員、開發人員和編譯
    的頭像 發表于 08-03 09:53 ?772次閱讀

    Vitis HLS知識庫總結

    對于AMD Xilinx而言,Vivado 2019.1之前(包括),HLS工具叫Vivado HLS,之后為了統一將HLS集成到
    的頭像 發表于 09-02 09:06 ?3025次閱讀

    AMD全新Vitis HLS資源現已推出

    AMD Vitis HLS 工具允許用戶通過將 C/C++ 函數綜合成 RTL,輕松創建復雜的 FPGA 算法。Vitis HLS 工具與 Viva
    的頭像 發表于 04-23 10:41 ?760次閱讀
    AMD全新<b class='flag-5'>Vitis</b> <b class='flag-5'>HLS</b>資源現已推出

    如何在Vitis HLS GUI中使用庫函數?

    Vitis? HLS 2023.1 支持新的 L1 庫向導,本文將講解如何下載 L1 庫、查看所有可用功能以及如何在 Vitis HLS GUI 中使用庫函數。
    的頭像 發表于 08-16 10:26 ?694次閱讀
    如何在<b class='flag-5'>Vitis</b> <b class='flag-5'>HLS</b> GUI中使用庫函數?

    Vitis HLS移植指南

    電子發燒友網站提供《Vitis HLS移植指南.pdf》資料免費下載
    發表于 09-13 09:21 ?0次下載
    <b class='flag-5'>Vitis</b> <b class='flag-5'>HLS</b>移植指南
    亚洲欧美日韩精品久久_久久精品AⅤ无码中文_日本中文字幕有码在线播放_亚洲视频高清不卡在线观看
    <acronym id="s8ci2"><small id="s8ci2"></small></acronym>
    <rt id="s8ci2"></rt><rt id="s8ci2"><optgroup id="s8ci2"></optgroup></rt>
    <acronym id="s8ci2"></acronym>
    <acronym id="s8ci2"><center id="s8ci2"></center></acronym>