Linux
FPGA
arm64
zynq
Vivado

UltraZed 向け Debian GNU/Linux で AXI HPC port を使う (実践編1)


はじめに

UltraZed に載っている Zynq UltraScale+ MPSoC は PL(Programmable Logic) から PS(Processing System) へのアクセスを行う AXI Port が複数あります。そのうち HPC0 と HPC1 はハードウェアで APU のキャッシュをスヌープすることによりコヒーレンシを維持して転送することが出来ます。しかし、ハードウェアは用意されていても実際に使うとなるとけっこうハードルが高いです。

この記事では UltraZed 向け Debian GNU/Linux で AXI HPC Port を使ってキャッシュコヒーレンシ転送する方法を説明します。

また次の記事で AXI HPC port によるキャッシュコヒーレンシ転送の基礎知識を説明しているので参照してください。


キャッシュコヒーレンシ転送の基本

Zynq UltraScale+ MPSoC でキャッシュコヒーレンシ転送を行うにはいくつかの条件が必要です。Xilinx の Wiki に詳しい説明があります。次の URL を参照してください。

上記の説明によれば、Linux 上で HPC を使ってキャッシュコヒーレンシ転送を行うには次の条件が必要だそうです。

1 AXI HPC0/HPC1 を使う。

2 AxCACHE 信号の上位2ビットを非ゼロにする。

3 AxPROT 信号を正しく設定する。

4 MPSoC の内部レジスタを変更して内部共有可能トランザクションをブロードキャストできるようにする。

5 コヒーレントなデバイスが dma-coherent プロパティを持つようにする。


Sample FPGA Design


リポジトリ

この記事で使うデザインは以下の URL にあります。

このリポジトリには次のようなファイルが含まれています。


  • negative2.bin - FPGAのビットストリームファイル

  • fclk0-zynqmp.dts - PL Clock 0 設定用 device-tree source

  • fpga-load.dts - FPGA ビットストリームロード用 device-tree source

  • negative2.dts - uio/udmabuf 設定用 device-tree source

  • negative.c - negative の Vivado-HLS C source

  • negative.py - negative テスト用 Python コード(sync_to_cpu/sync_to_device あり)

  • negative2.py - negative テスト用 Python コード(sync_to_cpu/sync_to_device なし)

  • udmabuf.py - udmabuf 用 Python ライブラリ

  • uio.py - uio 用 Python ライブラリ

  • boot/


    • boot.bif - boot.bin 生成用 BIF ファイル

    • boot.bin - boot.bin (regs.init 入り)

    • regs.init - MPSoC 内部レジスタ設定ファイル




デザインの説明

ここでは「UltraZed 向け Debian GNU/Linux (v2018.2版) で Vivado-HLS を使って合成した回路を動かす」 で紹介したデザインを変更して使っています。具体的には次のように変更しています。


HPC に接続

デザインのブロック図は次のようになっています。

Fig.1 Diagram

Fig.1 Diagram

オリジナルと異なっているのは、条件1 にもとづいて Zynq UltraScale+ MPSoC の HPC に接続されていることです。Zynq UltraScale+ MPSoC を 選択して Customize Block を行い、PS-PL Configuration > PS-PL Interfaces > Slave Interface > AXI HP を開き、AXI HPC0 FPD をチェックします。

Fig.2 Zynq UltraScale+ MPSoC Re-customize IP

Fig.2 Zynq UltraScale+ MPSoC Re-customize IP


AxCACHE/AxPROT を変更

さらに条件2と条件3にもとづいて AxCACHE と AxPROT の値を変更します。具体的には negative_0 を選択して Customize Block を行い、PROT value を "010" に、CACHE value を "1111" に変更します。

Fig.3 Negative Re-customize IP

Fig.3 Negative Re-customize IP


ビットストリームファイル

project/ の下にビルド用のスクリプトを用意しています。

なお、ビルド済みのビットストリームファイル(negative2.bit)をリポジトリに用意しているので、ビルドが面倒な方はこちらを使ってください。


バイナリーファイル

UltraZed 向け Debian GNU/Linux (v2018.2版) で FPGA にロードするためには、ビットストリームファイルをバイナリーファイルに変換する必要があります。バイナリーファイルへの変換は、次のような bif file を用意して、Vivado-SDK v2018.2 の bootgen コマンドを使います。


negative2.bif

all:

{
[destination_device = pl] negative2.bit
}

vivado% bootgen -image negative2.bif -arch zynqmp -w -o negative2.bin

