pynq祭りlt todotani
TRANSCRIPT
PYTHONからFPGA PLを操作する仕組みと自作OVERLAYの作成
PYNQ祭りLT
2017年3月4日@todotani
自己紹介
➤ @todotani(神谷 健司) ➤ 通信事業者(キャリア)向け通信システム関係のエンジニア
大型ルーター2000〜2013
NFV(仮想化)2014〜2015
3月から 某SDOに出向
(今ここ)
光通信(DWDM)2016
電話交換機1985〜1999
➤ 仕事の経歴
➤ 業務でハード開発を行ったことはなく、FPGAはまだ初心者 ➤ Arduino/mbedで電子工作をやってたのですが、 ➤ 2015年に右の本とDE0-CVを使って、
ARM命令が6個動くCPUを作ってFPGAの面白さに目覚める ➤ 大きめの回路でタイミング違反が発生するとうまく修正できません
(現状の壁)
私のFPGAボードコレクション
AZPR EvBOARDXilinx Spartan-3E搭載
書籍「CPU自作入門」にて使用するFPGA基板Verilogをちょっと動かしたがあまり活用せず
DE0-CVAltera Cyclone V搭載
書籍「ディジタル回路設計とコンピュータ・アーキテクチャー」のHDLを動かす為に活躍
➤ PYNQについてくる標準Overlay(FPGAのConfiguration)で画像の取り込みやOpenCVを使った画像処理とか色々できる
➤ だけど、出来合いの機能を使うだけでは、高価なRasPiになってしまう!! ➤ FPGAのReconfigurableな特徴を生かして、Linuxを動かしながらFPGAロジック
(Overlay)を自由に変更したい ➜ ということで、試してみました
PYNQ-Z1Xilinx ZYNQ搭載
Pythonを使ったプログラミング環境に興味が出て購入。本日のお題
ZYBOXilinx ZYNQ 搭載
初めてのSoC FPGA。開発環境がAlteraより使いやすくXilinxに転向。ネット情報も多い
PYNQのFPGA構成(ブロックデザイン)➤ PYNQの標準OverlayをVivadoで再現するとこんな感じになる
オンボードLEDやスイッチは➤ AXI-GPIOに繋がっています ➤ AXI-GPIOのI/OポートにデーターをWriteすることでLEDを点滅することができる
LEDGPIO
Lチカコードの例
Overlayをダウンロード
ip_dict表示
Lチカ実行
LEDがつながっているGPIOのアドレスが分かる
最新Imageでは出力形式が文字列から整数に変更された
Overlayを読み込む仕組み➤ PYNQ用に提供されているLinuxを起動すると、SMBサーバーも動くため、
macOS FinderやWindows Explorerでホームディレクトリのファルにアクセスができます
➤ /home/xilinx/pinkに各種ファイルが格納されています
➤ bitstream → Overlay(FPGAのbitstream)ファイル ➤ board → オンボードのswitch/LEDを操作するためのpythonスクリプト ➤ IOP → pmod/Arduinoコネクタに接続できる標準的なデバイスを操作するた
めのpythonスクリプト ➤ pinkディレクトリ直下にある、pl.pyを覗くとここで何かやってそう
pl.pyのコード
class Bitstream(PL): """This class instantiates a programmable logic bitstream. """
・・(中略)・・
def download(self): """The method to download the bitstream onto PL. """ # Compose bitfile name, open bitfile with open(self.bitfile_name, 'rb') as f: buf = f.read() # Set is_partial_bitfile device attribute to 0 with open(general_const.BS_IS_PARTIAL, 'w') as fd: fd.write('0') # Write bitfile to xdevcfg device with open(general_const.BS_XDEVCFG, 'wb') as f: f.write(buf)
Overlay(bitstream)の読み込み
OverlayをBS_XDEVCFGにライト
➤ BS_XDEVCFGの実態は、”/dev/xdevcfg”というデバイスファイル ➤ ここにbitstreamを書き込むとFPGAがconfigできるようだ
mmio.pyのコード(I/Oの制御)
class MMIO: """ This class exposes API for MMIO read and write. mem : mmap An mmap object created when mapping files to memory. """
def __init__(self, base_addr, length=4, debug=False): """ Return a new MMIO object. """ ・・・(中略)・・・
# Open file and mmap self.mmap_file = os.open(general_const.MMIO_FILE_NAME, os.O_RDWR | os.O_SYNC)
self.mem = mmap.mmap(self.mmap_file, (self.length + self.virt_offset), mmap.MAP_SHARED, mmap.PROT_READ | mmap.PROT_WRITE, offset=self.virt_base)
MMIO_FILE_NAMEの実態は/dev/mem
➤ Linuxのmmapを使ってGPIOのアドレスをマッピングしているようだ
カスタムOverlayの作成➤ AXI-GPIOにLEDを接続した最小限のブロックデザインを作成
mmapでアドレスを設定
/dev/xdevcfgとmmapを使って実験
動きました!!
Overlayをリード
Overlayをxdevcfgにライト
もうちょっとハイレベルな記述にしてみる➤ まずVivadoから、ブロックデザインをtclにエクスポートする ➤ ブロックデザインを開いて、「File > Export > Block Design..」を実行 ➤ 生成された、tclファイルをbitstreamファイルと同じディレクトリに格納する ➤ Overlayクラスのインスタンスを生成するとtclファイルがパースされて、GPIO
のアドレスを抽出してくれる
今回の構成では、GPIOの名称はSEG_axi_gpio_0_Reg
from pynq import MMIO from pynq import PL
LEDS_OFFSET0 = 0
class MyLED(object): """This class controls the onboard LEDs vi axi_gpio_0. """ _mmio = None _leds_value = 0
def __init__(self): """Create a new MyLED object. """ if MyLED._mmio is None: MyLED._mmio = MMIO(PL.ip_dict["SEG_axi_gpio_0_Reg"][0],16) MyLED._mmio.write(LEDS_OFFSET0, 0x0)
def set(self, value): """Turn on a LED """ MyLED._mmio.write(LEDS_OFFSET0, value)
MyLEDクラスを作成➤ SEG_axi_gpio_0_Regを使ってip_dictから、GPIOのアドレスを取得 ➤ MMIOクラスを使ってアドレスをマッピング
デバイスのアドレス
ハイレベル記述版のノートブック
まとめ➤ 単純なLチカですが、Linuxを動かした状態で、Overlayを
ダウンロードすることによって、ダイナミックにFPGAのコンフィグを変更できることが分かりました
➤ 必要に応じて独自の処理をFPGAに作り込んでオフロードできるので、RasPiでは絶対に真似できない柔軟性が得られる
➤ これは、なかなか画期的!! ➤ まだ、カスタムOverlayの作成にはFPGA開発のノウハウ
が必要ですが(HLSの高位合成なら少し敷居が下がる)、SDSoCと連携できるようになれば、ソフトエンジニアな方でも、カスタムOverlayが作れるようになるのでは
➤ ZYBOのように、PYNQのボード限定で安価なSDSoCのライセンスが来ないかしら
ありがとうございました