FPGA開発日記

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

Vivado Simulatorを用いてUVMに入門する (2. テストベンチの解析)

UVMに入門したくて、簡単な例を用いて試してみることにした。以下のようなシンプルなデザインをテストしたい。

vlsiverify.com

adderとのインタフェースとして、以下を定義する。これによりテストベンチとDUTを接続する。

  • verify/addr_if.sv
interface add_if(input logic clk, reset);

logic [ 7: 0] ip1, ip2;
logic [ 8: 0] out;

endinterface // add_if

次に、SequencerとDriverについて見て行く。Sequencerはテストベンチを作成するところだ。 まず、seq_itemによって、ドライブしたい要素をリストアップしていくらしい。ip1ip2はランダムに駆動するものと思われるが、outは値を受け取るだけなので駆動しない。

  • verify/seq_item.sv
 `include "uvm_macros.svh"
import uvm_pkg::*;

class seq_item extends uvm_sequence_item;
  rand bit [ 7: 0] ip1, ip2;
  bit [ 8: 0]      out;

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

  `uvm_object_utils_begin(seq_item)
    `uvm_field_int(ip1, UVM_ALL_ON)
    `uvm_field_int(ip2, UVM_ALL_ON)
  `uvm_object_utils_end

  constraint ip_c {ip1 < 100; ip2 < 100;}

endclass // seq_item

これに基づいて、seqcrを定義する。seq_itemを拡張する形で定義する。これはテンプレートとして使えそうな構成だ。

  • verify/seqcr.sv
 `include "uvm_macros.svh"
import uvm_pkg::*;

class seqcr extends uvm_sequencer#(seq_item);
  `uvm_component_utils(seqcr)

  function new(string name = "seqcr", uvm_component parent = null);
    super.new(name, parent);
  endfunction

  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
  endfunction // build_phase

endclass // seqcr

これに基づいてDriverを定義する。Driverはadder_ifを駆動するものだ。ポイントはvif.ip1vif.ip2を駆動するところだ。 どうもこれはseq_item_port.get_next_item(req)seq_item_port.item_done()で囲むところがポイントらしい。

  • verify/driver.sv
 `include "uvm_macros.svh"
import uvm_pkg::*;

class driver extends uvm_driver#(seq_item);
  virtual add_if vif;
  `uvm_component_utils(driver)

  function new(string name = "driver", uvm_component parent = null);
    super.new(name, parent);
  endfunction

  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    if(!uvm_config_db#(virtual add_if) :: get(this, "", "vif", vif))
      `uvm_fatal(get_type_name(), "Not set at top level");
  endfunction

  task run_phase (uvm_phase phase);
    forever begin
      // Driver to the DUT
      seq_item_port.get_next_item(req);
      `uvm_info(get_type_name, $sformatf("ip1 = %0d, ip2 = %0d", req.ip1, req.ip2), UVM_LOW);
      vif.ip1 <= req.ip1;
      vif.ip2 <= req.ip2;
      seq_item_port.item_done();
    end
  endtask // run_phase

endclass // driver