なお、変換済みのバイナリーファイル(negative2.bin)をリポジトリに用意しているので、変換が面倒な方はこちらを使ってください。


boot.bin の説明

Linux 上で HPC を使ってキャッシュコヒーレンシ転送を行うための条件として、「MPSoC の内部レジスタを変更して内部共有可能トランザクションをブロードキャストできるようにする」というのがあります。もう少し具体的に言うと「APUがリセット中に、LPD_SLCRモジュールの lpd_apu レジスタの brdc_inner ビットを書き込む」というものです。

この「APUがリセット中に」というのが曲者で、つまり FSBL や U-Boot や Linux からでは設定出来ないということです。なぜなら「UltraZed 向け Debian GNU/Linux (v2018.2版) の構築(Boot Loader編)」 で説明したように、FSBL、U-Boot、Linux は APU で動くからです。つまり FSBL の起動前、すなわちステージ0(PMU が内部ROMに格納されているブートローダーを実行している状態)でレジスタを設定する必要があります。

幸い、ステージ0でレジスタを設定できる仕掛けが用意されています。まずは以下のようなファイルを用意しておきます。


boot/regs.init

.set. 0xFF41A040 = 0x3;


boot.bin 生成時に使用する bif file に上記のファイルを init プロパティの値として追加します。


boot/boot.bif

the_ROM_image:

{
[fsbl_config] a53_x64
[init] regs.init
[bootloader] zynqmp_fsbl.elf
[pmufw_image] zynqmp_pmufw.elf
[destination_cpu=a53-0, exception_level=el-3, trustzone] bl31.elf
[destination_cpu=a53-0, exception_level=el-2] u-boot.elf
}

このようにして生成した boot.bin は、ブート時にステージ0で PMU がレジスタを設定するようになります。

なお、このように生成した boot.bin をリポジトリの boot/ に用意しています。


準備


UltraZed の準備

次の記事を参考に UltraZed に Debian GNU/Linux をインストールしてください。


fpga でログイン

Linux が起動したら ユーザー名 fpga でログインします。パスワードは fpga になっています。

debian-fpga login: fpga

Password:
fpga@debian-fpga:~$


リポジトリのダウンロード

サンプルとなる FPGA デザインやプログラムを下記の URL よりダウンロードします。

ここでは examples/negative2 としてダウンロードします。

fpga@debian-fpga:~$ mkdir examples

fpga@debian-fpga:~$ cd examples
fpga@debian-fpga:~/examples$ git clone https://github.com/ikwzm/ZynqMP-FPGA-Linux-Example-3-UltraZed negative2
fpga@debian-fpga:~/examples$ cd negative2


boot.bin の変更

リポジトリの boot/boot.bin を boot パーティションにコピーします。

fpga@debian-fpga:~/examples/negative2$ sudo cp boot/boot.bin /mnt/boot

なお、boot.bin を変更するには注意が必要です。失敗すると二度と起動できなくなる恐れがあります。念のため boot.bin のバックアップをとる等の施策をとってください。


リブート

boot.bin を変更したらリブートします。


FPGA のコンフィギュレーション


Binary File を /lib/firmware へコピー

FPGA Region では /lib/firmware にコンフィギュレーションするファイルを置いておく必要があります。

fpga@debian-fpga:~/examples/negative2$ sudo cp negative2.bin /lib/firmware


Device Tree Overlay による FPGA のコンフィギュレーション

FPGA Region では Device Tree を使って FPGA をコンフィギュレーションします。そこで次のような Device Tree Overlay 用のソースファイルを用意します。


fpga-load.dts

/dts-v1/;

/ {
fragment@0 {
target-path = "/fpga-full";
__overlay__ {
firmware-name = "negative2.bin";
};
};
};

次の手順で Device Tree Overlay による FPGA のコンフィギュレーションを行います。


  1. Device Tree Overlay 用ソースファイル(ここでは fpga-load.dts)を dtc(Device Tree Compiler) を使って dtb (ここでは fpga-load.dtb) に変換します。

  2. /config/device-tree/overlays 下に Device Tree Overlay 用のディレクトリ(ここでは fpga) を作ります。

  3. 2.で作ったディレクトリ下の dtbo に 1. で作った dtb を書き込みます。

これで次のようなカーネルメッセージが出れば、FPGA のコンフィギュレーションは成功です。

fpga@debian-fpga:~/examples/negative2$ dtc -I dts -O dtb -o fpga-load.dtb fpga-load.dts

