SystemVerilog|virtual function/taskについて考える

Systemverilog
田中太郎
田中太郎

たまに「vritual」がついたfunction/taskをみかけますが、動作の違いが不明だったので、試してみました

はじめに

UVMのコードを書いていると「virtural」型がついたfunction/taskをみかけます

しらべてもよくわからなったので、実際に動かして動作を確認します

vritualあり/なしでどうかわるか

virtualなしの場合

まず、virtual型を付けずに定義したクラスを使って以下のサンプルコードを作成しました

class base_class;
    function void print();
        $display("base_class");
    endfunction
endclass
class extends_class extends base_class;
    function void print();
        $display("extends_class");
    endfunction
endclass
module tb;
    initial begin
        base_class b_class; // base_class型のb_classを宣言
        extends_class e_class; // extends_class型のe_classを宣言

        e_class = new(); // e_classを初期化

        b_class = e_class; // e_classの内容をb_classに代入

        // 継承元のprintが反映されれば"base_class"を出力
        // 継承後のprintが反映されれば"extends_clss"を出力
        b_class.print;
        e_class.print;
    end
endmodule

// 実行結果
// base_class
// extends_class

base_classで宣言したb_classは、base_classのprint()が実行され

extends_classで宣言したe_classは、extends_classのprint()が実行されました

virtualありの場合

次に、virtualありでfunctionを定義してみます

class base_class;
    // function void print();
    virtual function void print();
        $display("base_class");
    endfunction
endclass
class extends_class extends base_class;
    function void print();
        $display("extends_class");
    endfunction
endclass
module tb;
    initial begin
        base_class b_class; // base_class型のb_classを宣言
        extends_class e_class; // extends_class型のe_classを宣言

        e_class = new(); // e_classを初期化

        b_class = e_class; // e_classの内容をb_classに代入

        // 継承元のprintが反映されれば"base_class"を出力
        // 継承後のprintが反映されれば"extends_clss"を出力
        b_class.print;
        e_class.print;
    end
endmodule

// 実行結果
// extends_class
// extends_class

base_classで宣言したb_classは、extends_classのprint()が実行され

extends_classで宣言したe_classは、extends_classのprint()が実行されました

解説

virtualあり/なしの動作の違いを解説します

virtualなしの場合、シミュレーション実行に動作が確定します

virtualありの場合、シミュレーション実行に動作が確定します

コードを追って説明します

virtualなしの場合

まずは、virtualがなしの場合です

base_class b_class; // base_class型のb_classを宣言
extends_class e_class; // extends_class型のe_classを宣言

base_class, extends_class型の変数b_class, e_classを宣言します

この時点で、print()がどんな動作をするか決定します

次からの行でnew()や代入を行っていますが、print()の動作は変化しません

virtualありの場合

次にvirtualありの場合です

base_class b_class; // base_class型のb_classを宣言
extends_class e_class; // extends_class型のe_classを宣言

virtualを付けてprint()を定義している場合、この時点では、print()がどんな動作をするか決定しません

e_class = new(); // e_classを初期化

new()でe_classを初期化しました。このとき、e_classのprint()の動作が決定します

extends_classのprint()は”extends_class”を出力するfunctionなので、”extends_class”が出力されます

b_class = e_class; // e_classの内容をb_classに代入

e_classをb_classに代入しました。このとき、b_classのprint()の動作が決定します

e_classのprint()の動作がb_classのprint()に引き継がれます

まとめ

「virtual」あり/なしでどう動作が変化するかをサンプルコードを作成して確認しました

コメント

タイトルとURLをコピーしました