• 検索結果がありません。

UVM入門

N/A
N/A
Protected

Academic year: 2021

シェア "UVM入門"

Copied!
76
0
0

読み込み中.... (全文を見る)

全文

(1)

Artgraphics

UVM 入門

Document Revision: 1.6, 2018.10.20 アートグラフィックス

(2)

©2018 アートグラフィックス 〒124-0012 東京都葛飾区立石 8-14-1 www.artgraphics.co.jp

UVM Primer

©2018 Artgraphics. All rights reserved.

8-14-1, Tateishi, Katsushika-ku, Tokyo, 124-0012 Japan www.artgraphics.co.jp

(3)

この入門書は UVM の概要を簡単に纏めた学習用の素材です。UVM の基礎を把握する事を主眼 にしている為、詳細の機能については触れていません。この入門書を読了後に、UVM User’s Guide([2])を熟読する事を薦めます。或いは、UVM の文献(例えば[4])を読む事を薦めます。 誤字訂正、及び、説明の補足を随時行います。従って、常に本書の内容は更新を余儀なくされま す。ご了承ください。 尚、本書の記述は UVM 1.2 をベースにしています。 アートグラフィックス 篠塚一也

(4)

変更履歴 日付 Revision 変更点 2018.03.10 1.0 第一版。 2018.04.05 1.1 ① 第二章の構成を変更、及び、節の追加。 ② 第五章を追加。 2018.05.31 1.2 ① 第一章の内容に補足。 2018.07.25 1.3 ① 1.7 を追加。 ② 他の節に於いて一部記述を変更していますが、読み直す 必要はありません。 2018.07.28 1.4 ① 随所で表現を正確にしました。 ② 「補足」の章を追加しました。 2018.08.07 1.5 ① 第一章を再編成しました。 ② フィールド・マクロ・フラグの記述を追加しました。 ③ virtual sequencer 及び virtual sequence の記述を追加しまし

た。

(5)

