FPGA開発日記

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

Vivado Simulatorを使ってUVMに入門する (10. UVM Testbench Exampleを試す)

UVMのさらなるテストベンチを試行するために、以下のウェブサイトのサンプルを試してみることにした。

www.chipverify.com

このページでは、別ページで作ったSystemVerilogのレジスタコントローラ(レジスタファイルみたいなもの)を検証するためのUVM環境を作り上げていくものになっている。

www.chipverify.com

インタフェースとしてはこんな感じのデザイン:

module reg_ctrl
  #(
    parameter ADDR_WIDTH = 8,
    parameter DATA_WIDTH = 16,
    parameter DEPTH = 256,
    parameter RESET_VAL = 16'h1234
    )
(
 input logic                    clk,
 input logic                    rstn,
 input logic [ADDR_WIDTH-1: 0]  addr,
 input logic                    sel,
 input logic                    wr,
 input logic [DATA_WIDTH-1: 0]  wdata,
 output logic [DATA_WIDTH-1: 0] rdata,
 output logic                   ready
 );

UVMのインタフェースとして作っていくのは以下のようなクラス:

  • Sequence Item (reg_item.sv) : ドライバに渡す前に入力アドレスと書き込みデータをランダム化するためのデータクラスを定義する。
class reg_item extends uvm_sequence_item;
  rand bit [`ADDR_WIDTH-1: 0] addr;
  rand bit [`DATA_WIDTH-1: 0] wdata;
  rand bit                    wr;
  bit [`DATA_WIDTH-1: 0]      rdata;
  • Driver (driver.sv) : このクラスは、reg_itemクラスをパラメータとして渡している。DUTのピンを駆動するためにvirtualインタフェースを定義しおり、get_next_itemitem_doneを使ってテスト値を受け取り、DUTのインタフェースを駆動する。
class driver extends uvm_driver #(reg_item);
  `uvm_component_utils (driver)

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

  virtual reg_if vif;
...
  virtual task drive_item (reg_item m_item);
    vif.sel   <= 1;
    vif.addr  <= m_item.addr;
    vif.wr    <= m_item.wr;
    vif.wdata <= m_item.wdata;
    @(posedge vif.clk);
    while (!vif.ready) begin
      `uvm_info ("DRV", "Wait until ready is high", UVM_LOW);
      @(posedge vif.clk);
    end
    vif.sel <= 0;
  endtask // drive_item
  • Monitor (monitor.sv): virtualインタフェースを持っており、インタフェースの動作を監視する。ピンの動作を監視・デコードし、テストベンチのコンポーネントに渡す。この例では、DUTのインタフェースを監視しreg_itemインスタンスを作成し、analysisポートに渡している。
class monitor extends uvm_monitor;
  `uvm_component_utils(monitor)
  function new(string name="monitor", uvm_component parent=null);
    super.new(name, parent);
  endfunction // new
...
  virtual task run_phase (uvm_phase phase);
    super.run_phase (phase);
    // This task monitors the interface for a complete
    // translactions and writes into analysis port when complete
        `uvm_info (get_type_name(), $sformatf("Monitor found packet %s", item.convert2str()), UVM_LOW)
        mon_analysis_port.write(item);
      end // if (vif.sel)
    end // forever begin
  endtask // run_phase
endclass // monitor
  • Agent (agent.sv): Sequencer, Driver, Monitorを1つのコンテナに包含する。sequencerはシーケンスをドライバに渡す責任を持つ。
class agent extends uvm_agent;
  `uvm_component_utils(agent);
  function new(string name="agent", uvm_component parent=null);
    super.new(name, parent);
  endfunction // new

  driver  d0;   // Driver handle
  monitor m0;   // Monitor handle
  uvm_sequencer #(reg_item) s0;  // Sequencer Handle

スコアボードから先は、これから実装していく。