0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

UVMについて学習してみたその1

0
Last updated at Posted at 2026-09-21

UVMについて学習

概要

参考記事にある実践UVM入門:検証のためのSystemVerilogクラスライブラリーをもとに学習した内容を本記事に記載.

実行環境概要

  • OS:Ubuntu 24.04
  • Verilator:5.053 devel rev v5.052-141-gc8b8c79ee

参考記事にある実践UVM入門:検証のためのSystemVerilogクラスライブラリーからサンプルソースコードをダウンロードできる.

UVMとは何か

UVMとは,検証分野で推奨されている技術,ルール,慣習,規律等をコードとして具体化したSystemVerilogのクラスライブラリー.
UVMは検証技術の再利用性を促進して生産性向上をさせる目的を持っている.

検証技術のトレンド

近年の検証技術では階層的テストベンチ記述手法が採用されている.
階層には以下表のような種類がある.

階層 機能例 検証目的および機能
テストレイヤー テストベンチ テストベンチのトップレベルのレイヤー.テストを生成して下位の層に送る.
シナリオレイヤー ジェネレーター シナリオに沿ってトランザクションのシーケンスを生成する.ジェネレーターは,UVMのシーケンサーに相当.
ファンクショナルレイヤー エージェント
スコアボード
チェッカー
高位レベルのコマンドを処理するレイヤー.例えば,DMA read/write等のコマンドを受け取ると,個々のbus read/write等のコマンドに分割してコマンドレイヤーに送る.
コマンドレイヤー ドライバー
モニター
コレクター
トランザクションレベルのコマンドをシグナルレベルに変換してシグナルレイヤーに送る.ドライバーはDUTをドライブする目的を持つ.コレクターはDUTからのレスポンスをサンプリングし,トランザクションに変換する.モニターはコレクターからトランザクションを受け取り,チェック,カバレッジ等の計算を行う.
シグナルレイヤー DUT DUTからのレスポンスは上位層に送られる.アサーション等の結果も上位層に戻される.

以下図ではそれぞれの階層における役割およびトランザクションの流れを検証環境として表現している.

環境構築

Verilatorのインストール

cd ~ # ホームディレクトリへ移動
sudo apt-get -y upgrade
sudo apt-get -y updata
sudo apt-get install           \
git help2man perl python3 make \
autoconf g++ flex bison ccache \
libfl2 libfl-dev zlib1g        \
zlib1g-dev liblz4-dev z3 # Verilatorに必要なパッケージをインストール

git clone https://github.com/verilator/verilator

cd verilator
unset VERILATOR_ROOT
autoconf
make -j `nproc`
sudo make install
hash -r

UVMのインストール

git clone https://github.com/chipsalliance/uvm-verilator.git
export UVM_HOME=$PWD/uvm-verilator # .bashrcに記載するなどして常に参照できるようにした方が良い

Verilator用UVMはここからダウンロードする必要がある.

GTKWaveのインストール

sudo apt-get install -y gtkwave

GTKWaveでVCD波形ファイルを出力し,動作確認をする.

サンプルの実行

サンプル環境概要

ディレクトリ構成は以下.

UVM
└── UVM_sample1
    ├── rundir
    └── src
        ├── UVM_sample1.sv
        ├── agent.sv
        ├── collector.sv
        ├── driver.sv
        ├── sequencer.sv
        ├── monitor.sv
        ├── sample_data.sv
        ├── sample_if.sv
        ├── sample_pkg.sv
        └── dut.sv

ソースコード

UVM_sample1.sv

`include "uvm_pkg.sv"
`include "uvm_macros.svh"
`include "sample_if.sv"
`include "sample_pkg.sv"

module tb_top;

  import  uvm_pkg::*;
  import  sample_pkg::*;

  bit   clk;
  agent parent;

  sample_if sif(clk);

  dut DUT(.a(sif.a),.b(sif.b),.co(sif.co),.sum(sif.sum));

  string wave_file;

  initial begin
    if( !$value$plusargs("wave=%s",wave_file) ) begin
      wave_file = "dump.vcd";
    end
    $dumpfile(wave_file);
    $dumpvars();

    parent = agent::type_id::create("agent0",null);
    uvm_config_db #(virtual sample_if)::set(null,"*agent0*","vif",sif);
    run_test();	
  end

  initial forever #10 clk = ~clk;

endmodule

agent.sv

