はじめに
Zynq評価ボード上のFTDI USB-JTAGインターフェースを使って、FPGA/SoCのピン状態を連続取得し、波形として表示するデスクトップツール「OWLTAP」(Open-source Waveform Logger for TAP)を作りました。
テスターやオシロスコープを使わずに、FPGAの実機デバッグを手軽に行えます。
さらにMCP(Model Context Protocol)に対応しています。MCPとは、AIアシスタントが外部ツールをAPIとして呼び出せる仕組みです。Claude DesktopなどのAIクライアントからFPGAへの書き込み・バウンダリスキャン・専用のILA IP制御を直接行えます。
動作環境: Windows 10/11(64-bit)、FTDI MPSSEアダプタ(FT2232H / FT4232H)が必要です。現時点での実機検証はZybo Z7020で行っています。他デバイスでの動作確認はまだできていません。
開発について: 本ツールの実装および本記事の執筆にはAIアシスタント(GitHub Copilot)を活用しています。
OWLTAPでできること
| 機能 | 概要 |
|---|---|
| JTAGチェーン検出 | IDCODEとIR長を自動読み取り |
| BSDLパーサ | ベンダBSDLファイルを読み込み、ピン名とBSRビット位置をマッピング |
| バウンダリスキャン (EXTEST) | 出力ピンをHIGH/LOW/Hi-Zに駆動、入力ピン値を読み取り |
| 安全ガード | Zynq PS_DDR / PS_MIO / PS_POR_B / PS_SRST_B ピン検出時はEXTESTをブロック |
| 波形キャプチャ | トリガ付き・フリーラン・シングル、バッファ深度可変 |
| トリガエンジン | 立ち上がり/立ち下がり/両エッジ/レベル、プレトリガ比率設定 |
| 内蔵ILA IP | SystemVerilog製ロジックアナライザIP(専用TAP / Xilinx BSCANE2対応) |
| JTAGデーモン | ハードウェア操作をバックグラウンドプロセスに分離、JSON-RPC TCP経由で制御 |
| 選択ピン最適化 | 選択ピンのみBSRをシフトアウト(1077bit→例: 341bit)でサンプルレート改善 |
| PLビットストリーム書き込み |
.bit/.binをJTAG経由でZynq PLに直接書き込み(電源断で消える揮発書き込み) |
| SPI フラッシュ書き込み | BSCAN SPIブリッジ経由でSPI Config ROM(MT25QL128)に書き込み、電源断後も保持(ユニットテスト済み・実機未検証) |
| MCP対応 | AI(Claude等)からJTAGデバッグツールを呼び出せる |
| VCDエクスポート | GTKWave / Vivado で読めるVCDファイルを出力 |
| スクリプトエンジン | set/expect/apply/highz の自動化スクリプト |
アーキテクチャ
OWLTAPは次の6層スタック構成になっています。
GUIとハードウェアはJTAGデーモンプロセスで分離されており、GUIはJSON-RPC over TCPでデーモンと通信します。これにより、MCPクライアント(AI)や外部スクリプトからも同じハードウェア操作を利用できます。
メインGUIは以下のような画面です。
バウンダリスキャン波形キャプチャ
JTAG BSDLを読み込み、信号パネルでピンを選択→RUNすることで波形キャプチャが始まります。
サンプル数の設定を行うこともできます。
サンプルレートの現実
Zynq XA7Z020のBSRは1077ビットあります。これをJTAGでシフトし続けるため、理論値と実測値にはギャップがあります。
| 要因 | 影響 |
|---|---|
| JTAGクロック6MHz + IR/DRオーバーヘッド | 理論最大 ~5.5 kHz |
| USB バルク転送レイテンシ(250〜500μs) | 実測 ~1〜2 kHz に低下 |
選択ピン最適化を使うと、BSR中の最後の選択ピン位置までのシフトで済みます。例えばBSRの前方寄りにある2ピンを選択した場合は1077ビットから341ビットへ削減でき(約1/3)、サンプルレートが比例して改善します。
内蔵ILA(ロジックアナライザIP)
高速信号を観測したい場合は、PLに同梱のILA IPをFPGAデザインに組み込みます。サンプルクロックをFPGAのシステムクロック(例: 125MHz)に接続することで、バウンダリスキャンの数万倍のサンプルレートで信号を取得できます。

