前回はSystemVerilogで書いたドライバモデルをベースとし、それを継承したモデルを記述して動くことを確認しました。

今回は、UVM-1.1で同じことを実装します。 
前回のドライバ雛形(driver_base)のクラス定義は以下のようなものでした。

class driver_base #(type VIF=virtual interface if_base);


UVMのドライバにするので、uvm_driverを継承することにします。
パラメータにトランザクションアイテムが必要なので、別途itemは定義しました。
class item extends uvm_sequence_item;
    `uvm_object_utils(item)
    function new(string name="item");
        super.new(name);
    endfunction
endclass
 
UVM版driver_baseクラスの定義は次のようになります。
class driver_base #(type VIF=virtual interface if_base) extends uvm_driver #(item);

ここで注意しなくてはいけないのが、uvm_component_utilsマクロです。
引数でクラス(型)を渡していますが、パラメータを含めて渡す必要があります。

`uvm_component_utils(driver_base#(VIF))

ここで、パラメータに指定している型がVIFとなっているのがキモです。
これをvirtual interface if_baseとすると、パラメータでif_base以外を指定されたときに辻褄が合わなくなってしまいエラーとなります。

driver_base、driver_customはUVMドライバを基底に持つことになるので、uvm_component_utilsマクロとコンストラクタ(new)を定義する必要があります。


最終的なコードはつぎのようになりました。
import uvm_pkg::*;
`include "uvm_macros.svh"

//////////////////////////////////
interface if_base();
    logic CLK;
endinterface

//////////////////////////////////
interface if_custom();
    logic CLK;
    logic[7:0] PORT;
endinterface

//////////////////////////////////
class item extends uvm_sequence_item;
    `uvm_object_utils(item)
    function new(string name="item");
        super.new(name);
    endfunction
endclass

//////////////////////////////////
class driver_base #(type VIF=virtual interface if_base) extends uvm_driver #(item);
    VIF vi;
    `uvm_component_utils(driver_base#(VIF))

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

    task wait_clk(int cycle);
        repeat(cycle)@(posedge vi.CLK);
    endtask
endclass

//////////////////////////////////
class driver_custom extends driver_base #(virtual interface if_custom);
    `uvm_component_utils(driver_custom)

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

    task set_port(bit[7:0] val);
        vi.PORT = val;
        $display("%t PORT set 0x%x",$time,val);
    endtask

    function bit[7:0] get_port();
        $display("%t PORT get 0x%x",$time,vi.PORT);
        return vi.PORT;
    endfunction
endclass

//////////////////////////////////
module tb_top();
    if_custom intf();

    initial begin
        driver_custom drv;
        drv = new;
        drv.vi = intf;
        drv.set_port(8'h5A);
        $finish();
    end
endmodule
前回とは違い、UVMライブラリのコンパイル等が必要になります。
 export UVM_HOME=/usr/bin/altera/12.0/modelsim_ase/verilog_src/uvm-1.1/
 vlib uvm-1.1
 vlog -work uvm-1.1 +incdir+$UVM_HOME/src $UVM_HOME/src/uvm_pkg.sv
 gcc -m32 -fPIC -DQUESTA -g -W -shared -x c -I $UVM_HOME/../../include $UVM_HOME/src/dpi/uvm_dpi.cc -o uvm_dpi.so

シミュレーション実行も少しオプションが増えました。
vlog -sv +incdir+$UVM_HOME/src -L uvm-1.1 test.sv
vsim -c -sv_lib uvm_dpi tb_top -do "run 1us;q"
今回はuvm_testを使わずdriverもitemを処理しないというUVM精神(?)からは外れたコードになっています…。