目次 1 概要 ... 1 1.1 UVM 概要 ...1 1.1.1 UVM とは何か? ...1 1.1.2 TLM (Transaction-Level Modeling) ...1 1.1.3 代表的なUVM クラス ...1 1.1.4 Virtual Interface ...2 1.1.5 UVM テストベンチの構造 ...2 1.2 検証技術のトレンド ...3 1.3 UVM の構成 ...4 1.3.1 uvm_pkg ...4 1.3.2 uvm_object と uvm_component ...4 1.3.3 UVM マクロ...4 1.4 シミュレーション・フェーズ(SIMULATION PHASES) ...7 1.5 ソース・コードの準備 ...8 1.5.1 `include ...8 1.5.2 import UVM ...8 1.6 UVM 使用例 ...9 1.7 UVM の DPI の意義 ... 11 2 UVM クラス・ライブラリーの基礎 ... 12 2.1 基本的な概念 ... 12 2.1.1 uvm_object と uvm_component ... 12 2.1.2 コンストラクタ ... 12 2.1.3 フィールド・マクロ ... 12 2.1.4 ファクトリ(factory) ... 15 2.1.5 シミュレーション・フェーズ(simulation phases) ... 16 2.1.6 コンフィギュレーションの設定変更 ... 16 2.2 TLM (TRANSACTION-LEVEL MODELING) ... 18 2.2.1 トランザクション ... 18 2.2.2 コンポーネント間の通信 ... 18 2.2.3 uvm_tlm_fifo ... 22

2.2.4 analysis ports と exports ... 23

2.3 プリント機能 ... 25 2.3.1 UVM プリンター ... 25 2.3.2 アレイのプリント ... 27 2.4 メッセージ機能 ... 30 2.5 UVM シミュレーション ... 30 2.5.1 raise_objection と drop_objection ... 30 2.5.2 シミュレーション進行状況の確認 ... 33 2.6 クラスの記述法 ... 33

3 UVC (UNIVERSAL VERIFICATION COMPONENTS)... 35

3.1 トランザクション ... 35

3.1.1 トランザクションの定義 ... 35

3.1.2 サブクラスによる制約 ... 36

3.2 ドライバー ... 37

(6)

3.3.2 シーケンサーとドライバーの基本的なハンドシェーク ... 40 3.4 モニター ... 40 3.4.1 コレクター ... 40 3.4.2 モニターの定義 ... 41 3.5 コンポーネントのインスタンスを作成する方法(UVM FACTORY) ... 43 3.6 AGENT ... 44 3.7 ENVIRONMENT ... 45 3.8 シナリオの作成 ... 48 3.8.1 シーケンス(sequences) ... 48 3.8.2 シーケンサー(sequencers) ... 49 3.8.3 シーケンスの開始 ... 49

3.8.4 Virtual Sequencer と Virtual Sequences ... 50

4 テストベンチの作成 ... 54 4.1 トップ・レベルのENVIRONMENTの作成 ... 54 4.2 ベース・テスト ... 54 4.3 テスト ... 55 4.4 テストの選択 ... 55 4.5 PROGRAMブロックとテストベンチ... 56 4.6 コマンド・ラインの操作 ... 56 5 UBUS ... 58 5.1 トップ・モジュール ... 58 5.2 ベース・テスト ... 59 5.3 トップ・レベルのエンバイロンメント ... 60 6 補足 ... 63 6.1 設計・検証作業の働き方改革 ... 63 6.2 WISH LIST ... 63 6.2.1 環境管理及びファイル管理 ... 63

6.2.2 SystemVerilog テキスト・エディタ(What You See Is What You Get) ... 63

6.2.3 データ・タイプのサポート ... 65

6.2.4 ウィザード ... 66

6.2.5 コード・スニペットとブックマーク ... 67

6.3 結論 ... 69

(7)

1 概要 1.1 UVM 概要

1.1.1 UVM とは何か?

Universal Verification Methodology (UVM)とは、検証分野で推奨されている技術、ルール、慣習、 規律等をコードとして 具体化し、検証技術の再利用性を促進して生産性向上をさせる 為の SystemVerilog のクラス・ライブラリーです。UVM は Accellera Systems Initiative により開発され ました。

UVM は SystemVerilog をベースにして記述されているので、SystemVerilog をサポートしている検 証ツールの環境で使用する事が出来ます。尚、UVM には C/C++コードが DPI として使用されて います。従って、DPI をサポートしている環境でのみ UVM を使用する事が出来ます。DPI をサ ポートしていないツールの環境においては、DPI の使用をオフに設定する必要があります。その 場合、UVM の一部の機能を使用する事が出来なくなります。 1.1.2 TLM (Transaction-Level Modeling) UVM は TLM を採用し、シグナル・レベルよりも高位の記述法を用いて検証タスクを表現します。 このアプローチはシステムの動作を考察する際の自然な方法です。 UVM ではトランザクションはオブジェクトであり、UVM コンポーネントがトランザクションを 操作します。その内の特別なコンポーネントとしてドライバー(uvm_driver のサブクラス)が存 在します。ドライバーはトランザクションをシグナル・レベルに変換して DUT を操作する役目 を持ちます。 DUT 側のシグナルの変化を検知する役目を持つ UVM コンポーネントも必要になります。そのコ ンポーネントは、一般的には、コレクター(collector)と呼ばれます。 ドライバーとコレクターの存在により、UVM ではトランザクション・レベルでシステムを記述 す る 事 が 出 来 る 様 に な り ま す 。 尚 、 UVM コ ン ポ ー ネ ン ト と DUT 間 の デ ー タ 授 受 に は SystemVerilog の virtual interface が使用されます。

1.1.3 代表的な UVM クラス UVM には多くのクラスが定義されていますが、ユーザが直接使用するのはその内の一部のクラ スで、メソドロジー・クラス(methodology class)と呼ばれます。代表的なメソドロジー・クラ スとトランザクション関連のクラスとしては、以下のクラスが存在します。 UVM クラス 種別 uvm_sequence_item トランザクション関連 uvm_sequence トランザクション関連 uvm_driver メソドロジー・クラス uvm_sequencer メソドロジー・クラス uvm_env メソドロジー・クラス uvm_agent メソドロジー・クラス uvm_test メソドロジー・クラス uvm_monitor メソドロジー・クラス uvm_scoreboard メソドロジー・クラス uvm_sequence_item はトランザクションを記述する為のクラスで、データ・オブジェクトになり ます。uvm_sequence もデータ・オブジェクトですが、トランザクションの生成を行います。

(8)

上記の表の uvm_driver 以降はコンポーネントで、データ・オブジェクトではありません。コンポ ーネントとは、シミュレーションの実行エントリーです。コンポーネントが実行する事によりシ ミュレーションが進行して行きます。この為、UVM ではデータ・オブジェクトとコンポーネン トを明確に分離しています。 UVM コンポーネントはシミュレーションの対象となるので、デザインにおける module の様な役 目を果たします。即ち、UVM において、コンポーネントは自然にコンポーネント・インスタン スの階層構造を構成します。階層のトップには、uvm_top と呼ばれるインスタンスが存在します。 UVM はその階層構造を使用してダイナミックなシミュレーションを制御します。例えば、階層 構造を使用して、テストベンチの構成をシミュレーション開始直前に変える事が出来ます。この 機能により、一度のコンパイルで複数のテスト・ケースを実行する事が出来ます。階層構造は、 シミュレーション開始直前に決定し、一度シミュレーションが開始(コンポーネントのタスク run_phase() の実行を開始した時点)するとコンポーネント・インスタンスの階層構造は変化しま せん。

実行エントリーであるドライバー(uvm_driver のサブクラス)は DUT を制御します。DUT はシ グナル・レベルで動作する為、ドライバーはトランザクション・レベルからシグナル・レベルへ の 変 換 を 行 い 、 DUT を ド ラ イ ブ し ま す 。 ドライバー はトランザクションを シーケンサー (uvm_sequencer のサブクラス)から受け取ります。ユーザはこれらの機能を実際に定義する必 要があります。ユーザはメソドロジー・クラスから継承したクラスの内部に、これらの変換手順、 及び、制御処理を定義します。 モニター(uvm_monitor のサブクラス)は DUT の信号変化を監視する機能を持ちます。モニター (通常はコレクター)は DUT の信号値をトランザクションに変換して、他のコンポーネントに 引き渡します。それらのコンポーネントの一つとしてスコアボード(uvm_scoreboard のサブクラ ス)が存在します。スコアボードは DUT の出力が期待する結果と一致するか否かのテストを行 います。その他、カバレッジ情報等も収集します。ユーザはメソドロジー・クラスから継承した クラスの内部に、これらの変換、及び、チェック手順を定義します。 シーケンサー、ドライバー、及び、モニターはエージェント(uvm_agent のサブクラス)として 纏められます。エンバイロンメント(uvm_env のサブクラス)はシーケンサー、スコアボード、 エージェント、及び、下位のエンバイロンメント(uvm_env のサブクラス)から構成されます。 1.1.4 Virtual Interface

DUT とのデータ授受は virtual interface を介して行われます。virtual interface は interface のインス タンスへのポインターです。interface のインスタンスはテストベンチ(トップ・モジュール)で 作られます。そのインスタンスが DUT と関連するコンポーネントの virtual interface に引き渡さ なれればなりません。その割り当てをハード・コーディングすると検証技術の再利用性に反する 為、実行時に virtual interface の情報を設定します。その際、前述したコンポーネント・インスタ ンスの階層構造が使用されます。 1.1.5 UVM テストベンチの構造 下図において、図の包含関係はクラス、又は、module のインスタンスを持つという関係を意味し ます。例えば、テストベンチは DUT のインスタンスを保有します。

(9)

図 1-1 UVM テストベンチの構造([2]) 以上述べた様に UVM は複雑な体系で構成されています。UVM の全容を理解する事は一朝一夕 に行きませんが、メソドロジー・クラスを理解すると自然に UVM への理解が深まります。 1.2 検証技術のトレンド 近年の検証技術では階層的にテストベンチを記述する手法(layered testbench)が採用されていま す。階層のレイヤー(layer)には以下の様な種類があります([3])。詳細は、関連する文献を参 照して下さい。 レイヤー 検証目的及び機能 test layer テストベンチのトップ・レベルのレイヤーです。テストを生成して下 位の層に送ります。 scenario layer シナリオに沿ってトランザクションのシーケンスを生成します。 functional layer 高位のレベルのコマンドを処理するレイヤーです。例えば、DMA

read/write 等のコマンドを受け取ると、個々の bus read/write 等のコ マンドに分解してcommand layer に送ります。

command layer トランザクション・レベルのコマンドをシグナル・レベルの値に変換 をしてsignal layer に送ります。Driver は DUT をドライブします。 signal layer (DUT) DUT からのレスポンスは上位の層に送られます。アサーション等の結果も上位の層に戻されます。 DUT UVM Agent UVM Agent UVM Environment UVM Environment UVM Sequencer UVM Scoreboard UVM Testbench Sequences Config UVM Test UVM Environment

(10)

これらの層で機能する要素を纏めると以下の様になります。

図 1-2 テストベンチとレイヤーの関係([3])

この layered testbench を良く考察すると UVM のメソドロジー・クラスの名称に対応している事 が分かります。言い換えると、UVM は検証技術のトレンドに沿って開発されている事を確認す る事が出来ます。 1.3 UVM の構成 1.3.1 uvm_pkg UVM の全てのクラスはパッケージ uvm_pkg に定義されています。従って、このパッケージを import する事により、UVM を使用する事が出来る様になります。 1.3.2 uvm_object と uvm_component

UVM は SystemVerilog クラスと UVM マクロから構成されます。UVM には多くのクラスが定義 されていますが、特別なクラスとして uvm_object が存在します。このクラスはアブストラクト・ クラスで他の全ての UVM クラスのベース・クラスになっています。 uvm_object クラスでは他の全てのクラスに共通する属性、及び、手順を宣言しています。具体的 な手順の内容はサブクラスで行います。手順としては、例えば、print 及び copy があります。 uvm_object はアブストラクト・クラスなので、オブジェクトを作成する事は出来ませんが、ハン ドルを宣言する事は出来ます。 uvm_object ク ラ ス か ら 二 つ の 重 要 な サ ブ ク ラ ス が 定 義 さ れ て い ま す 。 そ れ ら は 、 uvm_sequence_item と uvm_component です。前者は、トランザクションを定義する為に使用しま す。一方、後者はテストベンチを構築する為に使用します。全てのメソドロジー・クラスは uvm_component のサブクラスです。 1.3.3 UVM マクロ マクロには大きく分けて二種類あります。一つは、実マクロで、他方は補助マクロです。実マク ロは、実行命令に展開されるマクロで比較的分かり易いマクロです。補助マクロは、他の機能へ の情報を生成する為のマクロで、理解し難いマクロです。補助マクロには注意をする必要があり TEST SCENARIO FUNCTIONAL COMMAND SIGNAL Test Case Generator

Agent Scoreboard Checker

Driver Assertions Monitor

DUT Fu n ctio n al C o v er a g e Environment

(11)

ます。例えば、次のマクロは実マクロです。

`uvm_info(“INFO”,”Hello world!”,UVM_LOW)

このマクロはメッセージをプリントする命令を生成します。この機能は容易に想像する事が出来 ると思います。一方、次の例には補助マクロが使用されています。

これらの補助マクロは simple_item クラスのメンバー名(UVM では field 名と呼ぶ)を UVM に知 らせる機能を持っています。このマクロを与えないと、UVM は simple_item のメンバーを把握す る事が出来ません。 例えば、マクロ定義が無いと simple_item のオブジェクトをプリントしても、これらのメンバー はプリントされません。クラスのメンバーを定義した場合、必ず補助マクロの定義が必要になり ます。一方、`uvm_field マクロが存在しない場合には、 `uvm_object_utils(my_trans) の様に書きます。次に上記の例に対して print()を実行した結果を示します。 尚、以上の例はデータ・オブジェクトに適用されるルールです。コンポーネントの場合には、多 少異なる UVM マクロを使用しなければなりません。例えば、コンポーネントに対しては、次の 様に UVM マクロを使用しなければなりません。 // simple_item_delay_e