DATA_W(デフォルト32bit)とDEPTH(デフォルト1024サンプル)はパラメータで変更可能です。
2種類の接続バリアント
ILA IPにはJTAGへの接続方法が異なる2種類のトップレベルモジュールが用意されています。
ila_topは未検証です。
BSCANE2は実機で確認しています。
| バリアント | モジュール名 | 概要 |
|---|---|---|
| 専用TAP | ila_top |
独立したIEEE 1149.1 TAPをJTAGチェーンに追加(IR = 5bit)。Xilinx以外のFPGAにも対応 |
| BSCANE2 | ila_bscane2_top |
Xilinx BSCANE2 USER1 プリミティブ経由でFPGA既存のJTAG TAPを共用。追加ピン不要
|
専用TAPバリアント(ila_top)
ILA用の独立したTAPをJTAGチェーンに数珠つなぎします。
FTDIケーブル
TCK ──┬──► FPGA.TCK
TMS ──┼──► FPGA.TMS
TDI ──► FPGA.TDI
FPGA.TDO ──► ila_top.tdi
ila_top.tdo ──► ケーブルTDO
OWLTAPのJtagChain::detectDevicesがIDCODE(32'hA17A_0001)で自動認識します。IDCODEはIDCODE_VALパラメータで変更可能です。
BSCANE2バリアント(ila_bscane2_top)— Xilinx 7-Series / Zynq 推奨
XilinxのBSCANE2 USER1プリミティブを使うことで、FPGAの既存JTAGポートをそのまま流用できます。Zybo Z7のオンボードUSB-JTAGからも追加配線なしでアクセス可能です。
FTDIケーブル(またはZybo Z7 オンボードUSB-JTAG)
TCK/TMS/TDI/TDO ──► FPGA の JTAG TAP
│
BSCANE2 USER1(Xilinxプリミティブ)
│
ila_bscane2_top(FPGA内部)
専用TAPのようなIRスキャンではなく、37bitのDRフレームをUSER1スキャンチェーンに多重化するプロトコルを使います。
bits[4:0] = サブオペコード(ila_top のIRオペコードと同じ値)
bits[36:5] = 32bitデータペイロード
読み出し操作はスキャン2回:1回目のUpdateでオペコードをセット、2回目のCaptureでデータを取り出します。
トリガ構成
- グループA: レベル比較(マスク/値) + エッジ(立上/立下マスク)
- グループB: 独立レベル比較
- TRIG_CTRL.or_mode: グループA OR グループBでトリガ
ILAジェネレータウィザード
Tools → Generate ILA Core... でレーン定義からBSCANE2 ILAパッケージをワンクリック生成できます。
| 生成物 | 内容 |
|---|---|
| ラッパーRTL |
ila_bscane2_topをインスタンス化するSystemVerilogトップ |
| Vivado Tclスクリプト |
create_project.tcl / build_bitstream.tcl
|
| 制約ファイル |
ila_generated.xdc(サンプルクロック制約付き) |
| パッケージREADME | パラメータ・レーンマップ・使用法のサマリ |
接続とデバイス選択
FTDIアダプタをターゲットボードのJTAGヘッダに接続し、接続ダイアログでデバイスを選択します。
FTDIアダプタは MPSSE対応チップ(FT2232H / FT4232H) が必要です。安価なFT232RLはMPSSEを持たないため動作しません。検証済み構成はFT4232H(VID=0x0403 PID=0x6011)です。
MCP対応:AIからJTAGデバッグ
jtag_daemonはMCPサーバとしても動作します。Claude DesktopなどのMCP対応AIから以下のツールを呼び出せます。
detect_devices → JTAGチェーン上のデバイスを列挙
read_idcode → IDCODEを直接読み取り
list_devices → ロード済みデバイス情報を一覧
load_bsdl → BSDLファイルをロード
list_pins → 観測/駆動可能ピン一覧
read_pin → 1ピンの現在値を読み取り
set_pin → ピンをHIGH/LOW/Hi-Zに設定
capture_start → キャプチャ開始
capture_stop → キャプチャ停止
get_samples → サンプルデータ取得
program_bitstream → PLへビットストリーム書き込み
ila_run_capture → ILAキャプチャをトリガ・取得
read_ila_status → ILAのステータス取得
run_script → スクリプト実行
job_poll → 非同期ジョブの完了待ち
job_cancel → 非同期ジョブのキャンセル
...(全16ツール)
「このピンが今HIGHかLOWか確認して」をAIに頼むと、AIがMCP経由でJTAGをたたいて答えを返してくる、という使い方ができます。
スクリプトエンジン
シンプルなテキストスクリプトで自動化が可能です。
# LEDをHIGHに駆動して確認
set LED0 1
apply
expect LED0 1
# Hi-Zに戻す
highz LED0
apply
.suiteファイルで複数スクリプトをまとめて実行、.ictファイルで基板インターコネクトテストも対応しています。
PLビットストリーム書き込み
Tools → Program Bitstream で .bit / .bin ファイルをJTAG経由でZynq PLに直接書き込めます。電源断で消える揮発書き込みのため、反復デバッグに便利です。MCP経由(program_bitstream)でAIから呼び出すことも可能です。
SPI フラッシュ書き込み
注意: この機能はユニットテスト済みですが、実機での動作確認はまだ行っていません。
BSCAN SPIブリッジ経由でSPI Config ROM(MT25QL128)に書き込みます。PLビットストリーム書き込みとは異なり、電源断後も設定が保持されます。
ビルド方法
対応環境: Windows 10/11 (64-bit)、OpenGL 3.3 core profile 対応GPU が必要です。Linux/macOSは現時点で未対応です。
必要なもの
| ツール | 備考 |
|---|---|
| Bazelisk |
bazelisk.exeとしてPATHに配置 |
| Visual Studio 2022 | C++デスクトップ開発ワークロード |
| Python 3.x | Bazelホストスクリプト用 |
libftdi1とlibusb-1.0はリポジトリに同梱済みで別途インストール不要です。
Windows USBドライバ
ZadigでFTDIアダプタのJTAGインターフェース(通常FT4232HのInterface 0)にWinUSBまたはlibusbKを割り当てます。
ビルドコマンド
git clone https://github.com/MameMame777/OWLTAP.git
cd OWLTAP
# ビルド
bazelisk build //src:owltap
# 全ユニットテスト実行(ハードウェア不要)
bazelisk test //test/...
BSDLファイルについて: ターゲットデバイスのBSDLファイルはリポジトリに含まれていません。デバイスベンダ(Xilinx/AMDの場合はダウンロードセンター)から入手し、GUIの「Device → Load BSDL」で読み込んでください。
使い方(クイックスタート)
- FTDIアダプタとターゲットボードのJTAGヘッダを接続する
-
owltap.exeを起動する - Device → Connect: VID/PID/チャンネルを選択して接続
-
Device → Load BSDL: ターゲットの
.bsd/.bsdlファイルを読み込む - Signal Panel: 監視したいピンを選択する
- Capture → Start: 波形取得を開始する
- File → Export VCD: 取得した波形をVCDファイルに保存する(GTKWave / Vivadoで開ける)
テスト戦略
| テスト層 | 実行タイミング | ハードウェア要否 |
|---|---|---|
bazelisk test //test/...(22テスト) |
毎コミット | 不要 |
| Pythonハードウェアインザループ(HIL)テスト | リリース前・ハードウェア変更後 | 必要(FTDIアダプタ+ターゲット基板) |
ユニットテストはスタブハードウェアで動作し10秒以内に完走します。HILテストは実際のZynqシリコンに対してJTAGスキャンを実行し、モックでは検出できない統合レグレッションを捕捉します。
HILテスト結果(2026-04-27、XA7Z020-CLG484)
Result: 10/10 tests passed
detect_devices → 2 device(s): IDCODE=0x23727093, IDCODE=0x4BA00477
load_bsdl → entity='XA7Z020_CLG484'
list_pins → 333 observable, 327 drivable
read_pin → RSVDVCC3_T10 = high
capture (single)→ 1 samples, 333 pins per sample
program_bitstream→ state=complete ok=True
read_ila_status → version=3 depth=1024 data_width=32 sig_count=2
(sig_count はILA IPに接続された監視信号グループ数)
セキュリティ
jtag_daemonはローカル専用の開発ツールです。
- MCP / GUI-RPC ポートは127.0.0.1のみにバインドし、ネットワークインターフェースには露出しません
- 認証機能はありません(ループバック限定のため設計上許容)
- 共有マシンや不特定多数がアクセスできる環境での使用は避けてください
ライセンス
| 対象 | ライセンス |
|---|---|
| C++ソースコード(GUIアプリ・デーモン) | MIT |
ILA IP RTL / テストベンチ(hdl/ila/) |
Apache-2.0 |
| サードパーティライブラリ | 各ライブラリのライセンス(THIRD_PARTY_NOTICES.md 参照) |
ILA IPにApache-2.0を選んだのは、再利用可能なハードウェアIPとして特許許諾条項(Patent Grant)を明示するためです。MITには特許に関する明示的な条項がありませんが、Apache-2.0はコントリビュータの保有特許についてロイヤルティフリーのライセンスを明示的に付与するため、IPコアを自社製品に組み込む際の法的明確性が高くなります。
まとめ
OWLTAPはFPGA/SoCのJTAGバウンダリスキャンをオシロスコープのように使えるOSSツールです。
MCP連携によってAIが実際のHWデバッグを行うことも可能です。
- ImGui/ImPlotベースのGUI(Windows 10/11対応)
- FTDIアダプタ1本で接続でき、特殊なプローブ不要
- MCP対応でAIアシスタントからのJTAGデバッグが可能
- 内蔵ILA IPで高速信号キャプチャも対応
- 22ユニットテスト + HILテストで品質担保
BSDLファイルさえあれば大抵のIEEE 1149.1準拠FPGAで動作します。
興味があればぜひ試してみてください!
バグや改善案があればコメントやIssueにてお願いします。
参考リンク
- リポジトリ: https://github.com/MameMame777/OWLTAP
- libftdi1: https://www.intra2net.com/en/developer/libftdi/
- Dear ImGui: https://github.com/ocornut/imgui
- ImPlot: https://github.com/epezent/implot
- Zadig(WinUSBドライバ): https://zadig.akeo.ie/


