ジェネリクス

ジェネリクスはパラメータオーバーライドでは実現できないアイテムのパラメータ化を可能にします。以下のアイテムがジェネリクスをサポートしています。

  • 関数
  • モジュール
  • インターフェース
  • パッケージ
  • 構造体
  • ユニオン

それぞれのジェネリック定義はジェネリックパラメータ(T のような大文字1文字がよく使われます)を持ち、定義内で識別子や式として配置できます。ジェネリックパラメータはアイテムの識別子の後に ::<> を用いて宣言します。

各ジェネリックパラメータにはコロンの後に T: TypeName のようなジェネリック境界が必要です。ジェネリック境界はどのような値をそのパラメータに渡すことができるかを示します。使用可能なジェネリック境界は以下の通りです。

  • type: 任意の型を渡すことができる
  • inst: X : X のインスタンス
  • 名前付きプロトタイプ、ユーザ定義型、組み込みのデータ型

名前付きプロトタイプは特別なジェネリック境界です。詳細は プロトタイプ を参照してください。

ジェネリクスを使用するためには ::<> を用いて実パラメータを与えます。実パラメータとしては数値リテラルと :: で連結された識別子を使用することができます。

さらに、実パラメータはジェネリクス定義位置から参照できなければなりません。例えば、モジュール名はプロジェクト全体から参照できるので、実パラメータとして使用できます。一方、ローカルパラメータは多くの場合、実パラメータとして使用できません。これはローカルパラメータがジェネリクス定義位置からは参照できない場合に発生します。

ジェネリック関数

module ModuleA {
    function FuncA::<T: u32> (
        a: input logic<T>,
    ) -> logic<T> {
        return a + 1;
    }

    let _a: logic<10> = FuncA::<10>(1);
    let _b: logic<20> = FuncA::<20>(1);
}

ジェネリックモジュール/インターフェース

module ModuleA {
    inst u0: ModuleB::<ModuleC>;
    inst u1: ModuleB::<ModuleD>;
}

proto module ProtoA;

module ModuleB::<T: ProtoA> {
    inst u: T;
}

module ModuleC for ProtoA {}
module ModuleD for ProtoA {}

ジェネリックパッケージ

package PackageA::<T: u32> {
    const X: u32 = T;
}

module ModuleA {
    const A: u32 = PackageA::<1>::X;
    const B: u32 = PackageA::<2>::X;
}

ジェネリック構造体

package PackageA {
    type TypeB = u32;
    type TypeC = u64;
}

module ModuleA {
    type TypeA = i32;

    struct StructA::<T: type> {
        A: T,
    }

    // ローカルに定位された型が使用できています
    // これは `TypeA` が `StructA` の定義位置から参照できるためです
    var _a: StructA::<TypeA>          ;
    var _b: StructA::<PackageA::TypeB>;
    var _c: StructA::<PackageA::TypeC>;
}

gen 宣言

gen 宣言はジェネリックパラメータから派生する定数や型を定義します。定義された値はジェネリック引数として使用できます。

module ModuleA::<W: u32, T: type> (
    a: output logic<W>,
    b: output T       ,
) {
    always_comb {
        a = '0;
        b = '0;
    }
}
module ModuleB::<A: u32, B: u32, C: u32> {
    gen W: u32  = A + B;
    gen T: type = logic<C>;

    var a: logic<W>;
    var b: T       ;

    inst u: ModuleA::<W, T> (
        a  ,
        b  ,
    );
}
module ModuleC {
    inst u: ModuleB::<1, 2, 3>;

}

ModuleB::<1, 2, 3> では W = 1 + 2 = 3 と T = logic<3> が導出され、ModuleA::<3, logic<3>> がインスタンス化されます。

gen 宣言の右辺式は、その結果の値自体がジェネリック引数として使われるため、実ジェネリック引数と同じ制約を受けます。式に使用できるのは以下のものだけです。

  • リテラル
  • パッケージ内で定義されたシンボル
  • ジェネリックパラメータ
  • 他の gen 宣言

ジェネリック引数の推論

ジェネリック関数では、呼び出し引数からジェネリック引数を推論できる場合、::<> 後の実引数を省略できます。詳細は 型推論 を参照してください。