FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

Vivado Simulatorを使ってUVMに入門する (8. スコアボードの導入)

sites.google.com

次は、期待値の自動比較を考えていく。 スコアボードを導入するというわけだ。

1000回のランダム書き込みの後、1000回リードして比較をする、ということを自動化できるようにする。

このために、スコアボードを組み込む。このためにはモニタにanalysis_portというものを導入する。 まずはスコアボードのアイテムを定義しよう。これはスコアボードのエントリフィールドに相当するものだと思う。

class sample_scrbd_item extends uvm_object;
  bit [7:0] addr, data;
  `uvm_object_utils_begin(sample_scrbd_item)
    `uvm_field_int(addr, UVM_DEFAULT)
    `uvm_field_int(data, UVM_DEFAULT)
  `uvm_object_utils_end
  function new (string name="sample_scrbd_item");
    super.new(name);
  endfunction
endclass

そしてこのクラスを使って、analysis_portを使い挙動を書き込む:

  • 期待値用のanalysis_portを組み込む
  • 観測値用のanalysis_portを組み込む
  • analysis_portを用いて、スコアボードに書き込む

これらをsample_master_monitorに埋め込んでおく。

  • model/sample_master_monitor.sv
class sample_master_monitor extends uvm_monitor;
  virtual sample_if vif;
  uvm_analysis_port #(sample_scrbd_item) ap_write;
  uvm_analysis_port #(sample_scrbd_item) ap_read;
  event scrbd_e;  //イベント定義
  `uvm_component_utils(sample_master_monitor)
  function new (string name, uvm_component parent);
    super.new(name, parent);
    ap_write = new("ap_write", this);
    ap_read  = new("ap_read", this);
  endfunction

テストベンチ側のumv_envクラスを定義する(tb_env.sv)。なんとなく、sample_envgp_scoreboardをさらに上位で囲ったような構造をしている。

class tb_env extends uvm_env;
  sample_env    sample_model;
  gp_scoreboard #(sample_scrbd_item) sample_scrbd;  // Generic score-board
/* ... 途中省略 ... */

sample_test.svは以下のような構成になっている。

  • sample_test.sv
class sample_test extends uvm_test;

  `uvm_component_utils(sample_test)
  tb_env env;
/* ... 途中省略 ... */
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    uvm_config_db #(uvm_object_wrapper)::set(this,
      "env.sample_model.master.sequencer.run_phase", "default_sequence",
      write_read_seq::type_id::get()
      );
    uvm_config_db #(uvm_object_wrapper)::set(this,
      "env.sample_model.slave.sequencer.run_phase",  "default_sequence",
      normal_response_seq::type_id::get()
      );
    env = tb_env::type_id::create("env", this);
  endfunction // build_phase
UVM_INFO @ 0: uvm_test_top.env.sample_model.slave.driver [SLAVE] write access accept. addr=10h, data=5ah
UVM_INFO @ 0: uvm_test_top.env.sample_model.master.monitor [MON] write addr=10h wdata=5ah
UVM_INFO @ 0: uvm_test_top.env.sample_scrbd [SCRBD] write expected data
UVM_INFO @ 0: uvm_test_top.env.sample_model.master.driver [DRIVER] Hi
UVM_INFO @ 1000: uvm_test_top.env.sample_model.slave.driver [SLAVE] read access accept. adr=10h
UVM_INFO @ 1000: uvm_test_top.env.sample_model.slave.driver [SLAVE] read data is = 5ah
UVM_INFO @ 1000: uvm_test_top.env.sample_model.master.monitor [MON] read  addr=10h rdata=5ah
UVM_INFO @ 1000: uvm_test_top.env.sample_scrbd [SCRBD] write observed data
UVM_INFO @ 1000: uvm_test_top.env.sample_scrbd [SCRBD] data compare OK
UVM_INFO @ 1000: uvm_test_top.env.sample_model.master.driver [DRIVER] Hi