fpga@debian-fpga:~/examples/negative2$ sudo mkdir /config/device-tree/overlays/fpga
fpga@debian-fpga:~/examples/negative2$ sudo cp fpga-load.dtb /config/device-tree/overlays/fpga/dtbo
[ 56.218477] fpga_manager fpga0: writing negative2.bin to Xilinx ZynqMP FPGA Manager


FPGA のクロックの設定

FPGA をコンフィギュレーションするだけでは FPGA 側の回路は動きません。なぜなら FPGA へ供給するクロックの設定が終わっていないからです。

ここでは fclkcfg を使ってクロックを設定します。fclkcfg は筆者が作ったデバイスドライバで、次の URL に公開しています。

「UltraZed 向け Debian GNU/Linux ブートイメージの提供」をインストールしてあれば、すでに fclkcfg が組み込まれています。

クロックを設定するには、次のような Device Tree Overlay 用のソースファイルを用意します。


fclk0-zynqmp.dts

/dts-v1/;/plugin/;

/ {
fragment@0 {
target-path = "/amba";
__overlay__ {
fclk0 {
compatible = "ikwzm,fclkcfg-0.10.a";
clocks = <&clk 0x47>;
insert-rate = "100000000";
insert-enable = <1>;
remove-rate = "1000000";
remove-enable = <0>;
};
};
};
};

次の手順で Device Tree Overlay を使ってクロックを設定します。


  1. Device Tree Overlay 用ソースファイル(ここでは fclk0-zynqmp.dts)を dtc(Device Tree Compiler) を使って dtb (ここでは fclk0-zynqmp.dtb) に変換します。

  2. /config/device-tree/overlays 下に Device Tree Overlay 用のディレクトリ(ここでは fclk0) を作ります。

  3. 2.で作ったディレクトリ下の dtbo に 1. で作った dtb を書き込みます。

これで次のようなカーネルメッセージが出れば、FPGA クロックの設定は成功です。

fpga@debian-fpga:~/examples/negative2$ dtc -I dts -O dtb -o fclk0-zynqmp.dtb fclk0-zynqmp.dts

fpga@debian-fpga:~/examples/negative2$ sudo mkdir /config/device-tree/overlays/fclk0
fpga@debian-fpga:~/examples/negative2$ sudo cp fclk0-zynqmp.dtb /config/device-tree/overlays/fclk0/dtbo
[ 111.238976] fclkcfg amba:fclk0: driver installed.
[ 111.243617] fclkcfg amba:fclk0: device name : fclk0
[ 111.248737] fclkcfg amba:fclk0: clock name : pl0
[ 111.253678] fclkcfg amba:fclk0: clock rate : 99999999
[ 111.259085] fclkcfg amba:fclk0: clock enabled : 1
[ 111.263833] fclkcfg amba:fclk0: remove rate : 1000000
[ 111.269125] fclkcfg amba:fclk0: remove enable : 0


Uio と Udmabuf の準備

FPGA にコンフィギュレーションした回路にアクセスするには uio を使います。また、データのやりとりは udmabuf を使います。そのために次のような Device Tree Overlay 用のソースファイルを用意します。


negative2.dts

/dts-v1/;/plugin/;

/ {
fragment@0 {
target-path = "/amba_pl@0";
#address-cells = <2>;
#size-cells = <2>;

__overlay__ {
#address-cells = <2>;
#size-cells = <2>;

negative-uio {
compatible = "generic-uio";
reg = <0x0 0x80010000 0x0 0x10000>;
interrupt-parent = <&gic>;
interrupts = <0 89 4>;
};

negative-udmabuf4 {
compatible = "ikwzm,udmabuf-0.10.a";
device-name = "udmabuf4";
size = <0x00100000>;
};

negative-udmabuf5 {
compatible = "ikwzm,udmabuf-0.10.a";
device-name = "udmabuf5";
size = <0x00100000>;
};
};
};
} ;


次の手順で Device Tree Overlay を使って uio と udmabuf を設定します。


  1. Device Tree Overlay 用ソースファイル(ここでは negative2.dts)を dtc(Device Tree Compiler) を使って dtb (ここでは negative2.dtb) に変換します。

  2. /config/device-tree/overlays 下に Device Tree Overlay 用のディレクトリ(ここでは negative2) を作ります。

  3. 2.で作ったディレクトリ下の dtbo に 1. で作った dtb を書き込みます。

これで次のように /dev/uio1、/dev/udmabuf4、/dev/udmabuf5 が出来れば成功です。

