第2回~第4回では、UVMにおける、TLMによるコンポーネント間の通信の例を示します。今回は、analysis_port/analysis_exportを使用した例を示します。TLMの解説は、第1回 解説編をご覧ください。
関連記事
なお、ソースコードはGitHubに公開しています。
目次
トランザクションはuvm_sequence_itemを継承して作成します。第1回 解説編 の記事で解説したものと同じものを使います。
(1) simple_transaction.sv
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | class simple_transaction extends uvm_sequence_item; rand bit[7:0] data_e; rand bit[7:0] data_o; constraint CE { data_e[0] == 1'b0; } // Even number constraint CO { data_o[0] == 1'b1; } // Odd number `uvm_object_utils_begin(simple_transaction) `uvm_field_int(data_e, UVM_DEFAULT) `uvm_field_int(data_o, UVM_DEFAULT) `uvm_component_utils_end function new (string name = "simple_transaction"); super.new(name); endfunction endclass |
UVMのコンポーネントは3種類作成します。
(2) analysis_producer.sv
uvm_analysis_port#(T)により、analysis_portを定義します。トランザクションを生成し、analysis_port.write( )を呼び、Write動作を発生させます。19行目です。
実際のUVM環境では、collectorやmonitorに対してanalysis_portを実装することになります。これらは、DUT (検証対象の回路) の信号を収集してトランザクションを生成します。今回は簡単のため、analysis_producer内でrandomizeによりトランザクションの内容をつくります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | class analysis_producer extends uvm_component; uvm_analysis_port #(simple_transaction) analysis_port; `uvm_component_utils(analysis_producer) function new(string name, uvm_component parent); super.new(name, parent); analysis_port = new("analysis_port", this); endfunction task run_phase(uvm_phase phase); simple_transaction data; for (int i = 0; i < 5; i++) begin `uvm_info("PRODUCER", $sformatf("Producing data... i = %d", i), UVM_LOW) data = simple_transaction::type_id::create("data"); assert (data.randomize()); `uvm_info("PRODUCER", $sformatf("Write: data_e = %d, data_o = %d", data.data_e, data.data_o), UVM_LOW) analysis_port.write(data); // Initiate writing a transaction end endtask endclass |
(3) analysis_subscriber.sv
uvm_analysis_imp#(T, IMP)により、analysis_exportを定義します。function void write( )に、Writeされた時の動作を定義します。今回の”動作”は、単に受け取ったトランザクションの内容をプリント(`uvm_info)するだけです。subscriberは、1対N接続のN側なので、時間を消費できません。したがって、functionでwrite( )が定義されていることに注意してください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | class analysis_subscriber extends uvm_component; uvm_analysis_imp #(simple_transaction, analysis_subscriber) analysis_export; `uvm_component_utils(analysis_subscriber) function new(string name, uvm_component parent); super.new(name, parent); analysis_export = new("analysis_export", this); endfunction function void write(simple_transaction data); // Define behavior of write() in function `uvm_info(get_name(), // Just print received data with name of the object $sformatf("Got: data_e = %d, data_o = %d", data.data_e, data.data_o), UVM_LOW) endfunction endclass |
(4) analysis_parent.sv
build_phaseでanalysis_producerとanalysis_subscriberをインスタンスし、connect_phaseでanalysis_portとanalysis_exportを接続します。24, 25行目です。
今回は、subscriber1とsubscriber2の2つのサブスクライバーをインスタンスします。そして、1つのAnalysis portに対して、2つのAnalysis exportを接続します。
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 | class analysis_parent extends uvm_component; analysis_producer producer; analysis_subscriber subscriber1; analysis_subscriber subscriber2; `uvm_component_utils(analysis_parent) function new(string name, uvm_component parent); super.new(name, parent); endfunction function void build_phase(uvm_phase phase); super.build_phase(phase); producer = analysis_producer::type_id::create("producer", this); subscriber1 = analysis_subscriber::type_id::create("subscriber1", this); subscriber2 = analysis_subscriber::type_id::create("subscriber2", this); endfunction function void connect_phase(uvm_phase phase); super.connect_phase(phase); producer.analysis_port.connect(subscriber1.analysis_export); producer.analysis_port.connect(subscriber2.analysis_export); endfunction endclass |
(5) pkg.sv
作成したすべてのclassをpackageにしておきます。次のtop.svのように、importして使うことで、すっきりした記述になります。
1 2 3 4 5 6 7 8 9 10 11 12 13 | package pkg; `include "uvm_macros.svh" import uvm_pkg::*; /* Include transactions */ `include "simple_transaction.sv" /* Include classes */ `include "analysis_producer.sv" `include "analysis_subscriber.sv" `include "analysis_parent.sv" endpackage |
(6) top.sv
analysis_parentのインスタンスを生成し、run_testします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | `include "uvm_macros.svh" `include "pkg.sv" module top(); import uvm_pkg::*; import pkg::*; analysis_parent parent; initial begin `uvm_info("INFO", "get port test", UVM_LOW) parent = analysis_parent::type_id::create("parent", null); run_test(); end endmodule |
Vivado Simulatorで動作します。実行の手順はこちらの記事をご覧ください。QuestaとModelSimで行うためには有料版が必要です。randomize( )機能は有料版でないと使えないようです。
Printされた内容はTcl Consoleに出力されます。analysis_producerがwrite( )したトランザクションを、subscriber1とsubscriber2がそれぞれ受け取り、プリントしています。実際のUVM環境では、subscriber1は期待値との比較によるチェック、subscriber2はカバレッジ計算…というように使います。
UVM_INFO C:/sim_1/analysis_producer.sv(21) @ 0: parent.producer [PRODUCER] Producing data… i = 0
UVM_INFO C:/sim_1/analysis_producer.sv(28) @ 0: parent.producer [PRODUCER] Write: data_e = 248, data_o = 223
UVM_INFO C:/sim_1/analysis_subscriber.sv(18) @ 0: parent.subscriber1 [subscriber1] Got: data_e = 248, data_o = 223
UVM_INFO C:/sim_1/analysis_subscriber.sv(18) @ 0: parent.subscriber2 [subscriber2] Got: data_e = 248, data_o = 223
UVM_INFO C:/sim_1/analysis_producer.sv(21) @ 0: parent.producer [PRODUCER] Producing data… i = 1
UVM_INFO C:/sim_1/analysis_producer.sv(28) @ 0: parent.producer [PRODUCER] Write: data_e = 170, data_o = 145
UVM_INFO C:/sim_1/analysis_subscriber.sv(18) @ 0: parent.subscriber1 [subscriber1] Got: data_e = 170, data_o = 145
UVM_INFO C:/sim_1/analysis_subscriber.sv(18) @ 0: parent.subscriber2 [subscriber2] Got: data_e = 170, data_o = 145
UVM_INFO C:/sim_1/analysis_producer.sv(21) @ 0: parent.producer [PRODUCER] Producing data… i = 2
UVM_INFO C:/sim_1/analysis_producer.sv(28) @ 0: parent.producer [PRODUCER] Write: data_e = 114, data_o = 119
UVM_INFO C:/sim_1/analysis_subscriber.sv(18) @ 0: parent.subscriber1 [subscriber1] Got: data_e = 114, data_o = 119
UVM_INFO C:/sim_1/analysis_subscriber.sv(18) @ 0: parent.subscriber2 [subscriber2] Got: data_e = 114, data_o = 119
…略…
今回は、analysis_port/analysis_exportの使用例を示しました。ポートの生成、write( )メソッドの定義、ポートの接続については、参考にしていただけると思います。