Xilinxが公開しているVitisプラットフォームの作成チュートリアルの内容を試してみました。つまづいたポイントも含めてこのページにまとめています。
動作確認環境
- 開発環境(ホストPC)
-
Ubuntu 22.04 LTS(Windows 10 PC上のWSL)
- ツールバージョン
-
Vivado / Vitis 2022.1
Petalinux 2022.2
- FPGAボード
-
Kria KV260 Vision AI Starter Kit
少なくともこちらの記事の内容については、KV260上で一通り確認できていることを前提としています。
実行手順
Vivadoを使ってVitisアプリケーションの動作に必要なハードウェアを作成していきます。クロック、リセット、AXIインターフェース、割り込み信号等のハードウェア情報が含まれるXSA ファイルを生成します。
PetaLinux を使用して、Linux カーネル、ルートファイルシステム、デバイス ツリー等のブートに必要なソフトウェアコンポーネントを作成していきます。
作成したハードウェアデザインとソフトウェアコンポーネントを組み合わせたVitisプラットフォーム(XPFM)を作成します。
Vitisプラットフォームを利用してテストアプリケーションを作成します。KV260上にアプリケーションを転送し、実行して動作確認を行います。
ハードウェアデザインの作成
プロジェクトの作成
必要な環境変数を設定し、Vivadoを起動します。
$ source <VIVADO_INSTALL_DIR>/settings64.sh
$ vivado &
Vivadoが起動したら、Create Project、Nextの順にクリックします。
Project nameにkv260_custom_platformと入力します。Project Locationは任意のディレクトリを指定して、Nextをクリックします。次の画面ではProject is an extensble Vitis platformにチェックを入れて、Nextをクリックします。
Boardsタブをクリックし、Search欄にKVと入力するとKria KV260 Vision AI Starter Kitが表示されます。これを選択してNextをクリックし、最後にSummaryが表示されるのでFinishをクリックします。
プロジェクトが作成されたら、Create Block Designをクリックします。
Design nameに今回はsystemと入力してOKをクリックします。
右側のDiagramで+のマーク(Add IP)をクリックし、Search欄にzynqと入力してZynq UltraScale+ MPSoCを選択します。
Run Block Automationをクリックします。
以下の3つの項目にチェックが入っていることを確認してOKをクリックします。
- All Automation
- Zynq_ultra_ps_e_0
- Apply Boards Presets
クロック・リセットの作成
Clocking Wizardを追加して100MHz、200MHz、400MHzのCLKを新たに作成します。Add IPでClocking Wizardを追加し、Diagram上に配置されたclk_wiz_0をダブルクリックします。
Output Clocksタブを開き、デフォルトで設定されているclk_out1に加え、clk_out2を200MHz、clk_out3を400MHzに設定します。同じタブの下部にあるReset TypeについてActive Lowにチェックを入れて、OKをクリックします。
VitisフローではRTLやC/C++で記述されたハードウェアをKernelと呼び、Kernelはv++リンカでプラットフォームと接続されます。このKernelが使用するCLKは、PSが出力するpl_clkを利用することもできますが、最大4系統しかないことや各CLKの位相が揃っていないなどいくつかの制限があります。そのため、ここではClocking Wizardを追加し、Kernelが利用可能な100MHz、200MHz、400MHzのCLKを新たに作成しています。
同様の手順でProcessor System Resetを3つ追加します。Add IPで一つのProcessor System Resetを追加したら、Ctrl+Cでコピー、Ctrl+Vで貼り付けを繰り返すことで3つのIPを配置可能です。この状態でRun Connection Automationをクリックします。
All Automationにチェックを入れた後、clk_wiz_0のclk_in1を選択し、Clock Sourceを /zynq_ultra_ps_0/pl_clk0 (99MHz) に設定します。
3つのproc_sys_resetのslowest_sync_clkをそれぞれ選択し、Clock Sourceを以下のように設定します。
- proc_sys_reset_0のClock Sourceをclk_wiz_0/clk_out1 (100MHz) に
- proc_sys_reset_1のClock Sourceをclk_wiz_0/clk_out2 (200MHz) に
- proc_sys_reset_1のClock Sourceをclk_wiz_0/clk_out3 (400MHz) に
ここまで設定できたら、OKをクリックします。Diagram上でclk_wiz_0のlocked端子と3つのproc_sys_resetのdcm_locked端子を配線します。
Platform SetupタブでClockを選択し、clk_wiz_0のclk_out1~clk_out3のEnabledにチェックを入れます。また、それぞれのIDを0, 1, 2に割り当てます。clk_out2のIs Defaultにチェックを入れ、v++リンカが利用するデフォルトCLKを設定します。
割り込みコントローラの作成
再びDiagramに戻り、Zynq UltraScale+ MPSocのブロックをダブルクリックします。PS-PL Configuration、PS-PL Interfacesの順に選択し、AXI HPM0 FPDとAXI HPM1 FPDのチェックを外し、AXI HPM0 LPDにチェックを入れます。AXI HPM0 LPD Data Widthは32に設定し、OKをクリックします。
Kernelからの割り込みはv++リンカでプラットフォームと接続されます。KernelからPSの pl_ps_irqポートに割り込み信号を接続することもできますが、このままだと最大で16の割り込み信号しか扱えません。より多くの割り込み信号を供給できるよう、PSのAXI HPM0 LPDポートにAXI 割り込みコントローラーを接続します。
Zynq UltraScale+ MPSoCではPSからPLへのインターフェースとして、AXI HPM0 FPD、AXI HPM1 FPD、AXI HPM0 LPDの3つがあります。PS内には2種類のPower Domainが存在し、FPDはFull Power Domain、LPDはLow Power Domainのことを示しています。HPMはHigh Performance Masterの略です。今回はPSからAXI割り込みコントローラ等の32bitの制御レジスタを読み書きしたいだけなので、AXI HPM0 LPD を使用します。残りのポートは後でKernelを追加した際にVitisから利用できるよう、ここでは明示的に無効にしています。
Add IPでAXI Interrupt Controllerを追加し、Diagram上に配置されたaxi_intc_0をダブルクリックします。Interrupt Output ConnectionをSingleへと変更し、OKをクリックします。
Run Connection Automatinoをクリックし、そのままOKをクリックします。axi_intc_0のirq端子をzynq_ultra_ps_e_0のpl_ps_irq[0:0]へマウスで接続します。
Platform Setupタブ、Interruptの順に選択し、axi_intc_0のintrのEnabledにチェックを入れます。
AXIインターフェースの設定
Platform Setupタブ、AXI Portの順に選択し、zynq_ultra_ps_e_0のS_AXI_LPDを除く全てのポートのEnabledにチェックを入れ、MemportやSP Tagを以下のように設定します。これにより、Vitisで作成したKernelがこれらのAXI Portを介してPS側のDDRにアクセスすることができます。
以下はZynq UltraScale+ Device Technical Reference Manual(UG1085)内の図を引用しています。S_AXI_HPC0_FPDとS_AXI_HPC1_FPDのHPCはHigh Performance Coherentの略で、CCI(Cache-Coherent Interconnect)を介してAPU(Application Processing Unit)内のL1/L2キャッシュをスヌープすることにより、キャッシュコヒーレンシを維持しながらDDRにアクセス可能です。一方でS_AXI_HP0_FPD~S_AXI_HP3_FPDはキャッシュコヒーレンシは維持できないものの、HPCのポートよりもレイテンシが短いというメリットがあります。
参考URL: https://docs.xilinx.com/r/en-US/ug1085-zynq-ultrascale-trm
ここまでできたら、再びDiagramに戻ってValidate Designをクリックします。
Validate Designによりaxi_intc_0のintr端子が接続されていないとの警告が表示されますが、Vitisにより作成したKernelの割り込み信号がintrに接続されるため、この段階では警告は無視しても問題ありません。
ブロックデザインの最上位ラッパー作成します。Sourcesタブのsystem.bdを右クリックし、Create HDL Wrapperをクリックします。Let Vivado manage wrapper and auto-updateを選択してOKをクリックします。
XSAファイルの作成
Vitisにハードウェア情報を渡すためのXSAファイルを作成していきます。Generate Block Designをクリックし、Synthesis OptionsでGlobalを選択してGenerateをクリックします。これにより、Create Block Designで作成した各IPのネットリストが生成されます。
同様にFlow Navigatorの中のGenerate Bitstreamをクリックします。警告がいくつか出てくるケースがありますが、全て無視して進めます。ビットストリームが生成されると以下のようなポップアップが出てきますが、ここではView Reportsを選択してOKをクリックします。
Export Platformをクリックし、Nextをクリックします。Platform TypeではHardware and hardware emulationを選択し、Nextをクリックします。
Patform StateではPre-synthesisを選択し(デフォルトで既に選択されている状態)、Include bitstreamにチェックを入れてNextをクリックします。
Platform Propertiesでは作成したプラットフォームの説明を入力してNextをクリックします。以下はその一例です。
XSA file nameに出力するXSAファイルの名前を入力してNextをクリックします。最後に出力するプラットフォームの情報を確認してFinishをクリックすると、XSAファイルが出力されます。
ソフトウェアコンポーネントの作成
Petalinuxのビルド
Petalinux Tools 2022.2のインストーラをダウンロードし、インストーラを実行してPetalinux作成に必要なツール群をインストールしておきます。
KV260用のPetalinuxプロジェクトを作成していくためには、KV260用のBSP(Board Support Package)が必要になります。以下のURLから、KV260用のBSPをダウンロードしておきます。
Kria K26 SOM Wikiを見ると、Kria Starter Kit BSPの「2022.1」を利用する場合は、事前にPetaLinuxのアップグレードが必要と記載されています。「2022.2」の場合はアップグレードが必要か否か定かではありませんが、念のためPetalinux 2022.2のアップグレードを行っておきます。
$ source <PETALINUX_INSTALL_DIR>/settings.sh
$ petalinux-upgrade -u http://petalinux.xilinx.com/sswreleases/rel-v2022/sdkupdate/2022.2_update1/ -p "aarch64" --wget-args "--wait 1 -nH --cut-dirs=4"
ダウンロードしたBSPを指定してPetalinuxのプロジェクトを作成し、petalinux-configを実行してMenuconfigを開きます。Filesystem packages -> libx -> xrtの順にクリックし、xrtをONにします。これで、ルートファイルシステムにXRT(Xilinx Runtime Library)がインストールされるようになります。最後にpetalinux-buildでビルドを実行します。
$ petalinux-create --type project -s ./xilinx-kv260-starterkit-v2022.2-10141622.bsp
$ cd xilinx-kv260-starterkit-2022.2
$ petalinux-config -c rootfs # xrtをONに設定
$ petalinux-build
Webで検索すると、以下のようにVivadoで生成したXSAファイルを指定してコンフィグを行ってから、ビルドを実行している例が見つかります。
$ petalinux-config --get-hw-description=<path_to_xsa_file>
$ petalinux-config -c rootfs # xrtをONに設定
$ petalinux-build
私の環境では上記手順で生成したイメージファイルの場合、Linuxカーネルの起動時にハングしてしまう現象が見られています。よって、XSAファイルを指定したコンフィグはあえて省略しています。
ビルドエラーの解析
環境依存なのかもしれませんが、私の環境では途中で以下のようなErrorが発生しビルドが止まってしまいました。
FAILED: doc/zmq_atomic_counter_destroy.html <path_to_work>/xilinx-kv260-starterkit-2022.2/build/tmp/work/x86_64-linux/zeromq-native/4.3.4-r0/build/doc/zmq_atomic_counter_destroy.html
cd <path_to_work>/xilinx-kv260-starterkit-2022.2/build/tmp/work/x86_64-linux/zeromq-native/4.3.4-r0/build && /usr/bin/asciidoc -d manpage -b xhtml11 -f <path_to_work>/xilinx-kv260-starterkit-2022.2/build/tmp/work/x86_64-linux/zeromq-native/4.3.4-r0/zeromq-4.3.4/doc/asciidoc.conf -azmq_version=4.3.4 -o doc/zmq_atomic_counter_destroy.html ../zeromq-4.3.4/doc/zmq_atomic_counter_destroy.txt
<path_to_work>/xilinx-kv260-starterkit-2022.2/build/tmp/hosttools/python3: No module named asciidoc
asciidocによるHTMLドキュメント生成過程でのエラーのようですが、生成するソフトウェアの中身には直接関係ないように思えます。そこで、以下の手順でasciidocによるドキュメント生成自体を省略します(修正方法として正しいのかわかりません)。
xilinx-kv260-starterkit-2022.2/build/tmp/work/x86_64-linux/zeromq-native/4.3.4-r0/以下を探していると、CMakeLists.txtに以下のような記述を見つけました。
option(WITH_DOCS "Build html docs" ON)
if(WITH_DOCS)
...
if(WITH_DOC)
add_custom_command(
OUTPUT ${dst}
COMMAND ${ASCIIDOC_EXECUTABLE} -d manpage -b xhtml11 -f ${CMAKE_CURRENT_SOURCE_DIR}/doc/asciidoc.conf
-azmq_version=${ZMQ_VERSION} -o ${dst} ${src}
...
endif()
CMakeのオプション「WITH_DOCS」をOFFにすることで、asciidocを使ったドキュメント生成処理をOFFにできそうです。run.do_configureスクリプト内にcmakeの実行コマンドが記述されているので、ここにオプションを追記します。
cmake_do_configure() {
...
cmake \
-G 'Ninja' -DCMAKE_MAKE_PROGRAM=ninja \
...
-Wno-dev \
-DWITH_DOCS=OFF # これを追記
}
この状態でrun.do_configureスクリプトを手動で実行し、再びpetalinux-buildを実行します。無事にビルド処理が進み、images/linux以下にPetalinuxのイメージファイルが生成されました。
$ pushd <path_to_work>/xilinx-kv260-starterkit-2022.2/build/tmp/work/x86_64-linux/zeromq-native/4.3.4-r0/temp
$ ./run.do_configure
$ popd
$ petalinux-build
Petalinux SDKもここで作成しておきます。images/linux以下にsdk.shという名前のスクリプトが生成されます。
$ petalinux-build --sdk
ビルドしたPetalinuxが正常に起動するか確認するため、SDカードイメージを作成します。
$ petalinux-package --boot --u-boot --force
$ petalinux-package --wic --images-dir images/linux/ --bootfiles "ramdisk.cpio.gz.u-boot,boot.scr,Image,system.dtb,system-zynqmp-sck-kv-g-revB.dtb" --disk-name "mmcblk1"
images/linux以下に生成されるpetalinux-sdimage.wicがSDカードイメージになります。このファイルをbalenaEtcher等でSDカードに書き込み、KV260を起動します。しばらくすると以下のようなログインプロンプトが現れ、無事にビルドしたPetalinux で起動することを確認できました。
PetaLinux 2022.2_update1_04022314 xilinx-kv260-starterkit-20222 ttyPS1
xilinx-kv260-starterkit-20222 login:
デバイスツリーの作成
Linuxは起動時にデバイスツリーを読み込むことでハードウェア情報を認識します。KV260ではLinuxの起動後にPLをロードするため、Linuxが起動後に動的にPLを認識できるよう、デバイスツリーオーバーレイという仕組みを利用します。ここでは、オーバーレイに必要なデバイスツリーを作成していきます。
必要な環境変数を設定し、XSCT(Xilinx Software Command-Line Tool)を起動します。XSCTはVitisの機能をコマンドラインで実行可能なツールです。私の環境では、以下のようにxsctを実行するとSegmentation faultが発生してしまいました。
$ source <VITIS_INSTALL_DIR>/settings64.sh
$ mkdir kv260_vitis_platform
$ cd kv260_vitis_platform
$ xsct
<VITIS_INSTALL_DIR>/bin/xsct: line 241: 3305 Segmentation fault "$RDI_BINROOT"/unwrapped/"$RDI_PLATFORM$RDI_OPT_EXT"/rlwrap -rc -b "(){}[],+= & ^%$#@"";|\\" -f "$HDI_APPROOT"/scripts/xsct/xsdb/cmdlist -H "$LOG_FILE" "$RDI_BINROOT"/loader -exec rdi_xsct "${RDI_ARGS[@]}"
以下のように-norlwrapオプションをつけることにより、XSCTが起動するようになりました。
$ xsct -norlwrap
createdtsコマンドでXSAファイルからデバイスツリーを作成します。
xsct% createdts -hw <path_to_xsa_file> -zocl -platform-name mydevice -git-branch xlnx_rel_v2022.2 -overlay -compile -out mydevice
各オプションは以下のような意味となっています。
- -hw: Vivadoで出力したXSAファイルへのパスを指定
- -zocl: zoclドライバーの有効化
- -platform-name: 生成するソフトウェアプラットフォームの名前
- -git-branch: Linux device tree generator for the Xilinx SDK のブランチを指定(デフォルトではMasterブランチ)
- -overlay: デバイスツリーオーバーレイのサポートを有効化
- -compile: デバイスツリーソース(dts)をコンパイルしてバイナリのデバイスツリーブロブ(dtb)を生成する
- -out : ソフトウェアプラットフォームの生成ディレクトリを指定
オーバーレイ用のデバイスツリーをコンパイルし、生成されたバイナリをdtg_outputという名前のディレクトリに保存します。
$ dtc -@ -O dtb -o mydevice/mydevice/mydevice/psu_cortexa53_0/device_tree_domain/bsp/pl.dtbo mydevice/mydevice/mydevice/psu_cortexa53_0/device_tree_domain/bsp/pl.dtsi
$ mkdir dtg_output
$ cp mydevice/psu_cortexa53_0/device_tree_domain/bsp/pl.dtbo dtg_output
各オプションの意味は以下のようになっています。
- -@: シンボルを生成する
- -O: 出力フォーマットの指定
- -o: 出力ファイル名
Vitisプラットフォームの作成
Vitisプラットフォーム作成に必要なファイルを、既に作成済みのkv260_vitis_platformディレクトリに準備していきます。
sdk.shを実行しsysrootを生成します。このとき、環境変数LD_LIBRARY_PATHには何も設定しないでおきます。
$ cd kv260_vitis_platform
$ pushd <path_to_work>/xilinx-kv260-starterkit-2022.2/images/linux
$ ./sdk.sh -d <path_to_kv260_vitis_platform_dir>
$ popd
pfmという名前のディレクトリを作成し、その下にboot、sd_dirという名前のディレクトリをそれぞれ作成しておきます。
$ mkdir pfm
$ mkdir pfm/boot
$ mkdir pfm/sd_dir
KV260に電源が投入されると、PMU(Platform Management Unit)が起動し内部ROMに書き込まれているファームによって動作します。PMUはプライマリブートデバイス(KV260の場合はKria SOM上に配置されたQSPI Flash)上のBOOT.binというファイルを読みに行きます。pfm/bootには、BOOT.binを作成するのに必要なファイルを置いておきます。
- FSBL(fsbl.elf): 内部ROMファームにより内部RAM上に展開され、Cortex-A53により実行される
- PMUファームウェア(pmufw.elf): FSBLの中で内部RAM上に展開され、PMUにより実行される
- Arm Trusted Firmware(bl31.elf): FSBLの中でDRAM上に展開され、Cortex-A53により実行される
- U-boot(u-boot.elf): FSBLの中でDRAM上に展開され、Cortex-A53により実行される
pfm/sd_dirにはSDカードのFAT32パーティションに格納すべきファイル(boot.scrやsystem.dtb)を置いておきます。KV260の場合、BOOT.binはデフォルトでQSPI Flashに書き込まれているため、pfm/bootにファイルを格納しBOOT.binを新たに作成する必要はありません。また、今回は上述した手順で既に起動確認済みのSDカードをそのまま利用するため、pfm/sd_dirにもファイルを格納する必要はありません。
Vitisを起動し、Workspaceに任意のディレクトリを指定してLaunchをクリックします。Windowが現れたら、Create Platform Projectをクリックします。
私の環境では、Create Platform Projectをクリックしてもなぜか何も反応しませんでした。gnome-icon-themeをインストールすることで、Windowが起動するようになりました。
$ sudo apt install gnome-icon-theme
Platform project nameにkv260_customと入力し、Nextをクリックします。
XSA FileにVivadoで生成したXSAファイルを指定し、Operating systemにlinuxを選択します。ここでは、Generate boot componentsにチェックを入れていますが、特にチェックを入れなくても(ブート用のファイルを生成しなくても)手順は進められます。
linux on psu_cortexa53を選択し、Bif FileのドロップダウンアイコンをクリックしてGenerate Bifをクリックします。Boot Components DirectoryとFAT32 Partation Directoryにそれぞれpfm/bootとpfm/sd_dirのディレクトリを指定し、左上のBuildボタンをクリックすると、kv260_custom/export以下にVitisプラットフォームが生成されます。
以下のコマンドで生成したプラットフォームの内容を確認可能です。
$ platforminfo kv260_custom/export/kv260_custom/kv260_custom.xpfm
テストアプリケーションの作成
Vitisを起動し、Workspaceに任意のディレクトリを指定してLauchをクリックします。Windowが現れたら、Create Application Projectをクリックします。次の画面ではそのままNextをクリックします。
作成したVitisプラットフォームを追加するため、右上のAddをクリックします。
作成したVitisプラットフォームを指定してOpenをクリックします。kv260_customという名前のプラットフォームが追加されたら、それを選択してNextをクリックします。
Application project nameにvaddと入力し、Nextをクリックします。Sysroot pathにsdk.shを使って生成したsysrootへのパスを指定し、Nextをクリックします。
サンプルアプリケーションとしてSimple Vector Additionを選択し、Finishをクリックします。
Active build configurationでHardwareを選択します。Explorerタブのvadd_system_hw_link.prjを選択してBuildボタンをクリックすると、ハードウェアカーネルの合成が始まります。処理が完了したら、vadd.prjを選択してBuildボタンをクリックし、ホストアプリケーションをビルドします。
vaddprjという名前のディレクトリを作成し、この中にKV260上に転送が必要なファイルを集めていきます。このとき、binary_container_1.xclbinの拡張子を「xclbin」から「bin」に変更しておきます。
$ mkdir vaddprj
$ cd vaddprj
$ cp <path_to_work>/kv260_vitis_platform/dtg_output/pl.dtbo . # オーバーレイ用のデバイスツリー
$ cp <path_to_work>/kv260_vitis_application/vadd_system_hw_link/Hardware/binary_container_1.xclbin binary_container_1.bin # カーネルのビットファイルを含むバイナリ
$ cp <path_to_work>/kv260_vitis_application/vadd/Hardware/vadd . # カーネルを動作させるためのソフトウェア
また、shell.jsonという名前のファイルを新たに作成し、以下のように記述してvaddprjの中にファイルを置いておきます。
{
"shell_type" : "XRT_FLAT",
"num_slots": "1"
}
ホストPCからKV260上に集めたファイルを転送します。
$ scp -r vaddprj petalinux@192.168.0.14:~/
転送したファイルはKV260上の/lib/firmware/xilinx/以下に置いておく必要があります。xmutilコマンドを使ってハードウェア情報を登録します。
xilinx-k260-starterkit-20222:~$ sudo cp -R vaddprj /lib/firmware/xilinx/
xilinx-k260-starterkit-20222:~$ sudo xmutil listapps
xilinx-k260-starterkit-20222:~$ sudo xmutil unloadapp
xilinx-k260-starterkit-20222:~$ sudo xmutil loadapp vaddprj
カーネルを実行します。以下のように表示すれば成功です。
xilinx-k260-starterkit-20222:~$ cd vaddprj
xilinx-k260-starterkit-20222:~$ ./vadd binary_container_1.bin
Loading: 'binary_container_1.bin'
Trying to program device[0]: edge
Device[0]: program successful!
TEST PASSED