fpga@debian-fpga:~/examples/negative2$ dtc -I dts -O dtb -o negative2.dtb negative2.dts

fpga@debian-fpga:~/examples/negative2$ sudo mkdir /config/device-tree/overlays/negative2
fpga@debian-fpga:~/examples/negative2$ sudo cp negative2.dtb /config/device-tree/overlays/negative2/dtbo
[ 164.123998] udmabuf amba_pl@0:negative-udmabuf4: driver probe start.
[ 164.131871] udmabuf udmabuf4: driver installed
[ 164.136254] udmabuf udmabuf4: major number = 244
[ 164.141021] udmabuf udmabuf4: minor number = 0
[ 164.145619] udmabuf udmabuf4: phys address = 0x0000000070400000
[ 164.151689] udmabuf udmabuf4: buffer size = 1048576
[ 164.156811] udmabuf udmabuf4: dma coherent = 0
[ 164.161412] udmabuf amba_pl@0:negative-udmabuf4: driver installed.
[ 164.167998] udmabuf amba_pl@0:negative-udmabuf5: driver probe start.
[ 164.175758] udmabuf udmabuf5: driver installed
[ 164.180142] udmabuf udmabuf5: major number = 244
[ 164.184917] udmabuf udmabuf5: minor number = 1
[ 164.189505] udmabuf udmabuf5: phys address = 0x0000000070500000
[ 164.195576] udmabuf udmabuf5: buffer size = 1048576
[ 164.200698] udmabuf udmabuf5: dma coherent = 0
[ 164.205298] udmabuf amba_pl@0:negative-udmabuf5: driver installed.
fpga@debian-fpga:~/examples/negative2$ ls -la /dev/uio*
crw------- 1 root root 245, 0 Jan 8 18:07 /dev/uio0
crw------- 1 root root 245, 0 Jan 8 18:07 /dev/uio1
fpga@debian-fpga:~/examples/negative2$ ls -la /dev/udmabuf*
crw------- 1 root root 244, 0 Jan 8 18:07 /dev/udmabuf4
crw------- 1 root root 244, 1 Jan 8 18:07 /dev/udmabuf5


実際に走らせてみよう


negative2.py

FPGA にロードした回路を動かすために次のようなサンプルプログラムを用意しています。このプログラムは「UltraZed 向け Debian GNU/Linux (v2018.2版) で Vivado-HLS を使って合成した回路を動かす」 で紹介した negative.py の udmabuf の sync_for_device()、sync_for_cpu() を使っているところをコメントアウトしたものです。negative.py の詳細な説明は記事を参照してください。


negative2.py

from udmabuf import Udmabuf

from uio import Uio
import numpy as np
import time

if __name__ == '__main__':
uio1 = Uio('uio1')
regs = uio1.regs()
udmabuf4 = Udmabuf('udmabuf4')
udmabuf5 = Udmabuf('udmabuf5')
test_dtype = np.uint32
test_size = min(int(udmabuf4.buf_size/(np.dtype(test_dtype).itemsize)),
int(udmabuf5.buf_size/(np.dtype(test_dtype).itemsize)))

udmabuf4_array = udmabuf4.memmap(dtype=test_dtype, shape=(test_size))
udmabuf4_array[:] = np.random.randint(-21474836478,2147483647,(test_size))
udmabuf4.set_sync_to_device(0, test_size*(np.dtype(test_dtype).itemsize))

udmabuf5_array = udmabuf5.memmap(dtype=test_dtype, shape=(test_size))
udmabuf5_array[:] = np.random.randint(-21474836478,2147483647,(test_size))
udmabuf5.set_sync_to_cpu( 0, test_size*(np.dtype(test_dtype).itemsize))

total_setup_time = 0
total_cleanup_time = 0
total_xfer_time = 0
total_xfer_size = 0
count = 0

for i in range (0,9):

start_time = time.time()
# udmabuf4.sync_for_device()
# udmabuf5.sync_for_device()
regs.write_word(0x18, udmabuf4.phys_addr & 0xFFFFFFFF)
regs.write_word(0x20, udmabuf5.phys_addr & 0xFFFFFFFF)
regs.write_word(0x28, test_size)
regs.write_word(0x04, 0x000000001)
regs.write_word(0x08, 0x000000001)
regs.write_word(0x0C, 0x000000001)
uio1.irq_on()
phase0_time = time.time()
regs.write_word(0x00, 0x000000001)
uio1.wait_irq()