typedef enum {ZERO, SHORT, MDIUM, LARGE, MAX} simple_item_delay_e; // simple_item

class simple_item extends uvm_sequence_item; rand int unsigned addr;

rand int unsigned data; rand int unsigned delay;

rand simple_item_delay_e delay_kind; `uvm_object_utils_begin(simple_item) `uvm_field_int(addr,UVM_DEFAULT) `uvm_field_int(data,UVM_DEFAULT) `uvm_field_int(delay,UVM_DEFAULT) `uvm_field_enum(simple_item_delay_e,delay_kind,UVM_DEFAULT) `uvm_object_utils_end // new

function new(string name="simple_item"); super.new(name);

endfunction endclass

--- Name Type Size Value --- item simple_item - @273 addr integral 32 'h1cfe data integral 32 'hcb9 delay integral 32 'h3e8 delay_kind simple_item_delay_e 32 MAX ---

(12)

コンポーネントの field マクロには注意が必要です。field がコンポーネントである場合には、field マクロを定義する必要はありません。例えば、次の例に於いて、master 及び slave が field として 存在しますが、field マクロを定義する必要がありません。

何故なら、コンポーネントの階層が自動的に作られる為、UVM には master 及び slave の存在が自 明であるからです。コンポーネント master_comp のインスタンスを作る時に

master = master_comp::type_id::create("master",this);

の様にして、this を引き渡しています。これにより、parent_comp(this のコンポーネント・イン スタンス)の下に master_comp のインスタンスが作られます。slave に関しても同様です。

// master_comp

class master_comp extends uvm_component; int master_id;

`uvm_component_utils_begin(master_comp) `uvm_field_int(master_id,UVM_DEFAULT) `uvm_component_utils_end

function new(string name,uvm_component parent); super.new(name,parent);

endfunction endclass // slave_comp

class slave_comp extends uvm_component; int slave_id;

`uvm_component_utils_begin(slave_comp) `uvm_field_int(slave_id,UVM_DEFAULT) `uvm_component_utils_end

function new(string name,uvm_component parent); super.new(name,parent);

endfunction endclass

// parent_comp

class parent_comp extends uvm_component; master_comp master;

slave_comp slave;

`uvm_component_utils(parent_comp)

function new(string name,uvm_component parent); super.new(name,parent);

endfunction

function void build_phase(uvm_phase phase); super.build_phase(phase);

master = master_comp::type_id::create("master",this); slave = slave_comp::type_id::create("slave",this); endfunction

(13)

上記の build_phase に於いて、parent_comp のインスタンス内に master_comp 及び slave_comp のイ ンスタンスが作られています。これらが、master、及び、slave の field を構成します。従って、こ れらに対しての field マクロを定義する必要はありません。 parent_comp のインスタンスに対して print()を適用した例を示します。表示例で明らかな様に、 master 及び slave が正しくプリントされています。 1.4 シミュレーション・フェーズ(simulation phases) コンポーネントは実行エントリーですが、実行制御を受けるタイミングは UVM により決定され ています。そのタイミングはフェーズ(phases)と呼ばれ、以下の様に分類されます。以下のフ ェーズは記述されている順に UVM から実行制御を受けます。 フェーズ 機能 build_phase コンポーネントの階層を構築するフェーズです。従って、階層 のトップから順に呼ばれて行きます。通常、チャイルド・コン ポーネントをこのフェーズで作成します。 connect_phase コンポーネント間の接続を完成するフェーズです。例えば、 TLM ポートの接続を定義します。 end_of_elaboration_phase 全ての接続が終了するとこのフェーズに制御が移ります。通常 は、コンフィギュレーションをプリントする等の処理を記述し ます。 start_of_simulation_phase シミュレーションが開始する直前にこのフェーズが呼ばれま す。初期化処理等を行う事が出来ます。 run_phase シミュレーションを行う為のフェーズです。 extract_phase シミュレーションが終了すると、このフェーズに制御が移りま す。シミュレーション結果を抽出する為の処理を記述する事が 出来ます。 check_phase 抽出したシミュレーション結果をチェックする為の処理を記述 します。 report_phase シミュレーション結果のレポートを出力する処理を記述しま す。 全てのフェーズは virtual メソッドとして定義されています。ユーザは必要なフェーズだけを記述 すれば良い事になっています。run_phase() は時間を消費するシミュレーション・フェーズである 為、task として定義されていますが、その他のフェーズは function として定義されています。 以下は build_phase()の記述例です。 --- Name Type Size Value --- parent parent_comp - @272 master master_comp - @285 master_id integral 32 'h0 slave slave_comp - @294 slave_id integral 32 'h0 ---

(14)

通常、コンストラクタと build_phase() の定義は必須となります。 1.5 ソース・コードの準備 UVM を使用する際に必要なソース・コードに関する条件を説明します。UVM に関するサポート 機能は各ベンダーにより異なる為、ここで紹介する説明は必ずしも当てはまりません。準備を何 もしなくてもツールが全て自動的に理解してくれる可能性があります。利用しているツールに当 てはまらない場合には、本節の内容を読む必要はありません。ここでは、UVM を SystemVerilog で記述した一般的なパッケージとして取り扱います。 1.5.1 `include

UVM を使用するファイルの先頭で、次の様にファイルを`include して下さい。UVM を使用する 時には、これらのファイルは不可欠です。

1.5.2 import UVM

実際に UVM を使用するスコープの先頭で uvm_pkg を import して下さい。uvm_pkg をグローバル に import すると名称に関する矛盾が発生する可能性があります。その問題を未然に防ぐ為、 UVM を使用するスコープで uvm_pkg を import する様にして下さい。

以上を纏めると以下の様になります。

function void build_phase(uvm_phase phase); super.build_phase(phase); master = master_comp::type_id::create("master",this); slave = slave_comp::type_id::create("slave",this); endfunction `include "uvm_pkg.sv" `include "uvm_macros.svh" module test; import uvm_pkg::*; ... endmodule `include "uvm_pkg.sv" `include "uvm_macros.svh" `include "my_pkg.sv" module top; import uvm_pkg::*; import my_pkg::*; bit clk, rst; ... simple_if sif(clk,rst); initial begin ... run_test(); end ... endmodule

(15)

UVM のシミュレーションを実行する為には、run_test()を呼び出す事が必要です。この他、UVM をコンパイルする為には、`include 用のディレクトリを設定する必要があります。設定法はツー ルにより異なる為、ベンダー提供のマニュアルを参照して下さい。 1.6 UVM 使用例 UVM を使用して検証を行う場合、トランザクション、及び、テストに必要なコンポーネントを 用意しますが、ここでは簡単な例を使用して UVM を実行する感覚を示したいと思います。 通常は、トランザクション、及び、シーケンスの定義が必要になりますが、ここでは、それらの 定義を省略します。従って、interface 等の定義も省略します。テストベンチに必要なコンポーネ ント等の定義は package に定義すると仮定をします。 実際には多くのコンポーネントが package 内に定義される為、package はコンポーネントの定義を 含むファイルを`include する形式が得策であると考えられます。然し、ここでは簡単な例を示す 為、package の定義は非常に簡単な記述となっています。 以下で示す例は、UVM を使用する為の簡単な例であり、UVM を使用する際の高尚な原則に従っ ていません。それを念頭に置いて下記の例を参照して下さい。

先ずは、package の定義です。この例の package にはテストベンチの定義だけを含みます。UVM の実行を示すには十分な内容です。実際の検証では、ここで示した package の内容を詳細に定義 して下さい。また、package の定義では、`ifndef、`define、及び、`endif の制御文を忘れない様に して下さい。 以下は、テストベンチ(my_testbench.sv)の内容です。テストベンチには、build_phase()、及び、 run_phase()が定義されている事に注意して下さい。これらのメソッドは UVM により呼び出され ます。 `ifndef MY_PKG_H `define MY_PKG_H package my_pkg; import uvm_pkg::*; `include "my_testbench.sv" // Include other files as well. endpackage

(16)

