Vivado を Tcl バッチで回す — そして BOM で1時間溶かした話
GUI を開かずに合成する
Vivado は起動が重いソフトです。 プロジェクトを開いて、合成を回して、レポートを見る。 この一連を GUI でやっていると、**待ち時間の大半が「Vivado が立ち上がるまで」**になります。
しかも合成と実装は、一度設定が決まれば毎回同じ手順です。 人がクリックする必要はありません。
Vivado の自動化は、Tcl スクリプトをバッチモードで流すのが基本形になります。
vivado.bat -mode batch -source build.tcl
GUI は開かず、実行が終わればプロセスも終了します。
この記事が向いていない人
- 配置配線を手で詰めている方 — フロアプランやタイミング制約の作り込みは GUI の領域です
- Vivado を初めて触る方 — まず GUI で一通り流してからの方が、Tcl の各コマンドの意味が分かります
環境変数の設定は不要
意外と誤解されている点です。
Vivado には settings64.bat という環境設定スクリプトがありますが、
bin\vivado.bat は内部でこれを読みます。
つまり事前に環境変数を通しておく必要はなく、フルパスで叩けば動きます。
& "C:\Xilinx\Vivado\2024.2\bin\vivado.bat" -mode batch -source build.tcl
これだけで実行できます。CI やタスクスケジューラから叩くときも、環境の準備が要りません。
ラッパーを1枚かぶせる
素で叩いてもいいのですが、実際に運用していると毎回同じことをやるので、 PowerShell のラッパーを作りました。
.\run-vivado.ps1 -Source build.tcl # バッチ実行
.\run-vivado.ps1 -Source build.tcl -TclArgs @('top','xc7k70t') # 引数を渡す
.\run-vivado.ps1 -Command 'puts [version -short]' # インライン Tcl
.\run-vivado.ps1 -Source open_gui.tcl -Mode gui # GUI で開く
ラッパーに持たせている責務は3つです。
- ログの保存 —
.logと.jouを実行ごとにlogs/へ退避する。 Vivado はカレントディレクトリにログを吐き、次の実行で上書きするので、 失敗したときに前回のログが残っていないことがあります - BOM なしでの一時 Tcl 書き出し — 後述する事故の対策
- モードの切り替え — batch / tcl / gui
Tcl 側へ引数を渡すには -tclargs を使います。スクリプト側では $argv / $argc で受けられます。
BOM で1時間溶かした
ここが本題です。
Tcl スクリプトを PowerShell から書き出して実行したところ、こう出ました。
invalid command name "?"
? などというコマンドは書いていません。スクリプトの1行目は普通の create_project です。
原因は UTF-8 BOM でした。
Windows PowerShell 5.1 の Out-File -Encoding utf8 や Set-Content は、
ファイルの先頭に BOM(EF BB BF)を付けます。
そして Vivado の Tcl インタプリタは BOM を解釈できず、最初の1文字をコマンド名として読もうとします。
エラーメッセージに文字化けした記号が出るだけで、 「BOM が原因」とはどこにも書かれません。スクリプトの中身を何度見直しても見つかりません。
対策は単純で、BOM なしの UTF-8 で書き出すことです。
# NG: BOM が付く(PS 5.1)
$tcl | Out-File -Encoding utf8 build.tcl
# OK: BOM なし
[System.IO.File]::WriteAllText(
'build.tcl', $tcl, (New-Object System.Text.UTF8Encoding($false))
)
New-Object System.Text.UTF8Encoding($false) の $false が「BOM を付けない」の指定です。
ややこしいのは、逆のルールも同居していること
同じマシンで、PowerShell 5.1 のスクリプト自体は BOM が必要です。
.ps1 ファイルに日本語のコメントや文字列を含める場合、BOM が無いと
PS 5.1 はファイルをシステムの ANSI コードページとして読み、日本語が文字化けします。
ひどいときは構文エラーになります。
つまりこうなります。
| ファイル | BOM |
|---|---|
.ps1(日本語を含む・PS 5.1) | 必須 |
.tcl(Vivado に食わせる) | 厳禁 |
同じディレクトリの中で、真逆のルールが同時に成立します。 どちらも「文字化けした」「謎のエラーが出た」という似た症状で現れるので、 片方の知識だけ持っていると、もう片方で確実に踏みます。
エディタの設定を「常に BOM なし」に統一しても解決しません。 ファイルの種類で使い分けるしかありません。
バッチモードは終わったら勝手に閉じる
-mode batch は、スクリプトを流し終えるとプロセスが終了します。
プロジェクトを開いたまま眺めたい場合は、GUI モードで起動するか、
スクリプトの中で start_gui を呼びます。
open_project ./work/proj.xpr
start_gui ;# ここで GUI が開き、以降は対話操作
逆に GUI モードで走らせているスクリプトの中で stop_gui を呼べば、GUI を閉じられます。
長時間処理はバックグラウンドに逃がす
合成・実装・ビットストリーム生成は、規模によっては数十分から数時間かかります。
launch_runs synth_1 -jobs 8
wait_on_run synth_1
launch_runs impl_1 -to_step write_bitstream -jobs 8
wait_on_run impl_1
wait_on_run は完了までブロックするので、対話セッションから直接叩くとその間ずっと待たされます。
バックグラウンドのジョブとして投げて、完了通知を受け取る形にした方が現実的です。
非プロジェクトフローで済ませたい場合は、こちらの方が見通しが良くなります。
read_verilog [glob ./src/*.v]
read_xdc ./constr/top.xdc
synth_design -top top -part xc7k70tfbv676-1
opt_design
place_design
route_design
report_timing_summary -file ./rpt/timing.rpt
report_utilization -file ./rpt/util.rpt
write_bitstream -force ./out/top.bit
プロジェクトファイルを作らないので、Git で管理しやすいという利点もあります。
実機書き込みは自動化しない
program_hw_devices [get_hw_devices]
これは実際にハードウェアへ書き込みます。
自動化のスクリプトに混ぜてしまうと、意図しないタイミングで実機に流れます。 接続されているボードが想定と違えば、最悪の場合ハードウェアを壊します。
物理デバイスに触る操作は、必ず人間の確認を挟むという線引きにしています。 合成〜ビットストリーム生成までは自動、書き込みは手動です。
まとめ
- Vivado の自動化は
-mode batch+ Tcl が基本形。環境変数の準備は不要 - ラッパーを1枚かぶせて、ログの退避とBOM なしでの書き出しを任せる
- Tcl に BOM は厳禁。
invalid command name "?"が出たら、まずファイルの先頭バイトを疑う - PS 5.1 のスクリプトは逆に BOM が必要。 同じマシンで真逆のルールが同居する
wait_on_runはブロックする。長時間処理はバックグラウンドへprogram_hw_devicesは実機に書き込む。 自動化に混ぜない
エラーメッセージが原因を教えてくれないタイプの問題は、 知っているかどうかだけで解決時間が桁違いになります。 BOM はその典型でした。
関連: EasyEDA Pro を外部から自動操作する / Autodesk Fusion を外部から Python 制御する