Flip-Flopでお手軽UVM（uvm_test）

## はじめに

[前回の記事](https://qiita.com/ds54e/items/64ee47b8fc1cb5ae3cc1)……見ました？

なんですかね、UVMやるとか言っておきながら、結局最後まで一ミリもそんな要素なかったじゃないですか。おい、責任者をだせ！詐欺師め！「UVM」って単語さえ出しておけば、[RTL界隈](https://talkrtl.connpass.com/)からページビューが稼げて広告収入、アフィリエイトでウハウハ、不労所得で人生勝ち組、早期リタイアでついに半導体業界から足を洗えるぜ……とか考えていたんだろ！ほら、白状しろ！[^compl]

[^compl]: マジレスすると、こんな二ッチな世界でPVが稼げるわけないので特にメリットはないです。ほら、3年前に私が作った[この動画](https://www.youtube.com/watch?v=qTBm0yb9omk)、みてくださいよ。再生数360で……え？360！？一年で120再生、一か月で10再生もされてたってこと！？やべえな、この世界狂ってんな！

……っというわけで、はい、じゃあ今日の授業はじめまーす、みんな席についてー


## UVMテストベンチの構成（一般論）

なにこれぇ。


ええ、そうです、これがUVMの一般的な構成として紹介される、いつものやつです。もうね、この時点でね、やる気なくしちゃうじゃないですか。なにこれ、私は一体これからどれだけ沢山のことを、この「UVM」とやらのために学ばないといけないわけ？ こんなんやってたら、私のワークライフバランス壊れちゃうよぉ[^work]……ふぇぇ、ってね。

[^work]: 訓練された半導体エンジニア「ワークライフバランス？ははっ、もちろん完璧ですよ、平日は家に帰ってから25時にちょこっと会議があるだけですし、土曜日も午前中にレビューがあるだけ。日曜日だって、重たいシミュレーションを裏で流しながら無料のE-leaningをだらだら流し見しているだけだし……特に何もやってないかな。それに、月曜日は向こうがまだ日曜で半分休みみたいなもんで、邪魔が入ることもなく自分の作業に集中できますしね。仕事なんてのはあんまりなくて、毎日ほとんど遊んでるみたいなもんですよ。」

![UVM-test-bench-Architecture-All-complex-test-benches-may-be-architected-as-shown-in-the.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/863735/fd478414-6208-ff0d-b875-bc84201aa280.png)
[Pankaj S. Vitankar - UVM ARCHITECTURE FOR VERIFICATION](https://www.researchgate.net/publication/303759959_UVM_ARCHITECTURE_FOR_VERIFICATIONJTypeIJECETVType7IType3)から引用



## UVMテストベンチの構成（お手軽UVM）

一方で、今回私たちが作るテストベンチがこちら。

わお、驚きの白さ。Testの中に何もありません。Environment？Agent？SequenceにDriver、Monitor？そんなものは世界の果てに置いてきた。ここにあるのは、ほとんど空っぽのTestコンポーネント、ただそれだけだ。

![Screenshot 2024-12-30 100807.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/863735/ef8c6f61-9312-c7d2-d54b-c273b2f9001e.png)


## テストベンチ

私たちが今回作るテストベンチの大体のカタチが分かったところで、さっそくコーディングを始めていきましょう。

コードを書き終わったあと、時間があればぜひ、[前回の記事](https://qiita.com/ds54e/items/64ee47b8fc1cb5ae3cc1)で紹介した従来型のモジュールベースのテストベンチと比較しながら、コード全体を少し眺めてみてください。きっと、（何だかよくわからない儀式めいた呪文が各所でちょいちょい使われている以外は）前回のモジュールベースのテストベンチと大差ない……と感じると思います[^first]。

そうそう、こわくない、こわくないよー。UVMはこわくないからねー。
そーっと、そーっと近づいてなでなでして仲良くなろうねー

[^first]: UVMベースのテストベンチを初めて見た人は、この時点で、「`run_test()`の定義がどこにもなくね？」「これって結局、どういう仕組みで`simple_test::run_phase()`が呼び出されるの？」「ああああああああああ！！！！」「[わけがわからないよ](https://ja.wikipedia.org/wiki/%E3%82%AD%E3%83%A5%E3%82%A5%E3%81%B9%E3%81%88)」「[もぅﾏﾁﾞ無理。 ﾘｽｶしょ](https://dic.nicovideo.jp/a/%E3%82%82%E3%81%85%E3%83%9E%E3%83%82%E7%84%A1%E7%90%86)」……となりがちですが、とりあえず今は細かいことは置いといて、「`run_test()`を呼び出すと、背後で何か不思議な力が働き、`uvm_test`を継承して作った`simple_test`の`run_phase()`が勝手に呼ばれ、そこに記述されたテストパターンが流れ始める」くらいに思っておきましょう。

```verilog:top.sv
module top;
  timeunit 1ns;
  timeprecision 1ps;

  `include "uvm_macros.svh"
  import uvm_pkg::*;

  parameter realtime clk_period = 1ns;
  bit clk = 1'b0;

  initial begin
    forever begin
      #(0.5*clk_period);
      clk = ~clk;
    end
  end

  logic d;
  logic rstn;
  logic q;

  DFF dut (
    .D(d),
    .CLK(clk),
    .RSTN(rstn),
    .Q(q)
  );

  initial begin
    run_test();
  end
  
  class simple_test extends uvm_test;
    `uvm_component_utils(simple_test)
    
    function new (string name="simple_test", uvm_component parent=null);
      super.new(name, parent);
    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 top.clk);
      #(output_skew);
      top.d <= 1'b0;
      top.rstn <= 1'b0;
      `uvm_info(get_type_name(), "RSTN = 0", UVM_MEDIUM)

      @(posedge top.clk);
      #(output_skew);
      top.rstn <= 1'b1;
      `uvm_info(get_type_name(), "RSTN = 1", UVM_MEDIUM)

      @(posedge top.clk);
      #(output_skew);
      top.d <= 1'b1;
      `uvm_info(get_type_name(), "D = 1", UVM_MEDIUM)

      @(posedge top.clk);
      #(output_skew);
      top.d <= 1'b0;
      `uvm_info(get_type_name(), "D = 0", UVM_MEDIUM)

      repeat (2) begin
        @(posedge top.clk);
      end
      `uvm_info(get_type_name(), "Finished", UVM_MEDIUM)
      phase.drop_objection(this);
    endtask
  endclass

endmodule
```

## DSimの実行スクリプト

シミュレーション実行時に必要なオプションがちょっと増えました。具体的には、下記の`options.txt`の`// UVM`と書いてあるあたりです[^supress]。今回は[UVM-1.2](https://www.accellera.org/images/downloads/standards/uvm/uvm_users_guide_1.2.pdf)を使っていますが、どうやらお高い商用シミュレータでは「UVM 2020-2.0」というのもしっかり内蔵されていて簡単に選べるらしいです[^uvm2]。え？UVMのVersionごとの細かい違いは何かって？うーん、オラァ難しいことはよくわがんねぇだ。だがら業界標準として普及してそうな「UVM-1.2」のほうにしておくだぁ。

[^supress]: `-suppress IneffectiveDynamicCast:MissingTimescale`は、なんかデフォでいろいろ警告が出てきてログが汚れるので勝手に付け足した部分です。「動けばいいんだよ、動けば」の精神で、とりあえずDynamicCastとTimescaleのWarningを`-suppress`オプションで勝手にもみ消しちゃいました。てへぺろ。きっとそのうち、どこからともなくだれか心優しい親切な有識者がやってきて、このWarningがどうして出てくるのか、果たして無視していいものなのか……そっと私たちに教えてくれるはずです。インターネットは広いからね。きっとだれかが、この広大な世界のどこかでコメントしてくれることでしょう。知らんけど。

[^uvm2]: [vega77 - UVM 2020-2.0をちょっとだけ使ってみた](https://qiita.com/vega77/items/4b4b3f5354f6e859bc79)

```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
top.sv
```

```winbatch: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
```

## シミュレーション結果

`run.bat`を実行すると、こんな感じの結果が得られます。
とりあえずなんかまぁ動いてるから、[ヨシッ！](https://x.com/genbaneko_bot/status/1338982315721015296)

![Screenshot 2024-12-30 174618.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/863735/7fcd9194-88a9-313f-6e35-f8728319f55b.png)


## おわりに

今回はここまで！

実際のところ、これをUVMベースのテストベンチだと言い張るにはまだちょっと心もとないかもしれませんが、何はともあれ、UVMのライブラリを利用してテストパターンを流すことはできました。これは私たちにとって大きな一歩です。少なくとも、何もしないことより5000兆倍すばらしいです。すごい！UVMできてえらい！[^erai]

[次回](https://qiita.com/ds54e/items/48412f9172af9a7c4823)、「Virutal Interfaceを使って、もうちょっとモダンな感じに仕上げよう」
それでは、おつぺこでしたー、ばいばーい！[^peko]

![Screenshot 2024-12-30 123355.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/863735/cd811e41-92f0-2ddd-aa67-53d9664a9211.png)
[チキン冷やし会場2024](https://www.youtube.com/watch?v=n-QiDZa-mBE)

[^erai]: [えらい - バーチャルYouTuberに起きた出来事をまとめるWiki](https://scrapbox.io/vtuber/%E3%81%88%E3%82%89%E3%81%84)

[^peko]: [Pekora Ch. 兎田ぺこら](https://www.youtube.com/channel/UC1DCedRgGHBdm81E1llLhOQ)


## 2024/12/30 追記
本記事の投稿後、「package内からの階層参照がSystemVerilogの仕様に違反している」ことをご指摘いただきました[^tweet][^sv]。DSimではなぜかコンパイルエラーになりませんでしたが、他のシミュレータだと仕様に従ってエラーを出すようです[^sim]。そのため、packageを使わない形にテストベンチを修正し、シミュレーション結果を更新しました。Thanks！

![Screenshot 2024-12-30 173325.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/863735/9ebf0aa4-4161-35c1-cd8c-220bd2bed309.png)


[^tweet]: https://x.com/taichi600730/status/1873583460314718678

[^sim]: 修正前のテストベンチを、DSimではなく、試しにAldec Riviera Pro 2023.04で実行してみたところ、`ERROR VCP7600 "A hierarchical reference found in a package as the first component of the dotted name ""top.d"" has not been found in the current scope of the package."`というエラーが表示されました。他のシミュレータでは仕様通り、package内からの階層参照が禁止されているようです。実際に試してみたい方のために、[こちら](https://edaplayground.com/x/M523)にEDA Playgourndへのリンクを置いておきます。

[^sv]: [IEEE 1800-2017 SystemVerilog](https://ieeexplore.ieee.org/document/8299595) の「26.2 Package declarations」に、「パッケージ内から階層参照はできないよ」的なことが書いてあります。また、[Verification Academy Forum](https://verificationacademy.com/forums/latest) の [Illegal location for a hierarchical name (in a package)](https://verificationacademy.com/forums/t/illegal-location-for-a-hierarchical-name-in-a-package-issue/36214) に、この問題に関連した質問と回答があります。