はじめに
この記事は、下記の2つの続編です。
上の2つをまだ読んでない人は今すぐよんでk……あ、いや、やっぱ大丈夫っす。いきなりこの記事から読み始めてしまってもたぶん問題ないと思います1。それでは、今日も張り切って……!UVM、UVM!2
ねえ見て!ぼくの初めてのUVMテストベンチ!
前回、なるべく最短でUVMに触れるために、私たちはやや強引にuvm_test
を使い始めました。そのため、あれを満面の笑みで「みてみて!私が昨日書いたUVMテストベンチ!」と屈強なエンジニアのところに見せに行くと、もしかするともしかしなくても、微妙な表情をされるかもしれません3。
実際、あのテストベンチはかなり特殊な部類で、いわゆる普通のUVMテストベンチ4では必ず使われているようなものが使われていません。なかでも特に重要なものが、Virtual Interfaceです5。
あなたはVirtual Interfaceが使いたくなーる
とはいえ、いきなり「Virtual Interfaceを使え」なんて言われても困りますよね。なんでそんなん使わなあかんの?6……ってなるじゃないですか。なので7、我、ここに簡単な導入をばせしめんとす89。こころして聞くそす10。ゾス!!11
想像してごらん12
例えばここに、検証しなければならない2つのFlip-Flopがあったとします13。さらに、1つのFlip-Flopを検証するようなテストの開発がすでに完了していると仮定します。このとき、私たちはどのようにして、ラクして仕事をサボれるでしょうか検証を効率的に行うことで短TAT14を実現し、会社の利益に貢献できるでしょうか。
言い換えると、具体的に、どのような工夫によって「1つのFlip-Flopを検証するために用意されたテスト」を、これら2つのFlip-Flopの検証に流用できるでしょうか? ちょっと考えてみましょう。
`ifdef DUT1
まずは一つ目。`ifdef - `endif
で囲って、インスタンスの接続をコンパイルごとに切り替える案。-define DUT1
というオプションをつけてコンパイルし、シミュレーションを実行した後、今度は-define DUT2
をつけてもう一度コンパイルとシミュレーションを行います。
この方法の欠点は、DUTを切り替えるために再コンパイルが必要なことです。また、シミュレーション実行中にDUTを動的に切り替えることはできません。逆に利点はVerilog HDLやVeriog-AMSといった従来の言語15でも使用可能なこと……とかでしょうか。
MUX + dut_sel
続いて二つ目。dut_sel
という信号と、MUXを用意して、信号の経路を切り替える案です。dut_sel
によってDUTを動的に切り替えられるので、少なくとも先ほどの一つ目の案の欠点を克服しているはず。
しかし、それでもまだちょっと微妙16な感じです。simple_test
の中をみてください。階層参照を用いてtop
の変数d
にアクセスしています。まだsimple_test
とtop
の結合がちょっと密すぎるような気がします。
もしある時、テストベンチのモジュール名がtop
→tb_top
に変わったら?17 DUTやテストベンチの規模が大きくなってきたときにsimple_test
をmy_pkg.sv
というPackageに移動して管理したくなったら?18……ちょっと困りそうです。
Virtual Interface
最後に、Virtual Interfaceを使って、DUT1とDUT2のどちらのInterface(intf1
、intf2
)にアクセスするかを切り替える案。これが本命です。Virtual Intefaceは、Interfaceインスタンスへのポインタであり、動的に、自由に受け取ったり渡したりできます19。
この方法は、二つ目の案で問題だった「階層参照を使っている」という欠点を解決しています。一般的にUVMベースのテストベンチは、この「Virtual Interface」を介して、DUTの物理的なピンへの読み書きをおこないます。
テストベンチ
さて、話が長くなりましたが、私たちも、InterfaceとVirtual Interfaceを使い、前回のテストベンチを改良してみましょう。こちらが、新しいテストベンチの全体像です。simple_test
は、Interface(へのポインタであるVirtual Interface)を介してFlip-Flopのピンにアクセスします。
コードはこんな感じです。simple_test
クラスをtop
モジュール→my_pkg
パッケージへと移し、さらに、新たにFlip-Flop用のInterface dff_if
を用意しました。ぬるぽ。
module top;
timeunit 1ns;
timeprecision 1ps;
import uvm_pkg::*;
import my_pkg::*;
parameter realtime clk_period = 1ns;
bit clk = 1'b0;
initial begin
forever begin
#(0.5*clk_period);
clk = ~clk;
end
end
dff_if intf (
.clk
);
DFF dut (
.D(intf.d),
.CLK(intf.clk),
.RSTN(intf.rstn),
.Q(intf.q)
);
initial begin
uvm_config_db#(virtual dff_if)::set(uvm_root::get(), "*", "vif", intf);
run_test();
end
endmodule
interface dff_if (
input logic clk
);
timeunit 1ns;
timeprecision 1ps;
logic rstn;
logic d;
logic q;
modport mp (
output rstn,
output d,
input q,
input clk
);
endinterface
package my_pkg;
timeunit 1ns;
timeprecision 1ps;
`include "uvm_macros.svh"
import uvm_pkg::*;
class simple_test extends uvm_test;
`uvm_component_utils(simple_test)
virtual dff_if vif;
function new (string name="simple_test", uvm_component parent=null);
super.new(name, parent);
endfunction
virtual function void build_phase (uvm_phase phase);
super.build_phase(phase);
if(!uvm_config_db#(virtual dff_if)::get(this, "", "vif", vif)) begin
`uvm_fatal(get_type_name(), "Failed to get vif")
end
endfunction
parameter realtime output_skew = 0.2ns;
virtual task run_phase (uvm_phase phase);
phase.raise_objection(this);
`uvm_info(get_type_name(), "Started", UVM_MEDIUM)
@(posedge vif.mp.clk);
#(output_skew);
vif.mp.d <= 1'b0;
vif.mp.rstn <= 1'b0;
`uvm_info(get_type_name(), "RSTN = 0", UVM_MEDIUM)
@(posedge vif.mp.clk);
#(output_skew);
vif.mp.rstn <= 1'b1;
`uvm_info(get_type_name(), "RSTN = 1", UVM_MEDIUM)
@(posedge vif.mp.clk);
#(output_skew);
vif.mp.d <= 1'b1;
`uvm_info(get_type_name(), "D = 1", UVM_MEDIUM)
@(posedge vif.mp.clk);
#(output_skew);
vif.mp.d <= 1'b0;
`uvm_info(get_type_name(), "D = 0", UVM_MEDIUM)
repeat (2) begin
@(posedge vif.mp.clk);
end
`uvm_info(get_type_name(), "Finished", UVM_MEDIUM)
phase.drop_objection(this);
endtask
endclass
endpackage
なにやってるの?
いったいこのテストベンチの中で何がおこなわれているのか。ここではそれを簡単に順を追って説明しましょう。まず、top
モジュールにて、Interfaceインスタンスintf
をDUTの各ピンにつなぎます。
次に、Virtual Interface変数vif
に、先ほどDUTにつないだInterfaceインスタンスintf
を代入します。すると、Virtual Interface vif
がDUTのInterface intf
を指すようになります。これをConfig DBと呼ばれるデータベースに登録します20。
その後、simple_test
内でConfig DBからVirtual Interface vif
を取り出します。この取り出されたVirtual Interfaceは、もちろん、DUTのInterfaceを指しています。
つまり、例えばsimple_test
内でvif.d
を読み書きすると、実際にはtop
モジュールに置かれたDUTのInteface intf.d
への読み書きが行われることになります。今回のテストベンチではこのように、階層参照ではなく、Virtual Interfaceを利用してsimple_test
内からDUTのピンへのアクセスを実現しています。
DSimの実行スクリプト
dff_if.sv
とmy_pkg.sv
が増えた以外は、前回と同じです。
// DSim
-top top
+acc
-waves waves.vcd
// UVM
-suppress IneffectiveDynamicCast:MissingTimescale
-uvm 1.2
+UVM_NO_RELNOTES
+UVM_TESTNAME=simple_test
+UVM_VERBOSITY=UVM_MEDIUM
// DUT
DFF.v
// Test bench
dff_if.sv
my_pkg.sv
top.sv
@echo off
set "DSIM_LICENSE=%USERPROFILE%\AppData\Local\metrics-ca\dsim-license.json"
cd "%USERPROFILE%\AppData\Local\metrics-ca\dsim\20240923.7.0"
call shell_activate.bat
cd %~dp0
dsim -f options.txt
pause
exit
シミュレーション結果
あまり代わり映えしませんが、一応、ログの一部のスクリーンショットを貼っておきます。とくに深い意味はないです。ただの行数かせぎ、にぎやかしだったりします21。
おわりに
次回「Clocking blockとInterface内タスクでだだんだんだだん22」
デュエル、スタンバイ!
-
でもでもやっぱり、 前回/前々回の記事も読んでくれたら、それはとっても嬉しいなって。 ↩
-
あるいは、ものすごい勢いで「ホンモノのUVMテストベンチ」というものの何たるかを教えてもらえるかもしれません。知らんけど。 ↩
-
Virtual Interface以外にも不足しているものがたくさんあります……が、こまけぇこたぁいいんだよ!うるせぇエビフライぶつけんぞ(AA略 ↩
-
えせ関西弁です。この記事の著者は生まれも育ちも関東です。あ、え?きみ大阪からきたの?すごーい!ねえねえ、関西の人ってみんなお笑いみたいなのうまいんでしょ~?何でもいいからなんか面白いこと言ってよ~(笑) ↩
-
検証しなければならない2つのFlip-Flopがあります……って冷静に考えてどんな状況だよ ↩
-
TAT = Turn Around Timeの略。ここでは、「開発を開始してから実際に製品をリリースするまでにかかる時間」という意味で使っていますが、文脈によってどこからどこまでの時間を指してTATと言っているのかコロコロ変わったりします。たぶんね。 ↩
-
従来の言語……って言っちゃったけど、実際のところVerilog HDLとVerilog-AMSはどっちもまだまだ現役だよ!特にVerilog-AMSのほうは代わりが無いから、まだバリバリ使われてるよ! SystemVerilog AMSが来るまでの辛抱! ↩
-
「テストベンチのモジュール名に依存しないようにしたければ、
`define TOP_NAME tb_top
、`TOP_NAME.d = 1
とかにすればいいんじゃね?」「……せやな!」 ↩ -
Package内での階層参照はSystemVerilogの仕様で禁止されているため、コンパイル時にエラーが出ます。なぜかDSimだとエラーになりませんが。 ↩
-
Virtual Interfaceについての説明はこのあたり。
菅原システムズ - 仮想インターフェース (Virtual interface)
Verification Academy Forum - Why do we need virtual interfaces in system verilog? ↩ -
Config DBについての説明はこのあたり。
yakiraicho - 【SystemVerilog】UVMのconfig_dbって何なの
Shivam katiyar - ConfigDB: The Heart of UVM ↩ -
ちくわ大明神 ↩
-
ダンダダン……といえば何ですかね。ターミネーターのテーマ曲、とみせかけて最近人気のマンガとか。そういえば全然関係ないけど、今日はまだ一月一日ですね。あけおめことよろ。 ↩