はじめに
以下の記事で、Xilinx社のZYNQやAltera社のCyclone V SoC などのFPGA+SoCでFPGAのロードと連携したLinuxをブートのシーケンスについて説明しました。
- 「FPGA+SoC+Linuxのブートシーケンス(概要編)」 @Qiita
- 「FPGA+SoC+Linuxのブートシーケンス(ZYNQ+Vivado編)」@Qiita
- 「FPGA+SoC+Linuxのブートシーケンス(ZYNQ+U-Boot-SPL編)」@Qiita
- 「FPGA+SoC+Linuxのブートシーケンス(Altera SoC+EDS編)」@Qiita
上記のいずれの場合も、FPGAのロードはLinuxのブート前に行うことを前提にしています。
しかし、最近のLinuxには Device Tree Overlay と FPGA Manager がサポートされています。次の記事にそれらを紹介しました。
Device Tree Overlay と FPGA Manager を使えば、Linux が起動した後にも FPGA のロードや Device Driver のロードを行うことができます。
この記事では、Device Tree Overlay と FPGA Manager を使ってLinux が起動した後、FPGAのロードする場合のシーケンスについて説明します。
なお、現時点での Linux の FPGA Manager と Device Tree Overlay のサポートは暫定的かつ限定的なもので、将来どうなるかは未だ不明な部分があることをご了承ください。
ブートシーケンス
図1 Device Tree Overlay+FPGA Managerの ブートシーケンス
・ステージ 0 (BootROM)
ZYNQのステージ0ブートローダーはSDCardの第一パーティションにFATファイルシステムがある場合、そこからBOOT.binを探します。もし見つかったらBOOT.binを作る際に[bootloader]オプションを付けたブロック(ここにはU-Boot-splが入っている)を内部RAMに転送して制御を移します。
Altera SoC のステージ0ブートローダー(BootROM)は、SD Cardの特殊パーティション(パーティションタイプ=0xa2)にあるpreloader imageを内部RAMに転送して制御を移します。
・ステージ 1 (U-Boot-spl)
ZYNQのステージ1ブートローダー(U-Boot-spl)はPSの各種設定やSDRAMの設定をした後、SDCardの第一パーティションにある u-boot.img をSDRAMに転送して制御を移します。
Altera SoCのステージ1ブートローダー(preloader)は、Hard Processor System(HPS)の各種設定(HPS I/O pin、Clock、Interconnect、Timer、UART、SDRAM)を行った後、SD Cardの特殊パーティション(パーティションタイプ=0xa2)にあるu-boot.imgをSDRAMに転送して制御を移します。
・ステージ 2 (U-Boot)
ステージ2ブートローダー(U-Boot)はスクリプトや環境変数などが使えるので、その設定にしたがって処理を実行できます。一般的には次の処理をスクリプトにします。
- Linuxのカーネルイメージ、Device Tree、場合によってはルートファイルシステムをSDRAMにロード
- ロードしたLinuxカーネルイメージに制御を移す
LinuxでFPGAをロードする場合、システムをリセットしてからFPGAが動作するまで時間がかかります。FPGAが外部のモジュール(例えばモーターなど)を制御している場合などはFPGAがロードするまで動作が不安定になることがあります。それを防ぐために仮のFPGAプログラムをロードする場合はこのステージで行います。
・ステージ 3 (Linux Boot)
Linuxカーネルの初期化シーケンスが起動します。カーネルに含まれているデバイスドライバが、メモリにロードされているデバイスツリーを参照しながら、各種ペリフェラルの設定と起動を行います。
・Linux 動作中
FPGA Manager を使ってFPGAのロードを行います。また、Device Tree Overlay を使ってデバイスツリーを動的に追加したりとりはずしたりします。
デザインフロー
下図にZYNQで、Device Tree Overlay と FPGA Manager を使って FPGA のロードを動的に行う場合のデザインフローを示します。
図2 ZYNQでDevice Tree Overlay と FPGA Manager を使う場合のデザインフロー
「FPGA+SoC+Linuxのブートシーケンス(ZYNQ+Vivado編)」や「FPGA+SoC+Linuxのブートシーケンス(ZYNQ+U-Boot-SPL編)」などで説明したデザインフローに比べて、かなりシンプルになっているのが判ります。特にFPGA側のデザインフローが U-BootやLinux のデザインフローと完全に独立しているため、FPGAのデザインを変更してもU-Boot や Linux起動用の Device Tree を新たに作り直す必要がありません。
1. VivadoでFPGAビットストリームファイル(.bit)を生成する
VHDLやVerilog-HDLなどで記述された回路をVivadoを使って論理合成と配置配線を行いFPGAビットストリームファイルを生成します。ここでは詳細な説明は省略します。
2. Vivadoでハードウェア情報ファイル(.hdf)をexportする
1.のFPGAビットストリームファイルを生成したプロジェクトから、ハードウェア情報ファイル(.hdf)をexportします。exportの手順に関しては「Vivadoでハードウェア情報をエクスポートするTclスクリプト」を参照してください。
4. Vivado SDKでハードウェア情報ファイル(.hdf)からDevice Tree を作る
Vivado SDKを使って、ハードウェア情報ファイル(.hdf)からDevice Tree を作ります。ここで作ったDevice Tree から、FPGAに実装したモジュールのレジスタアドレスの記述と割り込み関連の記述だけをメモしておきます。
また、モジュールのレジスタアドレスと割り込み番号が判るのであれば、ここでDevice Treeを作る必要はありません。
ここで得られた情報を元に、Device Tree Overlay 用の Device Tree を作ります。
5. U-Bootのソースからu-boot.img と BOOT.binを作る
U-Bootの最新のリポジトリからU-Bootをビルドします。ただし、U-Bootに若干の修正を加える必要があります。詳細は「ZYBO用U-Bootを、ブート時にuEnv.txtを読むようにして、かつBOOT.binから起動できるようにする」を参照してください。
最新の U-Boot では自動的にu-boot-splから BOOT.bin を作ります。
7. Linux Kernel Source から zImageとDevice Tree Blob(.dtb)を作る
Linux Kernelのソースコードを入手してビルドします。最近のLinux はZYNQやAltera SoC用のカーネルもビルドできるようになっています。
ビルドすると、Linux Kernelのイメージと同時に Linux Kernel を起動するための Device Tree Blob(.dtb)も生成されます。
FPGA用のDevice Tree は Linux 起動後に Device Tree Overlay で追加するので、ここでは Linux Kernel ビルド時に生成された Device Tree Blob をそのまま使います。
9. uEnv.txtを用意する
u-bootがブート時に実行するスクリプトを記述したファイルを用意します。ここではuEnv.txtを使いますが、u-bootには他にも専用のスクリプトファイルがあるので、そちらを使ってもかまいません。
ここではSDカードからPLのロードとLinuxをブートする場合の uEnv.txt の例を示します。SDカードの第一パーティションをFAT(VFAT)でファイルシステムを作り、5.で作ったBOOT.binとu-boot.img、7.で作ったzImage(Linuxカーネルイメージ)とdevicetree.dtb(デバイスツリーファイル)と、このuEnv.txtを置きます。SDカードの第二パーティションにはLinuxのルートディレクトリがあるものとします。
uenvcmd=fatload mmc 0 0x03000000 zImage && fatload mmc 0 0x02A00000 devicetree.dtb && bootz 0x03000000 - 0x02A00000
- fatload mmc 0 0x03000000 zImage
Linux Kernel のイメージファイル(zImage)をメモリの0x03000000にロード - fatload mmc 0 0x02A00000 devicetree.dtb
Device Tree Blob(ここではdevicetree.dtb)をメモリの0x02A00000にロード - bootz 0x03000000 - 0x02A00000
メモリの0x03000000にロードしたLinux Kernelと0x02A00000にロードしたDevice Tree Blob を使ってブート
10. SD Card の第1パーティション(FAT File System)にBOOT.bin、u-boot.img、zImage、Device Tree Blob(.dtb)、uEnv.txtを置く
SD Card の第1パーティションにFATで File System を作って以下のファイルを置きます。
- 5.で作ったBOOT.bin
- 7.で作ったLinux Kernelのイメージ(zImage)
- 7.で作ったDevice Tree Blob(.dtb)
- 9.で作ったuEnv.txt
参考
- FPGA+SoCのLinuxブートシーケンス(概要) @Qiita
- FPGA+SoC+Linuxのブートシーケンス(ZYNQ+Vivado編) @Qiita
- FPGA+SoC+Linuxのブートシーケンス(Altera SoC+EDS編) @Qiita
- FPGA+SoC+Linuxのブートシーケンス(ZYNQ+U-Boot-SPL編)@Qiita
- ZYBO用U-Bootを、ブート時にuEnv.txtを読むようにして、かつBOOT.binから起動できるようにする @Qiita
- FPGA+SoC+LinuxでDevice Tree Overlayを試してみた @Qiita
- FPGA+SoC+LinuxでFPGA Managerを試してみた @Qiita
- 「FPGA マガジンNo.12」, CQ出版社
- 「Debian Linux on Zynq Setup Flow Version March 2016 for VIvado 2015.4」