Vivado Simulatorを使ってUVMに入門する (7. 複数のテストを試行する)

もう何回目になるのかわからないが、そろそろUVMを覚えなければならないのでVivado Simulatorを使ってUVMに入門してみよう。

前回作ったテストが、Vivado 2023.2 だと、なんとなく動かなかったので、DSimでも試行している。

参考にしているのは例によって以下のウェブサイトだ:

sites.google.com

UVMによりいくつかのテストシーケンスを用意する、という話だ。sample_testsample_test2というテストを用意している。

  • sample_test.sv
class sample_test extends uvm_test;
  `uvm_component_utils(sample_test)
/* ... 途中省略 ... */
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    uvm_config_db #(uvm_object_wrapper)::set(this, "env.master.sequencer.run_phase", "default_sequence", write_read_seq::type_id::get());
    uvm_config_db #(uvm_object_wrapper)::set(this, "env.slave.sequencer.run_phase",  "default_sequence", normal_response_seq::type_id::get());
    env = sample_env::type_id::create("env", this);
  endfunction // build_phase

class sample_test2 extends uvm_test;
  `uvm_component_utils(sample_test2)
/* ... 途中省略 ... */
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    uvm_config_db #(uvm_object_wrapper)::set(this, "env.master.sequencer.run_phase", "default_sequence", write_read_seq::type_id::get());
    uvm_config_db #(uvm_object_wrapper)::set(this, "env.slave.sequencer.run_phase",  "default_sequence", random_response_seq::type_id::get());
    env = sample_env::type_id::create("env", this);
  endfunction // build_phase

sample_testsample_test2の違いは、受け取り側のタスクがnormal_response_seqrandom_response_seqのどちらかである、ということだ。

  • model/sample_slave_seq_lib.sv
