UVMの環境構築第11回では、Topモジュールの定義(作成)方法について解説していきます。
なお、ソースコードはGitHubに公開しています。
目次
UVMの環境構築!シリーズの目次は、第1回 解説編の一番下をご覧ください。
検証におけるTopモジュールはテストベンチとも呼ばれます。テストベンチは一般に、DUTと検証機能をインスタンスとして保有します。
UVMのTopモジュールでは主に次のことを行います。
上記6.については、コマンドライン引数でテストコンポーネント(テストケース)を指定することで、Topモジュールでインスタンスの作成は不要となります。コマンドライン引数でテストコンポーネントを指定したほうが、Topモジュールの再利用性が高まります。
では早速ソースコードを見ながら、Topモジュールの定義方法について説明します。
top.sv
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | `include "uvm_macros.svh" `include "my_definitions.svh" `include "my_if.sv" `include "pkg.sv" module top(); import uvm_pkg::*; import pkg::*; bit clk; my_if sif (clk); //my_test1 test1; /* Clock generation */ initial forever #10 clk = ~clk; /* DUT */ MC_MULT #( .P_BW_A ( `BW_A ), /* Bit width of A_IN. P_BW_A clocks needed for calculation */ .P_BW_B ( `BW_B ) /* Bit width of B_IN */ ) MC_MULT ( .CLK ( sif.clk ), .RST ( sif.rst ), /* Active high */ .A_IN ( sif.a_in ), .B_IN ( sif.b_in ), .START ( sif.start ), /* Caluculation start */ .MULT_OUT ( sif.mult_out ), /* Multiply result. This value is valid when VALID==1'b1 */ .VALID ( sif.valid ) /* Result valid. 1 clock pulse */ ); /* Main */ initial begin /* my_monitor to my_monitor_coverage */ uvm_factory factory = uvm_factory::get(); factory.set_type_override_by_type(my_monitor::get_type(), my_monitor_coverage::get_type()); /* If create test instance, UVM runs this test */ //test1 = my_test1::type_id::create("test1", null); /* Set interface */ uvm_config_db #(virtual my_if)::set(null, "*env0*", "vif", sif); /* Run */ run_test(); end endmodule |
UVM環境構築で定義したclassをpkg.svにまとめます。そして、topでこのpkg.svをインクルードします。このようにすることで、すっきりした記述になります。
pkg.sv
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | package pkg; `include "uvm_macros.svh" import uvm_pkg::*; /* Transaction */ `include "my_item_base.sv" `include "my_item.sv" /* Typedef */ typedef virtual my_if VIF_DRIVER; typedef virtual my_if VIF_COLLECTOR; /* Include classes */ `include "my_driver_base.sv" `include "my_driver.sv" `include "my_sequencer.sv" `include "my_sequence_base.sv" `include "my_sequence1.sv" `include "my_collector_base.sv" `include "my_collector.sv" `include "my_monitor.sv" `include "my_monitor_coverage.sv" `include "my_agent.sv" `include "my_scoreboard.sv" `include "my_env.sv" `include "my_test_base.sv" `include "my_test1.sv" endpackage |
通常、コマンドライン引数でテストケースを指定します。一般的には次のように書きます。
+UVM_TESTNAME=my_test1 |
今回はXilinxのVivado環境でシミュレーションを行いました。この場合はVivadoのTools→Settingsと行って、図2のところに以下のように書きます。
-testplusarg UVM_TESTNAME=my_test1 |
なお、コマンドライン引数でテストケースを指定せず、topでテストコンポーネントのインスタンスも作成しない場合は、エラーとなってシミュレーションは進みません。これは、テストケースが何も指定されていない状態になるので、当然といえば当然です。
以上でUVMの環境構築ができました!実行すると、次のように出力されます。なお、DUTについては第1回 解説編で説明しています。
@ 450000: a_in = 85, b_in = 3, mult_out = 255
@ 670000: a_in = 66, b_in = 10, mult_out = 660
…略…
@ 3530000: a_in = 68, b_in = 6, mult_out = 408
@ 3750000: a_in = 170, b_in = 4, mult_out = 680
…略…
UVM_INFO my_test_base.sv(37) @ 3950000: uvm_test_top [my_test1] [PASS] Trial = 16, Error = 0
DUTにコーディングミスがあった場合
DUTのこちらの行を、
b_lat <= b_lat << 1; /* This is correct */ |
ミスにより、下記のように書いてしまった場合の実行結果を示します。
b_lat <= b_lat >> 1; /* This is miss cording */ |
以下のように、不具合を検出しています。
@ 450000: a_in = 85, b_in = 3, mult_out = 3
UVM_ERROR my_scoreboard.sv(34) @ 450000: uvm_test_top.env0.scoreboard0 [my_scoreboard] @
450000: a_in = 85, b_in = 3, mult_out = 3, mult_exp = 255
@ 670000: a_in = 66, b_in = 10, mult_out = 5
UVM_ERROR my_scoreboard.sv(34) @ 670000: uvm_test_top.env0.scoreboard0 [my_scoreboard] @
670000: a_in = 66, b_in = 10, mult_out = 5, mult_exp = 660
…略…
UVM_INFO my_test_base.sv(37) @ 3950000: uvm_test_top [my_test1] [FAIL] Trial = 16, Error = 16
…略…
UVM_FATAL : 0
UVM_ERROR : 16
UVM_WARNING : 0
UVM_INFO : 6
全11シリーズにてUVMの環境構築方法について解説しました。UVMはIEEE Std 1800.2-2017規格となっており、ハードウェア設計者および検証技術者にとっては必須の知識になってきています。今回の記事が技術習得の一助となれば幸いです。
長いシリーズになりましたが、ご覧いただきありがとうございました。