XillinuxをつかってFPGA－ARMプロセッサのデータ通信をしよう

# 1. はじめに
近年、FPGA＋CPUの協調処理による開発効率の向上や処理性能の向上に向けた動きが活発化しています。
そこで今回はFPGAとARMプロセッサが同時に積載してあるZynq上でLinuxを動作させ、
FPGAとARMプロセッサにおけるデータ通信をしてみたいと思います。

# 2. 準備
## 必要なモノ
- Windows PC(母艦PC)
- Zedboard (Zynq-7020搭載)
- SDカード 4GB
- micro USBケーブル
- イーサネットケーブル

## 母艦PCにインストールしておくべきソフトウェア
- Win32DiskImager
 - SDにイメージの書き込みを行う  
- Tera Term
 - シリアル通信ができるものならばなんでもOK
- Xilinx ISE Design Suite 14.7
 - FPGAの回路の論理合成を行う

# 3. Xillinuxを使おう
Zynq上ではLinux(Ubuntu)を動作させ,なおかつFPGAとARMプロセッサをつなぐ
通信路が必要です。でも、どうやって実装するの？となりますが、心配ご無用。
なんと、[Xillybus社](http://xillybus.com)から**Xillinux**というFPGA―ARM間の通信が可能な、
Ubuntu OSとFPGAの回路が一緒になったディストリビューションが公開されているのです！！
しかも、試用版だったら無料なんです。なんともすばらしい。
ではこのディストリビューションにおいてどのようにデータをやり取りするか説明します。
## 3.1. FPGA－ARMプロセッサのデータのやり取り
![図1.png](https://qiita-image-store.s3.amazonaws.com/0/57052/124baba3-8ce3-b82e-0e09-50bb7c054c3d.png)

ARMプロセッサ側(ソフトウェア側)ではデバイスファイルを介してFIFOにアクセスし、データを送受信します。
また、FPGA側ではFIFOに対してリード/ライト信号を制御して任意のタイミングでデータの読み書きができます。
実際の実装では、このFIFOのインスタンスを自身のFPGAの回路に導入してデータのやり取りを行います。


# 4. ZedboardへのXillinuxの導入
さて、ここからどのようにXillinuxを導入するのか説明します。
まずFPGAの回路データとSDカードイメージをダウンロードします。
[FPGAの回路 (xillinux-eval-zedboard-1.3c.zip)](http://xillybus.com/downloads/xillinux-eval-zedboard-1.3c.zip)
[SDカードイメージ (xillinux-1.3.img.gz)](http://xillybus.com/downloads/xillinux-1.3.img.gz)

## 4.1. xillinux-1.3.imgをSDカードに書き込む
SDカードへのイメージ書き込みは時間がかかるのではじめにやっておきます。
Win32DiskImagerを起動して、ファイルは**xillinux-1.3.img**(解凍済み)を指定します。
![スクリーンショット 2015-07-23 16.05.03.png](https://qiita-image-store.s3.amazonaws.com/0/57052/3b3f6d8b-d4b5-d943-85f8-ee4d939beeb2.png)
「Write」を押してイメージの書き込みスタート！

## 4.2. 回路を生成する
この作業は少し大変です。まず、ダウンロードした**xillinux-eval-zedboard-1.3c.zip**を
解凍、展開してください。解凍したファイルの中身は以下のようになっていると思います。

```
xillinux-eval-zedboard-1.3c
 |--bootfoles : ブートファイル
 |--cores     : Xillybus IPのプリコンパイル済みのバイナリ
 |--runonce   : FIFOの回路データ
 |--system    : プロセッサ周りの配線データ
 |--verilog   : 回路のソースコード
 |--vhdl      : 回路のソースコード
 |--vivado-essentials : 回路のソースコード

```
### 4.2.1. CPU周りの配線
ここからはISEで回路を生成していきます。
まず、**runonce**に入っている**system.xmp**をダブルクリックしてXilinx Platform Studioを起動します。
そこで*Generate Netlist*をクリック
![図2.png](https://qiita-image-store.s3.amazonaws.com/0/57052/ae78f01a-99f5-d42f-430b-712116941043.png)

```
"XST completed"
Done!
```
のメッセージがコンソールに出たら終了です。
### 4.2.2. FIFOの生成
次は**runonce**の**runonce.xise**をダブルクリックします。
ISE Project Navigatorが起動します。
そのなかの**fifo_32x512**、**fifo_8x2048**、**vga_fifo**についてそれぞれ*Regenerate Core*をしてください。
![図3.png](https://qiita-image-store.s3.amazonaws.com/0/57052/26822e06-91c1-5ae0-9db1-85a1c470c169.png)

### 4.2.3. ビットストリームファイルの生成
2.1、2.2の作業が終わりましたら、次はいよいよ回路の論理合成です。
私は普段、開発にはverilogを使用しているので**verilog**フォルダを選びました。
ほかにもvhdl、vivadoによる合成もできるようです。
**verilog**の中の**xillydemo.xise**をダブルクリックするとISE Project Navigatorが起動します。
_Generate Programming File_をダブルクリックして論理合成を開始します。
![図4.png](https://qiita-image-store.s3.amazonaws.com/0/57052/1e034aa4-a1a0-a6e3-eb0c-e48a0cbe31a5.png)

## 4.3. SDカードへ必要ファイルを入れる
そろそろSDカードへのイメージ書き込みも終わっているでしょうか。
SDカードをPCに挿しなおし、エクスプローラーなどで中身を見てみると
**uImage**というファイルがあると思います。これがLinuxカーネルです。
さらにここへブートファイルと回路のビットストリームファイルを入れます。
まず、ブートファイルは**xillinux-eval-zedboard-1.3c**のなかの
**bootfiles**に入っています。なかには**boot.bin**と**devicetree.dtb**というファイルが入っていますので
それをどちらもSDカードへコピーしてください。
また、回路のビットストリームファイルですが、先ほど行っていた**xillydemo.xise**における
論理合成が終わると**verilog**フォルダのなかに**xillydemo.bit**というファイルが出来ているはずです。
これもコピーしてください。最終的には以下のようなファイル構成になります。

```
SD_card
|-uImage
|-boot.bin
|-devicetree.dtb
|-xillydemo.bit
*すべてファイル
```
これでSDカードに必要なファイルが整いました。

## 4.4. 起動しよう
さぁ、いよいよシステムの起動に移ります。
下記の写真を参考にしてUSBケーブル、イーサネットケーブル、SDカードを接続 or 挿入してください。
SDカードの向きには気をつけてください。また赤枠で囲まれている部分が写真と同じであることを確認してください。
![図5.jpg](https://qiita-image-store.s3.amazonaws.com/0/57052/84ebc9be-5b0e-ba05-bfee-f20182d9f9b0.jpeg)

接続し終わったらスイッチを入れましょう！
ディスプレイを接続すればなんとGUIもしっかり出ます！！感動！
![図6.jpg](https://qiita-image-store.s3.amazonaws.com/0/57052/7c156f3c-a0ce-3224-b792-166f91d3669f.jpeg)

# 5. シリアル接続の設定
Zedboardにキーボードを接続して操作もできますが、何かと不便なので
母艦PCからシリアル接続してコンソールで操作できるようにしましょう。
ZedboardとPCをUSB接続するためのドライバインストーラを[ここ](http://www.cypress.com/documentation/software-and-drivers/microsoft-certified-usb-uart-driver)からダウンロードしてください。ダウンロードにはユーザ登録が必要です。
無事インストールできたらコントロールパネルからは以下のように見えるはずです。
![図7.jpg](https://qiita-image-store.s3.amazonaws.com/0/57052/aa2130af-06a1-a3eb-04f1-7c1fdf3506e2.jpeg)
場合によってはCOMの番号は違うかもしれません。

(2015.8.21追記)
実は、ほかのユーザさんのブログなどを眺めていると
ドライバインストールだけだとうまくUART接続できないなんて人もいるようです。
実は僕も最初できませんでした。そういう時は
スタートボタン >  デバイスとプリンターを開いてください。
下に示すような状態になっていればOKです。もしなっていなければ
写真と違うほうのデバイスを右クリックして「トラブルシューティング」することで
私の場合は正しく動作しました。
![スクリーンショット 2015-08-21 18.42.43.png](https://qiita-image-store.s3.amazonaws.com/0/57052/f53f6a20-e3b2-bd2f-57a2-f93484082f64.png)


TeraTermを起動して設定 > シリアルポートから以下のように設定してください。
![図8.jpg](https://qiita-image-store.s3.amazonaws.com/0/57052/4bca7a5e-0388-fdcb-f25b-fe9ac897a4a9.jpeg)

設定を保存してTeraTermを再起動します。するとキーボード入力が可能となります。
![図9.jpg](https://qiita-image-store.s3.amazonaws.com/0/57052/752b6361-bdc6-293b-358c-7f3b48a3036c.jpeg)

# 6. ネットワーク設定
Ubuntuのネットワーク設定を行います。**/etc/network/interfaces**を
エディタで開き次のように設定します。
なお、固定IPを設定する場合は[ここ](http://linux40.hateblo.jp/entry/20071017/1192624156)を参照してください

```
auto lo
iface lo inet loopback

auto eth0
iface eth0 inet dhcp
```
もしプロキシを使用している場合は以下のコマンドでプロキシを設定してください。

```
export http_proxy="http://proxy.example.com:8080/"
export https_proxy="https://proxy.example.com:8080/"
export ftp_proxy="ftp://proxy.example.com:8080/"
export socks_proxy="socks://proxy.example.com:1080/"
```
また/etc/apt/apt.conf内に次の記述をしてください

```
Acquire::http::proxy "http://proxy.example.com:8080/";
Acquire::https::proxy "https://proxy.example.com:8080/";
Acquire::ftp::proxy "ftp://proxy.example.com:8080/";
Acquire::socks::proxy "socks://proxy.example.com:1080/";
```
# 7. リモートログインするための設定
リモートログインをするためにsshをインストールします。
まずは**apt-get update**してください。

```
apt-get update
```
その後、sshをインストールしましょう

```
apt-get install ssh
```
リモートログインするには先ほど開いたTeraTermを使用します。
ファイル > 新しい接続からTCP/IPを選択し、ホストアドレス(Zedboard側のアドレス)を指定してください。
OKを押すとリモートログインします。ログイン名とパスワードはどちらも**root**です。
![図10.jpg](https://qiita-image-store.s3.amazonaws.com/0/57052/87f701a7-3b01-649b-8d50-39bf492db87b.jpeg)

# 8. FPGA－ARMの通信をしてみよう
やっとここまできました。あとちょっとです。
FPGA－ARMの通信は前述したとおり、ARM側からデバイスファイルにアクセスしFIFOへデータをプッシュします。

現在、シリアル接続しているコンソールとリモートログインしているコンソールの2つがあるかと思います。
まずは両方のコンソールでホームディレクトリ下にある**xillybus/demoapps**に移動しましょう。
demoappsのなかにはサンプルプログラムが入っています。makeしましょう。

```
root@localhost:~# cd xillybus/demoapps/
root@localhost:~/xillybus/demoapps# ls
Makefile  fifo.c  memread.c  memwrite.c  streamread.c  streamwrite.c
root@localhost:~/xillybus/demoapps# make
gcc  -g -Wall -O3 memwrite.c -o memwrite
gcc  -g -Wall -O3 memread.c -o memread
gcc  -g -Wall -O3 streamread.c -o streamread
gcc  -g -Wall -O3 streamwrite.c -o streamwrite
gcc  -g -Wall -O3 -pthread fifo.c -o fifo
```
今回は**streamread**と**streamwrite**を使います。
- streamread：デバイスファイルから出てくるデータを読み込み、画面出力をする
- streamwrite：キーボードから入力された値をデバイスファイルへ書き込みをする

それぞれのコンソールで以下のコマンドを入力してください。リード側から起動してください。

コンソール1

```
root@localhost:~/xillybus/demoapps# ./streamread /dev/xillybus_read_32
#「32」を「8」にすると8bitのFIFOにアクセスできる
```
コンソール2

```
root@localhost:~/xillybus/demoapps# ./streamwrite /dev/xillybus_write_32
```
write側でキーボード入力をするとread側へその入力値が出力されます。
今回はFPGA側において、FIFOはユーザ回路をくっつけていない(なにも処理していない)ので
データはFIFOに入ったものがそのまま出てきているだけです。つまり、
ARM→FIFO→FPGA回路(今回は空)→FIFOのような順番でデータが流れています。

![図11.jpg](https://qiita-image-store.s3.amazonaws.com/0/57052/6f614654-02dc-d783-d673-38250b154576.jpeg)

write側から入力した値がreadにそのまま出力すれば通信成功です！！！！

# 9. おわりに
いや～お疲れ様でした。これでFPGA側では回路を実装し、FIFOと接続すれば
ソフトウェアとのデータのやり取りを行えます。まぁ、システムの実装はここからが大変なんですが…。
みんなでFPGAを用いたシステムの未来を切り開きましょう！！！


# 参考文献
- Xillybus Xillinux http://xillybus.com/xillinux
- 偏差値40からのLinux http://linux40.hateblo.jp/entry/20071017/1192624156
- [Getting started with Xillinux for Zynq-7000 EPP (PDF)](http://xillybus.com/downloads/doc/xillybus_getting_started_zynq.pdf)