はじめに
Vivado HLSを使うと、C/C++で記述したアルゴリズムを高位合成 (HLS)し、FPGAで利用可能なカスタムIPコアとして生成できます。Zynqデバイス(ARMプロセッサ + FPGA)では、この自作IPをVivadoのIPカタログに登録し、ブロックデザイン (IP Integrator) 上で組み込むことで、プロセッサと連携したシステムを構築できます。この記事では、自分向けの備忘録のメモを少し広げて、なるべくVivado HLSでのIPコア作成からVivadoプロジェクトへの取り込み、ブロックデザインへインスタンス化する一連の手順が伝わるようにと、京都大学の鈴木先生のTclスクリプトをベースに解説します。特に、Tclスクリプト(例:dds_hls.tcl
)内のcreate_bd_cell
やlatest_ip
といったコマンドの意味を中心に、初心者にも分かりやすく説明します。
この記事の流れ:
-
Vivado HLSでC++からIPを生成 – C++デザイン(例:
dds_hls.cpp
)を高位合成し、Vivado用のIPにパッケージ化 - VivadoへIPを登録 – 生成したIPをVivadoのIPカタログに追加
- ブロックデザインにIPをインスタンス化 – Tclスクリプトを用いてIPをブロックデザイン上に配置し、設定や接続を行う
-
主要なVivado Tclコマンドの解説 –
create_bd_cell
やget_ipdefs
、set_property
などIP統合に使われるコマンドの使い方 - トラブルシューティング – 「No Catalog IPs found」といったエラーへの対処やVLNV不一致の問題解決
はじめての人でも雰囲気がわかるように、順を追った解説とコード例、ディレクトリ構成の例などを示します。要点は箇条書きやコードブロックで整理し、リファレンスも適宜引用します。まずは、高位合成IPをブロックデザインで利用する手順を見ていきましょう。
(この記事は、下記の記事のような超伝導遷移端検出器などの超伝導デバイスの読み出しにRFSoCを使うことを想定しています。)
基本的な流れの確認
Vivado Tcl フロー全体像(典型的な手順)
ステップ | 目的 | 主なコマンド例 |
---|---|---|
1️⃣ プロジェクト作成 | プロジェクト環境の初期化 | create_project |
2️⃣ ソース追加 | HDL/BDソースの追加 |
add_files , import_files
|
3️⃣ ボード or デバイス指定 | ターゲット FPGA を設定 |
set_part , set_property board_part ...
|
4️⃣ ブロックデザイン作成 | IP構成と接続を GUI / Tcl で定義 |
create_bd_design , create_bd_cell , connect_bd_net
|
5️⃣ デザイン保存と検証 | BDの整合性確認 |
validate_bd_design , save_bd_design
|
6️⃣ ラッパー生成 | RTLに変換 |
make_wrapper -files [get_files system.bd] -top , add_files
|
7️⃣ トップモジュール設定 | 合成対象のトップを指定 | set_property top <top_module_name> [current_fileset] |
8️⃣ 合成実行 | HDL → ネットリスト変換 |
launch_runs synth_1 , wait_on_run synth_1
|
9️⃣ インプリメンテーション実行 | 配置配線(P&R) |
launch_runs impl_1 , wait_on_run impl_1
|
🔟 ビットストリーム生成 | 最終FPGA用ファイル | launch_runs impl_1 -to_step write_bitstream |
✅ 完了後ファイル出力 | Bitファイルなどを取得 |
file copy , report_* 系 |
create_project → add_files / BD構築 → validate/save_bd_design
→ make_wrapper → set top → synth → impl → write_bitstream
この順序が基本となります。これを意識すれば、Vivado Tcl による自動化・再現性の高い設計フローの理解を進めましょう。
Vivado HLSでC++デザインをIPコアに高位合成する
まずはC++で書かれたアルゴリズムをVivado HLSでIPコア化する手順です。例として、Direct Digital Synthesizer (DDS) を実装したdds_hls.cpp
を用いると仮定します。Vivado HLSのGUIを使う場合、Projectを作成してソースを追加し、Run C Synthesisを実行した後、Export RTLを選択してIP化します。Export RTLを行うことで、高位合成結果がVivadoで利用可能なIPとしてパッケージ化されます。
例えばVivado HLS GUI上では以下の順序になります:
- Cシミュレーションやデバッグ (必要に応じて)
- Run C Synthesis (C/C++をRTLに合成)
- Export RTL (合成したRTLをIPパッケージとして出力)
GUIを使わずバッチ処理で行う場合、Vivado HLSはTclスクリプトで同様の操作が可能です。Vivado HLSのコマンドライン (vitis_hls
) からtcl
スクリプトを指定して実行できます(例:vitis_hls -f dds_hls.tcl
)。dds_hls.tcl
内では、プロジェクト作成から合成・IPエクスポートまでのコマンドが順番に呼ばれているはずです。以下はVivado HLS用Tclスクリプトの一例です(実際の内容に合わせて読み替えてください):
# Vivado HLS Tcl スクリプト例
open_project dds_hls ;# プロジェクト名を指定してオープン/新規作成
set_top dds_top ;# 合成するトップ関数名を指定 (例: dds_top)
add_files dds_hls.cpp ;# 高位合成するC++ファイルを追加
open_solution -reset solution1 -flow_target vivado
set_part {xc7z020clg400-1} ;# Zynqなどターゲットデバイスを設定
create_clock -period 10 -name default
csynth_design ;# C合成を実行
# cosim_design ;# (必要なら)C/RTL協調シミュレーション
export_design -format ip_catalog -rtl verilog -output "./solution1/impl/ip"
exit
上記は簡略化した例ですが、ポイントは最後のexport_design -format ip_catalog
です。-format ip_catalog
オプションにより、Vivado IPカタログに追加可能な形式でRTLがパッケージ化されます。export_design
にはオプションでVendorやLibrary、Name、VersionといったVLNV情報を指定することもできます。指定しない場合、デフォルトではVivado HLSプロジェクト名や関数名等から自動設定されます。例えば上記スクリプトでは-output
に"./solution1/impl/ip"
ディレクトリを指定しており、その中にIPが出力されます。デフォルトVendorはxilinx.com
、Libraryはhls
、Versionは1.0
になるケースが多いです(Vivado HLS GUIでExportする際に変更可能)。
高位合成が成功すると、プロジェクトのディレクトリにIPパッケージが生成されます。標準的には、<project_name>/solution1/impl/ip
以下にIPコア用のフォルダが作られ、その中にcomponent.xml
(IP定義ファイル)やHDLファイル、xciファイル等が含まれます。例えばdds_hls
プロジェクトの場合、以下のような構成になります(フォルダ名やファイル名はプロジェクト設定によって異なります):
dds_hls/solution1/impl/ip/
└── dds_hls_1.0/
├── component.xml # IPコアのメタデータ (VLNV やポート定義など)
├── synth/ # 合成されたHDL等
├── sim/ # シミュレーションモデル等 (あれば)
└── example_design/ # サンプルデザイン (オプション)
このようにVivado HLSでC++からIPが生成できました。次は、このIPをVivadoのプロジェクトで使用するための手順に移ります。
VivadoプロジェクトにHLS IPを統合する(IPカタログへの登録)
VivadoでカスタムIPを使うには、まずそのIPをVivadoのIPカタログに認識させる必要があります。Vivado GUIの場合、プロジェクトを開きFlow NavigatorのIP Integrator -> Create Block Designでブロックデザインを作成した後、空白部分で右クリックしてIP Settingsを開き、Repositoryに先ほどのIPフォルダを追加します。具体的には、Repositoriesリストで「+」ボタンを押し、先ほどVivado HLSが出力したsolution1/impl/ip
ディレクトリをパスとして追加します。するとVivadoがそのフォルダをスキャンし、中のcomponent.xml
を読み取ってIPカタログに登録します。GUI上では、solution1/impl/ip
を追加して「Select」すると検出されたIPの一覧(今回の場合自作IPひとつだけ)が表示されるのでOKします。これでIPカタログに自作IPが加わり、ブロックデザイン上でAdd IPから選択できるようになります。
Tclスクリプトで同様の操作を行う場合は、プロジェクトに対してip_repo_paths
プロパティを設定し、その後にupdate_ip_catalog
コマンドでカタログを更新します。例えば以下のように記述します:
# プロジェクトにローカルIPリポジトリを追加するTcl例
set_property ip_repo_paths "./dds_hls/solution1/impl/ip" [current_fileset]
update_ip_catalog
上記ではcurrent_fileset
に対してIPリポジトリのパスを設定しています(current_project
でも類似の効果がありますが、Vivadoの仕様上current_fileset
推奨)。update_ip_catalog
を呼ぶことで即座にカタログが更新され、追加したディレクトリ以下のcomponent.xml
を探してIP定義を読み込みます。実際、VivadoのTclスクリプトテンプレートでは以下のようにチェックして追加するコードが含まれています:
if {[info exists ip_repo_path_list] && [llength $ip_repo_path_list] > 0} {
set_property ip_repo_paths $ip_repo_path_list [current_fileset]
update_ip_catalog
}
この部分は、リポジトリパスのリストip_repo_path_list
に要素があれば、それらをプロジェクトに登録している例です。
以上でVivadoのIPカタログに自作IPが登録されました。登録が成功していれば、Tools -> IP Catalog
から自作IP(例えばdds_hls
など)を検索して一覧に出てくるはずです。次はいよいよ、このIPをブロックデザインに組み込んでみましょう。
ブロックデザインにIPを追加してシステムに組み込む
VivadoでZynq向けシステムを設計する際は、IP Integratorのブロックデザイン上で各種IPを配置し相互接続します。ここでは自作したHLS IPコアをブロックデザインにインスタンス化し、必要に応じて他のブロック(Zynq MPSoCやAXIインターコネクトなど)と接続する流れを説明します。Tclスクリプトで自動化する場合のコマンドに着目しつつ、ポイントを解説します。
ブロックデザインの作成 (GUI と Tcl)
GUIでは、Flow NavigatorのIP IntegratorからCreate Block Designを選び、新しいブロックデザイン(例: design_1)を作成します。Tclではcreate_bd_design
コマンドを使用して同様にブロックデザインを新規作成できます。例えば:
create_bd_design "design_1"
とすることで、design_1
という名前のBD (Block Design) が作られます。Note: 既にGUI上でBlock Designを作成済みの場合、Tclスクリプト内で改めてcreate_bd_design
する必要はありません。
カスタムIPのインスタンス化 – create_bd_cell
コマンド
自作IPをブロックデザインに追加するには、GUIなら「Add IP」から該当IPを選択しますが、Tclではcreate_bd_cell
コマンドを使います。このコマンドはVivado IPカタログからIPをブロックデザイン上にインスタンス化する役割を持ちます。基本的な構文は以下のとおりです:
create_bd_cell -type ip -vlnv <Vendor:Library:Name:Version> <インスタンス名>
-
-type ip
オプションでIPコアを追加する指定をします(省略時も既定でIP扱いですが-vlnv
指定が必要) -
-vlnv
に続けて、追加したいIPのVLNV(Vendor:Library:Name:Version)を指定します - 最後にブロックデザイン上でのインスタンス名を指定します(任意の名前。GUIでAdd IPした際につくデフォルト名に相当)
例えば、AXI FIFO IPコアを追加する場合は次のようになります:
create_bd_cell -vlnv xilinx.com:ip:axi_fifo_mm_s:4.0 axi_fifo_1
上記では、xilinx.com:ip:axi_fifo_mm_s:4.0
というVLNVのIP (AXI FIFO Memory Mapped Stream, Version 4.0) をaxi_fifo_1という名前でBDに追加しています。-type ip
はデフォルトなので省略されています。このように、カタログ上の既存IPはVLNVを完全指定することで直接インスタンス追加可能です。
では、自作のHLS IPの場合はどうでしょうか。HLSでエクスポートしたIPにもVLNVが割り当てられています。デフォルトではVendorはxilinx.com
、Libraryはhls
、Nameはトップ関数名やHLSプロジェクト名、Versionは1.0
になっていることが多いです。仮に我々のDDS IPのVLNVがxilinx.com:hls:dds_hls:1.0
だった場合、次のように追加できます:
create_bd_cell -type ip -vlnv xilinx.com:hls:dds_hls:1.0 dds_hls_0
ここではインスタンス名をdds_hls_0
としました。このコマンドが実行されると、VivadoはIPカタログから該当VLNVのIPコアを探し出し(事前にIPカタログに追加済みであることが前提です)、ブロックデザイン上に配置します。配置されたIPは[get_bd_cells dds_hls_0]
のように参照可能で、他のIP同様、GUI上にもブロックが現れます。
latest_ip
を使ったIPバージョン指定の動的化
🔍 latest_ip
Tcl 関数の意味と用途
proc latest_ip {i_ip} {
return [get_ipdefs -all -filter "VLNV =~ *:${i_ip}:* && \
design_tool_contexts =~ *IPI* && UPGRADE_VERSIONS == \"\""]
}
これは Vivado の IP Catalog から、指定した IP 名に一致する 最新バージョンの IP を探して返す ユーザー定義関数です。
🧠 各構文の意味を解説
構文 | 意味 |
---|---|
proc latest_ip {i_ip} { ... } |
Tcl関数latest_ip の定義。引数は1つ i_ip (IPの名前) |
get_ipdefs |
Vivadoで登録されたIP定義(VLNV)を取得するコマンド |
-all |
非表示のものも含め、すべての IP を対象に検索 |
-filter "..." |
条件式でフィルタ。ここが肝です。 |
VLNV =~ *:${i_ip}:* |
IPの名前に i_ip が含まれるものを探す(VendorとVersionはワイルドカード) |
design_tool_contexts =~ *IPI* |
Vivado のブロックデザイン用に作られた IP(IPI)に限定 |
UPGRADE_VERSIONS == "" |
アップグレード可能な旧バージョンを除く(最新バージョンのみ) |
🧩 使用例
set dds_hls [create_bd_cell -type ip -vlnv [latest_ip dds_hls] dds_hls]
上記のように使うと、
-
latest_ip dds_hls
が IP カタログの中からdds_hls
という名前に一致する 最新の IP の VLNV(Vendor:Library:Name:Version) を返す。 - それを
create_bd_cell
に渡すことで、ブロックデザイン上に IP を配置する。
🔁 置き換え可能な手動操作
この latest_ip
がなくても、代わりに明示的に VLNV を書けば動作します:
create_bd_cell -type ip -vlnv user.org:user:dds_hls:1.0 dds_hls
ただし、バージョンが将来変わるとこの方法では古いIPを指定してしまう可能性があるため、latest_ip
は非常に便利な補助関数なのです。
✅ まとめ
関数 | 用途 |
---|---|
latest_ip dds_hls |
IP Catalog の中から dds_hls という名前を含む 最新の IP VLNV を取得する |
create_bd_cell -vlnv ... |
指定した IP をブロックデザインにインスタンスとして追加する |
latest_ip
は、複数のプロジェクト・複数人開発環境で IPのバージョンが自動で追従されるため、特にチーム開発やスクリプト自動化で役立ちます。
latest_ip
は単独のVivadoコマンドは存在しません。これは**ユーザー定義のTclプロシージャで、VivadoのTcl出力スクリプトが生成する便宜上の関数名です。
に定義されています。
get_ipdefs
コマンドは、IP定義を検索し、最新バージョンをフィルタで取得することです。get_ipdefs
は現在プロジェクトで利用可能なIP定義を取得するコマンドで、-filter
オプションでプロパティに基づく絞り込みが可能です。例えば、名前に"axi"を含むIPを探す場合:
get_ipdefs -filter {NAME=~*axi*}
NAME=~*axi*
はDISPLAY_NAME(表示名)に"axi"が含まれるIPをゆるくマッチします。他にもIS_AXI==1
とすればAXIインターフェイスを持つIPに限定できます。
そして複数バージョンのIPが存在する場合、UPGRADE_VERSIONS
プロパティが空文字列かどうかで最新かどうかを判別できます。UPGRADE_VERSIONS
が空("")のIP定義は、それより新しいバージョンが存在しない=最新バージョンであることを意味します。従って、「最新バージョンのIP定義」を取得するには以下のようなフィルタが使えます:
get_ipdefs -all *dds_hls* -filter {UPGRADE_VERSIONS == ""}
上記では名前やVLNVにdds_hls
を含むIPを-all
(ユーザーIPも含め全カタログ対象)で探し、その中からアップグレード先がない(最新である)ものを取得しています。-all
オプションを付けているのは、Vivado標準IPカタログだけでなくプロジェクト追加IP(IP Integratorカタログ)も対象に含めるためです。get_ipdefs
はデフォルトではVivadoインストール済みの標準IPのみ検索しますが、-all
を指定するとユーザー追加IPも検索対象に含められます。
要するに、**create_bd_cell -vlnv [latest_ip ...] ...
**という記述は、「指定IPの最新バージョンを自動選択してセル生成する」ための工夫だと理解できます。スクリプトを読む際は、まずlatest_ip
がどのように定義されているか(proc latest_ip { ... } { ... }
のような記述が前後にないか)確認すると良いでしょう。
IPパラメータの設定 – set_property
コマンド
IPをブロックデザインに追加した直後は、IPはデフォルト設定のままです。必要に応じてパラメータを設定することで、IPの挙動や接続を調整します。Vivadoではset_property -dict
を用いてIPインスタンスのパラメータをまとめて設定できます。例えば、Block Memory Generator IPを「True Dual Port RAM」に設定する場合や、AXI BRAM Controllerを生成する場合のTclスクリプト例は以下の通りです:
set bmgName bmg_0
set bmg [create_bd_cell -type ip -vlnv xilinx.com:ip:blk_mem_gen:8.4 $bmgName]
set_property -dict [list \
CONFIG.Memory_Type {True_Dual_Port_RAM} \
CONFIG.Assume_Synchronous_Clk {true} \
] $bmg
set axiCtrlName axi_bram_ctrl_0
set axiCtrl [create_bd_cell -type ip -vlnv xilinx.com:ip:axi_bram_ctrl:4.1 $axiCtrlName]
上記では、まずBlock Memory Generator (blk_mem_gen) IPをbmg_0
として追加し、続いてset_property -dict
でそのIPオブジェクト$bmg
に対して複数のCONFIGプロパティを設定しています。CONFIG.Memory_Type
やCONFIG.Assume_Synchronous_Clk
などはUG付きマニュアルに記載のIPパラメータ名です。set_property -dict [list ...] <オブジェクト>
の形式で、一度に複数のプロパティをディクショナリ形式で適用できます。例えばHLSから生成されたIPで、カスタムのパラメータ(例えばデータ幅や係数など)があれば、同様にCONFIG.<パラメータ名>
で設定可能です。
HLS由来のIPの場合、AXIハンドシェイク等の制御方式によっては 制御インターフェイス (S_AXI) を持つものもあります。たとえばトップ関数に#pragma HLS INTERFACE s_axilite
がある場合、生成IPにはAXI Liteのコントロールレジスタが実装され、C_S_AXI_CONTROL_BASEADDR
などのパラメータが設定されています。そのようなパラメータもset_property
で変更可能ですが、通常デフォルトの0x4000_0000などが使われ、そのままで問題なければ手を加える必要はありません。いずれにせよ、特定のIPが持つ設定項目を知りたいときは、Vivado GUIでそのIPをダブルクリックして設定画面を見るか、report_property -all [get_bd_cells <インスタンス名>]
コマンドで可能なプロパティ一覧を出力すると良いでしょう。
IPの接続 – connect_bd_net
と connect_bd_intf_net
IPを追加しただけでは回路は完成しません。ZynqのようなプロセッサIP や他のIPとポートを接続する必要があります。Vivadoでは、スカラーの端子(1ビット信号やクロック、リセット線など) はconnect_bd_net
コマンドで、**バスインターフェイス(AXIやストリームなど)**はconnect_bd_intf_net
コマンドで接続します。
例えば、前述のAXI BRAM Controller (axi_bram_ctrl_0
)のBRAMポートと、Block Memory (bmg_0
)のBRAMポートを接続するには:
connect_bd_intf_net [get_bd_intf_pins $axiCtrlName/BRAM_PORTA] [get_bd_intf_pins $bmgName/BRAM_PORTA]
connect_bd_intf_net [get_bd_intf_pins $axiCtrlName/BRAM_PORTB] [get_bd_intf_pins $bmgName/BRAM_PORTB]
このように、get_bd_intf_pins <セル名/ポート名>
でインターフェイスピンを取得し、二つをconnect_bd_intf_net
で結びます。クロックやリセットのような普通のポート(スカラー信号)の場合はget_bd_pins
でピンを取得しconnect_bd_net
でつなぎます。
Zynqを含むシステムの場合、自作IPのAXIインターフェイス(例えばAXI4-StreamやAXI4-Lite)をZynq PSの対応するマスター/スレーブポートに接続する必要があります。Tclスクリプト上では、PS部分もcreate_bd_cell -type ip -vlnv xilinx.com:ip:processing_system7:5.5 ps_0
のように追加し(バージョンは適宜)、connect_bd_intf_net ps_0/M_AXI_HPM0_FPD <-> dds_hls_0/S_AXI
のように接続します。具体的な接続方法はIPの種類や目的によって異なりますが、クロックおよびリセットは必ず自作IPに供給する必要があります。AXI系IPなら、AXIインターフェイス同士をつなぎ、アドレスマップも設定します(後述)。
アドレスマップの設定(必要な場合)
AXI Liteのコントロールポートなどアドレス空間を持つIPをZynq PSに接続した場合、アドレスエディタでPSのマスター空間上にスレーブ側のアドレス範囲を割り当てる必要があります。Vivado GUIではBlock Design編集画面上のAddress Editorタブで操作できますが、Tclではassign_bd_address
コマンドで自動割り当てができます。例えば:
assign_bd_address [get_bd_addr_segs ps_0/Data/SEG_dds_hls_0_Reg]
のように、PSのアドレス空間に自作IP(例ではdds_hls_0
)のレジスタマップ領域を割り当てることができます(実際のパスや名前は環境により異なります)。割り当て後、set_property range 0x10000 [get_bd_addr_segs ps_0/Data/SEG_dds_hls_0_Reg]
といった具合に範囲やオフセットを変更することも可能です。アドレスマップ設定は少し難しい部分なので、GUIで一度割り当ててからExport Block DesignでTclを確認するとよいでしょう。
ブロックデザインの検証と保存
IPを追加し、パラメータ設定や接続が完了したら、デザインの検証と保存を行います。Vivadoではvalidate_bd_design
コマンドで接続や設定に不備がないかチェックでき、save_bd_design
でブロックデザインを保存できます。検証では、未接続ポートや不適合な接続があるとエラー/警告が表示されます。特にクロックやリセットの接続忘れに注意してください。
最後にgenerate_target
やcreate_hw_design
などでHDLラッパーの生成、合成・Implementationを行えば、ビットストリーム生成までたどり着けます(これらは本記事の範囲外なので割愛します)。
Vivado Tcl主要コマンドのまとめと解説
上記手順で登場したVivado Tclコマンドについて、要点を整理します。スクリプトを読み解く際の参考にしてください。
-
create_project: Vivadoプロジェクトを作成するコマンドです。引数にプロジェクト名、ディレクトリ、ターゲットデバイス/ボードなどを指定します。
-part
や-board
オプションでターゲットFPGAを設定できます。例:create_project myproj ./myproj -part xc7z020clg400-1
。プロジェクト作成後、current_project
でプロジェクトオブジェクトを参照できます。 -
set_property ip_repo_paths: カスタムIPの検索パスをプロジェクトに設定します。複数のディレクトリをリスト形式で指定可能です。指定後は
update_ip_catalog
を忘れずに実行します。例:set_property ip_repo_paths [list "./ip_repo" "/home/user/myIPs"] [current_fileset]
。なお、一度Vivadoを起動している間はこの設定がキャッシュされるため、スクリプトをやり直す際はプロジェクトを再作成/削除するか、update_ip_catalog
でリフレッシュしてください。 -
update_ip_catalog: 上記のように追加したIPリポジトリをスキャンし、IPカタログを更新します。実行後、
get_ipdefs
で追加IPが取得可能になります。 -
create_bd_design: 新規ブロックデザインを作成します。名前を引数に指定して呼び出します。既にデザインが存在する場合は上書きされるため注意してください。
-
create_bd_cell: IPやモジュールをブロックデザインに追加するコマンドです。
-type
にip
を指定し、-vlnv
にIPのVLNV文字列を与えて使用します。戻り値として作成したcellオブジェクト(インスタンス)の参照が得られます。例えばset my_ip [create_bd_cell -type ip -vlnv vendor:lib:name:ver inst_0]
のように使い、後続のset_property
で$my_ip
を指定することでそのIPに対する設定が可能です。 -
get_ipdefs: IPカタログ内のIP定義を取得します。
-filter
や-name
で検索可能。引数なしで呼ぶと大量のIPリストが返ってくるため、通常は何らかのフィルタを使います。カスタムIPを取得するには、-all
オプションを付けてユーザーIPまで含めることを忘れないでください。例えばget_ipdefs -all xilinx.com:hls:dds_hls:*
とすると、カタログ中のxilinx.com:hls:dds_hls
という名前のあらゆるバージョンのIP定義が取得できます。そのリストから特定要素(最新など)を選んで使う、という手法が考えられます。 -
set_property -dict: オブジェクト(IPインスタンス等)のプロパティを一括設定します。
-dict [list KEY1 VALUE1 KEY2 VALUE2 ...]
の形式で渡し、最後に対象オブジェクトを指定します。IPのパラメータ設定によく使われ、キー名にはCONFIG.<パラメータ名>
またはPARAMETER.<パラメータ名>
(IPごとに異なる)を指定します。複数設定する場合も一回のset_property
でまとめて記述できるため便利です。また、ボード周辺の設定(例: M_AXI GPポートのクロック接続先など)にもCONFIG
プロパティがありますので、IPを追加したら必要に応じてCONFIG
項目を確認しましょう。 -
connect_bd_net / connect_bd_intf_net: ブロックデザイン上のネット(配線)を接続するコマンドです。前者はクロック・リセット・割り込み線などの1ビット~複数ビットのスカラーポート接続に、後者はAXIやストリーム等のバスインターフェイス接続に使います。使用する際は
get_bd_pins
またはget_bd_intf_pins
で、それぞれ接続したいピン(ポート端子)を取得してから渡します。例えば、connect_bd_net [get_bd_pins ip1/clk] [get_bd_pins ip2/clk]
とすればip1
とip2
のクロックピンを同じネットに接続します。同一ネットに複数ピンをぶら下げる場合は、連続してconnect_bd_net
で同じネット名に繋ぐか、一度に複数ピンをリストで渡すこともできます。インターフェイス版も同様です。VivadoのExport Block Design機能で生成されたTclを見ると、これらの接続コマンドが多数並んでいるはずです。 -
assign_bd_address: アドレス空間の自動割り当てを行います。SoC設計ではPS側のマスターアドレス空間に各IPのスレーブ領域をマップする必要がありますが、手動で
set_property offset
等を設定する代わりに、このコマンドで自動的に未使用領域に割り当てられます。使用方法は少し分かりにくいですが、引数に[get_bd_addr_segs <マスター名/アドレス空間名/SEG_IPNAME_BaseName>]
という形でアドレスセグメントオブジェクトを指定します(SEG_~はVivadoが内部管理する名前)。割り当て後にget_bd_addr_segs
で得られるオブジェクトに対しrange
やoffset
プロパティをset_property
で設定することで、サイズ変更や開始アドレスの調整が可能です。このあたりは必要に応じVivadoのUG (IPIユーザーガイド UG895等)を参照してください。 -
validate_bd_design: ブロックデザインの整合性チェックを行います。未接続ポートがある、パラメータ不整合がある、クロックやリセットが未配置などの場合にエラー/警告を出します。スクリプトの最後に実行し、戻り値やメッセージを確認することで自動化時の問題検出ができます。
-
save_bd_design: ブロックデザインを保存します。Vivado GUIで言うところのFile -> Save Block Designに相当します。Non-Projectモードでは意味がないですが、プロジェクトモードであれば
.bd
ファイルが更新されます。 -
make_wrapper -top: Block DesignからHDLラッパーを生成するコマンドです。bitstream生成にはブロックデザインをHDLモジュールにラップしたファイルが必要になるため、
make_wrapper -files [get_files <design_name>.bd] -top
を実行しておきます。 -
launch_runs / wait_on_runs: 合成や実装をコマンドラインで回す場合、
launch_runs synth_1
やlaunch_runs impl_1
でRunを実行し、wait_on_runs
で完了待ちできます。
(※上記以外にもVivado Tclコマンドは多数ありますが、本記事の範囲に沿って主要なもののみ抜粋しました)
トラブルシューティングと注意点
No Catalog IPs found エラーが出る
初めてカスタムIPをスクリプトで扱う際によく遭遇するのが、"No Catalog IPs found" というエラーです。これは「指定したIPがIPカタログに見つからない」という旨のエラーで、典型的には次のようなメッセージが現れます:
WARNING: [Coretcl 2-175] No Catalog IPs found
ERROR: [BD::TCL 103-2012] The following IPs are not found in the IP Catalog:
xilinx.com:hls:dds_hls:1.0
Resolution: Please add the repository containing the IP(s) to the project.
上記の例では、xilinx.com:hls:dds_hls:1.0
というIPが見つからないと言われています。原因は、先述した「IPリポジトリの追加」がなされていないか、追加したパスが正しくない可能性が高いです。Vivadoは標準IP以外は自動ではカタログに出てこないため、HLSで生成したIPフォルダをプロジェクトのIPリポジトリに含めてからスクリプトを流す必要があります。解決策としては、エラーメッセージにある通り該当IPを含むリポジトリパスをプロジェクトに追加し、update_ip_catalog
することです。具体的には前述のset_property ip_repo_paths ...; update_ip_catalog
をエラーが出る前(例えばプロジェクト作成直後、BD作成前)に挿入すればOKです。以下に例を示します:
# 指定のIPリポジトリを追加してカタログ更新(エラー解消のために挿入)
set_property ip_repo_paths "$script_folder/solution1/impl/ip" [current_fileset]
update_ip_catalog
$script_folder
はスクリプト自身のディレクトリパスを指す変数(実際にはfile normalize [info script]
等で取得)で、上記ではその配下のパスを指定しています。このようにTclスクリプトに直接リポジトリ登録処理を入れておくと、後から単独でスクリプトを実行してもエラー無く復元できるので便利です。実際、VivadoのBlock DesignをエクスポートしたTclをそのまま使うとユーザーIPのパス情報が含まれず、再実行時にエラーになることがあるため、こうした処置が推奨されています。参考までにXilinxのフォーラム記事やKnowledge Base (AR# 70400)でも、同様の対処法が案内されています。
VLNVの不一致・バージョン違い
カスタムIPが見つからないもう一つの要因はVLNVの不一致です。HLSでIPをエクスポートする際、デフォルト値からVendorやLibrary、Nameを変更した場合や、プロジェクト名に依存したNameが付いている場合、スクリプト内のVLNV文字列と実際のIPのVLNVが食い違うことがあります。例えば、HLSエクスポート時にVendorをuser.org
、Libraryをuser
に変更していたのに、Tclスクリプトではxilinx.com:hls:...
のままになっているといったケースです。この場合、当然ながら一致しないためIPが見つかりません。対処法は、正しいVLNVを調べてスクリプトを修正することです。正しいVLNVは、HLS生成フォルダ内のcomponent.xml
をテキストエディタで開くと確認できます。 <spirit:vendor>
や<spirit:library>
タグに記載されている内容がそれです。またはVivadoでIPカタログ追加後にGUI上で該当IPを右クリック→Detailsを見てもVLNVが表示されます。これらを参照し、Tcl内のcreate_bd_cell -vlnv
引数を修正してください。
また、バージョン違いにも注意です。Vivadoのバージョンを上げた際にザイリンクス提供IPのバージョンが繰り上がることがあります。今回の自作IPはユーザーIPなので自分で変えない限りバージョンは1.0のままですが、スクリプト作成時からHLS IPを再エクスポートしてバージョンを更新した場合(例えば1.1にした等)は、スクリプト側も同じバージョンに合わせるか、前述のlatest_ip
的な手法で自動化する必要があります。VivadoのエクスポートされたBD Tclでは、IPバージョンが異なる環境で実行したときに警告を出しつつ継続する仕組みがあります。自前のスクリプトでも、バージョン番号をワイルドカードにしたVLNV指定(例: xilinx.com:hls:dds_hls:*
)が可能ですので、環境によって変わり得る部分は柔軟に対応させると良いでしょう。
その他の注意点
-
IPの互換性: HLS IPは基本的に生成に使用したFPGAファミリで使えるようになっています。例えばZynq-7000用に合成したIPはUltraScale+でも使える場合がありますが、Vivadoが「Compatible」かどうかを判断します。もしIPをカタログに追加しても表示されない場合、現在のプロジェクトのデバイスに非対応の可能性があります(HLS IPでは稀ですが)。その際はHLS合成時に適切な
set_part
を指定して再合成してください。 -
Block Design Tclの再利用: VivadoのBlock DesignはGUI操作からFile -> Export -> Export Block DesignでTclスクリプトに書き出せます。これを用いて一度環境構築したブロックデザインをTcl化し、編集・再実行することで自動プロジェクト生成が可能です。エクスポートされたスクリプトにはIPパラメータや接続も一通り含まれます。本記事で解説したコマンドを理解しておけば、そのエクスポートTclも読み解きやすくなるでしょう。
-
日本語名やスペース: プロジェクト名やフォルダパスに日本語や空白が入ると、Tclでエスケープが必要になったり予期せぬ不具合のもとになります。可能な限り半角英数字のみで構成することをお勧めします。特にLinux環境ではパスの大文字小文字も区別されるため、HLSスクリプト内とVivado側でパスがずれないよう注意してください。
-
GUIとの併用: Tclスクリプトで自動生成した後にGUIで開いて微修正、といった使い方もできます。ただし、GUIで変更を加えたら
write_bd_tcl
やwrite_project_tcl
でTclを書き出しておき、それを元に次回はスクリプトを更新するようにしましょう。でないとスクリプトと手動編集内容が乖離してしまいます。
おわりに
今回は、Vivado HLSで作成したカスタムIPをVivadoのブロックデザインで使用するまでの一連の流れを、初心者向けに解説しました。HLSツールでC++からIPを生成し、VivadoプロジェクトにIPリポジトリを追加してIPカタログに登録、そしてTclスクリプトを用いてブロックデザイン上にIPをインスタンス化する方法を順を追って説明しています。特にスクリプト中のcreate_bd_cell
コマンドはIPコアを配置する要となるコマンドであり、その引数であるVLNVや、スクリプト上でバージョンを管理するための工夫(latest_ip
相当の処理)について詳しく述べました。また、get_ipdefs
によるIP検索、set_property -dict
によるIPパラメータ設定、connect_bd_net
等による接続方法にも触れています。
最後に、初心者の方がつまづきやすいエラーである「No Catalog IPs found」の対処や、VLNV不一致への注意点についても解説しました。Tclスクリプトは慣れるまで難しく感じるかもしれませんが、一行ずつ意味を追っていけばGUI操作の自動記録にすぎないことがわかるはずです。VivadoのTclコマンドは膨大ですが、公式のTclコマンドリファレンスUG835やユーザーガイドUG894/UG895等に詳細が記載されています。必要に応じてリファレンスを参照しつつ、少しずつスクリプトを書いて試してみてください。
この記事が、Vivado HLS初心者の方が**「生成したIPをどうVivadoで使うか」**を理解する一助になれば幸いです。ブロックデザインTclスクリプトを読み解けるようになれば、大規模なデザインの自動生成やバージョン管理にも役立ちます。ぜひチャレンジしてみてください。お疲れ様でした!
補足事項
古いvivadoを使う場合
コマンド名 | 対応するツール | 状況 |
---|---|---|
vivado_hls |
Vivado HLS | Vivado 2019.1 以前の古いツールチェーン |
vitis_hls |
Vitis HLS | Vivado 2019.2 以降の新しい統合環境 |
なぜ変わったのか?
- Xilinx は 2019.2 以降、開発ツールを Vivado / SDx / HLS → Vitis に統合。
- これにより、HLS ツールも
vivado_hls
からvitis_hls
に移行。 - Vitis HLS では、Vivado HLS 互換の
.tcl
スクリプトや.cpp
ファイルが基本的にそのまま動作しますが、プロジェクトの構造や一部オプションが微妙に異なることがあります。
自分の環境で確認するには?
以下のいずれかをターミナルで実行してみてください:
which vivado_hls
which vitis_hls
出力があれば、それがインストールされている方の HLS コマンドです。
例:dds_hls.tcl
を使うとき
open_project -reset proj_dds_hls
add_files dds_hls.cpp
set_top dds_hls
open_solution -reset solution1 -flow_target vivado
このような .tcl
スクリプトは、Vivado HLS (vivado_hls
) に最適化されていますが、vitis_hls
でも -flow_target vivado
を指定すれば通常問題なく動作します。
- Vivado 2019.1以前 →
vivado_hls
- Vivado 2019.2以降 →
vitis_hls
(推奨)
どちらで .tcl
スクリプトを実行するかは、Vivado/Vitisのバージョンに依存します。
参考文献など
- Vivado High-Level Synthesis ユーザーガイド (UG902)
- Vivado IP Integrator ユーザーガイド (UG895)
- Vivado Tcl コマンドリファレンス (UG835)
理学系のRFSoC関係
- 「超伝導検出器のマイクロ波読み出し技術開発」 京都大学 鈴木惇也 先生の発表資料
- 「ダークフォトン探索に向けた広帯域分光計の開発と評価」竹内 広樹 さんの修士論文