Closed3

Xilinx Kria KV260でPL (VexRiscv, etc) からPS (ARM PetaLinux) に割り込みを入れたい

Ryo TakahashiRyo Takahashi

目的

第 6 回 AI エッジコンテスト [presentation, code] では、KV260 の PL での RISC-V (VexRiscv) 実装 + PS 側 ARM からの演算オフロード機構を作れた。しかし、RISC-V からの ARM への割り込みは実装しきれず、演算完了はポーリングで確認していた。そもそも、私個人は上記コンテスト中、Vitis AI との格闘に終始していたこともあり、本来目的であった FPGA + HDL の技術習得をあまり行えておらず「割り込みは良い教材?」と思い、いろいろと調査・試行錯誤してみた

Ryo TakahashiRyo Takahashi

AXI GPIO から PS (ARM PetaLinux) への割り込み

筆者は FPGA + HDL 素人であり、いきなり VexRiscv からの割り込みを入れるのは大変そうなので、まずは既存 IP で割り込みを行い、PetaLinux で割り込みを確認してみる。公式の Confluence有志の LinkedIn の記事 がこの目的を達成しているのだが、例によって記事が古かったり、ボードが違ったり、いくつかの差分があるので、ここでは差分中心に手順を記録する。

手順 1: PetaLinux のビルド

まず、basaro さんの記事 をベースに、.wic ファイルの作成を目指す。差分は、BSP として xilinx-kv260-starterkit-v2022.1-05140151.bsp を使用、また公式の Confluenceと同様に UIO Driver を組み込む。

$ petalinux-create -t project -s xilinx-kv260-starterkit-v2022.1-05140151.bsp
$ cd xilinx-kv260-starterkit-2022.1
$ petalinux-config -c kernel; # 下記のようにモジュールを built-in する
$ : "Device Drivers -> Userspace I/O drivers \
<*> Userspace I/O platform driver with generic IRQ handling \
<*> Userspace platform driver with generic irq and dynamic memory \
<*> Xilinx AI Engine driver"
$ ${EDITOR} project-spec/meta-user/recipes-bsp/device-tree/files/system-user.dtsi # 下記のように uio_pdrv_genirq.of_id=generic-uio を足す
$ cat project-spec/meta-user/recipes-bsp/device-tree/files/system-user.dtsi
/include/ "system-conf.dtsi"
/ {
	chosen {
                bootargs = "earlycon console=ttyPS1,115200 clk_ignore_unused init_fatal_sh=1 cma=900M uio_pdrv_genirq.of_id=generic-uio ";
                stdout-path = "serial1:115200n8";
        };
};
$ petalinux-build
$ 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"

手順 2: Vivado での作業

Block Design

basaro さんのもう 1 つの記事 を参考に kv260_hardware_platform というプロジェクトを作成する。このプロジェクトでは、下記のようなハードウェアを Block Design -> Diagram で組み、Linux の UIO から AXI Internconnect 経由で AXI GPIO のレジスタを叩けるようにする。ポイントは以下の通り。

  • PS の pl_ps_irq のビット幅を 1 に設定し、割り込み用に AXI GPIO ip2intc_irpt と繋ぐ
  • Block Design -> Address Editor で /axi_gpio_0/S_AXI0x00_A000_0000 から 64K 分の Range を割く
    • 仕様書 の Register Space を見る限り、64K も要らないが、動認を 64K で行なったというだけ

Export Platform

Export Platform を利用し、上記ハードウェアを XSA 形式の uio_with_interrupt.xsa というファイルで出力する。次の手順で生の bitstream のファイルが必要になるが、これは *.runs から拾い上げても、*.xsa (実体は ZIP 形式) から取り出しても良い。

$ unzip -v kv260_hardware_platform/uio_with_interrupt.xsa | grep bit
 7797810  Defl:N    71607  99% 2023-06-11 16:31 fe3481ff  uio_with_interrupt.bit
$ find kv260_hardware_platform -name "*.bit"
kv260_hardware_platform/kv260_hardware_platform.runs/impl_1/system_wrapper.bit

手順 3: Dynamic Function eXchange (DFX) 向けのアーティファクト生成

lp6m さんの素晴らしい記事 を参考に、DFX で読み込むための Boot Image、Deviccetree Overlay、JSON のファイルを作成する。

Boot Image 形式での bitstream の格納

$ mkdir bit
$ cd bit
$ cp ../kv260_hardware_platform/kv260_hardware_platform.runs/impl_1/system_wrapper.bit system.bit
$ echo 'all:{system.bit}' > bootgen.bif
$ bootgen -w -arch zynqmp -process_bitstream bin -image bootgen.bif
$ mv system.bit.bin uio_with_interrupt.bit.bin

Devicetree Overlay (.dtbo) の出力

まず、Devicetree Overlay の PL 向けソースとなる pl.dtsi を作成する。

xsct
createdts -hw kv260_hardware_platform/uio_with_interrupt.xsa -zocl -platform-name mydevice -git-branch xlnx_rel_v2022.1 -overlay -compile -out mydevice
exit