これだけではシミュレーションが実行しない為、トップを定義しなければなりません。以下にそ の定義を示します。 トップではテストベンチのインスタンスを作成しています。シミュレーションを行う為には、 run_test()を呼び出さなければなりません。run_test()を呼び出す事により、UVM に実行制御が移 管されます。 run_test() を 呼 び 出 さ な けれ ば UVM のシミュレーションは行われません。また、通常は、 run_test()に対して何も指定しません。この場合の実行結果の一部を以下に示します。 テストベンチ内に定義した build_phase()、及び、run_phase()が順に呼び出されている事が分かり ます。実際のテストベンチでは、これらのメソッド及び他の phase メソッドを必要に応じて定義 して下さい。

class my_testbench extends uvm_test; `uvm_component_utils(my_testbench) // new

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

endfunction

// build_phase

function void build_phase(uvm_phase phase); super.build_phase(phase);

`uvm_info("MY_TESTBENCH","build_phase running.",UVM_LOW) endfunction

// run_phase

task run_phase(uvm_phase phase);

`uvm_info("MY_TESTBENCH","run_phase running.",UVM_LOW) endtask endclass `include "uvm_pkg.sv" `include "uvm_macros.svh" `include "my_pkg.sv" module top; import uvm_pkg::*; import my_pkg::*; my_testbench testbench; initial begin testbench = my_testbench::type_id::create("testbench",null); run_test(); end endmodule

UVM_INFO @ 0: reporter [RNTST] Running test ...

UVM_INFO D:/Users/my_pkg.sv(16) @ 0: testbench [MY_TESTBENCH] build_phase running. UVM_INFO D:/Users/my_pkg.sv(20) @ 0: testbench [MY_TESTBENCH] run_phase running.

(17)

尚 、 実 際 の シ ミ ュ レ ー シ ョ ン に 於 い て は 、 こ れ だ け で は 不 十 分 で す 。 UVM の メ ソ ッ ド raise_objection() と drop_objection() が呼ばれなければなりません。簡単に言えば、これらのメソ ッドを呼び出さないと、UVM はシミュレーションを実行しません。詰まり、時刻 0 でシミュレ ーションが終了します。詳細に関しては、後章を参照して下さい。 1.7 UVM の DPI の意義 既に述べた様に UVM には DPI が積極的に使用されています。それには二つの意義があると思わ れます。一つには、SystemVerilog が提供していない機能を実現する為です。もう一つの理由は、 interoperability を実現する為にあります。 SystemVerilog は規格であり、言語仕様を各 EDA ベンダーが遵守しなければなりません。然し、 各ベンダーの実装法は異なる為、実装上の違いを何処かで吸収して interoperability を実現しなけ ればなりません。DPI がその役目を果たしています。もし、DPI を使用しなければ、各ベンダー の特殊機能を含んだ幾つかの SystemVerilog の方言が誕生してしまう事になります。

(18)

2 UVM クラス・ライブラリーの基礎 2.1 基本的な概念 2.1.1 uvm_object と uvm_component 既に述べた様に、uvm_object クラスが他の全ての UVM クラスのベース・クラスになっています。 uvm_object クラスはアブストラクト・クラスである為、uvm_object のインスタンスを作る事は出 来ません。但し、uvm_object クラスのハンドルを定義する事は可能です。例えば、メソッドの引 数として generic なハンドルを宣言する為に使用する事が出来ます。

uvm_object クラスから定義された重要なクラスとして、uvm_sequence_item と uvm_component が あります。前者はデータ(トランザクション)を記述する為に使用します。後者は、シミュレー ションのエンティティ(コンポーネント)を記述する為に使用します。UVM はコンポーネン ト・インスタンスを実行する事によりシミュレーションを遂行します。トランザクションはシミ ュレーションの対象ではありません。従って、トランザクションには phase メソッドが定義され ていません。 コンポーネントは、module と同様に階層を構築します。階層はシミュレーション実行開始直前に 決定します。通常は、コンポーネントの build_phase()、及び、connect_phase()で階層を定義しま す。コンストラクタではコンポーネント・インスタンスを作らないのが一般的です。特別な場合 を除き、コンストラクタではコンポーネント・インスタンスを作るべきではありません。 2.1.2 コンストラクタ UVM では、コンストラクタに対して一般的なルールがあります。データ・オブジェクトでは、 名称に対して標準値を設定します。例えば、次の様に名称の標準値を定義します。この設定をし ないと、意味不明のコンパイル・エラーが発生する場合があります。 一方、コンポーネントは階層を構築する為、親コンポーネントの指定が必要になります。また、 インスタンス名称には標準値を設定しません。同じ階層レベル内には、ユニークなインスタンス 名称が必要な為、この様な配慮が必要になります。例えば、次の様に定義します。 何れのコンストラクタにも共通して言える事は、super.new()を呼び出す事です。この呼び出しは 必須です。尚、コンポーネント・インスタンスの階層のトップには uvm_top が存在します。 2.1.3 フィールド・マクロ UVM ではクラスを定義する場合、UVM マクロを使用しなければなりません。 class simple_item extends uvm_sequence_item;

...

function new(string name="simple_item"); super.new(name);

endfunction ...

endclass

class master_comp extends uvm_component; ...

function new(string name,uvm_component parent); super.new(name,parent);

endfunction ...

(19)

2.1.3.1 uvm_object データ・オブジェクトを定義する場合には、プロパーティ名に対して `uvm_object_utils マクロを 使用しなければなりません。以前使用した例を以下に示します。 ク ラ ス が フ ィ ー ル ド ・ マ ク ロ を 持 た な い 場 合 に は 、 次 の 様 に 簡 単 に な り ま す 。 `uvm_object_utils_begin と`uvm_object_utils_end を指定する必要はありません。 `uvm_field_int は広い意味での整数を意味します。即ち、整数型(byte、shortint、int、longint)に 限らず、bit、logic、integer 型等にも適用されます。例えば、addr が となっていても、`uvm_field_int(addr,UVM_DEFAULT)を使用する事が出来ます。 プロパーティが enum 型である場合には、`uvm_field_enum を使用します。この場合、実際の enum 型も指定しなければなりません。enum 定数に対して定義されている名称を取得する為に利 用されます。上記の例では、simple_item_delay_e が指定されています。この指定により、UVM がラベル名 ZERO、SHORT 等をプリントする事が出来る様になります。 2.1.3.2 uvm_component コンポーネントに関しては、`uvm_component_utils マクロを使用しなければなりません。以前使 用した例を以下に示します。 // simple_item_delay_e

typedef enum {ZERO, SHORT, MDIUM, LARGE, MAX} simple_item_delay_e; // simple_item

class simple_item extends uvm_sequence_item; rand int unsigned addr;

rand int unsigned data; rand int unsigned delay;

rand simple_item_delay_e delay_kind; `uvm_object_utils_begin(simple_item) `uvm_field_int(addr,UVM_DEFAULT) `uvm_field_int(data,UVM_DEFAULT) `uvm_field_int(delay,UVM_DEFAULT) `uvm_field_enum(simple_item_delay_e,delay_kind,UVM_DEFAULT) `uvm_object_utils_end // new

function new(string name="simple_item"); super.new(name);

endfunction endclass

`uvm_object_utils(my_trans)

(20)

コ ン ポ ー ネ ン ト が フ ィ ー ル ド ・ マ ク ロ を 持 た な い 場 合 に は 、 次 の 様 に 簡 単 に な り ま す 。 `uvm_component_utils_begin と`uvm_component_utils_end を指定する必要はありません 2.1.3.3 フィールド・マクロの種類 多くのフィールド・マクロが定義されています。データ宣言に適したマクロを選択しなければな りません。ここでは使用法の例を示す事は出来ませんが、マクロの種類を紹介します。  `uvm_field_int  `uvm_field_real  `uvm_field_enum  `uvm_field_object  `uvm_field_event  `uvm_field_string  `uvm_field_array_enum  `uvm_field_array_int  `uvm_field_sarray_int  `uvm_field_sarray_enum  `uvm_field_array_object  `uvm_field_sarray_object  `uvm_field_array_string  `uvm_field_sarray_string  `uvm_field_queue_enum  `uvm_field_queue_int  `uvm_field_queue_object  `uvm_field_queue_string  `uvm_field_aa_int_string  `uvm_field_aa_object_string  `uvm_field_aa_string_string  `uvm_field_aa_object_int  `uvm_field_aa_int_int  `uvm_field_aa_int_int_unsigned  `uvm_field_aa_int_integer  `uvm_field_aa_int_integer_unsigned  `uvm_field_aa_int_byte  `uvm_field_aa_int_byte_unsigned  `uvm_field_aa_int_shortint  `uvm_field_aa_int_shortint_unsigned  `uvm_field_aa_int_longint  `uvm_field_aa_int_longint_unsigned

