Quartus Prime IPライブラリをVUnitに統合する:ステップバイステップガイド
VHDLシミュレーションでQuartus IPコアをVUnit検証フレームワークを通じて実行したいと思ったことはありませんか?
FPGAエンジニアのKonstantinos Paraskevopoulos氏がまさにそれを考えていましたが、適切なチュートリアルが見つかりませんでした。幸い、彼は自身の才能で解決方法を見つけ、VHDLwhizを通じてこのゲスト記事として共有してくれました。
Konstantinos氏に語っていただきましょう!
VUnitでシステムをシミュレートする際、Quartus IPカタログから事前定義されたIPを設計に組み込みたいケースはよくあります。このチュートリアルでは、外部Quartus IPライブラリをVUnit環境で生成、組み込み、リンクするために必要な知識を提供します。
VUnitを初めて使う方へ:VUnit入門チュートリアルをご覧ください
概要
このチュートリアルは3つの主要パートで構成されます:
- 選択したIPの簡単な説明
- 適切なライブラリの生成とリンクに必要な手順
- VUnitとModelSimを利用した検証
必要要件
- Quartus
- Quartus Primeをダウンロード
- QSYSをPATHに追加(STEP 2のCMDオプション用)
- Intel ModelSim
- こちらの記事を参照してModelSimを無料インストール
- ModelSimをPATHに追加
- VUnit
- こちらの記事を参照してVUnitを無料インストール
- Python 3.6以上
- Pythonをダウンロード
- PythonをPATHに追加
基本的なVHDL知識とModelSimスキルがあることを前提としています。
テスト対象設計
シナリオとして、Quartus整数演算IPリストのパラレルアダーIPを使用します。

この設計は3つの16ビット入力ベクトルを受け取り、加算結果を17ビットベクトルで出力します。
ステップ1:IPの生成
IPカタログウィンドウで、Library/Basic functions/Arithmetic配下のパラレルアダーコンポーネントをダブルクリックしてアダーを生成します。
名前を付け、ニーズに基づいてコンポーネントをカスタマイズした後、右下の「Generate HDL」ボタンをクリックします。

この時点で、次の図のようなウィンドウが表示されます。
注: SimulationセクションのCreate simulation modelをVHDLまたはVerilogに設定する必要があります。デフォルトはnoneです。選択しない場合、given_ip_name.spdファイルが生成されず、次のステップが失敗します。

上記のプロセスにより、quartusディレクトリ配下にファイルとフォルダが生成されます:
- ファイル:
given_ip_name.ip - フォルダ:
given_ip_name
フォルダには後でrun.pyスクリプトに追加する必要のある.vhdおよび.vファイルが含まれます。
ステップ2:IPシミュレーションファイルの生成
- GUI: Tools ➤ Generate Simulator Setup Script for IPを選択し、プロンプトウィンドウで出力ディレクトリを指定
- CMD: Qsysコマンドを利用して、ターミナルで以下のコマンドを入力して同じファイルを生成
ip-setup-simulation --quartus-project= <project's_QPF_filepath> \ --output-directory= <my_dir>
上記いずれかの方法で、Quartusにサポートされる各シミュレータ用のディレクトリを生成させ、IPライブラリの作成とコンパイル用スクリプトを保持させます。
ステップ3:ModelSim用IPライブラリの生成とコンパイル
次のステップは、前のステップで作成されたmentorフォルダ内のmsim_setup.tclスクリプトを見つけ、それをsetup.tclという名前で複製することです。次に、setup.tclファイルで図示されたコマンドをアンコメントし、$QSYS_SIMDIR変数を設定します。
# # QSYS_SIMDIR is used in the Quartus-generated IP simulation script to # # construct paths to the files required to simulate the IP in your Quartus # # project. By default, the IP script assumes that you are launching the # # simulator from the IP script location. If launching from another # # location, set QSYS_SIMDIR to the output directory you specified when you # # generated the IP script, relative to the directory from which you launch # # the simulator. # set QSYS_SIMDIR <script generation output directory> # # # Source the generated IP simulation script. source $QSYS_SIMDIR/mentor/msim_setup.tcl # # # Set any compilation options you require (this is unusual). # set USER_DEFINED_COMPILE_OPTIONS <compilation options> # set USER_DEFINED_VHDL_COMPILE_OPTIONS <compilation options for VHDL> # set USER_DEFINED_VERILOG_COMPILE_OPTIONS <compilation options for Verilog> # # # Call command to compile the Quartus EDA simulation library. dev_com # # # Call command to compile the Quartus-generated IP simulation files. com #
setup.tclを変更・保存後、vsimコマンドでTclファイルを安全に実行できます。
vsim -c -do "do setup.tcl; quit"
これにより、コンパイル済みライブラリがmentorフォルダに生成されます。
ステップ4:VUnitへのリンク
IPライブラリが生成されたので、Pythonrun.pyスクリプトを使用してリンクします。
以下の図を参照して、例のディレクトリ構造を理解してください。初期トポロジは、ルートフォルダdemo、tb、vunit、quartusフォルダで構成されていました。quartusフォルダ配下のすべてのサブフォルダとファイルは、プロジェクト作成とステップ1~3の完了後にQuartusフレームワークによって生成されます。
注: Quartusはさらに多くのファイルとフォルダを生成しますが、以下の画像は私たちに関連するものを示しています。

