ジェネリクス
ジェネリクスはパラメータオーバーライドでは実現できないアイテムのパラメータ化を可能にします。以下のアイテムがジェネリクスをサポートしています。
- 関数
- モジュール
- インターフェース
- パッケージ
- 構造体
- ユニオン
それぞれのジェネリック定義はジェネリックパラメータ(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宣言
ジェネリック引数の推論
ジェネリック関数では、呼び出し引数からジェネリック引数を推論できる場合、::<> 後の実引数を省略できます。詳細は 型推論 を参照してください。