次に、./mydevice/mydevice/mydevice/psu_cortexa53_0/device_tree_domain/bsp/pl.dtsi 内の axi_gpio_0compatible = "generic-uio" にして、AXI GPIO のレジスタを UIO から触れるようにする。

/dts-v1/;
/plugin/;
/ {
         fragment@2 {
                 target = <&amba>;
                 overlay2: __overlay__ {
                         #address-cells = <2>;
                         #size-cells = <2>;
                         axi_gpio_0: gpio@a0000000 {
                                 #gpio-cells = <2>;
                                 #interrupt-cells = <2>;
                                 clock-names = "s_axi_aclk";
                                 clocks = <&zynqmp_clk 71>;
                                 compatible = "generic-uio";

そして、最後に .dtbo ファイルを生成する。

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

DFX 向けの Packing

Xilinx の本ドキュメント 曰く、DFX では shell.json なる設定ファイルが必要らしいので、上記アーティファクトを DFX MGR に読み込ませる用のディレクトリに収集しつつ、設定ファイルを作る。

$ mkdir uio_with_interrupt
$ cp bit/uio_with_interrupt.bit.bin uio_with_interrupt
$ cp mydevice/mydevice/mydevice/psu_cortexa53_0/device_tree_domain/bsp/pl.dtbo uio_with_interrupt/uio_with_interrupt.dtbo
$ cat << EOF > uio_with_interrupt/shell.json
{
  "shell_type" : "XRT_FLAT",
  "num_slots": "1"
}
EOF

手順 4: KV260 上での作業

ここでは 1) 上記の uio_with_interrupt を DFX MGR で読み込み、2) 物理アドレス 0x00_A000_0000 に配置された AXI GPIO のレジスタを仕様書に従って叩き、3) PS の Petalinux で AXI GPIO からの割り込みを観測する。

xilinx-kv260-starterkit-20221:~$ sudo xmutil unloadapp
Password:
remove from slot 0 returns: 0 (Ok)
xilinx-kv260-starterkit-20221:~$ grep gpio /proc/interrupts
xilinx-kv260-starterkit-20221:~$ sudo xmutil loadapp uio_with_interrupt
Loaded to slot 0
xilinx-kv260-starterkit-20221:~$ grep gpio /proc/interrupts # /proc/interrupts にエントリが追加される 
 58:          0          0          0          0     GICv2 121 Level     gpio
xilinx-kv260-starterkit-20221:~$ sudo devmem 0xA0000004 32 0x01
xilinx-kv260-starterkit-20221:~$ sudo devmem 0xA0000128 32 0x01
xilinx-kv260-starterkit-20221:~$ sudo devmem 0xA000011c 32 0x80000000
xilinx-kv260-starterkit-20221:~$ sudo devmem 0xA0000120 32 0x1
xilinx-kv260-starterkit-20221:~$ grep gpio /proc/interrupts
 58:          1          0          0          0     GICv2 121 Level     gpio

自分でレジスタを操作して、自分で割り込みを見ているから自作自演っぽいが、この有志の記事のようにボタンと AXI GPIO を繋げば、物理ボタンで Linux に割り込みを入れられるようになるはず (KV260 での実現方法は未調査)。

Ryo TakahashiRyo Takahashi

VexRiscv から PS (ARM PetaLinux) への割り込み [結局出来ていない]

VexRiscv のコア生成

AI エッジコンテストでは、第 5 回から VexRiscv と呼ばれる、OSS のソフトプロセッサの PL 実装例を公開している。公式の資料lp6m さんの日本一分かりやすい記事 を参考に(各種ツールのバージョンを厳密に揃え、慎重に作業さえ)すれば、KV260 でも bootsrapping まで辿り着く。

VexRiscv から GPIO を生やす

GenSignate.scala に Plugin を組み込むと、ここの説明通り、GPIO ピンを生やせるようになる。CSRxx のインストラクションを VexRiscv で叩けば、High/Low の制御ができるはず。

Vivado で VexRiscv の GPIO を PS に繋ぐ [ここから上手くいかない]

上記の Block Diagram と同じ要領で pl_ps_irq に GPIO ピンを繋げば、/proc/interrupts に現れると思いきや、ここが上手くいかない。恐らく、読み込まれる Deviccetree Overlay の問題と考えるが、その元となる xsa や Vivado 側に根本原因があると考えている。下記のスクリーンショットは、上記のプラグインで生成した GPIO ピンだが、Block Pin Properties が TYPE: undef となってしまっている。一方、/proc/interrupts まで到達した、上記の AXI GPIO では、ここが TYPE: intr となる。ここが現状の原因だと考える。

今後の打開策

上記のような特殊の TYPE の設定を行うためには、本家の Common Internal Bus Interfaces のドキュメントを見る限り、VHDL/Verilog のレイヤで Xilinx 独自の Attributes を挿入しなければいけないらしい。ただ、ここを少し試行錯誤したが、何故か TYPE の設定が上手くいかない…そうこうしている内に、別の分野の技術習得が必要になったため、一時撤退するが、Xilinx さん、ここら辺の Runnable なサンプルがないと、正直素人には厳しい…と思ったりする。

このスクラップは2023/07/25にクローズされました