エミュレーションの実行
FPGA をターゲットとするユーザー アプリケーションおよびハードウェア カーネルの開発には、段階的な開発アプローチが必要です。FPGA、Versal™ ACAP、および Zynq UltraScale+ MPSoC はプログラマブル デバイスであるため、ハードウェアのデバイス バイナリの構築には時間がかかります。Vitis™ ツールではエミュレーション ターゲットでアプリケーションとカーネルを実行できるので、ハードウェア コンパイル フロー全体を実行することなく迅速なイテレーションを実行できます。エミュレーション ターゲットのコンパイルは、実際のハードウェアのコンパイルよりもかなり高速です。また、エミュレーション ターゲットはアプリケーションまたはアクセラレータを完全に可視化するため、デバッグの実行がより簡単になります。デザインがエミュレーションに合格したら、開発後半にハードウェア プラットフォーム上でアプリケーションをコンパイルおよび実行できます。
Vitis ツールには、次の 2 つのエミュレーション ターゲットがあります。
- ソフトウェア エミュレーション (sw_emu)
- ソフトウェア エミュレーション ビルドは迅速にコンパイルおよびリンクされ、ホストプログラムは x86 プロセッサまたは QEMU エミュレーション環境のいずれかでネイティブに実行されます。PL カーネルはネイティブにコンパイルされ、ホスト マシン上で実行されます。このビルド ターゲットを使用すると、ホスト コードとカーネル ロジックの両方をすばやく反復できます。
- ハードウェア エミュレーション (hw_emu)
- ホストプログラムは
sw_emuを使用して x86 または QEMU でネイティブに実行されますが、カーネル コードは RTL ビヘイビアー モデルにコンパイルされ、Vivado® シミュレータまたはその他のサポートされているサード パーティ シミュレータで実行されます。この場合、ビルドおよび実行ループにかかる時間は長くなりますが、カーネル ロジックがサイクル精度で表示されます。
どちらのエミュレーション ターゲットのコンパイルも、Vitis コマンド ラインおよび IDE フローにスムーズに統合されています。ソース コードを変更せずに、いずれかのエミュレーション ターゲット用にホストとカーネルのソース コードをコンパイルできます。ホスト コードの場合、同じホストの実行ファイルまたは PS アプリケーションの ELF バイナリをエミュレーションで使用できるため、エミュレーション用に別にコンパイルする必要はありません。エミュレーション ターゲットでは、XRT API、バッファ転送、プラットフォーム メモリ SP タグ、カーネル間接続などのほとんどの機能がサポートされます。
エミュレーション ターゲットの実行
エミュレーション ターゲットには、XRT で読み込まれる独自のドライバーがターゲット別にあります。このため、ランタイム中にターゲット モードを変更するだけで、再コンパイルしないで同じ CPU バイナリをそのまま実行できます。XRT は XCL_EMULATION_MODE 環境変数の値に基づいてターゲット別のドライバーを読み込み、ハードウェアのエミュレーション モデルを使用してアプリケーション インターフェイスを作成します。XCL_EMULATION_MODE に指定できる値は sw_emu および hw_emu です。XCL_EMULATION_MODE が設定されていない場合、 XRT はハードウェア ドライバーを読み込みます。
XCL_EMULATION_MODE を設定する必要があります。xrt.ini ファイルを使用しても、エミュレーションに適用可能なさまざまなオプションを設定できます。xrt.ini ファイル に説明するように、xrt.ini にはエミュレーション用の [Emulation] セクションがあります。
データセンター vs エンベデッド プラットフォーム
エミュレーションは、データセンターとエンベデッド プラットフォームの両方でサポートされています。データセンター プラットフォームの場合、ホストアプリケーションが x86 サーバー用にコンパイルされ、デバイスはハードウェアをエミュレーションする別々の x86 プロセスとしてモデル化されます。ユーザー ホスト コードとデバイス モデル プロセスは、RPC 呼び出しを使用して通信します。CPU コードがエンベデッド Arm プロセッサで実行されるエンベデッド プラットフォームの場合、エミュレーション フローが QEMU (Quick Emulator) を使用して Arm ベースの PS サブシステムを模倣します。QEMU では、エンベデッド Linux を起動し、エミュレーション ターゲット上で Arm バイナリを実行できます。
データセンター アプリケーションのソフトウェア エミュレーション (sw_emu) およびハードウェア エミュレーション (hw_emu) を実行するには、アプリケーションを起動する前に、emconfigutil コマンドを使用してアクセラレータ カードのエミュレーション モデルをコンパイルし、XCL_EMULATION_MODE 環境変数を設定する必要があります。手順の詳細は、Alveo データセンター アクセラレータ カードでのエミュレーションの実行 を参照してください。
エンベデッド アプリケーションの sw_emu または hw_emu を実行するには、x86 プロセッサで QEMU エミュレーション環境を起動して、Arm プロセッサの実行環境をモデル化する必要があります。このためには、launch_emulator コマンドまたはビルドプロセス中に生成されるシェル スクリプトを使用する必要があります。このフローの詳細は、エンベデッド プロセッサ プラットフォームでのエミュレーションの実行 を参照してください。
QEMU
QEMU とはクイック エミュレーターのことで、汎用のオープンソースのマシン エミュレーターです。ザイリンクスでは、Versal ACAP、Zynq® UltraScale+™ MPSoC および Zynq-7000 SoC デバイスに存在する Arm ベースのプロセッシング システムを模倣する、カスタマイズされた QEMU モデルを提供しています。QEMU モデルには、実際のハードウェアを必要とせずに、ほぼリアルタイムで CPU 命令を実行する機能があります。詳細は、『ザイリンクス クイック エミュレーター ユーザー ガイド: QEMU』 を参照してください。
ハードウェア エミュレーションでは、Vitis エミュレーション ターゲットが QEMU を使用し、残りのデザインを RTL および SystemC ベースのモデルを使用して協調シミュレーションし、プラットフォーム全体の完全な実行モデルを提供します。そのモデルでエンベデッド Linux カーネルを起動し、XRT ベースのアクセラレータ アプリケーションを実行できます。QEMU は Arm 命令を実行できるので、Arm バイナリを再コンパイルすることなく、そのままエミュレーション フローで実行できます。また、ザイリンクス システム デバッガー (XSDB) から GDB および TCF ベースのターゲット接続を使用してアプリケーションをデバッグすることもできます。
Vitis エミュレーション フローでも、QEMU を使用して MicroBlaze™ プロセッサをエミュレートし、デバイスのプラットフォーム管理モジュール (PLM および PMU) をモデル化します。Versal デバイスでは、PLM ファームウェアを使用して PDI をロードし、PS および AI エンジンモデルのセクションをプログラムします。
QEMU 設定がプラットフォームと一致するようにするため、Vitis プラットフォームの sw ディレクトリに追加ファイルを含める必要があります。qemu_args.txt および pmc_args.txt の 2 つの共有ファイルには、QEMU の起動時に使用されるコマンド ライン引数が含まれます。カスタム プラットフォームを作成すると、これらの 2 つのファイルがデフォルトの内容で自動的にプラットフォームに追加されます。ファイルを確認し、必要に応じて編集してカスタムプラットフォームをモデル化できます。例については、ザイリンクス エンベデッド プラットフォームを参照してください。
QEMU は汎用モデルであるため、 Linux デバイス ツリー形式の DTB フォーマット ファイルを使用して、さまざまなハードウェア モジュールを有効にして設定します。デフォルトの QEMU ハードウェア DTB ファイルは Vitis ツールに含まれ、<vitis_installation>/data/emulation/dtbs に含まれます。ただし、プラットフォームで別の QEMU DTB が必要な場合は、プラットフォームに含めてパッケージすることもできます。
Alveo データセンター アクセラレータ カードでのエミュレーションの実行
- xrt.ini ファイルで必要なランタイムを設定します。この手順はオプションです。
xrt.ini ファイル に説明されているように、このファイルには、デバッグ、プロファイリング、ホスト アプリケーションおよびカーネルを実行する際に XRT で記録されるメッセージを制御するためのさまざまなパラメーターを指定します。これにより、アプリケーションの実行中にランタイムでデバッグおよびプロファイル データを取得できます。xrt.ini の
Emulationグループでは、エミュレーションの実行に影響する機能を指定します。ヒント: カーネル コードをエミュレーション モードでコンパイルするには、v++ -gオプションを使用してください。 - emconfigutil ユーティリティ の説明に従って、ターゲット プラットフォームから emconfig.json ファイルを作成します。これは、ハードウェアまたはソフトウェア エミュレーションの実行には必須です。
エミュレーション コンフィギュレーション ファイル (
emconfig.json) は、emconfigutilコマンドを使用して指定のプラットフォーム用に生成され、エミュレーション中に XRT ライブラリで使用される情報を提供します。次の例は、指定したターゲット プラットフォーム用のemconfig.jsonファイルを作成します。
エミュレーション モードでは、ランタイムがホスト実行と同じディレクトリで emconfig.json ファイルを検索し、エミュレーションのターゲット設定を読み込みます。emconfigutil --platform xilinx_u200_xdma_201830_2ヒント: ターゲット プラットフォームでエミュレーションを実行するには、JSON ファイルを最新の状態にしておく必要があります。 XCL_EMULATION_MODE環境変数をsw_emu(ソフトウェア エミュレーション) またはhw_emu(ハードウェア エミュレーション) に設定します。これにより、アプリケーションの実行がエミュレーション モードになります。C シェル (csh) の環境変数を設定するには、次のコマンドを使用します。
setenv XCL_EMULATION_MODE sw_emubash シェルの環境変数を設定するには、次のコマンドを使用します。
export XCL_EMULATION_MODE=sw_emu重要:XCL_EMULATION_MODE環境変数が正しく設定されていないと、エミュレーション ターゲットが実行されません。- アプリケーションを実行します。
ランタイム初期化ファイル (xrt.ini)、エミュレーション コンフィギュレーション ファイル (emconfig.json)、および
XCL_EMULATION_MODE環境変数を設定し、必要なコマンド ライン引数を指定してホスト実行ファイルを実行します。重要: INI および JSON ファイルは実行ファイルと同じディレクトリに含める必要があります。次に例を示します。
./host.exe kernel.xclbinヒント: このコマンド ラインでは、多くの Vitis サンプルおよびチュートリアルと同様に、ホスト プログラムが xclbin ファイルの名前を引数として使用することを想定していますが、アプリケーションによっては xclbin ファイルの名前がホスト プログラムにコード記述されていたり、アプリケーションの実行に別の方法が必要であったりすることがあります。
エンベデッド プロセッサ プラットフォームでのエミュレーションの実行
- xrt.ini ファイルで必要なランタイムを設定します。
xrt.ini ファイル に説明されているように、このファイルには、デバッグ、プロファイリング、ホスト アプリケーションおよびカーネルを実行する際に XRT で記録されるメッセージを制御するためのさまざまなパラメーターを指定します。アプリケーションでのプロファイリングのイネーブル で説明されるように、アプリケーションの実行中にランタイムでデバッグおよびプロファイル データを取得できるようになります。
xrt.ini ファイルには、エンベデッド プラットフォームのパッケージ で説明されるように、ファイルとアプリケーションの実行に必要なその他のファイルも出力ファイルに含める必要があります。
ヒント: カーネル コードをエミュレーション モードでコンパイルするには、v++ -gオプションを使用してください。 - launch_sw_emu.sh スクリプトまたは launch_hw_emu.sh スクリプトを実行して、QEMU エミュレーション環境を起動します。
launch_sw_emu.sh -forward-port 1440 22スクリプトは、パッケージ プロセス中にエミュレーション ディレクトリに作成され、
launch_emulatorコマンドを使用して QEMU を設定して起動します。エミュレーション スクリプトを起動するときに、launch_emulatorコマンドにオプションを指定することもできます。たとえば、-forward-portオプションを使用すると、QEMU ポートをローカル システムのオープン ポートに転送できます。これは、次の手順 5 で説明するように、QEMU からファイルをコピーしようとする場合に必要となります。コマンドの詳細は、launch_emulator ユーティリティ を参照してください。また、
launch_hw_emu.sh -enable-debugを指定して、QEMU および PL プロセスのために開く追加の XTERM を設定すると、アプリケーションのデバッグに役立つコマンド実行のライブ トランスクリプトを監視できます。これはデフォルトではイネーブルになっていませんが、デバッグに役立ちつことがあります。 - 必要な設定で QEMU シェルをマウントして設定します。
ザイリンクス エンベデッドのベース プラットフォームには、SD カード上の別の EXT4 パーティションに
rootfsがあります。Linux の起動後、このパーティションをマウントする必要があります。エミュレーションを手動で実行している場合は、QEMU シェルから次のコマンドを実行する必要があります。mount /dev/mmcblk0p1 /mnt cd /mnt export LD_LIBRARY_PATH=/mnt:/tmp:$LD_LIBRARY_PATH export XCL_EMULATION_MODE=hw_emu export XILINX_XRT=/usr export XILINX_VITIS=/mntヒント:XCL_EMULATION_MODE環境変数は、ソフトウェア エミュレーションの場合はsw_emuに、ハードウェア エミュレーションの場合はhw_emuに設定できます。これで、ホスト アプリケーションがエミュレーション モードで実行されるように設定されます。 - QEMU シェル内からアプリケーションを実行します。
ランタイム初期化 (xrt.ini) を使用して
XCL_EMULATION_MODE環境を設定し、ホスト アプリケーションに必要なコマンド ラインを使用してホスト実行ファイルを実行します。次に例を示します。./host.elf kernel.xclbinヒント: このコマンド ラインでは、多くの Vitis サンプルおよびチュートリアルと同様に、ホスト プログラムが xclbin ファイルの名前を引数として使用することを想定していますが、アプリケーションによっては xclbin ファイルの名前がホスト プログラムにコード記述されていたり、アプリケーションの実行に別の方法が必要であったりすることがあります。 - アプリケーション実行が終了したら、profile_summary.csv、timeline.csv、xclbin.run_summary などのファイルが生成されます。これらのファイルは、QEMU 環境内の /mnt フォルダーに含まれます。ただし、これらのファイルは、QEMU Linux システムからローカル システムにコピーしないと表示できません。これらのファイルをコピーするには、次のように
scpコマンドを使用します。scp -P 1440 root@<host-ip-address>:/mnt/<file> <dest_path>説明:
1440は接続する QEMU ポートです。root@<host-ip-address>は、指定した IP の QEMU 下で実行される PetaLinux のルート ログインです。デフォルトのルート パスワードは root です。- /mnt/<file> は、QEMU 環境からコピーするファイルのパスと名前です。
- <dest_path> には、コピーするローカル システム先のパスとファイル名を指定します。
次に例を示します。scp -P 1440 root@172.55.12.26:/mnt/xclbin.run_summary - アプリケーションのエミュレーションが完了して必要なファイルをすべてコピーしたら、Ctrl + a + x キーをクリックして QEMU シェルを終了し、Linux シェルに戻ります。 注記: QEMU 環境を終了できない場合は、起動したプロセスを強制終了して、環境を実行できます。ツールがトランスクリプトの開始時にプロセス ID (PID) をレポートします。または、エミュレーションの開始時に PID をキャプチャする
-pid-fileオプションを指定できます。
ハードウェア エミュレーションの速度と精度
ハードウェア エミュレーションは、SystemC と RTL 協調シミュレーションを組み合わせて使用して、シミュレーションの精度と速度のバランスを調整します。SystemC モデルは、純粋関数モデルとパフォーマンス概要モデルを組み合わせたモデルです。ハードウェア エミュレーションは、ハードウェア精度を 100% を模倣するわけではないので、エミュレーションの実行とハードウェア上でのアプリケーションの実行の間には、動作に多少の違いがあるはずです。これにより、アプリケーションのパフォーマンスに大きな違いが生じる可能性があり、場合によっては、機能の違いを確認できることもあります。
ハードウェアとの機能的な違いは、通常、競合状態やデザイン内の予測不可能な動作になるので、ハードウェアで発生する問題がハードウェア エミュレーションで再現できるとは限りません。ただし、ホストとアクセラレータ間またはアクセラレータとメモリ間の送受信に関連するほとんどの動作は、ハードウェア エミュレーションで再現可能です。このため、ハードウェア エミュレーションは、ハードウェア上で実行する前にアクセラレータの問題をデバッグするための優れたツールといえます。
次の表は、ハードウェア プラットフォームとその精度レベルを模倣するために使用されるモデルを示しています。
| ハードウェア機能 | 説明 |
|---|---|
| ホストからカードへの PCIe® 接続と DMA (XDMA、SlaveBridge) |
データセンター プラットフォームでは、PCIe を使用した x86 ホスト サーバーへの接続は純粋関数モデルとして実行されるので、パフォーマンス モデリングはありません。したがって、PCIe 帯域幅に関連する問題は、ハードウェア エミュレーションの実行に反映されません。 |
| UltraScale™ DDR メモリ、SmartConnect | DDR メモリ コントローラー、AXI SmartConnect、およびその他のデータパス IP 用の SystemC モデルでは、通常スループットは概算です。通常、ハードウェア IP の正確な遅延はモデル化されません。このモデルを使用すると、アプリケーションやアクセラレータ カーネルを変更する際の相対的なパフォーマンス傾向を測定できます。 |
| AI エンジン | AI エンジン SystemC モデルはサイクル概算ですが、サイクル精度は 100% にはなりません。AI エンジン シミュレータとハードウェア エミュレーション間では共通のモデルが使用されるため、2 つのステージは妥当に比較できます。 |
| Versal NoC および DDR モデル | Versal NoC および DDR SystemC モデルは、サイクル概算です。 |
| Arm Processing Subsystem (PS、CIPS) | Arm PS は、純粋関数の実行モデルである QEMU を使用してモデル化されます。詳細は、QEMU を参照してください。 |
| ユーザー カーネル (アクセラレータ) | ハードウェア エミュレーションは、ユーザー アクセラレータに RTL を使用します。次のように、アクセラレータの動作自体は 100% 正確です。ただし、アクセラレータはほかの概算モデルに囲まれています。 |
| その他の I/O モデル | ハードウェア エミュレーションには、エミュレーション プロセスとインターフェイスできる汎用 Python または C ベースのトラフィック ジェネレーターがあります。デザインの I/O を模倣する AXI プロトコル レベルで抽象トラフィックを生成できます。これらのモデルは抽象的なものであるため、特定のハードウェア ボードで見られた問題はハードウェア エミュレーションでは表示されません。 |
ハードウェア エミュレーションは RTL 協調シミュレーションを実行モデルとして使用するため、実行速度は実際のハードウェアと比較してかなり遅くなります。ザイリンクスでは、小さなデータ バッファーを使用することをお勧めしています。たとえば、コンフィギャラブルなベクター加算があり、ハードウェアで 1024 のエレメントの vadd を実行している場合、エミュレーションでは 16 のエレメントに制限できます。これにより、アクセラレータを使用してアプリケーションをテストしつつ、妥当な時間内に実行を完了できます。
ハードウェア エミュレーションでの RTL シミュレータの使用
RTL シミュレータのサポート
Vitis ツールは、Alveo データセンター アクセラレータ カードや Versal および Zynq UltraScale+ MPSoC エンベデッド プラットフォームを含むすべてのプラットフォームのデフォルト シミュレータとして Vivado ロジック シミュレータ (xsim) を使用します。ただし、xilinx_vck190_base のような Versal エンベデッド プラットフォーム (または類似のカスタム プラットフォーム) の場合は、Vitis ツールでハードウェア エミュレーション用のサードパーティー シミュレータ (Mentor Graphics 社の Questa Advanced Simulator、Xcelium、および VCS) の使用もサポートされます。サポートされるシミュレータのバージョンは、Vivado Design Suite でサポートされるバージョンと同じです。
サードパーティー シミュレータをイネーブルするには、デバイス バイナリ (.xclbin) およびサポートされる Tcl スクリプトの生成時に、追加でコンフィギュレーション オプションをインプリメントする必要があります。各シミュレータの要件については、次に説明します。
- Questa
- リンク中に使用する次の詳細パラメーターと Vivado プロパティをコンフィギュレーション ファイルに追加します。
## Final set of additional options required for running simulation using Questa Simulator [advanced] param=hw_emu.simulator=QUESTA [vivado] prop=project.__CURRENT__.simulator.questa_install_dir=/tools/gensys/questa/2020.2/bin/ prop=project.__CURRENT__.compxlib.questa_compiled_library_dir=<install_dir>/clibs/questa/2020.2/lin64/lib/ prop=fileset.sim_1.questa.compile.sccom.cores={4}コンフィギュレーション ファイルを生成したら、次のようにv++コマンド ラインで使用できます。v++ -link --config questa_sim.cfg - Xcelium
- リンク中に使用する次の詳細パラメーターと Vivado プロパティをコンフィギュレーション ファイルに追加します。
## Final set of additional options required for running simulation using Questa Simulator [advanced] param=hw_emu.simulator=XCELIUM [vivado] prop=project.__CURRENT__.compxlib.xcelium_compiled_library_dir=/proj/xbuilds/2020.2_daily_latest/clibs/xcelium/20.03.005/lin64/lib/ prop=fileset.sim_1.xcelium.elaborate.xmelab.more_options={-timescale 1ns/1ps}コンフィギュレーション ファイルを生成したら、次のようにv++コマンド ラインで使用できます。v++ -link --config xcelium.cfg - VCS
- リンク中に使用する次の詳細パラメーターと Vivado プロパティをコンフィギュレーション ファイルに追加します。
## Final set of additional options required for running simulation using Questa Simulator [advanced] param=hw_emu.simulator=VCS [vivado] prop=project.__CURRENT__.simulator.vcs_install_dir=/tools/gensys/vcs/Q-2020.03/bin/ prop=project.__CURRENT__.compxlib.vcs_compiled_library_dir=/proj/xbuilds/2020.2_daily_latest/clibs/vcs/Q-2020.03/lin64/lib/ prop=project.__CURRENT__.simulator.vcs_gcc_install_dir=/tools/installs/synopsys/vg_gnu/2019.06/amd64/gcc-6.2.0_64/binコンフィギュレーション ファイルを生成したら、次のようにv++コマンド ラインで使用できます。v++ -link --config vcs_sim.cfg
launch_emulator コマンドに -user-pre-sim-script オプションおよび -user-post-sim-script オプションを使用すると、シミュレーションの開始前またはシミュレーションの完了後に実行する Tcl スクリプトを指定できます。たとえば、これらのスクリプトでは、$cwd コマンドを使用してシミュレータの実行ディレクトリを取得し、シミュレーションの前に必要なファイルをコピーしたり、シミュレーションの最後に生成された出力ファイルをコピーしたりできます。
ハードウェア エミュレーションをイネーブルにするには、Vivado Design Suite でシミュレーション用の環境を設定する必要があります。重要なのは、シミュレータで使用する RTL および SystemC モデルをプリコンパイルしておくことです。これには、Vivado ツールで compile_sim_lib コマンドを実行する必要があります。シミュレーション モデルのプリコンパイルの詳細は、『Vivado Design Suite ユーザー ガイド: ロジック シミュレーション』 (UG900: 英語版、日本語版) を参照してください。
シミュレーション準備が整った Versal プラットフォームを作成すると、Vivado ツールでシミュレーション ラッパーが生成されます。このラッパーは、シミュレーション テストベンチにインスタンシエートする必要があります。そのため、デザイン モジュールの最上位が <top> である場合、Vivado ツールで launch_simulation を呼び出すと、<top>_sim_wrapper モジュールが生成され、xlnoc.bd も生成されます。これらのファイルはシミュレーション専用のソースとして生成され、Vivado ツールで launch_simulation が呼び出されるたびに上書きされます。プラットフォーム開発者は、独自の <top> モジュールではなく、このモジュールをテストベンチにインスタンシエートする必要があります。
シミュレータ波形ビューアーの使用
ハードウェア エミュレーションは、RTL および SystemC モデルを実行に使用します。通常のアプリケーションおよび HLS ベースのカーネル開発者の場合、ハードウェア レベルの詳細は必要ありません。Vitis アナライザーの提供するハードウェア実行モデルの詳細で十分です。ただし、ハードウェア信号とプロトコルに精通している上級ユーザーの場合、[Waveform] ビューおよびライブ波形ビューアー で説明するように、シミュレータ波形を使用してハードウェア エミュレーションを開始できます。
デフォルトでは、v++ --link -t
hw_emu を実行すると、最適化モードでシミュレーション モデルがコンパイルされます。ただし、-g オプションも設定した場合は、ハードウェア エミュレーション モデルをデバッグ モードでコンパイルできます。アプリケーション ランタイム中に、launch_hw_emu.sh コマンドに -g オプションを付けて実行すると、波形が表示された状態で GUI モードでシミュレータをインタラクティブに実行できます。デフォルトでは、ハードウェア エミュレーション フローで該当する共通の信号が波形ウィンドウに追加されます。シミュレータを一時停止すると、該当する信号を追加し、シミュレーションを再開できます。
XSIM 波形の AXI トランザクション表示
xsim で次の Tcl コマンドを使用します。add_wave <HDL_objects>
add_wave コマンドを使用すると、HDL オブジェクトへの絶対パスまたは相対パスを指定できます。TLM 波形の解釈方法および GUI でのインターフェイスの追加方法については、『Vivado Design Suite ユーザー ガイド: ロジック シミュレーション』 (UG900: 英語版、日本語版) を参照してください。
I/O トラフィック ジェネレーターの使用
概要
ビデオ ストリーミングやイーサネット ベースのアプリケーションなどの一部のユーザーアプリケーションでは、プラットフォーム上の I/O ポートを使用して、プラットフォームを出入りするデータをストリーミングします。これらのアプリケーションの場合、デザインのハードウェア エミュレーションを実行するには、I/O ポートのハードウェア動作を模倣して、ポートを通過するデータ トラフィックをシミュレーションするメカニズムが必要です。I/O トラフィック ジェネレーターを使用すると、Vitis アプリケーション アクセラレーション開発フローのハードウェア エミュレーション中、または Vivado Design Suite のロジック シミュレーション中に、I/O ポートを通過するトラフィックをモデル化できます。
デザインへのトラフィック ジェネレーターの追加
ザイリンクス デバイスには豊富な I/O インターフェイスがあります。Alveo アクセラレータ カードには、独自のモデルを持つ PCIe および DDR メモリ インターフェイスがあります。ただし、プラットフォームに GT カーネル ベースの汎用 I/O、ビデオ ストリーム、センサー データなどのほかの I/O が含まれることもあります。I/O トラフィック ジェネレーター カーネルを使用すると、シミュレーション中にプラットフォームとアプリケーションが I/O にトラフィックを挿入できるようになります。
このソリューションでは、ストリーミング I/O カーネル (XO) または IP の両方をデザインに含める必要があるほか、ザイリンクスの提供する Python または C++ API を使用して、トラフィックを挿入したり、エミュレーション プロセスからの出力データを取り込んだりする必要があります。ザイリンクスの提供する Python または C++ ライブラリを使用すると、トラフィック ジェネレーター コードをアプリケーションに統合し、別のプロセスとして実行し、エミュレーション プロセスとインターフェイスさせることができます。現在のところ、ザイリンクスでは、ストリーミング I/O を模倣する AXI4-Stream レベルでのインターフェイスをイネーブルにするライブラリを提供しています。
ストリーミング I/O モデルを使用すると、プラットフォーム上のストリーミング トラフィックをエミュレーションしたり、遅延モデリングをサポートしたりできます。アプリケーションにストリーミング I/O を追加することも、次に説明するようにカスタムプラットフォーム デザインに追加することもできます。
- ストリーミング I/O カーネルはほかのコンパイル済みカーネル オブジェクト (XO) ファイルと同様、
v++ --linkコマンドを使用してデバイス バイナリ (XCLBIN) ファイルに追加できます。Vitis インストールには、さまざまなデータ幅の AXI4-Stream インターフェイス用のカーネルが含まれます。これらは、ソフトウェアのインストール ディレクトリの $XILINX_VITIS/data/emulation/XO に含まれます。次のコマンド例を使用して、これらをデザインに追加します。
v++ -t hw_emu --link $XILINX_VITIS/data/emulation/XO/sim_ipc_axis_master_32.xo $XILINX_VITIS/data/emulation/XO/sim_ipc_axis_slave_32.xo ...上記の例では、sim_ipc_axis_master_32.xo および sim_ipc_axis_slave_32.xo が 32 ビットのマスターおよびスレーブ カーネルを提供し、ターゲット プラットフォームおよびデザイン内のほかのカーネルとリンクしてハードウェア エミュレーション ビルド用の .xclbin ファイルを作成可能にしています。
- また、Versal および Zynq UltraScale+ MPSoC カスタム プラットフォームの Vivado IP インテグレーター機能を使用して、IPC モジュールをプラットフォーム ブロック デザインに追加することもできます。このツールには、プラットフォーム デザインに追加する
sim_ipc_axis_master_v1_0およびsim_ipc_axis_slave_v1_0IP が含まれます。これらは、ソフトウェアのインストール ディレクトリの $XILINX_VIVADO/data/emulation/hw_em/ip_repo に含まれます。次に、IPC IP をプラットフォーム デザインに追加する Tcl スクリプトの例を示します。このスクリプトを使用すると、Python または C++ で記述された外部プロセスからシミュレーションにデータ トラフィックを挿入できます。
#Update IP Repository path if required set_property ip_repo_paths $XILINX_VIVADO/data/emulation/hw_em/ip_repo [current_project] ## Add AXIS Master create_bd_cell -type ip -vlnv xilinx.com:ip:sim_ipc_axis_master:1.0 sim_ipc_axis_master_0 #Change Model Property if required set_property -dict [list CONFIG.C_M00_AXIS_TDATA_WIDTH {64}] [get_bd_cells sim_ipc_axis_master_0] ##Add AXIS Slave create_bd_cell -type ip -vlnv xilinx.com:ip:sim_ipc_axis_slave:1.0 sim_ipc_axis_slave_0 #Change Model Property if required set_property -dict [list CONFIG.C_S00_AXIS_TDATA_WIDTH {64}] [get_bd_cells sim_ipc_axis_slave_0]
Python でのトラフィック ジェネレーターの記述
I/O トラフィック ジェネレーターでデータ トラフィックを生成するため、またはエミュレーション プロセスから出力データを取り込むためには、アプリケーションをシミュレーションするときにトラフィック ジェネレーター プロセスも含める必要があります。ザイリンクスの提供する Python または C++ ライブラリを使用すると、次に説明するようにトラフィック ジェネレーター コードを作成できます。
- Python の場合は、コマンド ターミナルで
$PYTHONPATHを次のように設定します。setenv PYTHONPATH $XILINX_VIVADO/data/emulation/hw_em/lib/python:\ $XILINX_VIVADO/data/python/xtlm_ipc/xtlm_ipc_v1_0 gt_masterインスタンスに接続する Python コードの例は、次のようになります。Blocking Send from xilinx_xtlm import ipc_axis_master_util from xilinx_xtlm import xtlm_ipc import struct import binascii #Instantiating AXI Master Utilities master_util = ipc_axis_master_util("gt_master") #Create payload payload = xtlm_ipc.axi_stream_packet() payload.data = "BINARY_DATA" # One way of getting "BINARY_DATA" from integer can be like payload.data = bytes(bytearray(struct.pack("i", int_number))) More info @ https://docs.python.org/3/library/struct.html payload.tlast = True #AXI Stream Fields #Optional AXI Stream Parameters payload.tuser = "OPTIONAL_BINARY_DATA" payload.tkeep = "OPTIONAL_BINARY_DATA" #Send Transaction master_util.b_transport(payload) master_util.disconnect() #Disconnect connection between Python & Emulationgt_slaveインスタンスに接続する Python コードの例は、次のようになります。Blocking Receive from xilinx_xtlm import ipc_axis_slave_util from xilinx_xtlm import xtlm_ipc #Instantiating AXI Slave Utilities slave_util = ipc_axis_slave_util("gt_slave") #Sample payload (Blocking Call) payload = slave_util.sample_transaction() slave_util.disconnect() #Disconnect connection between Python & Emulation
C++ でのトラフィック ジェネレーターの記述
- C++ の場合、API は $XILINX_VIVADO/data/cpp/xtlm_ipc/xtlm_ipc_v1_0/src/ にあります。C++ API は、ブロッキング関数とノンブロッキング関数の両方をサポートします。次のコード部分は、その使用方法を示しています。 ヒント: 実行ファイルを生成するサンプル Makefile もあります。
- ブロッキング送信:
#include "xtlm_ipc.h" //Include file void send_packets() { //! Instantiate IPC socket with name matching in IPI diagram... xtlm_ipc::axis_initiator_socket_util<xtlm_ipc::BLOCKING> socket_util("gt_master"); const unsigned int NUM_TRANSACTIONS = 8; xtlm_ipc::axi_stream_packet packet; std::cout << "Sending " << NUM_TRANSACTIONS << " Packets..." <<std::endl; for(int i = 0; i < NUM_TRANSACTIONS; i++) { xtlm_ipc::axi_stream_packet packet; // generate_data() is your custom code to generate traffic std::vector<char> data = generate_data(); //! Set packet attributes... packet.set_data(data.data(), data.size()); packet.set_data_length(data.size()); packet.set_tlast(1); //Additional AXIS attributes can be set if required socket_util.transport(packet); //Blocking transport API to send the transaction } } - ブロッキング受信:
#include "xtlm_ipc.h" void receive_packets() { //! Instantiate IPC socket with name matching in IPI diagram... xtlm_ipc::axis_target_socket_util<xtlm_ipc::BLOCKING> socket_util("gt_slave"); const unsigned int NUM_TRANSACTIONS = 8; unsigned int num_received = 0; xtlm_ipc::axi_stream_packet packet; std::cout << "Receiving " << NUM_TRANSACTIONS << " packets..." <<std::endl; while(num_received < NUM_TRANSACTIONS) { socket_util.sample_transaction(packet); //API to sample the transaction //Process the packet as per requirement. num_received += 1; } } - ノンブロッキング送信:
#include <algorithm> // std::generate #include "xtlm_ipc.h" //A sample implementation of generating random data. xtlm_ipc::axi_stream_packet generate_packet() { xtlm_ipc::axi_stream_packet packet; // generate_data() is your custom code to generate traffic std::vector<char> data = generate_data(); //! Set packet attributes... packet.set_data(data.data(), data.size()); packet.set_data_length(data.size()); packet.set_tlast(1); //packet.set_tlast(std::rand()%2); //! Option to set tuser tkeep optional attributes... return packet; } void send_packets() { //! Instantiate IPC socket with name matching in IPI diagram... xtlm_ipc::axis_initiator_socket_util<xtlm_ipc::NON_BLOCKING> socket_util("gt_master"); // Instantiate Non Blocking specialization const unsigned int NUM_TRANSACTIONS = 8; xtlm_ipc::axi_stream_packet packet; std::cout << "Sending " << NUM_TRANSACTIONS << " Packets..." <<std::endl; for(int i = 0; i < NUM_TRANSACTIONS; i++) { packet = generate_packet(); // Or user's test patter / live data etc. socket_util.transport(packet); } } - ノンブロッキング受信:
#include <unistd.h> #include "xtlm_ipc.h" void receive_packets() { //! Instantiate IPC socket with name matching in IPI diagram... xtlm_ipc::axis_target_socket_util<xtlm_ipc::NON_BLOCKING> socket_util("gt_slave"); const unsigned int NUM_TRANSACTIONS = 8; unsigned int num_received = 0, num_outstanding = 0; xtlm_ipc::axi_stream_packet packet; std::cout << "Receiving " << NUM_TRANSACTIONS << " packets..." <<std::endl; while(num_received < NUM_TRANSACTIONS) { num_outstanding = socket_util.get_num_transactions(); num_received += num_outstanding; if(num_outstanding != 0) { std::cout << "Outstanding packets = "<< num_outstanding <<std::endl; for(int i = 0; i < num_outstanding; i++) { socket_util.sample_transaction(packet); print(packet); } } usleep(100000); //As transaction is non-blocking we would like to give some delay between consecutive samplings } } - 次は、上記のブロッキング受信の Makefile の例です。
GCC=/usr/bin/g++ IPC_XTLM=$(XILINX_VIVADO)/data/cpp/xtlm_ipc/xtlm_ipc_v1_0/src/ PROTO_PATH=$(XILINX_VIVADO)/data/simmodels/xsim/2020.2/lnx64/6.2.0/ext/protobuf/ BOOST=$(XILINX_VIVADO)/tps/boost_1_64_0/ SRC_FILE=b_receive.cpp .PHONY: run all default: all all : b_receive b_receive: $(SRC_FILE) $(GCC) $(SRC_FILE) $(IPC_XTLM)xtlm_ipc.pb.cc -I$(IPC_XTLM)/ -I$(PROTO_PATH)/include/ -L$(PROTO_PATH) -lprotobuf -o $@ -lpthread -I$(BOOST)/
トラフィック ジェネレーターの実行
$XILINX_VIVADO/data/cpp/xtlm_ipc/xtlm_ipc_v1_0/src/ にあるライブラリを使用して、上記のように外部プロセス バイナリを生成したら、次の手順を使用してエミュレーションを実行できます。
- 標準プロセスを使用する Vitis ハードウェア エミュレーションまたは Vivado シミュレーションを起動し、シミュレーションが開始されるのを待ちます。
- 別のターミナルから、 Python や C++ などの外部プロセスを起動します。