class random_response_seq extends sample_slave_base_seq;
  `uvm_object_utils(random_response_seq)

  function new (string name="random_response_seq");
    super.new(name);
  endfunction // new

  virtual task body();
    forever begin
      `uvm_create (req);
      req.wait_cycle <= $urandom_range(8, 0);
      `uvm_send(req)
    end
  endtask // body

endclass // random_response_seq

sample_test2では、レスポンスのためのreadyの立ち上がりのタイミングがランダムになる。

UVM_INFO @ 1000: uvm_test_top.env.slave.driver [SLAVE] write access accept. addr=10h, data=5ah
UVM_INFO @ 1000: uvm_test_top.env.master.monitor [MON] write addr=10h wdata=5ah
UVM_INFO @ 1000: uvm_test_top.env.master.driver [DRIVER] Hi
UVM_INFO @ 2000: uvm_test_top.env.slave.driver [SLAVE] read access accept. adr=10h
UVM_INFO @ 2000: uvm_test_top.env.slave.driver [SLAVE] read data is = 5ah
UVM_INFO @ 2000: uvm_test_top.env.master.monitor [MON] read  addr=10h rdata=5ah
UVM_INFO @ 2000: uvm_test_top.env.master.driver [DRIVER] Hi

Vivado Simulatorを使ってUVMに入門する (6. MasterとSlaveのモデルを試行する)

もう何回目になるのかわからないが、そろそろUVMを覚えなければならないのでVivado Simulatorを使ってUVMに入門してみよう。

前回作ったテストが、Vivado 2023.2 だと、なんとなく動かなかったので、DSimでも試行している。

参考にしているのは例によって以下のウェブサイトだ:

sites.google.com

MasterとSlaveのシーケンスを確認している。以下のページを参考にした。

sites.google.com

いくつかの修正点について、自分で詰まってしまった部分をまとめよう。

  • model/sample_slave_seq_lib.sv
virtual class sample_slave_base_seq extends uvm_sequence #(sample_seq_item);
  function new(string name="sample_slave_base_seq");
    super.new(name);
    do_not_randomize = 1;
    // set_automatic_phase_objection(1);  <-- これを追加しているとシミュレーションが終了しない
  endfunction // new
endclass
  • model/sample_slave_driver.sv
  task run_phase (uvm_phase phase);
    uvm_report_info ("DRIVER", "Hi");
    vif.ready <= 1'b0;
    // vif.valid <= 1'b0;  <-- たぶんここはvif.readyなんだと思う
    @(posedge vif.rstz);  // wait reset negate
    forever begin
      seq_item_port.get_next_item (req); // wait seq_item from sequence (via sequencer)
      @(posedge vif.valid);
      repeat (req.wait_cycle) @(posedge vif.clk);
      vif.ready <= 1'b1;
      if (vif.write === 1'b1) begin
        mem_write (vif.addr, vif.wdata);
      end else if (vif.write === 1'b0) begin
        vif.rdata <= mem_read(vif.addr);
      end
      @(posedge vif.clk) vif.ready <= 1'b0;
      seq_item_port.item_done (req);
    end // forever begin
  endtask // run_phase

DSim / Vivado Simulatorの両方で動作を確認できた。

Hello Master SEQ
UVM_INFO @ 1000: uvm_test_top.env.slave.driver [SLAVE] write access accept. addr=10h, data=55h
UVM_INFO @ 1000: uvm_test_top.env.master.monitor [MON] write addr=10h wdata=55h
UVM_INFO @ 1000: uvm_test_top.env.master.driver [DRIVER] Hi
UVM_INFO @ 2000: uvm_test_top.env.slave.driver [SLAVE] read access accept. adr=10h
UVM_INFO @ 2000: uvm_test_top.env.slave.driver [SLAVE] read data is = 55h
UVM_INFO @ 2000: uvm_test_top.env.master.monitor [MON] read  addr=10h rdata=55h
UVM_INFO @ 3000: uvm_test_top.env.master.driver [DRIVER] Hi
UVM_INFO @ 3000: uvm_test_top.env.master.sequencer@@write_seq [SEQ] read data is 55h

Vivado Simulatorを使ってUVMに入門する (5. DSimで動作を確認する)

もう何回目になるのかわからないが、そろそろUVMを覚えなければならないのでVivado Simulatorを使ってUVMに入門してみよう。

前回作ったテストが、Vivado 2023.2 だと、なんとなく動かなかったので、DSimでも試行している。

参考にしているのは例によって以下のウェブサイトだ:

sites.google.com

dsim -top work.tb_top -genimage image -uvm 1.1d +incdir+model -f filelist.f +acc+b
dsim -image image -uvm 1.1d -waves waves.mxd +UVM_NO_RELNOTES +UVM_TESTNAME=sample_test

とりあえず動いたようだ。Vivadoだと同じデザインで何で動かないのだろうか...?

UVM_INFO @ 0: reporter [RNTST] Running test sample_test...
UVM_INFO @ 0: uvm_test_top.env.agent.driver [DRIVER] Hi
UVM_INFO @ 0: uvm_test_top.env.agent.monitor [MONITOR] Hi
UVM_INFO @ 0: uvm_test_top.env.agent [AGENT] Hi
UVM_INFO @ 0: uvm_test_top.env [ENV] Hello ENV
UVM_INFO @ 0: uvm_test_top [TEST] Hello World
UVM_INFO @ 0: reporter [UVMTOP] UVM testbench topology:
--------------------------------------------------------------
Name                       Type                    Size  Value
--------------------------------------------------------------
uvm_test_top               sample_test             -     @448 
  env                      sample_env              -     @460 
    agent                  sample_agent            -     @468 
      driver               sample_driver           -     @477 
        rsp_port           uvm_analysis_port       -     @494 
        seq_item_port      uvm_seq_item_pull_port  -     @485 
      monitor              sample_monitor          -     @503 
      sequencer            sample_sequencer        -     @511 
        rsp_export         uvm_analysis_export     -     @519 
        seq_item_export    uvm_seq_item_pull_imp   -     @625 
        arbitration_queue  array                   0     -    
        lock_queue         array                   0     -    
        num_last_reqs      integral                32    'd1  
        num_last_rsps      integral                32    'd1  
--------------------------------------------------------------

UVM_INFO ./model/sample_seq_lib.sv(9) @ 0: uvm_test_top.env.agent.sequencer@@write_seq [write_seq] write_seq pre_body() raising run objection
Hello SEQ
UVM_INFO @ 200: uvm_test_top.env.agent.monitor [MON] write addr=10h data=55h

Vivado Simulatorを使ってUVMに入門する (4. Vivado Simでの動作確認)

もう何回目になるのかわからないが、そろそろUVMを覚えなければならないのでVivado Simulatorを使ってUVMに入門してみよう。

今回はVivado 2023.2を使っている。

参考にしているのは例によって以下のウェブサイトだ:

sites.google.com

前回のコードをVivadoで動かすためには、UVM 1.2で動かす必要があり、そのためには多少の改造が必要だ。

virtual class sample_base_seq extends uvm_sequence #(sample_seq_item);
  function new(string name="sample_base_seq");
    super.new(name);
    do_not_randomize = 1;
    set_automatic_phase_objection(1);  // ここを追加
  endfunction // new

  // ここを全部コメントアウト
  // virtual task pre_body();
  //   if (starting_phase!=null) begin
  //      `uvm_info(get_type_name(),
  //                $sformatf("%s pre_body() raising %s objection",
  //                          get_sequence_path(),
  //                          starting_phase.get_name()), UVM_MEDIUM);
  //      starting_phase.raise_objection(this);
  //   end
  // endtask // pre_body
  //
  // // Drop the objection in the post_body so the objection is removed when
  // // the root sequence is complete.
  // virtual task post_body();
  //   if (starting_phase!=null) begin
  //      `uvm_info(get_type_name(),
  //                $sformatf("%s post_body() dropping %s objection",
  //                          get_sequence_path(),
  //                          starting_phase.get_name()), UVM_MEDIUM);
  //     starting_phase.drop_objection(this);
  //   end
  // endtask
endclass

これで、Vivadoで動作するようになった。

UVM_INFO /tools/Xilinx/Vivado/2023.2/data/system_verilog/uvm_1.2/xlnx_uvm_package.sv(18648) @ 0: reporter [NO_DPI_TSTNAME] UVM_NO_DPI defined--getting UVM_TESTNAME directly, without DPI
UVM_INFO @ 0: reporter [RNTST] Running test sample_test...
UVM_INFO /tools/Xilinx/Vivado/2023.2/data/system_verilog/uvm_1.2/xlnx_uvm_package.sv(20867) @ 0: reporter [UVM/COMP/NAMECHECK] This implementation of the component name checks requires DPI to be enabled
UVM_INFO @ 0: uvm_test_top [TEST] Hello World
UVM_INFO /tools/Xilinx/Vivado/2023.2/data/system_verilog/uvm_1.2/xlnx_uvm_package.sv(18752) @ 0: reporter [UVMTOP] UVM testbench topology:
--------------------------------------------------------------
Name                       Type                    Size  Value
--------------------------------------------------------------
uvm_test_top               sample_test             -     @341 
  env                      sample_env              -     @358 
    agent                  sample_agent            -     @367 
      driver               sample_driver           -     @377 
        rsp_port           uvm_analysis_port       -     @396 
        seq_item_port      uvm_seq_item_pull_port  -     @386 
      monitor              sample_monitor          -     @406 
      sequencer            sample_sequencer        -     @415 
        rsp_export         uvm_analysis_export     -     @424 
        seq_item_export    uvm_seq_item_pull_imp   -     @542 
        arbitration_queue  array                   0     -    
        lock_queue         array                   0     -    
        num_last_reqs      integral                32    'd1  
        num_last_rsps      integral                32    'd1  
--------------------------------------------------------------

UVM_INFO @ 0: uvm_test_top.env [ENV] Hello ENV
UVM_INFO @ 0: uvm_test_top.env.agent [AGENT] Hi
UVM_INFO @ 0: uvm_test_top.env.agent.monitor [MONITOR] Hi
UVM_INFO @ 0: uvm_test_top.env.agent.driver [DRIVER] Hi
Hello SEQ
UVM_INFO @ 0: uvm_test_top.env.agent.monitor [MON] write addr=10h data=55h
UVM_INFO /tools/Xilinx/Vivado/2023.2/data/system_verilog/uvm_1.2/xlnx_uvm_package.sv(19968) @ 1000: reporter [TEST_DONE] 'run' phase is ready to proceed to the 'extract' phase
UVM_INFO /tools/Xilinx/Vivado/2023.2/data/system_verilog/uvm_1.2/xlnx_uvm_package.sv(13673) @ 1000: reporter [UVM/REPORT/SERVER] 

Vivado Simulatorを使ってUVMに入門する (3. テストのシーケンスを作る)

もう何回目になるのかわからないが、そろそろUVMを覚えなければならないのでVivado Simulatorを使ってUVMに入門してみよう。

今回はVivado 2023.2を使っている。

参考にしているのは例によって以下のウェブサイトだ:

sites.google.com

今回はUVMのスティミュラス(テストパタン)を追加する、ということになりそうだ。

  • sequenceから
    • sequence_item
    • sequencerに渡す
  • sequencerが受け取って、
  • driverに渡す

  • sequence_itemについて:トランザクションの発行に必要な情報を格納する構造体を示す。

  • model/sample_seq_item.sv

class sample_seq_item extends uvm_sequence_item;
  rand byte addr, data;
  bit  write;
  `uvm_object_utils(sample_seq_item)

  function new (string name="sample_seq_item_inst");
    super.new(name);
  endfunction

endclass // sample_seq_item
  • driversequencerをつなぐ:sample_driver.svsample_sequencer.svをわずかに変更する。上記で作成した構造体を、driverとsequencerに渡しているもんだと思う。
class sample_driver extends uvm_driver #(sample_seq_item);
class sample_sequencer extends uvm_sequencer #(sample_seq_item);

driversequencerをつなぐ。uvm_agentを修正して、connect_phase()を追加する。

  • model/sample_agent.sv
class sample_agent extends uvm_agent;
/* ... 途中省略 ... */
  function void connect_phase(uvm_phase phase);
    if(get_is_active() == UVM_ACTIVE)begin
      driver.seq_item_port.connect(sequencer.seq_item_export);
    end
  endfunction
  • interfaceの記述:とりあえず、上記のsample_seq_itemで定義した信号と同じようなものを定義する。

  • sample_if.sv

interface sample_if(input logic clk, rstz);

  logic write;  // 1:write, 0:read                                                                                                                                                                                                                                                                                                                                                        
  logic valid;
  logic [7:0] addr, data;

endinterface // sample_if                                                                                                                                                                                                                                                                                                                                                                 
  • virtual interfaceとのリンク:クラスの中に、仮想的にinterfaceを置く。この辺は良く分からない。データベースへの仮想interfaceの登録ということになる。
initial begin
  uvm_config_db#(virtual sample_if)::set(uvm_root::get(), "*.env.*", "vif", vif);
  run_test();
end

uvm_config_dbについて:指定したオブジェクトの、指定した範囲の、指定したフィールド名(変数、メンバ)に、このmoduleに組み込んだ「vif」をセットする、ということらしい(?)

  • uvm_root::get() : uvm_root::get() でuvm_testをゲットする?
  • "*.env.*" : uvm_testの中に定義しているsample_env envの中身をリンクする、という意味になる
  • "vif" : 第2引数の中で引きだしたインスタンスの各階層でvifというフィールド名を探す。
  • vif : 第3引数のフィールドに対してvifを渡す

model/sample_driver.svvirtual sample_ifを追加する。また、build_phase()も追加してuvm_config_dbを追加する。

class sample_driver extends uvm_driver #(sample_seq_item);
  virtual sample_if vif;
/* ... 以下省略 ... */
  function void build_phase(uvm_phase phase);
    bit status;
    super.build_phase(phase);
    status = uvm_config_db#(virtual sample_if)::get(this, "", "vif", vif);
    if (status==1'b0)
      uvm_report_fatal("NOVIF", {"virtual interface must be set for: ",get_full_name(),".vif"});
  endfunction // build_phase                                                                                                                                                                                                                                                                                                                                                              
  • sequenceつまり、テストベクトルを作成する。その基本的な流れは、

  • baseとなるsequenceクラスを定義して、そこに「共通記述」を埋め込む

  • sequence毎に異なる記述を、1番をextendsしたクラスの中に定義することで、記述量の削減を行う

なるほど。以下は、共通クラスとしてのsample_base_seqとそれを継承したwrite_seqの記述だ。sample_base_seqvirtualなので、そのままインスタンス化してはいけないのだと思う。

virtual class sample_base_seq extends uvm_sequence #(sample_seq_item);

class write_seq extends sample_base_seq;
  • function new() : do_no_randomizeは削除してもよい。
  • virtual task pre_body(), post_body() ここでは、raise_objection()を実行しているのと、drop_objection()を実行している。これは、実行すべきテストが存在していることを示すのだと思われる。

  • write_seqクラスでは、body()タスクを作成して、実際にシーケンスを作成している。

virtual class sample_base_seq extends uvm_sequence #(sample_seq_item);
  function new(string name="sample_base_seq");
    super.new(name);
    do_not_randomize = 1;
  endfunction // new                                                                                                                                                                                                                                                                                                                                                                      

  virtual task pre_body();
    if (starting_phase!=null) begin
       `uvm_info(get_type_name(),
                 $sformatf("%s pre_body() raising %s objection",
                           get_sequence_path(),
                           starting_phase.get_name()), UVM_MEDIUM);
       starting_phase.raise_objection(this);
    end
  endtask // pre_body                                                                                                                                                                                                                                                                                                                                                                     

  // Drop the objection in the post_body so the objection is removed when                                                                                                                                                                                                                                                                                                                 
  // the root sequence is complete.                                                                                                                                                                                                                                                                                                                                                       
  virtual task post_body();
    if (starting_phase!=null) begin
       `uvm_info(get_type_name(),
                 $sformatf("%s post_body() dropping %s objection",
                           get_sequence_path(),
                           starting_phase.get_name()), UVM_MEDIUM);
      starting_phase.drop_objection(this);
    end
  endtask
endclass

//------------------------------------------------------------------------                                                                                                                                                                                                                                                                                                                
class write_seq extends sample_base_seq;
  `uvm_object_utils(write_seq)

  function new (string name="write_seq");
    super.new(name);
  endfunction // new                                                                                                                                                                                                                                                                                                                                                                      

  virtual task body();
    $display("Hello SEQ");
    `uvm_create(req)
    req.write <= 1'b1;
    req.addr  <= 8'h10;
    req.data  <= 8'h55;
    `uvm_send(req)
    #1000;
  endtask // body                                                                                                                                                                                                                                                                                                                                                                         

endclass // write_seq                                                                                                                                                                                                                                                                                                                                                                     
  • sample_driver.svを更新し、vifを使って実際にデータを駆動し、seq_item_portから次のリクエストを受け取る記述を実装する。
  task run_phase(uvm_phase phase);
    uvm_report_info("DRIVER", "Hi");
    vif.valid <= 1'b0;
    @(posedge vif.rstz);  // wait reset negate                                                                                                                                                                                                                                                                                                                                            
    forever begin
      seq_item_port.get_next_item(req);  // wait seq_item from sequence (via sequencer)                                                                                                                                                                                                                                                                                                   
      @(posedge vif.clk); // sync clk                                                                                                                                                                                                                                                                                                                                                     
      vif.valid <= 1'b1;
      vif.write <= req.write;
      vif.addr  <= req.addr;
      vif.data  <= req.data;
      @(posedge vif.clk);
      vif.valid <= 1'b0;
      seq_item_port.item_done(rsp);
    end
  endtask

Vivado Simulatorを使ってUVMに入門する (2. sequencer, monitor, driver)

もう何回目になるのかわからないが、そろそろUVMを覚えなければならないのでVivado Simulatorを使ってUVMに入門してみよう。

今回はVivado 2023.2を使っている。

参考にしているのは例によって以下のウェブサイトだ:

sites.google.com

前回に追加して、以下のファイルを追加した:

uvm_driver

デザインに対して制御信号や入力データを与える役割を持つ。

  • sample_driver.sv
class sample_driver extends uvm_driver;
  `uvm_component_utils(sample_driver)

  function new (string name, uvm_component parent);
    super.new(name, parent);
  endfunction

  task run_phase(uvm_phase phase);
    uvm_report_info("DRIVER", "Hi");
  endtask

endclass // sample_driver

uvm_monitor

デザインの信号を監視し、テストベンチにその情報を報告する。DUT (Device Under Test) に対して信号を駆動せず、単にDUTから出力される信号や内部の動作を観測する。

  • sample_monitor.sv
class sample_monitor extends uvm_monitor;
  `uvm_component_utils(sample_monitor)

  function new (string name, uvm_component parent);
    super.new(name, parent);
  endfunction

  task run_phase(uvm_phase phase);
    uvm_report_info("MONITOR", "Hi");
  endtask

endclass // sample_monitor

uvm_sequencer

トランザクション(データ、命令、操作など)を生成し、それをドライバに送信する。テストデータや命令の流れを管理し、設計検証のためにDUTに入力される信号を間接的に制御する。

  • sample_sequencer.sv
class sample_sequencer extends uvm_sequencer;
  `uvm_component_utils(sample_sequencer)

  function new (string name, uvm_component parent);
    super.new(name, parent);
  endfunction

  task run_phase(uvm_phase phase);
    uvm_report_info("SEQR", "Hi");
  endtask

endclass // sample_sequencer

uvm_agent

sequencer, driver, monitor を1つにまとめたコンポーネントで、特定の役割を持ったコンポーネントの集合体として動作する。

  • sample_agent.sv
class sample_agent extends uvm_agent;
  `uvm_component_utils(sample_agent)
  sample_driver    driver;
  sample_monitor   monitor;
  sample_sequencer sequencer;
  function new (string name, uvm_component parent);
    super.new(name, parent);
  endfunction
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    driver    = sample_driver::type_id::create("driver", this);
    monitor   = sample_monitor::type_id::create("monitor", this);
    sequencer = sample_sequencer::type_id::create("sequencer", this);
  endfunction
  task run_phase(uvm_phase phase);
    uvm_report_info("AGENT", "Hi");
  endtask
endclass

sample_env をアップデートする。

sample_agent を埋め込む。

`include "uvm_macros.svh"
import uvm_pkg::*;

class sample_env extends uvm_env;
  `uvm_component_utils(sample_env)

  sample_agent agent;

  function new (string name, uvm_component parent);
    super.new(name,parent);
  endfunction

  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    agent = sample_agent::type_id::create("agent", this);
  endfunction

  task run_phase(uvm_phase phase);
    uvm_report_info("ENV", "Hello ENV");
  endtask
endclass

実行結果は以下のようになった。

UVM_INFO @ 0: uvm_test_top [TEST] Hello World
UVM_INFO @ 0: uvm_test_top.env [ENV] Hello ENV
UVM_INFO @ 0: uvm_test_top.env.agent [AGENT] Hi
UVM_INFO @ 0: uvm_test_top.env.agent.sequencer [SEQR] Hi
UVM_INFO @ 0: uvm_test_top.env.agent.monitor [MONITOR] Hi
UVM_INFO @ 0: uvm_test_top.env.agent.driver [DRIVER] Hi