第５回 PYNQのOverlayを作ってみた

## はじめに
第４回で、PSでbase overlay動かすところまではできたので、次のステップはカスタムoverlayをつくってみます。

第１回 [Setup PYNQ-Z1](https://qiita.com/0x20FE/items/9b5e8e7a51ac0d9eabbc)
第２回 [はじめてのJupyter](https://qiita.com/0x20FE/items/7fa2fa59c930c571f197)
第３回 [pythonとPYNQ PL資源へのアクセス](2019-08-15_FPGA_PYNQ_Python_zynq_2fbcf08ba9d29b2452be.md)
第４回 [PYNQ OVERLAY](2019-08-15_FPGA_PYNQ_Python_zynq_36755b7e5b60cfbfec87.md)
第５回 [PYNQのOverlayを作ってみた](https://qiita.com/0x20FE/private/81098851f8c8010ca2c8)
第６回 [カスタムIPを作ってPYNQ overlayに組み込む](2019-08-22_FPGA_PYNQ_zynq_ece9f0cc0340763dde61.md)
第７回 [PYNQのHDMI出力overlayを作る](2019-08-24_FPGA_PYNQ_zynq_820e68d300dd978ad21c.md)
番外編　[python ジャンプスタート](https://qiita.com/0x20FE/items/6f8b6d893b9c5c197c5b)
### 用語
PS	:Processing System 基本周辺回路を含むマイコン部分
PL	:Programmable Logic ユーザがプログラムできる回路
overlay :PLで作る周辺回路
base overlay : デフォルトの周辺回路

### 資料集
1) DIGLENT [PYNQ-Z1 リファレンスマニュアル](https://reference.digilentinc.com/reference/programmable-logic/pynq-z1/reference-manual) - まずはここ。Zynqから周辺機器の情報、結線まで。
2) DIGLENT [PYNQ-Z1](https://reference.digilentinc.com/reference/programmable-logic/pynq-z1/start) ここのDesign ResourceにMaster XDCとZynq Presetsがある
3) marseeさん FPGAの部屋[PYNQボード用PSの設定方法](http://marsee101.blog.fc2.com/blog-entry-3599.html)
4) @kamotsuruさん [PYNQ-Z1でカスタムIP作成してLEDチカ](https://qiita.com/kamotsuru/items/0a04bd696006880b4e68)

## PLの作成
### vivado web packのインストール
(手順省略)。
### ボード資源情報の入手
Zynq Presets（PYNQ-Z1のPLまわりの設定)を上記2)からダウンロードして解凍。
MasterXDC(制約ファイル)もダウンロードして解凍しておく。
### サンプルプロジェクトの作成
Zynqなどプロセッサ付きの開発では、IP Integratorベースで設計するのが定石かな。
marseeさんの記事 3)を参考にしながら、kamotsuruさんの記事 4) にそってやってみる。

1. プロジェクトを作る(略)
2. ここで開発対象とするFPGAまたはボード情報を選択しなければならない。vivado web packには、PYNQ-Z1のボード情報はないので、xc7z020clg400-1を選択して、あとから先ほどダウンロードしたボード資源情報を突っ込んでいく。

### IP Integratorを用いてブロックデザインを作成する。
IP Integratorを使うと、GUIをつかって、ハード部品(IP)のブロックを設定したりつないだりしてデザインを作ることができる。
#### Zynqの設定

2. ブロックデザインに、ご本尊のZynqを追加し、ダブルクリックし設定を加えていく。
3. まず、presetとして、先ほどダウンロードしたZynq Presetsファイルを適用する。これにより、PSの機能のうちPYNQ-Z1で実際に使用する機能がセットされる。
2. LEDにアクセスするには、AXIのGPIO（出力、つまりマスター)を使うが、presetでは、AXIのGPIOは設定されていない。そこで、Zynq BlockダイヤグラムのAXI Master Portをクリックして（メニュ-からPS-PL Configurationから選んでもよい)M AXI GP0にチェックをいれる
3. OK

#### Zynqのピンの接続
4. DDRやFIXED_IOを外に出す(Make External)。これらは接続PINが固定されているので「Run Block Automation」をクリックすると自動配線される。（端子を右クリックしてMake Externalとしてもよい）