class master_comp extends uvm_component; int master_id;

`uvm_component_utils_begin(master_comp) `uvm_field_int(master_id,UVM_DEFAULT) `uvm_component_utils_end

function new(string name,uvm_component parent); super.new(name,parent);

endfunction endclass

(21)

 `uvm_field_aa_int_key  `uvm_field_aa_int_enumkey

省略形の意味を容易に推測出来ると思います。array はダイナミックなアレイ型です。一方、 sarray はスタティックなアレイ型です。aa は associative array の略です。

UVM を使用してコードを記述する場合、多くの文字をタイプする事が必要になります。タイプ 負荷を軽減すると共にミスを減少する為に、UVM をサポートした EDA ツールを使用するのが得 策と言えます。 2.1.3.4 フィールド・マクロ・フラグ フィールド・マクロを指定する場合、フィールドが使用される目的を記述する項目がフィール ド・マクロ・フラグです。例えば、UVM_DEFAULT はフィールド・マクロ・フラグです。フィ ールド・マクロ・フラグは以下の様に纏められます。 マクロ・フラグ 機能 UVM_DEFAULT フィールドを全ての操作に使用します。 UVM_COPY フィールドをuvm_object::copy()に使用します。 UVM_COMPARE フィールドをuvm_object::compare()に使用します。 UVM_PRINT フィールドをuvm_object::print()に使用します。 UVM_RECORD フィールドをuvm_object::record()に使用します。 UVM_PACK フィールドをuvm_object::pack()に使用します。 UVM_NOCOPY フィールドをuvm_object::copy()に使用しません。 UVM_NOCOMPARE フィールドをuvm_object::compare()に使用しません。 UVM_NOPRINT フィールドをuvm_object::print()に使用しません。 UVM_NORECORD フィールドをuvm_object::record()に使用しません。 UVM_NOPACK フィールドをuvm_object::pack()に使用しません。

UVM_DEEP フィールドがオブジェクトである場合、deep copy します。即 ち、フィールドをrecursive に処理します。

UVM_SHALLOW フィールドがオブジェクトである場合、shallow copy します。 UVM_REFERENCE フィールドはオブジェクトを参照しています。この場合、deep copy はされません。 UVM_READONLY フィールドは自動的にconfigure されません。 これらのフラグを ORing して使用します。例えば、 の様に指定します。 2.1.3.5 `uvm_object_param_utils*と`uvm_component_param_utils*マクロ クラスの定義にパラメータを使用している場合、これらのマクロを使用しなければなりません。 2.1.4 ファクトリ(factory) オブジェクト、及び、コンポーネントのインスタンスを作る場合、new オペレータを使用する代 わりに、factory メソッドを使用する事が推奨されています。例えば、コンポーネントのインスタ ンスを作る場合、new を使用せずに以下の様にします。

(22)

この様にインスタンスを作ると、ソース・コードを修正せずに master に master_comp のサブクラ スを割り当てる事が可能になります。検証技術の再利用性を高める為には、ファクトリ技術を適 用する必要があります。 2.1.5 シミュレーション・フェーズ(simulation phases) コンポーネントは実行エントリーであり、実行する内容の記述を含まなければなりません。フェ ーズの種類を既に紹介しました。実践では、特別な処理が必要なフェーズのみ記述します。多く の場合、build_phase() と run_phase() の記述は必要になります。コンポーネントの階層が構築され ると以下のメソッドは重宝になります。 メソッド 機能 get_parent() 呼び出しているコンポーネントの親コンポーネントへのハンド ルを戻します。親が存在しない場合には、ナルが戻されます。 get_full_name() 階層から構成されたインスタンス名を戻します。 get_child(string name) 指定した名称を持つチャイルド・コンポーネントを戻します。 例えば、次の様に使用します。 2.1.6 コンフィギュレーションの設定変更 コンフィギュレーションを実行時に変更する事を可能にする為には、uvm_config_db#(type)クラス を使用しなければなりません。このクラスを使用する事により、ソース・コードを修正せずに、 コンポーネントの構成を変える事が出来ます。 例えば、ソース・コード中ではコンポーネント内の data_size が 2 と定義されていても、テストベ ンチで data_size を 8 に変更する事が出来ます。但し、この変更情報を build_phase() が実行する前 に指定しなければなりません。build_phase()では、テストベンチで指定した情報が使用されるの で、階層構造が指定した状態に変更されます。

具体的には、build_phase() で super.build_phase(phase)を呼び出すと apply_config_settings()が呼ばれ て data_size に変更値(この場合には 8)が設定されます。この様に、super.build_phase(phase)は必 須な呼び出しとなります。テストベンチでは、uvm_config_db#(int)::set()メソッドを使用して変更 値を設定します。そして、この変更が有効になる為には、`uvm_field マクロが正しく設定されて いなければなりません。 例を示す為に、先ず、コンポーネントのコンフィギュレーションを定義しているコンポーネント master_comp master; ... master = master_comp::type_id::create("master",this);

task run_phase(uvm_phase phase); uvm_component child, parent;

`uvm_info("SIMPLE_COMP","run_phase: Executing.",UVM_LOW) parent = get_parent(); `uvm_info("SIMPLE_COMP",{"parent: ",parent.get_full_name()},UVM_LOW) child = get_child("master"); `uvm_info("SIMPLE_COMP",{"child: ",child.get_name()},UVM_LOW) child = get_child("slave"); `uvm_info("SIMPLE_COMP",{"child: ",child.get_name()},UVM_LOW) ... endtask

(23)

を紹介します。この例では、data_size、及び、header_name を実行時に変更します。

テストベンチでは、次の様に data_size、及び、header_name に新しい値を設定します。

この様に設定すると、以下の様な結果を得ます。 class my_comp extends uvm_component; int data[];

int data_size = 2;