phase1_time = time.time()
regs.write_word(0x0C, 0x000000001)
# udmabuf4.sync_for_cpu()
# udmabuf5.sync_for_cpu()

end_time = time.time()
setup_time = phase0_time - start_time
xfer_time = phase1_time - phase0_time
cleanup_time = end_time - phase1_time
total_time = end_time - start_time

total_setup_time = total_setup_time + setup_time
total_cleanup_time = total_cleanup_time + cleanup_time
total_xfer_time = total_xfer_time + xfer_time
total_xfer_size = total_xfer_size + test_size
count = count + 1
print ("total:{0:.3f}[msec] setup:{1:.3f}[msec] xfer:{2:.3f}[msec] cleanup:{3:.3f}[msec]".format(round(total_time*1000.0,3), round(setup_time*1000.0,3), round(xfer_time*1000.0,3), round(cleanup_time*1000.0,3)))

print ("average_setup_time :{0:.3f}".format(round((total_setup_time /count)*1000.0,3)) + "[msec]")
print ("average_cleanup_time:{0:.3f}".format(round((total_cleanup_time/count)*1000.0,3)) + "[msec]")
print ("average_xfer_time :{0:.3f}".format(round((total_xfer_time /count)*1000.0,3)) + "[msec]")
print ("throughput :{0:.3f}".format(round(((total_xfer_size/total_xfer_time)/(1000*1000)),3)) + "[MByte/sec]")

udmabuf4_negative_array = np.negative(udmabuf4_array)
if np.array_equal(udmabuf4_negative_array, udmabuf5_array):
print("np.negative(udmabuf4) == udmabuf5 : OK")
else:
print("np.negative(udmabuf4) == udmabuf5 : NG")
count = 0
for i in range(test_size):
if udmabuf4_negative_array[i] != udmabuf5_array[i] :
count = count + 1
if count < 16:
print("udmabuf4_negative_array[0x{0:08X}] = 0x{1:08X} udmabuf5_array[0x{0:08X}] = 0x{2:08X}".format(i, udmabuf4_negative_array[i], udmabuf5_array[i]))
print("NG Count:{0}".format(count))



実行結果


negative2.py

うまくいくと次のような結果が得られます。

fpga@debian-fpga:~/examples/negative2$ python3 negative2.py

total:0.182[msec] setup:0.130[msec] xfer:0.041[msec] cleanup:0.012[msec]
total:0.107[msec] setup:0.077[msec] xfer:0.020[msec] cleanup:0.010[msec]
total:0.106[msec] setup:0.076[msec] xfer:0.019[msec] cleanup:0.010[msec]
total:0.105[msec] setup:0.075[msec] xfer:0.019[msec] cleanup:0.010[msec]
total:0.104[msec] setup:0.075[msec] xfer:0.019[msec] cleanup:0.010[msec]
total:0.105[msec] setup:0.075[msec] xfer:0.019[msec] cleanup:0.011[msec]
total:0.104[msec] setup:0.075[msec] xfer:0.019[msec] cleanup:0.010[msec]
total:0.387[msec] setup:0.077[msec] xfer:0.298[msec] cleanup:0.012[msec]
total:0.268[msec] setup:0.075[msec] xfer:0.181[msec] cleanup:0.012[msec]
average_setup_time :0.082[msec]
average_cleanup_time:0.011[msec]
average_xfer_time :0.071[msec]
throughput :3713.172[MByte/sec]
np.negative(udmabuf4) == udmabuf5 : OK

udmabuf の sync_for_device()、sync_for_cpu() を使っていない(つまりソフトウェアでキャッシュのフラッシュと無効化をしていない)にも関わらず正常に動作していることがわかります。


negative.py

キャッシュのフラッシュと無効化をソフトウェアで行っている negative.py を実行すると次のような結果が得られます。

fpga@debian-fpga:~/examples/negative2$ python3 negative.py

total:1.411[msec] setup:0.813[msec] xfer:0.042[msec] cleanup:0.555[msec]
total:1.218[msec] setup:0.673[msec] xfer:0.020[msec] cleanup:0.525[msec]
total:1.172[msec] setup:0.667[msec] xfer:0.020[msec] cleanup:0.485[msec]
total:1.173[msec] setup:0.667[msec] xfer:0.020[msec] cleanup:0.486[msec]
total:1.190[msec] setup:0.667[msec] xfer:0.020[msec] cleanup:0.503[msec]
total:1.184[msec] setup:0.677[msec] xfer:0.020[msec] cleanup:0.487[msec]
total:9.057[msec] setup:0.666[msec] xfer:7.903[msec] cleanup:0.489[msec]
total:1.169[msec] setup:0.664[msec] xfer:0.020[msec] cleanup:0.485[msec]
total:1.201[msec] setup:0.696[msec] xfer:0.020[msec] cleanup:0.485[msec]
average_setup_time :0.688[msec]
average_cleanup_time:0.500[msec]
average_xfer_time :0.898[msec]
throughput :291.837[MByte/sec]
np.negative(udmabuf4) == udmabuf5 : OK