DDRやFIXED_IOピンについては、Debuggin' Everyday [ZYBO で FreeBSD が動くまで (ハードウェア編)](http://yasu2.prosou.nu/blog/index.php/2015/03/26/zybo_freebsd/)の記事を参考にさせていただきました。

<!-- 長名先生かな -->

#### LEDを接続するGPIO追加
次にパラレルIO(GPIO)のインターフェースを追加します。marseeさんの3)を参考にします。ひきつづき、IP IntegratorのBLOCK DESIGNでの作業です。
1. 「＋」アイコン(Add IP)をクリックして、AXI GPIOを選択してブロックデザインに追加
2. 4bit幅に変更
2. AXIバスを接続するため、Run Connection Automationをクリックすると、接続対象がでてくる。
3. そのまま作業をすすめるとGPIO側まで自動でつなごうとするが、きまったピンはないので、あとで手作業でつなぐ。このため、GPIOのチェックをはずし、S_AXIのチェックだけ残し、OK。
4. AXI_GPIOブロックのGPIO側のピンを展開し、gpio_io_oを選択し、右クリックしてMake Externalを選択
5. でてきたgpio_io_oのポートを選択すると、Block_propertiesのウィンドウに、External Port Propertiesが現れるので、Generalタブを選択し、名前をledに変更。

#### validate Design
CRITICAL WARNING `PCW_UIPARAM_DDR_DQS_TO_CLK_DELAY_2 has negative value -0.009 ...`が２つでる。
Forumsの記事[Vivado critical warning when creating hardware wrapper](https://forums.xilinx.com/t5/Design-Entry/Vivado-critical-warning-when-creating-hardware-wrapper/td-p/762938)や[2017.2 - [PSU-1] critical warning with basic Zynq design on DDR interface](https://forums.xilinx.com/t5/Design-Entry/2017-2-PSU-1-critical-warning-with-basic-Zynq-design-on-DDR/m-p/789339/highlight/true#M14285) によれば、まあ気にしなくてもよいようです。

### Hardware wrapper作成

1. constraintに2)からダウンロードしたxdcファイルをcopy
2. xdcのledのエントリの先頭の＃をはずす
3. synthesisののちgenerate bitstreamを実行
4. 成功したら、`***.runs/impl_1/デザイン名_wrapper.bit`をとりだす。
4. Tcl Console のログ出力で、Generated を検索し、Generated Block Design Tcl fileのパスを調べて`sources_1_bd/design_1/hw_handof`にあるdesign_1_bd.tclを取り出す
5. PYNQのsmbに接続し、`¥¥pynq¥xilinx¥pynq¥overlays¥`に格納フォルダ(PQ001など）を作成し、前述のbitとtclをcopyしファイル名を同じにする。

## Juniper notebookスクリプトの作成
ここからは@kamotsuruさんの記事4)でやってみます。

```python:PLをインポート
from pynq import Overlay
from pynq import PL
OL = Overlay("/home/xilinx/pynq/overlays/PQ001/design_1.bit")
```

```python:GPIOの名前を確認
#OL.downoad()  # Overlayを作成した時点で自動ダウンロード
PL.ip_dict
```

```python:MemoryMapedIOでアクセス
from pynq import MMIO
mmio=MMIO(int(PL.ip_dict["axi_gpio_0"]['phys_addr']),4,True)
mmio.write(0,15)
```

```python:Lチカby@kamotsuruさん
import time
while(True):
    for i in range(16):
        mmio.write(0,i)
        time.sleep(0.5)
```

## まとめ
- 開発ツールはvivado webpack
- PYNQ-Z1固有データ(Zynq Presets,制約)をdigilentから取得
- vivadoを起動して、projectを作る。FPGAはxc7z020clg400-1を選択
- IP Integratorでzynqを配置し、Zynq Presetsをセット。AXI GPIOなどC使用するIOをチェック。
- AXI GPIOを配置し、配線
- 使用ピンのコメントをはずした制約を追加
- tclとbitをコピー
- pythonスクリプトを書く


つぎは@kamotsuruさんの記事4)を参考にして、カスタムIPをつくってみよう。