class agent extends uvm_component;
  driver    d;
  sequencer s;
  collector c;
  monitor   m;

  `uvm_component_utils(agent)

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

  extern function void build_phase(uvm_phase phase);
  extern function void connect_phase(uvm_phase phase);
endclass

function void agent::build_phase(uvm_phase phase);
  super.build_phase(phase);
  d = driver::type_id::create("driver",this);
  s = sequencer::type_id::create("sequencer",this);
  c = collector::type_id::create("collector",this);
  m = monitor::type_id::create("monitor",this);
endfunction

function void agent::connect_phase(uvm_phase phase);
  super.connect_phase(phase);
  d.get_port.connect(s.get_export);
  c.analysis_port.connect(m.analysis_export);
endfunction

collector.sv

class collector extends uvm_component;
  virtual sample_if vif;
  uvm_analysis_port #(sample_data_t) analysis_port;

  `uvm_component_utils(collector)

  function new(string name,uvm_component parent);
    super.new(name,parent);
    analysis_port = new("analysis_port",this);
  endfunction

  extern function void connect_phase(uvm_phase phase);
  extern task run_phase(uvm_phase phase);
  extern task get_response();
endclass

function void collector::connect_phase(uvm_phase phase);
  super.connect_phase(phase);
  if( !uvm_config_db #(virtual sample_if)::get(this,get_full_name(),"vif",vif) )
    `uvm_error("NO-VIF",{"VIF error for ",get_full_name(),".vif"})
endfunction

task collector::run_phase(uvm_phase phase);
  get_response();
endtask

task collector::get_response();
  sample_data_t data;
  data = sample_data_t::type_id::create("collected_data");
  forever begin
    @(vif.a,vif.b);         // wait until inputs change
    #0;                     // wait until outputs become stable
    data.a = vif.a;
    data.b = vif.b;
    data.co = vif.co;
    data.sum = vif.sum;
    analysis_port.write(data); // send transaction to monitor
  end
endtask

driver.sv

class collector extends uvm_component;
  virtual sample_if vif;
  uvm_analysis_port #(sample_data_t) analysis_port;

  `uvm_component_utils(collector)

  function new(string name,uvm_component parent);
    super.new(name,parent);
    analysis_port = new("analysis_port",this);
  endfunction

  extern function void connect_phase(uvm_phase phase);
  extern task run_phase(uvm_phase phase);
  extern task get_response();
endclass

function void collector::connect_phase(uvm_phase phase);
  super.connect_phase(phase);
  if( !uvm_config_db #(virtual sample_if)::get(this,get_full_name(),"vif",vif) )
    `uvm_error("NO-VIF",{"VIF error for ",get_full_name(),".vif"})
endfunction

task collector::run_phase(uvm_phase phase);
  get_response();
endtask

task collector::get_response();
  sample_data_t data;
  data = sample_data_t::type_id::create("collected_data");
  forever begin
    @(vif.a,vif.b);         // wait until inputs change
    #0;                     // wait until outputs become stable
    data.a = vif.a;
    data.b = vif.b;
    data.co = vif.co;
    data.sum = vif.sum;
    analysis_port.write(data); // send transaction to monitor
  end
endtask

sequencer.sv

class sequencer extends uvm_component;
  uvm_blocking_get_imp #(sample_data_t,sequencer) get_export;

  `uvm_component_utils(sequencer)

  function new(string name,uvm_component parent);
    super.new(name,parent);
    get_export = new("get_export",this);
  endfunction

  extern task get(output sample_data_t data);
endclass

task sequencer::get(output sample_data_t data);
  data = sample_data_t::type_id::create("sample_data");
  assert( data.randomize() );
endtask

monitor.sv

class monitor extends uvm_component;

  uvm_analysis_imp #(sample_data_t,monitor) analysis_export;

  `uvm_component_utils(monitor)

  function new(string name,uvm_component parent);
    super.new(name,parent);
    analysis_export = new("analysis_export",this);
  endfunction

  extern function void write(sample_data_t data);
endclass

function void monitor::write(sample_data_t data);
  `uvm_info( "MONITOR",$sformatf("a=%0d b=%0d {co,sum}=%0d", data.a, data.b, {data.co,data.sum}), UVM_LOW );
endfunction

sample_data.sv

class sample_data_t extends uvm_sequence_item;

  rand bit [1:0]  a, b;
  bit [1:0]       sum;
  bit             co;

  `uvm_object_utils_begin(sample_data_t)
    `uvm_field_int(a,UVM_DEFAULT)
    `uvm_field_int(b,UVM_DEFAULT)
    `uvm_field_int(sum,UVM_DEFAULT|UVM_NOCOMPARE|UVM_NOPACK)
    `uvm_field_int(co,UVM_DEFAULT|UVM_NOCOMPARE|UVM_NOPACK)
  `uvm_object_utils_end

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

endclass

sample_if.sv

interface sample_if(input bit clk);
  bit [1:0] a, b, sum;
  bit       co;

  clocking cb @(posedge clk); endclocking
  
endinterface

sample_pkg.sv

`ifndef PKG_H
`define PKG_H

package sample_pkg;
import uvm_pkg::*;

`include "sample_data.sv"
`include "sequencer.sv"
`include "driver.sv"
`include "monitor.sv"
`include "collector.sv"
`include "agent.sv"

endpackage

`endif

dut.sv

module dut(input [1:0] a,b,output co,[1:0] sum);
  assign {co,sum} = a+b;
endmodule

コンパイルから実行

コンパイル

cd UVM/UVM_sample1/rundir
export UVM_HOME=${HOME}/uvm-verilator
verilator --binary -j 0 --vpi \
          --timescale 1ns/1ps \
          --trace-vcd --trace-structs \
          --top-module tb_top \
          -Wno-WIDTH \
          -CFLAGS -O0 \
          +incdir+$UVM_HOME/src \
          +incdir+../src \
          $UVM_HOME/src/uvm_pkg.sv \
          $UVM_HOME/src/dpi/uvm_dpi.cc \
          UVM_sample1.sv

実行

コンパイルしたrundirディレクトリで以下コマンドを実行する.

./obj_dir/Vtb_top +UVM_VERBOSITY=UVM_LOW +UVM_NO_RELNOTES

参考のため実行ログおよびGTKWaveによる波形を表示する.

UVM_INFO @ 0: reporter [RNTST] Running test ...
UVM_INFO ../src/monitor.sv(16) @ 10000: agent0.monitor [MONITOR] a=3 b=1 {co,sum}=4
UVM_INFO ../src/monitor.sv(16) @ 30000: agent0.monitor [MONITOR] a=2 b=2 {co,sum}=4
UVM_INFO ../src/monitor.sv(16) @ 50000: agent0.monitor [MONITOR] a=0 b=2 {co,sum}=2
UVM_INFO ../src/monitor.sv(16) @ 70000: agent0.monitor [MONITOR] a=3 b=1 {co,sum}=4
UVM_INFO ../src/monitor.sv(16) @ 90000: agent0.monitor [MONITOR] a=3 b=0 {co,sum}=3
UVM_INFO ../src/monitor.sv(16) @ 110000: agent0.monitor [MONITOR] a=1 b=2 {co,sum}=3
UVM_INFO ../src/monitor.sv(16) @ 130000: agent0.monitor [MONITOR] a=2 b=2 {co,sum}=4
UVM_INFO ../src/monitor.sv(16) @ 150000: agent0.monitor [MONITOR] a=3 b=2 {co,sum}=5
UVM_INFO ../src/monitor.sv(16) @ 170000: agent0.monitor [MONITOR] a=0 b=2 {co,sum}=2
UVM_INFO ../src/monitor.sv(16) @ 190000: agent0.monitor [MONITOR] a=0 b=0 {co,sum}=0
UVM_INFO ../src/monitor.sv(16) @ 210000: agent0.monitor [MONITOR] a=2 b=3 {co,sum}=5
UVM_INFO ../src/monitor.sv(16) @ 230000: agent0.monitor [MONITOR] a=2 b=0 {co,sum}=2
UVM_INFO ../src/monitor.sv(16) @ 250000: agent0.monitor [MONITOR] a=2 b=2 {co,sum}=4
UVM_INFO ../src/monitor.sv(16) @ 270000: agent0.monitor [MONITOR] a=0 b=3 {co,sum}=3
UVM_INFO ../src/monitor.sv(16) @ 290000: agent0.monitor [MONITOR] a=3 b=1 {co,sum}=4
UVM_INFO /home/uvm_exeuter/uvm-verilator/src/base/uvm_report_server.svh(1009) @ 290000: reporter [UVM/REPORT/SERVER] 
--- UVM Report Summary ---

** Report counts by severity
UVM_INFO :   16
UVM_WARNING :    0
UVM_ERROR :    0
UVM_FATAL :    0
** Report counts by id
[MONITOR]    15
[RNTST]     1

- /home/uvm_exeuter/uvm-verilator/src/base/uvm_test_runner.svh:297: Verilog $finish
- S i m u l a t i o n   R e p o r t: Verilator 5.053 devel
- Verilator: $finish at 290ns; walltime 0.045 s; speed 6.473 us/s
- Verilator: cpu 0.022 s on 1 threads; allocated 18 MB

image.png

参考記事

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?