string header_name = "data[0..1]"; `uvm_component_utils_begin(my_comp)

`uvm_field_string(header_name,UVM_DEFAULT) `uvm_field_int(data_size,UVM_DEFAULT) `uvm_field_array_int(data,UVM_DEFAULT) `uvm_component_utils_end

function new(string name,uvm_component parent); super.new(name,parent);

endfunction

function void build_phase(uvm_phase phase); super.build_phase(phase);

data = new[data_size]; foreach(data[i])

data[i] = i; endfunction

function void end_of_elaboration_phase(uvm_phase phase); super.end_of_elaboration_phase(phase); this.print(); endfunction endclass module top; import uvm_pkg::*; import Pkg::*; my_comp test; initial begin

// fix the configuration.

uvm_config_db#(string)::set(null,"test", "header_name","data[0..7]"); uvm_config_db#(int)::set(null,"test","data_size",8); // create components. test = my_comp::type_id::create("test",null); run_test(); end endmodule

(24)

uvm_config_db#(type)クラスは、type に関して厳密です。即ち、設定するプロパーティのタイプと 完全に一致しなければなりません。例えば、もし data_size が int 型ではなく byte 型であれば、 uvm_config_db#(byte)::set()を使用しなければなりません。 型の不一致は設定変更の失敗を導く為、UVM はより寛大なクラスを提供しています。例えば、 uvm_config_int::set()を使用すると、整数型の全てのプロパーティに対して設定変更をする事が出 来ます。詳細に関しては、UVM のマニュアルを参照して下さい。 2.2 TLM (Transaction-Level Modeling) トランザクションは RTL より高位のレベルでのデータ処理に適用されます。UVM では TLM (Transaction-Level Modeling)を使用します。SystemC の TLM 1.0 に対応していますが、それよ りも高速に動作します。 SystemC の TLM 1.0 と異なり、UVM TLM ではトランザクションをポインターで引き渡します。 従って、処理の高速化を実現しています。一方、consumer がトランザクションに変更を加えると その変更が producer 側に反映されてしまうという欠点があります。consumer がトランザクション に変更を与える場合には、トランザクションのコピーを作らなければなりません。 2.2.1 トランザクション トランザクションは二つのコンポーネント間の通信をモデルする為に必要な情報を意味します。 UVM では、uvm_sequence_item クラス、又は、そのサブクラスからトランザクションを定義しな ければなりません。前述の simple_item はトランザクションです。 2.2.2 コンポーネント間の通信

通信には TLM-port と TLM-export が使用されます。TLM-port はトランザクションを操作する為の 方法を定義します。一方、TLM-export ではトランザクションを処理する為に必要な実処理を記述 します。ここではブロッキング・メソッドを使用して説明をします。ノンブロッキングの方法も 殆ど同様にして行えます。通信は、producer、及び、consumer の関係になります。

producer、及び、consumer は一対一の関係にあり、producer に対して consumer が必ず存在しなけ ればなりません。然し、producer を定義する時点では consumer に関する知識は一切必要ありませ ん。言い換えると、producer が使用するプロトコルに従うコンポーネントがあれば producer と通 信を行なえる事になります。即ち、producer コンポーネントの再利用が可能となります。同様の 事が consumer 側にも言えます。

--- Name Type Size Value --- test my_comp - @280 header_name string 10 data[0..7] data_size integral 32 'h8 data da(integral) 8 - [0] integral 32 'h0 [1] integral 32 'h1 [2] integral 32 'h2 [3] integral 32 'h3 [4] integral 32 'h4 [5] integral 32 'h5 [6] integral 32 'h6 [7] integral 32 'h7 ---

(25)

producer と consumer の接続を親コンポーネントが決定します。親コンポーネントはコンストラク タ、又は、build_phase() で producer、及び、consumer のインスタンスを作成します。そして、 connect_phase() で producer と consumer の関係を確立します。具体的には、以下の例を参照下さい。

2.2.2.1 ブロッキング put producer コンポーネントは TLM-port を使用してトランザクションを引き渡す操作を行います。 一方、consumer コンポーネントは TLM-export を使用してトランザクションを受け取り、トラン ザクションを処理する手順を記述します。この関係を UVM では以下の様に記します。 図 2-1 Producer が Consumer にトランザクションを送る操作 例えば、producer の記述は以下の様になります。 producer は相手方のコンポーネントに関する知識を持たずに記述している事に注意して下さい。 producer のインスタンスを作る親コンポーネントが producer の相手方のコンポーネントを指定し ます。更に、producer はトランザクション・オブジェクトを作る必要があります。また、put()は ブロッキングである為、producer は put()が終了する迄待ち状態に入る様になっても動作する様に しなければなりません。尚、上記の例ではトランザクションを一つだけ生成していますが、一般 的な実処理では、トランザクションを繰り返し生成する必要があります。 一方、consumer は以下の様になります。

class producer extends uvm_component;

uvm_blocking_put_port #(simple_item) put_port; `uvm_component_utils(producer)

function new(string name,uvm_component parent); super.new(name,parent);

put_port = new("put_port",this); endfunction

virtual task run_phase(uvm_phase phase); simple_item tr;

// prepare transaction. make_transaction(tr);

// send transaction to consumer. put_port.put(tr);

endtask

task make_transaction(output simple_item item); // ... endtask endclass producer consumer port export

(26)

consumer ではトランザクションに対する put()の実処理を記述します。producer は、単に、トラン ザクションをパスするだけですが、トランザクションを受け取るコンポーネントはトランザクシ ョンに関する実処理を定義しなければなりません。ユーザはタスク consumer::put()の内容を定義 しなければなりません。

producer と同様に、consumer は相手方の producer に関する知識を持たずに記述している事に注意 して下さい。親コンポーネントは、producer と consumer の接続を次の様にして確立します。

親コンポーネントは、producer、及び、consumer のインスタンスを作り、connect_phase()に於いて TLM-port と TLM-export の接続を完了します。この接続により、producer が put_port.put(tr)を呼ぶ と、consumer のタスク put(tr)が呼び出される様になります。connect_phase() はシミュレーション の実行フェーズ run_phase()より先に実行します。従って、producer と consumer の接続関係がダイ ナミックに確立した後に、シミュレーションが実行します。

2.2.2.2 ブロッキング get

put の逆は get になります。この場合には、次の様な関係になります。 class consumer extends uvm_component;

uvm_blocking_put_imp #(simple_item,consumer) put_export; `uvm_component_utils(consumer)

function new(string name,uvm_component parent); super.new(name,parent);

put_export = new("put_export",this); endfunction

task put(simple_item tr); // consume the transaction. endtask

endclass

class parent_comp extends uvm_component; producer p;

consumer c;

`uvm_component_utils(parent_comp)

function new(string name,uvm_component parent); super.new(name,parent);

p = new("producer",this); c = new("consumer",this); endfunction

virtual function void connect_phase(uvm_phase phase); p.put_port.connect(c.put_export);

endfunction endclass

(27)

図 2-2 Consumer がトランザクションを get する操作

put の場合と同様の概念なので詳細を省略して、簡単な記述例だけを紹介します。例えば、 get_producer は以下の様になります。

一方、get_consumer は以下の様になります。

親コンポーネントは、get_producer と get_consumer の関係を以下の様に確立します。 class get_producer extends uvm_component;

uvm_blocking_get_imp #(simple_item,get_producer) get_export; `uvm_component_utils(get_producer)

function new(string name,uvm_component parent); super.new(name,parent);

get_export = new("get_export",this); endfunction

task get(output simple_item tr); tr = simple_item::type_id::create(); // ...

endtask endclass

class get_consumer extends uvm_component;

uvm_blocking_get_port #(simple_item) get_port; `uvm_component_utils(get_consumer)

function new(string name,uvm_component parent); super.new(name,parent);

get_port = new("get_port",this); endfunction

virtual task run_phase(uvm_phase phase); simple_item tr; // ... get_port.get(tr); endtask endclass get_producer get_consumer get_export get_port

(28)

2.2.3 uvm_tlm_fifo

上記の put の手順では、consumer は producer が put()を呼び出している時のみアクティブになって います。一般の実処理では、producer、及び、consumer は独立したプロセスとして実行します。 その場合、producer が送信したトランザクションを損失しない為の処理、又は、トランザクショ ンが存在しない場合の consumer 側の処理を考慮する必要があります。UVM では、それらの問題 を解決する為に FIFO キュー(uvm_tlm_fifo)を準備しています。 FIFO キューにより、producer、及び、consumer は独立したプロセスで動作する事が可能になりま す。しかも、トランザクションの損失等の問題はありません。両者の関係は以下の様になります。

図 2-3 uvm_tlm_fifo を使用した producer と consumer の通信

図から容易に分かる様に、producer、及び、consumer はそれぞれ、put()、及び、get()を呼び出す だけで済みます。

FIFO キューにトランザクションが存在すれば、get()は直ぐに戻りますが、FIFO が空であれば、 get()はブロックします。同様に、FIFO に空きがあれば、put()は直ぐに完了しますが、FIFO がフ ルであれば、put()はブロックします。これらの一連の制御を uvm_tlm_fifo が行います。FIFO の サイズを無制限に設定しておくと、常に put()は直ぐに完了します。

producer、FIFO、consumer の関係の確立は親コンポーネントで行います。前述した方法で行って 下さい。

class parent_comp extends uvm_component; get_producer p;

get_consumer c;

