FPGA開発日記

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

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

前回はこちら: msyksphinz.hatenablog.com

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

www.chipverify.com

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

www.chipverify.com

スコアボードの構成は、write()を呼び出すことによってスコアボードを更新する。

  virtual function write (reg_item item);
    if (item.wr) begin
      if (refq[item.addr] == null) begin
        refq[item.addr] = new;
      end
      refq[item.addr] = item;
      `uvm_info (get_type_name(), $sformatf("Store addr=0x%0h wr=0x%0h data=0x%0h", item.addr, item.wr, item.wdata), UVM_LOW)
    end

プロトコルが読み出し操作の時は、スコアボード内で比較して整合性をチェックしている:

    if (!item.wr) begin
      if (refq[item.addr] == null) begin
        if (item.rdata != 'h1234) begin
          `uvm_error(get_type_name(),
                     $sformatf("First time read, addr=0x%0h exp=1234 act=0x%0h",
                               item.addr, item.rdata))
        end else begin
          `uvm_info(get_type_name(),
                    $sformatf("PASS! First time read, addr=0x%0h exp=1234 act=0x%0h",
                              item.addr, item.rdata), UVM_LOW)
        end
      end else begin // if (refq[item.addr] == null)                                                                                                                                                                                                                                                                                                                                      
        if (item.rdata != refq[item.addr].wdata) begin
          `uvm_error(get_type_name(),
                     $sformatf("addr=0x%0h exp=0x%0h act=0x%0h",
                               item.addr, refq[item.addr].wdata, item.rdata))
        end else begin
          `uvm_info(get_type_name(),
                    $sformatf("PASS! First time read, addr=0x%0h exp=0x%0h act=0x%0h",
                              item.addr, refq[item.addr].wdata, item.rdata), UVM_LOW)
        end
      end // else: !if(refq[item.addr] == null)                                                                                                                                                                                                                                                                                                                                           
    end // if (!item.wr)                                                                                                                                                                                                                                                                                                                                                                  
  endfunction // write                                                                                                                                                                                                                                                                                                                                                                    

tb_top.sv を以下のように構成して、テストベンチを構築した:

`timescale 1ps/1ps

module tb_top;

// UVM class library                                                                                                                                                                                                                                                                                                                                                                      
`include "uvm_macros.svh"
import uvm_pkg::*;

// uvm user code                                                                                                                                                                                                                                                                                                                                                                          
`include "model.svh"

`include "test.sv"

/////////////////////////////////////                                                                                                                                                                                                                                                                                                                                                     
logic clk, rstz;
reg_if vif(clk);
// clk                                                                                                                                                                                                                                                                                                                                                                                    
initial begin
  clk <= 1'b1;
  #100;
  forever #50 clk <= ~clk;
end

// rstz                                                                                                                                                                                                                                                                                                                                                                                   
initial begin
  rstz     <= 1'b0;
  #80 rstz <= 1'b1;
end

reg_ctrl u0
  (
   .clk   (clk ),
   .rstn  (vif.rstn ),
   .addr  (vif.addr ),
   .sel   (vif.sel  ),
   .wr    (vif.wr   ),
   .wdata (vif.wdata),
   .rdata (vif.rdata),
   .ready (vif.ready)
   );


initial begin
  uvm_config_db #(virtual reg_if)::set(uvm_root::get(), "*.*", "reg_vif", vif);
  run_test();
end

endmodule // tb_top                                                                                                                                                                                                                                                                                                                                                                       

テストシーケンスは以下のように構築している:

class test extends uvm_test;
  `uvm_component_utils(test);
  function new(string name="test", uvm_component parent=null);
    super.new(name, parent);
  endfunction // new                                                                                                                                                                                                                                                                                                                                                                      

  env e0;
  virtual reg_if vif;

  virtual function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    e0 = env::type_id::create("e0", this);
    if (!uvm_config_db#(virtual reg_if)::get(this, "", "reg_if", vif))
      `uvm_fatal("TEST", "Did not get vif")

    uvm_config_db #(virtual reg_if)::set(this, "e0.a0.*", "reg_vif", vif);
  endfunction // build_phase                                                                                                                                                                                                                                                                                                                                                              

  virtual task run_phase (uvm_phase phase);
    gen_item_seq seq = gen_item_seq::type_id::create("seq");
    phase.raise_objection(this);
    apply_reset();

    seq.randomize() with {num inside {[20:30]}; };
    seq.start(e0.a0.s0);
    #200;
    phase.drop_objection(this);
  endtask // run_phase                                                                                                                                                                                                                                                                                                                                                                    

  virtual task apply_reset();
    vif.rstn <= 0;
    repeat(5) @ (posedge vif.clk);
    vif.rstn <= 1;
    repeat(10) @ (posedge vif.clk);
  endtask // apply_reset                                                                                                                                                                                                                                                                                                                                                                  

endclass // test                                                                                                                                                                                                                                                                                                                                                                          

これでVivado Simulatorで走らせてみたが、uvm_config_dbが何となくうまくいっていないらしい。

UVM_FATAL test.sv(14) @ 0: uvm_test_top [TEST] Did not get vif