3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【SystemVerilog】UVMのconfig_dbって何なの

Last updated at Posted at 2020-12-06

少し前になりますが、Mentor GraphicsからASIC・FPGAの検証方法について、レポートが出ましたね。

  • 2020 Wilson Research Group Functional Verification Study: FPGA Functional Verification Trend Report
  • 2020 Wilson Research Group Functional Verification Study: IC/ASIC Functional Verification Trend Report

レポートによるとUVMの採用率は、

  • ASICプロジェクトのうち約72%
  • FPGAプロジェクトのうち約48%

のようです。
ホントか!? 僕はFPGAしか触らないのですが、そんなにUVMが流行っているイメージはありません・・・。Qiitaをはじめ、ググってもろくにUVMを日本語で扱っているサイトは見当たらないし。
リサーチ対象に偏りがある気もするのですが、まぁ、世界的にはスタンダードになってきていると考えていいのかな。
僕がUVMを勉強している理由は、テストライブラリを自前で作るのが面倒だからです。自前の環境を作ったところで、他人はおろか、未来の自分さえ理解できないですからねw 日本でもスタンダードになってくれると、引継ぎが楽でいいんだけどなー。

config_dbとの出会い

さて、本題になります。UVMのチュートリアルをやっていると、必ず以下のような記述を目にすると思います。

test.sv
uvm_config_db#(virtual xxx_if)::set(null, "*", "vif", vif);
uvm_config_db#(virtual xxx_if)::get(this, "", "vif", vif);

そして以下のような解説が続きます。
「uvm_config_dbは、UVMに内蔵しているデータベースで、とても便利だ。ここにデータを登録すると、(uvmのスコープ上からは)どこからでもデータを参照できる」

いやいや、便利と言われても。。。
引数4つもあるし、仕組みわかんないし、困るんですけどw

それが僕の最初の感想で、今回のタイトルです。この疑問はしばらく続きました。UVMを使っている中で、ようやく腑に落ちてきたので、僕なりに解説したいと思います。

いつ使うの?

いつconfig_dbを使えばいいのでしょうか。チュートリアルを見る感じ、黙って真似しろよという雰囲気はありますがw
そうはいっても最初はとっつきにくいにので、ユースケースの一つを紹介します。

あくまで僕のイメージですが、UVM(SystemeVerilog)の世界を現実世界に例えると、以下のようになります。
uvm_image.png

現実世界 UVMの世界
専用IC テスト対象のモジュール
評価基板 テストベンチ
コネクタ SystemVerilogのinterface
測定器 テストクラス

ある専用ICをテストするために、評価基板を起こした様子を想像しています。
基板設計と、IC設計はきっと別の人が担当するでしょう。
ここで基板設計者側の気持ちに立って考えてみます。
「IC設計者に言われたから、基板上にコネクタの配置まではやりました。
ICに対してどんな試験をするかって?
IC設計者に聞いてくれよ。
こっちは回路設計やアートワークで大変だったんや。」

UVMの世界でも同じことがいえます。
テストベンチは静的要素ですから、動的要素であるテストクラスまでケアするのは大変です。テストベンチ側でinterfaceまで用意したら、後はテストクラス側の責任としたいものです。すると、テストベンチとテストクラスでinterfaceの橋渡しをする機構が必要になります。
ここでconfig_dbの出番というわけです!

僕はテストベンチを用意したら、とりあえずinterfaceをconfig_dbに登録しちゃいます。そしてテストクラスを作る時に、興味のあるinterfaceをconfig_dbから引っ張てきます。他にもconfig_dbの活用法はありますが、これが一番シンプルな使い方な気がします。

どうやって使うの?

それでは使い方の説明です。
まずconfig_dbの構造ですが、以下のようになっています。
(公式の情報ではありませんが、ベンダの資料を参考にしています)

name scope type value
conf1 * int 1
conf2 uvm_test_top.env.agent string test

データベースのカラムは(name、scope、type、value)になります。
登録済みのレコードは一例です。また、以降の説明ではapb_ifという名前のinterfaceを使用します(=ARMペリフェラルバスです)。

apb_if.sv
interface apb_if (input clk, input resetn);
 logic [31:0] addr;
 logic write;
 logic [31:0] wdata
 logic enable;
 logic [15:0] sel
 logic [31:0] rdata;
 logic slverr;
 logic ready;