negative2.py の結果に比べて、setup と cleanup にけっこうな時間がとられているのがわかります。それだけキャッシュのフラッシュと無効化には時間がかかっていることがわかります。


おまけ

boot.bin を変更しない(すなわちMPSoC の内部レジスタを変更して内部共有可能トランザクションをブロードキャストできるようにしない)状態で negative2.py を実行すると次のように計算値と期待値が一致しません。

fpga@debian-fpga:~/examples/negative2$ python3 negative2.py

total:0.222[msec] setup:0.168[msec] xfer:0.043[msec] cleanup:0.011[msec]
total:0.119[msec] setup:0.090[msec] xfer:0.019[msec] cleanup:0.010[msec]
total:0.118[msec] setup:0.088[msec] xfer:0.019[msec] cleanup:0.011[msec]
total:0.118[msec] setup:0.088[msec] xfer:0.019[msec] cleanup:0.010[msec]
total:0.118[msec] setup:0.088[msec] xfer:0.019[msec] cleanup:0.010[msec]
total:0.117[msec] setup:0.087[msec] xfer:0.019[msec] cleanup:0.010[msec]
total:0.117[msec] setup:0.088[msec] xfer:0.019[msec] cleanup:0.010[msec]
total:0.117[msec] setup:0.088[msec] xfer:0.019[msec] cleanup:0.010[msec]
total:0.159[msec] setup:0.129[msec] xfer:0.019[msec] cleanup:0.010[msec]
average_setup_time :0.102[msec]
average_cleanup_time:0.011[msec]
average_xfer_time :0.022[msec]
throughput :12009.229[MByte/sec]
np.negative(udmabuf4) == udmabuf5 : NG
udmabuf4_negative_array[0x00001160] = 0x2BF44900 udmabuf5_array[0x00001160] = 0x4AAC10A6
udmabuf4_negative_array[0x00001161] = 0xE19DF117 udmabuf5_array[0x00001161] = 0xDE4038DE
udmabuf4_negative_array[0x00001162] = 0x6B655459 udmabuf5_array[0x00001162] = 0x4745277B
udmabuf4_negative_array[0x00001163] = 0xCB40962A udmabuf5_array[0x00001163] = 0x3A6ED662
udmabuf4_negative_array[0x00001164] = 0x7932EB61 udmabuf5_array[0x00001164] = 0x65701BBC
udmabuf4_negative_array[0x00001165] = 0x8B8146FD udmabuf5_array[0x00001165] = 0x5A550861
udmabuf4_negative_array[0x00001166] = 0x99AC4841 udmabuf5_array[0x00001166] = 0x265323B0
udmabuf4_negative_array[0x00001167] = 0xA46B6593 udmabuf5_array[0x00001167] = 0x5513097F
udmabuf4_negative_array[0x00001168] = 0x726FF784 udmabuf5_array[0x00001168] = 0x6FEBBC08
udmabuf4_negative_array[0x00001169] = 0xD834BBCE udmabuf5_array[0x00001169] = 0x2ECBBFB8
udmabuf4_negative_array[0x0000116A] = 0x70580503 udmabuf5_array[0x0000116A] = 0x70B08FFC
udmabuf4_negative_array[0x0000116B] = 0xA3704FC6 udmabuf5_array[0x0000116B] = 0x0CED699C
udmabuf4_negative_array[0x0000116C] = 0x1922A3D6 udmabuf5_array[0x0000116C] = 0x41D123D5
udmabuf4_negative_array[0x0000116D] = 0x554F7E03 udmabuf5_array[0x0000116D] = 0xEF6F420B
udmabuf4_negative_array[0x0000116E] = 0x06A95EE2 udmabuf5_array[0x0000116E] = 0x754C3622
NG Count:63968

これはキャッシュのコヒーレンシ維持が出来ていないために、PL 側の回路が間違った値を読んでいるか PL が書いた値を CPU が正常に読めていないために起ったものです。


参考