SDSoCチュートリアル with ZYBO (Zynq) (2)Linuxプラットフォーム

# この記事について
XilinxのSDSoC環境を使った開発の流れをステップバイステップで紹介していきます。
(僕自身、この記事を書いている時点でSDSoCを初めて使ってから1日も経っていないので、間違えがあるかもしれません。その際は教えてください)

- [(1)standaloneプラットフォーム](https://qiita.com/take-iwiw/items/8948def8d0eb699d3811)
- __[(2)Linuxプラットフォーム](https://qiita.com/take-iwiw/items/482ecc7355b39be1795f) <--- 今回の内容__

## 環境
- 開発用PC: Windows 10 64-bit 
	- Vivado 2018.2 WebPACKライセンス
	- Xilinx SDK 2018.2
	- SDx IDE 2018.2
- 開発用PC (Linux): Ubuntu 16.04 本家 (日本語版じゃない) (on VirtualBox 5.2.4)
	- PetaLinux 2018.2
- ターゲットボード: ZYBO (Z7-20) 

## 事前知識
[ZYBO (Zynq) 初心者ガイド](https://qiita.com/take-iwiw/items/966f252f6ca954aff08b) シリーズの1, 2, 3, 4, 7, 8, 9, 10, 11の内容を理解してあると捗ると思います。

## 参考資料
- ug1027-sdsoc-user-guide.pdf
- ug1028-sdsoc-intro-tutorial.pdf
- ug1146-sdsoc-platform-development.pdf
- ug1236-sdsoc-platform-tutorial.pdf

## 今回やること
- Linux用のSDSoCプラットフォームを作る
- 作成したSDSoCプラットフォーム上で、行列積の計算を高速化するアプリケーションを作る

ハードウェアは[前回](https://qiita.com/take-iwiw/items/8948def8d0eb699d3811) のものを使います。

# SDSoCプラットフォームを作る
## ハードウェア
以下のファイルが既にあるとします。

- design_1.hdf (ビットストリームなし)
- design_1.dsa


## ソフトウェアコンポーネントを作る (on PetaLinux)
用意したハードウェア用のLinuxイメージを、PetaLinuxを使って作成します。SDSoCで使用できるようにいくつか設定を変更する必要がありますので、そこも見ていきます。

design_1.hdfをPetaLinuxインストール済みのubuntuの~/workにコピーしておきます。

### PetaLinux プロジェクトを作る
```sh:PetaLinuxプロジェクトを作る(ターミナルonUbuntu)
cd ~/work
petalinux-create --type project --template zynq --name design_1_linux
cd design_1_linux/
petalinux-config --get-hw-description=../
```

ブートローダの設定画面が表示されるので、`generate boot args automatically`のチェックを外して、`user set kernel bootargs`に`console=ttyPS0,115200 earlyprintk quiet`を設定します。

__追記:__ この設定はなくても大丈夫でした。

![01.jpg](https://qiita-image-store.s3.amazonaws.com/0/214268/7e0a320a-6179-7cff-03e1-eea1ccd6fda6.jpeg)
![02.jpg](https://qiita-image-store.s3.amazonaws.com/0/214268/562088fe-4571-2cd6-6205-18304f885530.jpeg)


### PetaLinux カーネルコンフィグ
プロジェクトが作成されたら、下記コマンドでカーネルコンフィグをします。

```sh:PetaLinuxカーネルコンフィグ
petalinux-config -c kernel 
```

Device Drivers -> Generic Driver Options -> Size in Mega Bytesに`256`を設定します。

![03.jpg](https://qiita-image-store.s3.amazonaws.com/0/214268/45476aaf-1676-857b-b8f5-d5dea6023650.jpeg)


Device Drivers -> Staging driverをイネーブル(`*`)にして、その中の Xilinx APF Accelerator driverと、Xilinx APF DMA engines supportもイネーブル(`*`)にします。

![04.jpg](https://qiita-image-store.s3.amazonaws.com/0/214268/5fe42761-5567-57fd-0d65-9dea8e8d81c7.jpeg)
![05.jpg](https://qiita-image-store.s3.amazonaws.com/0/214268/3f61743b-a1ad-d3a2-b8f2-e1debf91046a.jpeg)
![06.jpg](https://qiita-image-store.s3.amazonaws.com/0/214268/fc92ebeb-eaf5-972e-d406-62f5a9f91956.jpeg)


### PetaLinux rootfsコンフィグ
下記コマンドでrootfsのコンフィグをします。

```sh:PetaLinuxrootfsコンフィグ
petalinux-config -c rootfs
```

Confiburation -> Filesystem Packages -> misc -> gcc-runtime -> libstdc++をイネーブル(`*`)にします。

![07.jpg](https://qiita-image-store.s3.amazonaws.com/0/214268/6496732e-cb35-158b-9746-c31c6153f073.jpeg)


### デバイスツリーの編集
デバイスツリーにAPFドライバ用の設定を追加します。

```sh:デバイスツリーの編集
code project-spec/meta-user/recipes-bsp/device-tree/files/system-user.dtsi &
```

```txt:system-user.dtsi
/include/ "system-conf.dtsi"
/{
	xlnk {
		compatible = "xlnx,xlnk-1.0";
	};
};
```

### PetaLinuxのビルド
```sh:PetaLinuxのビルド
petalinux-build
```

### 必要なファイルをまとめる
ビルド結果は`image/linux/`に生成されます。その下に`boot/`と`image/`ディレクトリを作って、必要なファイルをまとめておきます。

```sh:必要なファイルをまとめる
cd images/linux/
mkdir ./boot
mkdir ./image
cp u-boot.elf ./boot/u-boot.elf
cp *fsbl.elf ./boot/fsbl.elf
# cp bl31.elf ./boot/bl31.elf	## zyboの場合不要
# cp linux/pmufw.elf ./boot/pmufw.elf	## zyboの場合不要
cp image.ub ./image/image.ub
```

また、以下のようなbifファイルを作成します。`code boot.bif&`

```txt:boot.bif
/* linux */
the_ROM_image:
{
	[bootloader]<fsbl.elf>
	<bitstream>
	<u-boot.elf>
}
```

最終的に、まとめたすべてのファイルをWindows側にコピーしておきます。(`~/Desktop/win_share`を共有フォルダとします)

```sh:Windows側へコピー
cp -rf boot ~/Desktop/win_share/design_1_linux
cp -rf image ~/Desktop/win_share/design_1_linux
cp boot.bif ~/Desktop/win_share/design_1_linux
```

### 生成物
- boot/
	- fsbl.elf
	- u-boot.elf
- image/
	- image.ub
- boot.bif

以上で、必要なものは全てそろいました。PetaLinuxはもう使用しないのでUbuntuは閉じてしまってOKです。

## SDSoCプラットフォームを作る (on SDx)
SDxを使用してSDSoCプラットフォームを作ります。design_1というハードウェア用のプラットフォームは前回既に作成済みです。今回はそこに、Linux用のSystem Configを追加します。

SDxを起動します。前回と同じworkspaceを開くと、既にdesign_1があります。そこで① Define System Configurationをクリックして、システム設定をします。今回作成するのはLinux用のプラットフォームなので、Nameはlinuxにします。ここで、先ほど作成したbootフォルダと、boot.bifを指定します。

![08.jpg](https://qiita-image-store.s3.amazonaws.com/0/214268/1709dd3e-5167-f327-538f-6c09c85ffcd5.jpeg)
![09.jpg](https://qiita-image-store.s3.amazonaws.com/0/214268/21b92e76-3366-d4a7-042c-10520cdb20bc.jpeg)


② Add Processor Group/Domainをクリックします。OSにlinuxを設定し、Prebuilt Linux Imageに先ほど作成したimageフォルダを指定します。

![10.jpg](https://qiita-image-store.s3.amazonaws.com/0/214268/316bd7cf-c9b4-4f3f-cede-9946accb511a.jpeg)


最後に、③Generate Platformと④Add to Custom Repositoryをクリックして完成です。
以下のようにdesign_1の下にstandaloneの設定(前回作成)と、linuxの設定が作られます。

![11.jpg](https://qiita-image-store.s3.amazonaws.com/0/214268/6509d47e-22b8-f7b6-90aa-561399b1bf4a.jpeg)



# SDxアプリケーションの作成
作成したSDSoCプラットフォームを使って、SDxアプリケーションを作成します。
New -> SDx Projectを選びます。Project TypeとしてApplicationを選びます。前回はsample01というプロジェクトを作ったので、区別するために今回はsample01_linuxとします。

![12.jpg](https://qiita-image-store.s3.amazonaws.com/0/214268/af2a8811-143c-f8fa-c1a6-de0f3cda49fc.jpeg)
![13.jpg](https://qiita-image-store.s3.amazonaws.com/0/214268/ad8e8abc-7423-3c71-b921-43ea4ddf0074.jpeg)


その後、Platformを選択する画面で、先ほど作成したdesign_1というプラットフォームが選びます。このとき、System configurationとして、linuxを選びます。(前回はstandaloneしか選べませんでした)

![14.jpg](https://qiita-image-store.s3.amazonaws.com/0/214268/ad8f7d5a-400e-e45d-a970-b6f0920bcc4f.jpeg)
![15.jpg](https://qiita-image-store.s3.amazonaws.com/0/214268/ea07e604-84fe-3989-4af7-03054d481c18.jpeg)



Templateとして、前回と同じくArray Partitioningを選びます。
![16.jpg](https://qiita-image-store.s3.amazonaws.com/0/214268/b4232ddd-e098-c110-49fd-6db0d86f678f.jpeg)



## SDxアプリケーションのビルドと実行
作成したプロジェクトで右クリックして、Build Projectします。今回も15分ほど待ちます。
ビルドが完了すると、SDカードイメージも作られるので(BOOT.bin, image.ub, sample01_linux.elf)、まずはその中身をSDカードにコピーします。

![17.jpg](https://qiita-image-store.s3.amazonaws.com/0/214268/a3186d6f-bfb1-bb85-07af-c35ad62b2fb9.jpeg)


前回のstandaloneプロジェクトではこのままデバッグできたのですが、今回はまず、SDカードからLinux起動する必要があります。ZYBOのJP5をSDに切り替えてSDカードから起動するようにします。この状態で電源ONすると、Linuxが起動します。

実行バイナリ(sample01_linux.elf)自体は、SDカードに入っているので、まずはこれを実行してみます。SDカードは`/run/media/mmcblk0p1/`にマウントされているようです。

```sh:ZYBOターミナル
/run/media/mmcblk0p1/sample01_linux.elf
```

すると、以下のように実行されていることが分かります。

![18.jpg](https://qiita-image-store.s3.amazonaws.com/0/214268/689f2483-50b7-f4a5-1981-08f507ae357d.jpeg)



## SDxアプリケーションのデバッグ
SDxからTCF経由でデバッグできるようにします。
まず、SDxとZYBOをTCF(on LAN)で接続します。
Run -> Debug COnfigurationsを開き、Xilinx SDx Application Debugger -> Debugger_sample01_linuxを選び、ConnectionでNewします。HostにZYBOのIPアドレスを設定してOKします。その後、Debugをクリックすると、デバッグが開始するはずです。この時の出力はUARTではなくSDx上のターミナルになります。

![19.jpg](https://qiita-image-store.s3.amazonaws.com/0/214268/7c87a4c7-167e-407d-5057-895b380525bf.jpeg)
![20.jpg](https://qiita-image-store.s3.amazonaws.com/0/214268/5ac86eec-17d5-a3d2-d904-ae6a80a89c3a.jpeg)
![21.jpg](https://qiita-image-store.s3.amazonaws.com/0/214268/d838c611-aa32-1af5-043a-e6f169fe1137.jpeg)


# (追記)HLS(PL)コード変更後は要注意
注意点というか、僕がハマった点です。もしかしたら別の解決策があるかもしれません。

SDx上でソースコードを変更後は、Build後にRun/Debugすれば変更したコードを実行できます。しかし、HLS (ハードウェア:FPGA) 側のコードを変更後は、Run/Debugしてもハードウェア(ビットストリーム)の変更は反映されません。変更を反映するためには、SDカード内のイメージ(BOOT.bin)を再度上書きする必要があります。

これに気付かずに、1週間くらいハマっていました。。。気づいてしまえば、当然といえば当然なのですが。。。

ただ、開発フローとしてHLS変更後に毎回SDカード書き換えが必要というのもあり得ないと思うので、もしかしたらもっといい方法があったり、手順を僕が飛ばしているだけかもしれません。

(追記)
SDカードを抜き差ししないでも、scpで転送してrebootすると比較的楽にビットストリームを更新できます。

```sh:msysなどのターミナル(onHostPC)
scp /c/path-to-project/sample01/Debug/sd_card/* root@192.168.1.87:/run/media/mmcblk0p1/.
```

```sh:ZYBOターミナル
reboot
~~リブート後~~
/run/media/mmcblk0p1/sample01.elf
```