1
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?

Flip-Flopでお手軽UVM(Virtual Interface)

Last updated at Posted at 2024-12-30

はじめに

この記事は、下記の2つの続編です。

上の2つをまだ読んでない人は今すぐよんでk……あ、いや、やっぱ大丈夫っす。いきなりこの記事から読み始めてしまってもたぶん問題ないと思います1。それでは、今日も張り切って……!UVM、UVM!2

Screenshot 2025-01-01 085406.png
第3次スーパーロボット大戦 AG

ねえ見て!ぼくの初めてのUVMテストベンチ!

前回、なるべく最短でUVMに触れるために、私たちはやや強引にuvm_testを使い始めました。そのため、あれを満面の笑みで「みてみて!私が昨日書いたUVMテストベンチ!」と屈強なエンジニアのところに見せに行くと、もしかするともしかしなくても、微妙な表情をされるかもしれません3

Screenshot 2024-12-31 180122.png

実際、あのテストベンチはかなり特殊な部類で、いわゆる普通のUVMテストベンチ4では必ず使われているようなものが使われていません。なかでも特に重要なものが、Virtual Interfaceです5

download (1).png
パチンコフォントメーカー

あなたは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をつけてもう一度コンパイルとシミュレーションを行います。

Screenshot 2024-12-30 201121.png

この方法の欠点は、DUTを切り替えるために再コンパイルが必要なことです。また、シミュレーション実行中にDUTを動的に切り替えることはできません。逆に利点はVerilog HDLやVeriog-AMSといった従来の言語15でも使用可能なこと……とかでしょうか。

MUX + dut_sel

続いて二つ目。dut_selという信号と、MUXを用意して、信号の経路を切り替える案です。dut_selによってDUTを動的に切り替えられるので、少なくとも先ほどの一つ目の案の欠点を克服しているはず。

Screenshot 2024-12-30 201157.png

しかし、それでもまだちょっと微妙16な感じです。simple_testの中をみてください。階層参照を用いてtopの変数dにアクセスしています。まだsimple_testtopの結合がちょっと密すぎるような気がします。

もしある時、テストベンチのモジュール名がtoptb_topに変わったら?17 DUTやテストベンチの規模が大きくなってきたときにsimple_testmy_pkg.svというPackageに移動して管理したくなったら?18……ちょっと困りそうです。

Virtual Interface

最後に、Virtual Interfaceを使って、DUT1とDUT2のどちらのInterface(intf1intf2)にアクセスするかを切り替える案。これが本命です。Virtual Intefaceは、Interfaceインスタンスへのポインタであり、動的に、自由に受け取ったり渡したりできます19

Screenshot 2024-12-30 201301.png

この方法は、二つ目の案で問題だった「階層参照を使っている」という欠点を解決しています。一般的にUVMベースのテストベンチは、この「Virtual Interface」を介して、DUTの物理的なピンへの読み書きをおこないます。

テストベンチ

さて、話が長くなりましたが、私たちも、InterfaceとVirtual Interfaceを使い、前回のテストベンチを改良してみましょう。こちらが、新しいテストベンチの全体像です。simple_testは、Interface(へのポインタであるVirtual Interface)を介してFlip-Flopのピンにアクセスします。

Screenshot 2024-12-30 203000.png

コードはこんな感じです。simple_testクラスをtopモジュール→my_pkgパッケージへと移し、さらに、新たにFlip-Flop用のInterface dff_ifを用意しました。ぬるぽ。

top.sv
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
dff_if.sv
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
my_pkg.sv
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の各ピンにつなぎます。

Screenshot 2024-12-30 203057.png

次に、Virtual Interface変数vifに、先ほどDUTにつないだInterfaceインスタンスintfを代入します。すると、Virtual Interface vifがDUTのInterface intfを指すようになります。これをConfig DBと呼ばれるデータベースに登録します20

Screenshot 2024-12-30 203319.png

