Vivado SDK でZynq FSBL(First Stage Boot Loader)をビルドするTclスクリプト

# はじめに

Xilinx 社のFPGA開発環境の Vivado SDK、いちいち GUI でマウスボタンをポチポチするのは面倒です。
Vivado SDK は Tcl スクリプトでバッチ処理が出来るので、決まり切った仕事なら Tcl スクリプトを書いて処理させたほうが楽です。
この記事では、Vivado SDK で Zynq の FSBL(First Stage Boot Loader)を自動的に生成するスクリプトを紹介します。

# 環境

 - Xilinx Vivado SDK 2015.4
 - Xilinx Vivado SDK 2016.4

ここで紹介する Tcl スクリプトは、Xilinx Vivado SDK 2017.1 以降では動作しません。Xilinx Vivado SDK 2017.1 で同様のことを行うには、[「Vivado SDK でZynq FSBL(First Stage Boot Loader)をビルドするTclスクリプト(hsi編)」](https://qiita.com/ikwzm/items/e09fab6b17986471cbda)を参照してください。

# 手順

## ハードウェアスペックファイルを用意しておく

この Tcl スクリプトではワークスペース(後述)の下にハードウェアスペックファイルを用意しておく必要があります。
通常は Vivado でインプリメンテーションした後、Export > Export Hardware... でハードウェアスペックファイルを作ります。
また、こちらの記事([Vivadoでハードウェア情報をエクスポートするTclスクリプト](http://qiita.com/ikwzm/items/057d67d4a9e0828663cf))も参考にしてください。

## Tclスクリプトを用意する

まずはスクリプト全体を示します。

````Tcl:build_fsbl.tcl
#!/usr/bin/tclsh

set app_name            "fsbl"
set app_type            {Zynq FSBL}
set bsp_name            "fsbl_bsp"
set hw_name             "design_1_wrapper_hw_platform_0"
set hwspec_file         "design_1_wrapper.hdf"
set proc_name           "ps7_cortexa9_0"
set project_directory   [file dirname [info script]]
set workspace           [file join $project_directory "project.sdk"]

if {[info commands sdk::setws] ne ""} {
    sdk::setws        $sdk_workspace
} else {
    sdk set_workspace $sdk_workspace
}

if {[info commands sdk::createhw] ne ""} {
    sdk::createhw         -name $hw_name -hwspec [file join $sdk_workspace $hwspec_file]
} else {
    sdk create_hw_project -name $hw_name -hwspec [file join $sdk_workspace $hwspec_file]
}

hsi::open_hw_design  [file join $workspace $hw_name "system.hdf"]
hsi::create_sw_design $bsp_name -proc $proc_name -os standalone
hsi::add_library xilffs
hsi::generate_bsp -sw $bsp_name -dir [file join $workspace $bsp_name] -compile
hsi::close_sw_design  $bsp_name

if {[info commands sdk::createapp] ne ""} {
    sdk createapp          -name $app_name -hwproject $hw_name -proc $proc_name -os standalone -lang C -app $app_type -bsp $bsp_name
} else {
    sdk create_app_project -name $app_name -hwproject $hw_name -proc $proc_name -os standalone -lang C -app $app_type -bsp $bsp_name
}

if {[info commands sdk::projects] ne ""} {
    sdk projects -build
} else {
    sdk build_project $app_name
}

exit
````

## Vivado SDK を実行する

Vivado SDK のバッチモードで前節の Tclスクリプトを実行します。
これでワークスペース(後述)の下の fsbl/Release に fsbl.elf が出来ていれば成功です。

````shell
Vivado% xsdk -batch -source build_fsbl.tcl
````

# Tclスクリプトの説明

## 各種定数を定義しておく

まずは様々な定数を定義しておきます。
この例ではハードウェアスペックファイルの名前を design_1_wrapper.hdf としていますが、実際には Vivado で Export した時のファイル名を設定します。

````Tcl:build_fsbl.tcl

set app_name            "fsbl"
set app_type            {Zynq FSBL}
set bsp_name            "fsbl_bsp"
set hw_name             "design_1_wrapper_hw_platform_0"
set hwspec_file         "design_1_wrapper.hdf"
set proc_name           "ps7_cortexa9_0"
````

## ワークスペースを設定する

Vivado SDK はワークスペースを設定する必要があります。
ここでは Tclスクリプトのあるディレクトリの下の project.sdk という名前のディレクトリをワークスペースとして設定します。
SDK 2016.1 あたりから set_workspace コマンドではなく setws コマンドを使うことが推奨されているので、setws コマンドが存在するならばそちらを使うようにしています。

````Tcl:build_fsbl.tcl
set project_directory   [file dirname [info script]]
set workspace           [file join $project_directory "project.sdk"]
if {[info commands sdk::setws] ne ""} {
    sdk setws         $sdk_workspace
} else {
    sdk set_workspace $sdk_workspace
}
````

## ハードウェアプラットフォームプロジェクトを作る

ここでワークスペースの下に事前に用意しておいたハードウェアスペックファイルを指定します。
SDK 2016.1 あたりから create_hw_project コマンドではなく createhw コマンドを使うことが推奨されているので、createhw コマンドが存在するならばそちらを使うようにしています。

````Tcl:build_fsbl.tcl
if {[info commands sdk::createhw] ne ""} {
    sdk createhw          -name $hw_name -hwspec [file join $sdk_workspace $hwspec_file]
} else {
    sdk create_hw_project -name $hw_name -hwspec [file join $sdk_workspace $hwspec_file]
}
````

## BSP(Board Support Package)プロジェクトを作る

BSPプロジェクトを作るにはちょっとしたコツ(~~というかVivado SDK のバグ回避？~~)が必要です。
本来なら、次のように create_bsp_project コマンドを使ってプロジェクトを作るのがスジなのですが、

````Tcl:build_fsbl.tcl
sdk create_bsp_project -name $bsp_name -hwproject $hw_name -proc $proc_name -os standalone
````

何故か Vivado SDK 2015.4(以前)のバージョンでは、次のフェーズのアプリケーションプロジェクト生成時に次のようなメッセージが出て失敗します。

````shell
BSP project 'fsbl_bsp' created successfully.
Specified template name 'Zynq FSBL' is not valid for configuration. Reason: This
 application requires xilffs and xilrsa libraries in the Board Support Package..
 List of valid names are Empty Application, Zynq DRAM tests, Peripheral Tests, H
ello World, Memory Tests, Dhrystone.
Failed to create Application project 'fsbl'.
Failed to create Application project fsbl.
    while executing
"error [dict get $msg err]"
    (procedure "xsdk_eval" line 15)
    invoked from within
"xsdk_eval $chan createProject "o{$fmt}" e [list $data]"
    (procedure "::xsdb::sdk::create_app_project" line 43)
    invoked from within
"sdk create_app_project -name $app_name -hwproject $hw_name -proc $proc_name -os
 standalone -lang C -app $app_type -bsp $bsp_name"
````

どうやら、xilffs と xilrsa というライブラリが無いと言っているようです。
ここで躓きましたが、[こちら(AR# 63384)](http://japan.xilinx.com/support/answers/63384.html)に解決策が載っていました。
次のように BSP(Board Support Package)プロジェクトに xilffs ライブラリを(強引に？)追加してやれば、上手くいくようです。

````Tcl:build_fsbl.tcl
hsi::open_hw_design  [file join $workspace $hw_name "system.hdf"]
hsi::create_sw_design $bsp_name -proc $proc_name -os standalone
hsi::add_library xilffs
hsi::generate_bsp -sw $bsp_name -dir [file join $workspace $bsp_name] -compile
hsi::close_sw_design  $bsp_name
````
create_bsp_project を使わずに、まずは create_sw_design でソフトウェアプロジェクトを作って xilffs ライブラリを追加してから generate_bsp で BSP(Board Support Package)プロジェクトを作るようです。

## アプリケーションプロジェクトを作る

create_app_project を使ってアプリケーション(Zynq FSBL)プロジェクトを作ります。
SDK 2016.1 あたりから create_app_project コマンドではなく createapp コマンドを使うことが推奨されているので、createapp コマンドが存在するならばそちらを使うようにしています。

````Tcl:build_fsbl.tcl
if {[info commands sdk::createapp] ne ""} {
    sdk createapp          -name $app_name -hwproject $hw_name -proc $proc_name -os standalone -lang C -app $app_type -bsp $bsp_name
} else {
    sdk create_app_project -name $app_name -hwproject $hw_name -proc $proc_name -os standalone -lang C -app $app_type -bsp $bsp_name
}
````

## FSBLをビルドする

build_project を使ってアプリケーション(Zynq FSBL)プロジェクトをビルドします。
SDK 2016.1 以降、build_project コマンドではなく projects -build コマンドを使用しなければなりません。

````Tcl:build_fsbl.tcl
if {[info commands sdk::projects] ne ""} {
    sdk projects -build
} else {
    sdk build_project $app_name
}
````

# 参考

- [Generating Basic Software Platforms Reference Guide UG1138(v2014.4) November 19,2014](http://www.xilinx.com/support/documentation/sw_manuals_j/xilinx2014_4/ug1138-generating-basic-software-platforms.pdf)
- [Using SDK Batch Mode](http://www.xilinx.com/support/documentation/sw_manuals/xilinx2014_3/SDK_Doc/concepts/sdk_c_batch_mode.htm)
- [AR# 63384 2014.4 - SDK - バッチ モードで SDK を使用する SDK プロジェクトの作成方法](http://japan.xilinx.com/support/answers/63384.html)
- [「VivadoをGUIを使わずに実行するためのTclスクリプト達」@Qiita](http://qiita.com/ikwzm/items/a0120079d2f7f86a5904)
- [「Vivado SDK でZynq FSBL(First Stage Boot Loader)をビルドするTclスクリプト(hsi編)」@Qiita](https://qiita.com/ikwzm/items/e09fab6b17986471cbda)
- [「Vivado(Vitis) で Zynq FSBL(First Stage Boot Loader) をビルドするTclスクリプト」@Qiita](https://qiita.com/ikwzm/items/165481921c3e984a9e70)