このトポロジの明確なビューを参考に、ROOTパスと生成されたライブラリへのパスを以下のように指定できます。
sim_filesはステップ2で指定したディレクトリで、mentorフォルダが格納されています。
from vunit import VUnit
from os.path import join, dirname, abspath
# ROOT
root = join(dirname(__file__), '../')
# 生成ライブラリへのパス
path_2_lib = '/quartus/sim_files/mentor/libraries/'
# ROOT
vuというVUnitインスタンスを作成後、VHDLコード用の設計ライブラリを指定し、必要な外部ライブラリをリンクします:
# コマンドライン引数を解析してVUnitインスタンスを作成
vu = VUnit.from_argv()
# 設計ライブラリを作成
my_lib = vu.add_library('my_lib')
# 外部ライブラリをリンク
vu.add_external_library("parallel_adder", root + path_2_lib + "parallel_adder")
最後に、ソースファイルを追加します。これらはgiven_ip_nameディレクトリ配下の3つのサブフォルダにあります:
parallel_add_191synthsim
synthとsimディレクトリには同じ情報、つまりIPのトップレベル設計が含まれます。ただし、ステップ1で選択した言語に応じてVHDLまたはVerilogでフォーマットされています。
トップレベル設計がサブコンポーネントを含む場合、それらのソースファイルも含める必要があります。それらはgiven_ip_nameディレクトリ配下のサブフォルダにあり、今回はparallel_add_191コンポーネントが該当します。
my_lib.add_source_files(join(root,'quartus','parallel_adder','sim','parallel_adder.vhd'))
my_lib.add_source_files(join(root,'quartus','parallel_adder','parallel_add_191','sim','parallel_adder_parallel_add_191_oh4guxa.vhd'))
my_lib.add_source_files(join(root,'tb','tb_demo.vhd'))
testbench = my_lib.entity("tb_demo")
vu.main()
テストベンチ
まず、VUnitテストベンチ形成の基礎についてはこちらのリンクをご覧ください。
テストベンチに戻り、必要なVUnitライブラリと使用したいその他のライブラリを追加し、信号を定義します。
注: 例でのプロセス実行は逐次的です。したがって、制御信号(フラグと呼ばれる)を使用して、プロセスが開始または終了すべきかを通知します。
library IEEE;
use IEEE.std_logic_1164.all;
use ieee.numeric_std.all;
library vunit_lib;
context vunit_lib.vunit_context;
entity tb_demo is
generic (runner_cfg : string:= runner_cfg_default);
end tb_demo;
architecture sim of tb_demo is
constant clk_period : time := 10 ns;
signal clk : std_logic := '0';
signal rst : std_logic := '0';
-- INPUTS
signal data_a : std_logic_vector(0 to 15):= (others => '0');
signal data_b : std_logic_vector(0 to 15):= (others => '0');
signal data_c : std_logic_vector(0 to 15):= (others => '0');
-- OUTPUTS
signal result : std_logic_vector(0 to 16);
-- CONTROL FLAGS
signal reset_done :boolean := false;
signal sim_done :boolean := false;
signal start_sim :boolean := false;
続いて、UUTをインスタンス化します。Quartusは、ファイル名規則ip_name_inst.vhdとip_name_inst.vで、VHDLとVerilogのコンポーネントインスタンス化例を提供しています。
begin
-- Unit Under Test
UUT : entity work.parallel_adder port map (
data0x => data_a, -- parallel_add_input.data0x
data1x => data_b, -- .data1x
data2x => data_c, -- .data2x
result => result -- parallel_add_output.result
);
最初に開始する2つのプロセスはclk_processとreset_relです。後者はリセット後とreset_doneフラグをtrueに駆動した後に一時停止しますが、clk_processはシミュレーション時間中ずっと動作します。
clk_process : process begin
clk <= '1';
wait for clk_period/2;
clk <= '0';
wait for clk_period/2;
end process clk_process;
reset_rel : process begin
rst <= '1';
wait for clk_period*2;
wait until rising_edge(clk);
rst <= not rst;
reset_done <= true;
wait;
end process reset_rel;
リセットが完了したので、テスト実行のためにtest_runnerプロセスを呼び出せます。さらに、テストランナーはsim_doneフラグがtrueになるまでアクティブであり、これは最後のプロセスで行われます。
test_runner : process begin
test_runner_setup(runner, runner_cfg);
wait until reset_done and rising_edge(clk);
iterate : while test_suite loop
start_sim <= true;
if run("test_case_1") then
info ("Start");
info (running_test_case);
wait until sim_done;
end if;
end loop;
test_runner_cleanup(runner);
end process test_runner;
最後に、data_generatorプロセスがforループを利用して、パラレルアダーの3つの入力に値を割り当て、複数の加算を実行します。
注: このプロセスは、test_runnerプロセスがstart_simフラグを設定することで指示したときにトリガーされます。このプロセスの最後にsim_doneフラグを立て、テストランナーにシミュレーション一時停止を命令します。
data_generator : process
constant tag2 : log_level_t := new_log_level("INFO", fg => blue, bg => black, style => bright);
variable a,b,c,d : integer;
begin
wait until start_sim;
wait until rising_edge(clk);
show(display_handler, tag2);
if running_test_case = "test_case_1" then
for i in 0 to 10 loop
data_a <= std_logic_vector(to_unsigned(i+10,data_a'length));
data_b <= std_logic_vector(to_unsigned(i+20,data_a'length));
data_c <= std_logic_vector(to_unsigned(i+30,data_a'length));
wait until rising_edge(clk);
a := to_integer(unsigned(data_a));
b := to_integer(unsigned(data_b));
c := to_integer(unsigned(data_c));
d := to_integer(unsigned(result));
log(integer'image(a) & " + " & integer'image(b) & " + " & integer'image(c) & " = " & integer'image(d), tag2);
end loop;
end if;
sim_done <= true;
end process data_generator;
検証
テストケースを実行し、すべてが期待通りに動作することを確認するには、run.pyスクリプトが配置されているディレクトリからターミナルで以下のコマンドを入力するだけです。
python ./run.py -v
注: カスタマイズされたロガーを使用しており、冗長オプション-vを指定することで出力に表示されます。また、テストケースが1つしか定義されていないため、それを指定するオプションを提供する必要はありません。

最後に、ModelSimで結果を検証するには、以下のコマンドを入力します:
python ./run.py --gui

(画像をクリックすると拡大表示されます)
結論
結論として、IPカタログに存在するQuartus IPをVUnit環境内で組み込み、テストする方法を学びました。このチュートリアルでは事前定義IPを使用しましたが、同じプロセスがカスタムパッケージIPにも適用されます。
まだの方はこちらのVUnitチュートリアルもご覧ください:
VUnit入門
VHDL
- チェーンリンクフェンス製造機:仕組みとメリット
- テクノロジーが鍵:透明で倫理的なサプライチェーンの実現
- 油圧ギアポンプのプライミング手順:最適な性能を引き出すために
- フォードトラクター油圧ポンプのプライミング手順:ステップバイステップガイド
- SigFox解説:技術、市場インパクト、Link Labsとの比較
- VUnit 101:自動化VHDL検証の実践ガイド
- VHDLで文字列リストを作成する: ベスト・プラクティスと実装例
- VHDLテストベンチ・シミュレーションを優雅に終了させる方法
- VHDLでPWMコントローラを実装: 設計、シミュレーション、FPGAデモ
- VHDLで乱数生成: 一様分布からOSVVMまで
- VHDLで自己検証テストベンチを構築する実践ガイド