Vivado を Tcl バッチで回す — そして BOM で1時間溶かした話

設計ツール自動化 2026年8月5日

GUI を開かずに合成する

Vivado は起動が重いソフトです。 プロジェクトを開いて、合成を回して、レポートを見る。 この一連を GUI でやっていると、**待ち時間の大半が「Vivado が立ち上がるまで」**になります。

しかも合成と実装は、一度設定が決まれば毎回同じ手順です。 人がクリックする必要はありません。

Vivado の自動化は、Tcl スクリプトをバッチモードで流すのが基本形になります。

vivado.bat -mode batch -source build.tcl

GUI は開かず、実行が終わればプロセスも終了します。

この記事が向いていない人

環境変数の設定は不要

意外と誤解されている点です。

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つです。

  1. ログの保存.log.jou を実行ごとに logs/ へ退避する。 Vivado はカレントディレクトリにログを吐き、次の実行で上書きするので、 失敗したときに前回のログが残っていないことがあります
  2. BOM なしでの一時 Tcl 書き出し — 後述する事故の対策
  3. モードの切り替え — 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 utf8Set-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]

これは実際にハードウェアへ書き込みます

自動化のスクリプトに混ぜてしまうと、意図しないタイミングで実機に流れます。 接続されているボードが想定と違えば、最悪の場合ハードウェアを壊します。

物理デバイスに触る操作は、必ず人間の確認を挟むという線引きにしています。 合成〜ビットストリーム生成までは自動、書き込みは手動です。

まとめ

エラーメッセージが原因を教えてくれないタイプの問題は、 知っているかどうかだけで解決時間が桁違いになります。 BOM はその典型でした。


関連: EasyEDA Pro を外部から自動操作する / Autodesk Fusion を外部から Python 制御する