`uvm_component_utils(parent_comp)

function new(string name,uvm_component parent); super.new(name,parent);

p = new("get_producer",this); c = new("get_consumer",this); endfunction

virtual function void connect_phase(uvm_phase phase); c.get_port.connect(p.get_export);

endfunction endclass

tlm_fifo get_consumer producer

(29)

2.2.4 analysis ports と exports モニターは passive エントリーで、DUT の信号に変化があるとその信号値をトランザクションに 変換し、他のコンポーネントに知らせます(broadcast)。知らせる相手(subscribers)は不特定 多数である為、一対一の関係ではありません。従って、TLM-port、及び、TLM-export の概念を 適用する事が出来ません。 UVM では、1対 N の関係を確立する為に、analysis-ports、及び、analysis-exports の機能を持って い ま す 。 そ し て 、 FIFO キ ュ ー を 使 用 す る 場 合 に は 、 uvm_tlm_fifo の 代 わ り に uvm_tlm_analysis_fifo を使用します。理由は簡単です。uvm_tlm_fifo には analysis-exports が存在し ないからです。下図の◇は analysis-port を意味します。

図 2-4 Analysis-ports を使用した通信

analysis_port は void function write()を定義しています。この function を使用してトランザクション の broadcast を行います。以下はその例を示しています。

class parent_comp extends uvm_component; producer p;

get_consumer c;

uvm_tlm_fifo #(simple_item) fifo; `uvm_component_utils(parent_comp)

function new(string name,uvm_component parent); super.new(name,parent);

p = new("producer",this); c = new("get_consumer",this); fifo = new("fifo",this,16); endfunction

virtual function void connect_phase(uvm_phase phase); p.put_port.connect(fifo.put_export); c.get_port.connect(fifo.get_export); endfunction endclass tlm_analysis_fifo get_consumer_ap producer sub1 sub2

(30)

broadcast する為には、トランザクションを準備しなければなりません。上記の例では、タスク make_transaction()に於いて処理をする事を意味しています。ユーザ自身で内容を記述して下さい。 トランザクションの準備を終えると、write()を呼び出してトランザクションを送信します。 トランザクションを受け取る側のサブスクライバ―(subscriber)を次の様に定義します。

サブスクライバ―では write()ファンクションの実装をしなければなりません。上記で示す様に、 UVM 1.2 User’s Guide では、サブスクライバ―の定義には uvm_subscriber クラスを使用する様に 記述されています。uvm_subscriber クラスにはプロパーティ analysis_export が定義されているの で便利です。但し、スコアボードはサブスクライバ―の一つですが、メソドロジー・クラス uvm_scoreboard を使用して定義します。

以前と同じ様に、analysis-ports の接続は親コンポーネントで行います。 class get_consumer_ap extends uvm_component;

uvm_analysis_port #(simple_item) analysis_port; `uvm_component_utils(consumer)

function new(string name,uvm_component parent); super.new(name,parent);

analysis_port = new("analysis_port",this); endfunction

virtual task run_phase(uvm_phase phase); simple_item item = new();

// ...

make_transaction(item); analysis_port.write(item); endtask

task make_transaction(output simple_item item); // ...

endtask endclass

class subscriber #(type T=simple_item) extends uvm_subscriber #(T); // ...

function new(string name,uvm_component parent); super.new(name,parent);

endfunction

function void write(T tr); // ...

endfunction endclass

(31)

2.3 プリント機能 2.3.1 UVM プリンター クラスのメンバーをプリントする為には、print()メソッドを使用します。このメソッドが正しく 動作する為には、`uvm_field マクロを設定する必要があります。UVM は次の三種類のプリンター を定義しています。 プリンター 機能 uvm_default_table_printer 表形式にプリントします。最も複雑なプリント処理となりま す。 uvm_default_tree_printer 各行に名称と値の対をプリントします。 uvm_default_line_printer 名称と値の対を一行にプリントします。 uvm_default_table_printer は複雑である為、処理時間が最も多く必要なプリンターであると言われ ています。プリント件数が膨大な数になる場合には、他のプリンターの使用が勧められます。次 に、これらの相違を示します。先ず、データを以下の様に定義します。

class my_env extends uvm_env; get_consumer_ap con_ap; subscriber sub1,

sub2;

`uvm_component_utils(my_env)

function new(string name,uvm_component parent); super.new(name,parent);

con_ap = new("con_ap",this); sub1 = new("sub1",this); sub2 = new("sub2",this); endfunction

function void connect_phase(uvm_phase phase);

con_ap.analysis_port.connect(sub1.analysis_export); con_ap.analysis_port.connect(sub2.analysis_export); endfunction

endclass