endinterface : apb_if

レコードを登録する

データベースにレコードを登録するには、以下のように記述します。

tb_top.svh
uvm_config_db#(virtual apb_if)::set(null, "*", "vif", vif);

仰々しい記述ですね。僕はさっそく気が滅入ったのを覚えています。
意味を説明すると、

uvm_config_db#(virtual apb_if)::
uvm_config_dbクラスの持つ関数は全てスタティックです。またパラメータとして型を指定する必要があります。

set(null, "*", "vif", vif)
第一引数、第二引数はスコープです。今回はスコープを設定しない場合の記述ですね。スコープを設定する場合は後述します。
第三引数はconfig_db上の名前です。
第四引数は値です。パラメータで指定した型の値を入れてください。
なお、今回の例では第三引数と第四引数の文字列が同じですが、一致させる必要はありません。

実行すると、データベースが更新されます。

name scope type value
conf1 * int 1
conf2 uvm_test_top.env.agent string test
vif * virtual apb_if /tb_top/vif

レコードを参照する

先ほど登録したレコードを参照するには、以下のように記述します。

tb_top.v
virtual apb_if vif;
uvm_config_db#(virtual apb_if)::get(null, "*", "vif", vif);

get()の引数の意味は、set()と同じです。
get()が成功すると、変数vifを通して、先ほど登録したinterfaceにアクセスできるようになります。
もしconfig_dbに検索条件に合ったレコードがない場合、get()の結果は失敗に終わります。この時は返り値としてfalseが返るので、何かしらのエラーハンドリングが必要になります。

スコープについて

uvmのテストクラス階層に基づいて、スコープを設定できます。
例えば、uvm_test_top -> env -> agent1という階層があるとします。envから見て、agent1を対象としたデータを登録する場合、以下のように記述します。

env.svh
uvm_config_db#(int)::set(this, "agent1", "conf_agent1", 10);

config_dbは、以下のように更新されます。

name scope type value
conf1 * int 1
conf2 uvm_test_top.env.agent string test
vif * virtual apb_if /tb_top/vif
conf_agent1 uvm_test_top.env.agent1 int 10

scope列が「uvm_test_top.env.agent1」となっていることに注目です。
set()の第1引数として指定した「this」は、「uvm_test_top.env」に変換されています。これはSystem Verilogのキーワードですね。そしてset()の第2引数「agent1」を結合した文字列が、scope列に入ったことになります。
このことは、set()の第一引数と第二引数に機能的な違いはないことを意味します。コンテキスト(第一引数)とインスタンス(第二引数)に分けた方が、プログラム上で理解しやすいというだけの話です。

agent1内でこのデータを参照するには、以下のように記述します。

agent1.svh
int conf_agent1;
uvm_config_db#(int)::get(this, "", "conf_agent1", conf_agent1);

型について

nameやscopeが同じでも、typeが違うと、別のレコードとして扱われます。
例えば、asb_if(ARMシステムバス)があるとしたら、以下みたいな登録も可能です。

name scope type value
conf1 * int 1
conf2 uvm_test_top.env.agent string test
vif * virtual apb_if /tb_top/vif
conf_agent1 uvm_test_top.env.agent1 int 10
vif * virtual asb_if /tb_top/vif

デバックしてみる

簡単に使い方を紹介してみましたが、理解するには実際に触るのが一番です。
最後にデバック方法を紹介して、終わりとしたいと思います。

〇方法1
ソースコード上に次のように記述する。

debug.svh
uvm_config_db_options::turn_on_tracing();

〇方法2
シミュレータのオプションで「+UVM_CONFIG_DB_TRACE」を指定する。

いずれも結果は同じで、config_dbへの操作を行うたびに、シミュレータにログが表示されます。

#UVM_INFO C:/intelFPGA_lite/18.1/modelsim_ase/verilog_src/uvm-1.2/src/base/uvm_resource_db.svh(121) @ 0: reporter [CFGDB/SET] Configuration '*.conf1' (type int) set by  = (int) 1
#UVM_INFO C:/intelFPGA_lite/18.1/modelsim_ase/verilog_src/uvm-1.2/src/base/uvm_resource_db.svh(121) @ 0: reporter [CFGDB/SET] Configuration '*.conf1' (type string) set by  = (string) test

以上です。

3
2
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
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?