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(Driver)

Last updated at Posted at 2025-01-04

はじめに

やあ (´・ω・`) ようこそ、バーボンハウスへ。
このテキーラはサービスだから、まず飲んで落ち着いて欲しい1

1)Flip-Flopでお手軽UVM(できなかった)
2)Flip-Flopでお手軽UVM(uvm_test)
3)Flip-Flopでお手軽UVM(Virtual Interface)
4)Flip-Flopでお手軽UVM(Clocking block)
5)Flip-Flopでお手軽UVM(Driver)←いまここだよ

……というわけで、このシリーズもついに第5話に突入しました。すごいですね。多くの投稿者が挫折し失踪すると呼ばれる第5話目、5話目ですってよ奥さん。これはお祝いしないといけないレベルでございますわ!23

Screenshot 2025-01-04 155117_3.png
投資入門アニメ

想定読者

ないんだな、それが。しいて言えば、おれだ。俺自身が読者なのだ4
それでは、今日も一日がんばるぞいっ5

今回の目標

前回までに、やりたいことはおおよそ完了しました6。あれでも一応動きはするので、まあとりあえず完成と言ってしまっても良い……のですが、今回はもうちょっと頑張って、第二話で見たような「普通のUVMテストベンチ」の構成に少し近づける工夫をしてみましょう。

UVM-test-bench-Architecture-All-complex-test-benches-may-be-architected-as-shown-in-the.png
Pankaj S. Vitankar - UVM ARCHITECTURE FOR VERIFICATION

今回組み上げる予定のテストベンチの構成

これが今回作る予定のテストベンチの全体像です。どうでしょう。だいぶサマになってきたんじゃないでしょうか。少なくとも、第二話で作ったベンチと比べて、当社比1000倍くらいそれっぽい見た目になった気がします。

Screenshot 2025-01-03 214521.png

テストベンチ

テストベンチトップのコードはこんなかんじ。my_pkg.svを見ると……なんかやたらとファイルが増えてますね。トランザクションとか、シーケンスとか、ドライバーとか。横文字ばっかで意味わかんにゃい。一方、top.svのほうは前回とほぼ同じです。

my_pkg.sv
package my_pkg;
  timeunit 1ns;
  timeprecision 1ps;

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

  `include "my_transaction.sv"
  `include "my_sequence.sv"
  `include "my_driver.sv"
  `include "my_agent.sv"
  `include "my_environment.sv"
  `include "simple_test.sv"

endpackage
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(), "uvm_test_top.env.agt", "vif", intf);
    run_test();
  end
  
endmodule

Sequence、Sequence item、Driver

さて、真面目な解説記事であれば、トランザクションレベルモデリングがどうとか、こういう図を使った、なにやら難しそうな話がここで始まったりするわけですが……うーん、まあとりあえず動けばいいから手短に使い方だけ教えてよ、ってことでね、ここではやっていこうと思います。

お↓ら↑よ↓7強者たちよ、出てこいやっ!

気になるあの娘はシーケンス8

まずはこの子、「シーケンス」の紹介から始めましょう。

UVMでは「トランザクション」というカタマリを介して、コンポーネント9間で必要な情報のやり取りをします。そのトランザクションとやらを作ってるのが、この「シーケンス」です10。ほら、見てください、`uvm_info(get_type_name(), "Reset", UVM_MEDIUM)のすぐ下のあたり。「DUTをリセットしろー」的な情報というか指示みたいなものを詰め込んでいるような……そんな波動を感じませんか

my_sequence.sv
class my_sequence extends uvm_sequence;
  `uvm_object_utils(my_sequence)

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

  virtual task body ();
    my_transaction tr;
    
    `uvm_info(get_type_name(), "Reset", UVM_MEDIUM)
    tr = my_transaction::type_id::create("tr");
    tr.reset = 1'b1;
    tr.data = 1'b0;
    tr.delay = 'd0;
    start_item(tr);
    finish_item(tr);

    `uvm_info(get_type_name(), "50 random data", UVM_MEDIUM)
    for (int i=0; i<50; i++) begin
      `uvm_do_with(tr, {tr.reset == 1'b0; tr.delay == 'd0;})
    end
  endtask
endclass

ちなみに、`uvm_info(get_type_name(), "50 random data", UVM_MEDIUM)の下の部分は、「ランダムなデータを送ってねー、ただし、リセット無し&ディレイ無しで。よろぴくー11」というTransactionを50回送ってるかんじのアレです。

君に胸キュン、トランザクション12

つづいて、これが今回の私たちの「トランザクション」です。

resetdatadelayというメンバー変数を持っています。randキーワードが付いているので、`uvm_do(tr)`uvm_do_with(tr, constraints)マクロを使った際、これらの変数には基本的にランダムな値がセットされます。それだけっちゃそれだけ。

my_transaction.sv
class my_transaction extends uvm_sequence_item;
  rand bit reset;
  rand bit data;
  rand int unsigned delay;

  `uvm_object_utils_begin(my_transaction)
    `uvm_field_int(reset, UVM_DEFAULT)
    `uvm_field_int(data, UVM_DEFAULT)
    `uvm_field_int(delay, UVM_DEFAULT)
  `uvm_object_utils_end

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

endclass

みむかゥわナイスドライバー13

ざぁーこざぁーこ♡、ざぁーこざぁーこ♡

……ごほん。えー、これが今回の主役、「ドライバー」です。先ほど定義したトランザクションを受け取って、実際に、DUTであるFlip-Flopを操作してくれるコンポーネントです。言い換えると、「トランザクション」という抽象的なサムシングを、D <= 0;とかRSTN <= 0; @(cb); RSTN <= 1;のような抽象度の低い「DUTに対する具体的な操作」に変換してくれるえらいやつです14。仲良くしてあげてね。

my_driver.sv
class my_driver extends uvm_driver #(my_transaction);
  `uvm_component_utils(my_driver)

  virtual dff_if vif;

  function new (string name="my_driver", 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

  virtual task run_phase (uvm_phase phase);
    forever begin
      seq_item_port.get_next_item(req);
      if (req.reset) begin
        vif.mp.reset();
      end else begin
        vif.mp.write(req.data);
      end
      vif.mp.delay(req.delay);
      seq_item_port.item_done();
    end
  endtask
endclass

Agent

Agentは、シーケンサ15とドライバを入れる箱です。以上!

my_agent.sv
class my_agent extends uvm_agent;
  `uvm_component_utils(my_agent)

  uvm_sequencer #(my_transaction) sqr;
  my_driver drv;
  virtual dff_if vif;
  
  function new (string name="my_agent", uvm_component parent=null);
    super.new(name, parent);
  endfunction

  virtual function void build_phase (uvm_phase phase);
    super.build_phase(phase);
    sqr = uvm_sequencer#(my_transaction)::type_id::create("sqr", this);
    drv = my_driver::type_id::create("drv", this);
    if (!uvm_config_db#(virtual dff_if)::get(this, "", "vif", vif)) begin
      `uvm_fatal(get_type_name(), "Failed to get vif")
    end
    uvm_config_db#(virtual dff_if)::set(this, "drv", "vif", vif);
  endfunction
  
  virtual function void connect_phase (uvm_phase phase);
    super.connect_phase(phase);
    drv.seq_item_port.connect(sqr.seq_item_export);
  endfunction
endclass

Test、Environment

Environmentは、Agentを入れる箱です。
Testは、Sequence(シーケンス16)とEnvironmentを入れる箱です。

simple_test.sv
class simple_test extends uvm_test;
  `uvm_component_utils(simple_test)
  
  my_environment env;
  my_sequence seq;

  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);
    env = my_environment::type_id::create("env", this);
    seq = my_sequence::type_id::create("seq", this);
  endfunction

  virtual task run_phase (uvm_phase phase);
    phase.raise_objection(this);
    `uvm_info(get_type_name(), "Started", UVM_MEDIUM)
    seq.start(env.agt.sqr);
    `uvm_info(get_type_name(), "Finished", UVM_MEDIUM)
    phase.drop_objection(this);
  endtask
endclass
my_environment.sv
class my_environment extends uvm_env;
  `uvm_component_utils(my_environment)

  my_agent agt;

  function new (string name="my_environment", uvm_component parent=null);
    super.new(name, parent);
  endfunction

  virtual function void build_phase (uvm_phase phase);
    super.build_phase(phase);
    agt = my_agent::type_id::create("agt", this);
  endfunction
endclass

DSimの実行スクリプト

もう五回目なので、見慣れた光景ですね。今回から`includeを使い始めたので、options.txtに、新しく-incdirが追加されたことにだけご注意くださいませ17

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
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
-incdir .
dff_if.sv
my_pkg.sv
top.sv

シミュレーション結果

キェェェェェェアァァァァァァウゴイタァァァァァァァ!!!!!!!!!!!!

Screenshot 2025-01-04 165154_2.png
Screenshot 2025-01-04 165311_2.png

おわりに

Flip-Flopでお手軽UVMシリーズは、これにておしまい!18
ここまで読んでくれてありがとう!

Screenshot 2025-01-03 180028.png
びんちょうたん

  1. ニコニコ大百科 - バーボンハウス

  2. 実際のところ、通常なら1ページで終わるような短い内容を引き延ばして引き延ばして、それこそもう向こう側の景色が透けて見えてしまうくらいに、あるいは、なんだこれおまえの実家のカルピスかよってくらいに薄くして、やっとこさ五回分、って感じかもしれなくもない。

  3. まあまさに今日今回これを最後に失踪する予定なわけですが

  4. このように言っておくと、自分の記事が誰にも読まれなかったときに「いや、でもこれ自分用に備忘録として書いたやつだしっ、ぜんぜん誰にも読まれなくてもかなしくねーしっ、全然ノーダメージだしっ、むしろそのほうがいい、っていうか!!???そんなかんじ???(泣」っていう逃げ道になるのでオススメだぞっ、この卑怯者っ!

  5. NEW GAME!-「今日も一日がんばるぞい!」

  6. ※「いまだに何のチェッカーも実装されておらず、毎回シミュレーション結果を目視確認している」という致命的な問題点を除く

  7. ホロライブ非公式Wiki - 戌神ころね 語録集

  8. 気になるあの娘 - 相対性理論 (cover)|somunia

  9. DriverとかMonitorとか。(正確にはちがうけど)静的なオブジェクト的なサムシングだと思っておいてください。Difference Between UVM_OBJECT and UVM_COMPONENT

  10. 大雑把に、シーケンス=「実際にDUTのピンを操作してくれるドライバー君への指示書をつくるための場所」みたいな理解でもいいと思います。たぶんね。

  11. のりピー語辞典 - よろぴく

  12. 君に、胸キュン。- YMO (cover)|まりあ†ほりっく

  13. みむかゥわナイストライ - ぬぬぬぬぬぬぬぬぬぬぬぬぬぬぬぬぬぬぬぬぬぬぬぬぬぬぬぬぬぬぬぬぬぬぬぬぬぬぬぬぬぬぬぬぬぬぬぬぬぬぬぬぬぬぬぬぬぬぬぬぬぬぬぬぬぬぬぬぬぬ (cover)|ななひら

  14. 前回の記事で、Interfaceの中にwriteresetといったタスクを入れておいたので、今回の私たちのテストベンチでのDriverくんのお仕事は、「受け取ったトランザクションに従って、適切にそれらのタスクを呼び出すこと」だけです。「簡単なお仕事でサクッと高収入☆彡」「未経験者歓迎☆彡」「アットホームな明るい職場☆彡」

  15. Environmentの中にいるのが「シーケンス(Sequence)」で、Agentの中にいるのが「シーケンサ(Sequencer)」です。文字にすると一文字違いでややこしいので、慣れるまではご注意くださいまし。シーケンスはオブジェクトで、シーケンサはコンポーネント。

  16. アルファベットでSequenceって書いたり、カタカナでシーケンスって書いたり……表記揺れしまくっててごめんぬ!英語ばっかだとなんか文章がお堅く見えちゃう気がして、この記事では、なるべくカタカナで代用したいなぁ……という気持ちがあったりなかったりするよ!外来語表記警察のひとも生暖かく見守ってあげてね。

  17. 実はoptions.txt-incdir .は無くてもよかったりします。DSimくんは、カレントディレクトリをデフォで走査してくれるっぽいので。あと、今回は`includeするファイルをフォルダにまとめずに、run.batと同じ場所に直にベタ置きしてます。雑ぅ!

  18. ちょっとシリーズが長くなりすぎたのでここでいったん一区切り。MonitorとかScoreboardとか、RALとかその辺の話はまた今度別枠でやれたらやりたいなあと思ったーり、ぽけったーり、もんすたーり、おどったり、まわったり

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?