その後、simple_test内でConfig DBからVirtual Interface vifを取り出します。この取り出されたVirtual Interfaceは、もちろん、DUTのInterfaceを指しています。

Screenshot 2024-12-30 203523.png

つまり、例えばsimple_test内でvif.dを読み書きすると、実際にはtopモジュールに置かれたDUTのInteface intf.dへの読み書きが行われることになります。今回のテストベンチではこのように、階層参照ではなく、Virtual Interfaceを利用してsimple_test内からDUTのピンへのアクセスを実現しています。

Screenshot 2024-12-30 203540.png

DSimの実行スクリプト

dff_if.svmy_pkg.svが増えた以外は、前回と同じです。

options.txt
// 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
run.bat
@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

Screenshot 2024-12-30 214214.png

おわりに

次回「Clocking blockとInterface内タスクでだだんだんだだん22
デュエル、スタンバイ!

Screenshot 2025-01-01 201526.png

  1. でもでもやっぱり、 前回/前々回の記事も読んでくれたら、それはとっても嬉しいなって

  2. ニコニコ大百科 - AG(スパロボ)

  3. あるいは、ものすごい勢いで「ホンモノのUVMテストベンチ」というものの何たるかを教えてもらえるかもしれません。知らんけど。

  4. ふつうって……なんですかね(哲学)

  5. Virtual Interface以外にも不足しているものがたくさんあります……が、こまけぇこたぁいいんだよ!うるせぇエビフライぶつけんぞ(AA略

  6. えせ関西弁です。この記事の著者は生まれも育ちも関東です。あ、え?きみ大阪からきたの?すごーい!ねえねえ、関西の人ってみんなお笑いみたいなのうまいんでしょ~?何でもいいからなんか面白いこと言ってよ~(笑)

  7. NHK 放送文化研究所 -「なので」ということばの使い方がおかしいと言われました

  8. 学研全訳古語辞典 - ~をば

  9. 日常生活の知恵袋 - ~せしめんとする

  10. ピクシブ百科事典 - ファプタが「そす」と言うのはなぜ?

  11. 鎌田和樹 -「オス!」と「ゾス!!」について

  12. John Lennon - Imagine

  13. 検証しなければならない2つのFlip-Flopがあります……って冷静に考えてどんな状況だよ

  14. TAT = Turn Around Timeの略。ここでは、「開発を開始してから実際に製品をリリースするまでにかかる時間」という意味で使っていますが、文脈によってどこからどこまでの時間を指してTATと言っているのかコロコロ変わったりします。たぶんね

  15. 従来の言語……って言っちゃったけど、実際のところVerilog HDLとVerilog-AMSはどっちもまだまだ現役だよ!特にVerilog-AMSのほうは代わりが無いから、まだバリバリ使われてるよ! SystemVerilog AMSが来るまでの辛抱!

  16. ことば研究館 - 「微妙」の用法

  17. 「テストベンチのモジュール名に依存しないようにしたければ、`define TOP_NAME tb_top`TOP_NAME.d = 1とかにすればいいんじゃね?」「……せやな!」

  18. Package内での階層参照はSystemVerilogの仕様で禁止されているため、コンパイル時にエラーが出ます。なぜかDSimだとエラーになりませんが。

  19. Virtual Interfaceについての説明はこのあたり。
    菅原システムズ - 仮想インターフェース (Virtual interface)
    Verification Academy Forum - Why do we need virtual interfaces in system verilog?

  20. Config DBについての説明はこのあたり。
    yakiraicho - 【SystemVerilog】UVMのconfig_dbって何なの
    Shivam katiyar - ConfigDB: The Heart of UVM

  21. ちくわ大明神

  22. ダンダダン……といえば何ですかね。ターミネーターのテーマ曲、とみせかけて最近人気のマンガとか。そういえば全然関係ないけど、今日はまだ一月一日ですね。あけおめことよろ。

1
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
1
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?