class my_obj extends uvm_object; bit [7:0] request; bit [7:0] grant; bit [31:0] data[8]; `uvm_object_utils_begin(my_obj) `uvm_field_int(request,UVM_DEFAULT); `uvm_field_int(grant,UVM_DEFAULT) `uvm_field_sarray_int(data,UVM_DEFAULT) `uvm_object_utils_end

function new(string name="my_obj"); super.new(name);

endfunction endclass

(32)

プリント処理は以下の様にします。同じ内容を三つのプリンターを使用してプリントする事にし ます。 uvm_default_table_printer の結果は以下の様になります。 uvm_default_tree_printer の結果は以下の様になります。 module top; my_obj obj; initial begin obj = my_obj::type_id::create(); obj.request = 8'hf0; obj.grant = 8'h01; obj.data = { 1, 2, 3, 4, 5, 6, 7, 8 }; obj.print(); obj.print(uvm_default_tree_printer); obj.print(uvm_default_line_printer); end endmodule --- Name Type Size Value --- my_obj my_obj - @272 request integral 8 'hf0 grant integral 8 'h1 data sa(integral) 8 - [0] integral 32 'h1 [1] integral 32 'h2 [2] integral 32 'h3 [3] integral 32 'h4 [4] integral 32 'h5 [5] integral 32 'h6 [6] integral 32 'h7 [7] integral 32 'h8 --- my_obj: (my_obj@272) { request: 'hf0 grant: 'h1 data: { [0]: 'h1 [1]: 'h2 [2]: 'h3 [3]: 'h4 [4]: 'h5 [5]: 'h6 [6]: 'h7 [7]: 'h8 } }

(33)

uvm_default_line_printer の結果は以下の様になります。 プリンターの設定には、uvm_default_printer を使用すると便利です。トップ・モジュールで以下 の様に設定するとプリント形式が変わります。 2.3.2 アレイのプリント クラス・インスタンスをプリントすると全てのメンバーがプリントされますが、アレイのプリン トに関しては制限が付きます。例えば、アレイ・サイズが 30 であるとすると、最初の 5 個と最 後の 5 個のアレイ要素がプリントされます。 コンフィギュレーションの設定変更で使用した例に於いて data_size を 30 に変更してみると以下 の様にプリントされます。 多くの場合、トランザクションとして使用するアレイはダイナミックであり、アレイ・サイズを ランダムに決定します。その様な場合、全てのアレイ要素をプリントする意味が余りありません。 その為に、アレイ要素のプリントにはこの様な配慮がされていると考えられます。ダイナミッ

my_obj: (my_obj@272) { request: 'hf0 grant: 'h1 data: { [0]: 'h1 [1]: 'h2 [2]: 'h3 [3]: 'h4 [4]: 'h5 [5]: 'h6 [6]: 'h7 [7]: 'h8 } } module top; import uvm_pkg::*; ... initial begin ... uvm_default_printer = uvm_default_tree_printer; run_test(); end endmodule --- Name Type Size Value --- test my_comp - @280 header_name string 11 data[0..29] data_size integral 32 'h1e data da(integral) 30 - [0] integral 32 'h0 [1] integral 32 'h1 [2] integral 32 'h2 [3] integral 32 'h3 [4] integral 32 'h4 ... ... ... ... [25] integral 32 'h19 [26] integral 32 'h1a [27] integral 32 'h1b [28] integral 32 'h1c [29] integral 32 'h1d ---

(34)

プリント制御には次のクラスが関連を持ちます。  uvm_printer  uvm_printer_knobs uvm_printer はプロパーティとして uvm_printer_kbobs のインスタンスを持っています。そして、 uvm_printer_knobs ク ラ ス は プ リ ン ト 制 御 の プ ロ パ ー テ ィ を 持 っ て い ま す 。 以 下 に uvm_printer_knobs クラスの一部を紹介します。 UVM のソース・コードを見ると、アレイの最初と最後の 5 個ずつプリントする様に設定されて いるのが分かります。同時に、begin_elements に-1 を設定すると全ての要素をプリントする事が 出来る事も分かります。 全てのアレイ要素をプリントする為にはプリンターのノブを使用して、プリント制限を変更しま す。以下は、その一例です。他の方法もあると思います。 class uvm_printer_knobs; ... // Variable: begin_elements //

// Defines the number of elements at the head of a list to print. // Use -1 for no max.

int begin_elements = 5; // Variable: end_elements //

// This defines the number of elements at the end of a list that // should be printed. int end_elements = 5; ... endclass module top; import uvm_pkg::*; import Pkg::*; my_comp test; string print_option; initial begin

// fix the configuration.

uvm_config_db#(string)::set(null,"test", "header_name","data[0..29]");

uvm_config_db#(int)::set(null,"test","data_size",30); //

// command line parameters. //

if( !$value$plusargs("PRINT=%s",print_option) ) print_option = "short";

if( print_option.tolower() == "all" )

(35)

この例では、プリンターの制御をコマンド・ラインの指示で変更する様にしています。コマン ド・ラインで以下の様にタイプするとアレイ要素を全てプリントします。 ソース・コードを見て分かる様に、入力したパラメータを小文字に変換しています。従って、 でも同様の効果を得ます。 コマンド・ラインのパラメータの取得に SystemVerilog の$value$plusargs 関数を使用していますが、 UVM にも同種の関数が存在します。但し、使用方法は若干異なります。ここでは、敢えて標準 的な関数を使用しました。アレイ要素を全てプリントすると以下の様になります。 // create components. test = my_comp::type_id::create("test",null); run_test(); end endmodule svsim +PRINT=ALL svsim +PRINT=all --- Name Type Size Value --- test my_comp - @280 header_name string 11 data[0..29] data_size integral 32 'h1e data da(integral) 30 - [0] integral 32 'h0 [1] integral 32 'h1 [2] integral 32 'h2 [3] integral 32 'h3 [4] integral 32 'h4 [5] integral 32 'h5 [6] integral 32 'h6 [7] integral 32 'h7 [8] integral 32 'h8 [9] integral 32 'h9 [10] integral 32 'ha [11] integral 32 'hb [12] integral 32 'hc [13] integral 32 'hd [14] integral 32 'he [15] integral 32 'hf [16] integral 32 'h10 [17] integral 32 'h11 [18] integral 32 'h12 [19] integral 32 'h13 [20] integral 32 'h14

(36)

2.4 メッセージ機能 UVM にはメッセージをプリントするユーティリティがありますが、マクロを使用した方が便利 です。マクロを使用するとファイル名称、及び、行番号も一緒にプリントされます。 プリント・マクロ 機能 `uvm_info(ID,MSG,VERBOSITY) VERBOSITY は相対的な重要性を示します。設定されて いる verbosity レベル以下であれば、メッセージがプリ ントされます。 ID はメッセージ・タグと呼ばれます。 MSG は文字列のメッセージです。 `uvm_warning(ID, MSG) 警告メッセージをプリントします。 `uvm_error(ID, MSG) エラー・メッセージをプリントします。 `uvm_fatal(ID, MSG) 致命的なエラーをプリントします。 例えば、 の様に記述すると の様にプリントされます。 2.5 UVM シミュレーション

UVM を知り始めた際に、最も分かり難い概念の一つとして raise_objection()と drop_objection()が あります。簡単に言えば、これらのメソッドを呼び出さないと、UVM はシミュレーションを実 行しません。それ故、これらのメソッドを何れかのコンポーネントで呼び出さなければなりませ ん。 テストベンチからタスク run_test()を呼び出すとシミュレーションが開始しますが、上記のメソッ ドが呼び出されていなければ、時刻 0 でシミュレーションが終了してしまいます。即ち、各 phase メソッドの一部しか実行しません。イベント待ち、及び、ディレー制御をしている命令は 無効になります。 2.5.1 raise_objection と drop_objection

raise_objection() は UVM に実行すべき内容がある事を知らせます。一方、drop_objection() は実行 すべき内容が完了した事を UVM に知らせます。全ての内容が完了した時点で UVM は run_phase を終了して、次の phase(通常は、extract_phase)に進みます。 [21] integral 32 'h15 [22] integral 32 'h16 [23] integral 32 'h17 [24] integral 32 'h18 [25] integral 32 'h19 [26] integral 32 'h1a [27] integral 32 'h1b [28] integral 32 'h1c [29] integral 32 'h1d --- `uvm_info("TEST","It's Monday",UVM_NONE)

(37)

全ての raise_objection() を drop しても直ぐには終了しません。UVM では drain time 等の概念をサ ポートしています。詳細に関しては UVM のマニュアルを参照して下さい。

raise_objection() メソッドの使用法は以下の様になっています。

コンポーネントのインスタンス(obj)の objection カウントを count だけインクリメントします。 コンポーネント階層で上位にあるインスタンスの objection カウントも一斉にインクリメントされ ます。従って、何処かのインスタンスが raise_objection() を呼び出せば、UVM シミュレーション は進行します。obj==null の場合には、uvm_top が仮定されます。 drop_objection() メソッドの使用法は以下の様になっています。 このメソッドは raise_objection() と正反対の動作をします。コンポーネントのインスタンス(obj) の objection カウントを count だけ減少します。コンポーネント階層で上位にあるインスタンスの objection カウントも一斉に減少されます。obj==null の場合には、uvm_top が仮定されます。 インスタンスの objection カウントが 0 の場合、drop_objection() を適用するとエラーになるので注 意して下さい。

次に簡単な例を示します。この例では、ディレーを設定してメッセージを出力しようとしていま す。但し、raise_objection()、及び、drop_objection() を呼び出していません。

virtual function void raise_objection ( uvm_object obj = null, string description = "", int count = 1

)

virtual function void drop_objection ( uvm_object obj = null, string description = "", int count = 1

)

class testbench_comp extends uvm_component; `uvm_component_utils(testbench_comp)

function new (string name,uvm_component parent); super.new(name,parent);

endfunction

task run_phase(uvm_phase phase); #10;

`uvm_info("TBENCH",{"Executing @",$sformatf("%0t",$time)},UVM_LOW) endtask

図 1-1  UVM テストベンチの構造([2])  以上述べた様に UVM は複雑な体系で構成されています。UVM の全容を理解する事は一朝一夕 に行きませんが、メソドロジー・クラスを理解すると自然に UVM への理解が深まります。  1.2  検証技術のトレンド  近年の検証技術では階層的にテストベンチを記述する手法(layered  testbench)が採用されていま す。階層のレイヤー(layer)には以下の様な種類があります([3])。詳細は、関連する文献を参 照して下さい。  レイヤー  検証
図 1-2  テストベンチとレイヤーの関係([3])
図 2-2  Consumer がトランザクションを get する操作
図 2-3  uvm_tlm_fifo を使用した producer と consumer の通信
+7

参照

関連したドキュメント

In the two−phase operation mode, the two output power rails are connected together by an external switch and current−sharing control is enabled to balance power delivery

[r]

To be able to operate with diverse DrMOSs and phase doublers, the NCP81233 has 6 tri-level PWM outputs which may be connected to PWM inputs of these receivers. As shown in Figure 13,

A carnet is an international, unified Customs document under an international system based on “Customs Conventions on the Temporary Importation of Private Road Vehicles”

34 V1_top Vertical phase 1, top of die 35 LOD_top Lateral overflow drain, top of die 36 VDD_d Amplifier supply, Output D 37 VOUT_d Video output D.. 38 VSS_d Amplifier return, Output

23 NB_CS Non−inverting input to the current sense amplifier for the VDDNB regulator 24 NB_CSN Inverting input to the current sense amplifier for the VDDNB regulator 25 VID4

18 VDRP Voltage output signal proportional to current used for current limit and output voltage droop 19 VDFB Droop Amplifier Voltage Feedback.. 20 CSSUM Inverted Sum of

Practically, some logic grounds the In−rush protection output when it detects the presence of current cycles with a zero current detection signal provided by the auxiliary