ハードウェア記述言語 Veryl

Veryl は SystemVerilog をベースに設計されたハードウェア記述言語であり、以下のような特徴があります。
最適化された構文
Verylは、SystemVerilogの経験者にとって親しみやすい基本構文に基づきながら、論理設計に最適化された構文を採用しています。この最適化には、たとえば合成可能性の保証やシミュレーション結果の一致の保証、頻出する定型文を簡素化する多数の構文などの提供が含まれます。このアプローチにより、学習の容易さ、設計プロセスの信頼性と効率の向上、およびコードの記述の容易さが実現されます。
相互運用性
VerylはSystemVerilogとの相互運用性を考慮して設計されており、既存のSystemVerilogコンポーネントやプロジェクトとの組み合わせや部分的な置き換えをスムーズに行うことができます。さらに、VerylからトランスパイルされたSystemVerilogソースコードは、その高い可読性により、シームレスな統合やデバッグを可能にします。
生産性
Verylはパッケージマネージャ、ビルドツール、そしてVSCode、Vim、Emacsなどの主要なエディタに対応するリアルタイムチェッカー、自動補完機能、自動フォーマッタなど、豊富な開発支援ツールを備えています。これらのツールは、開発プロセスを加速し、生産性を大幅に向上させることができます。
これらの特性により、Verylは設計者が高品質なハードウェア設計をより効率的かつ生産的に行うための強力なサポートを提供します。
特徴
この章ではVerylの特徴的な機能をわかりやすい例とともに紹介します。
- リアルタイム診断
- 自動フォーマット
- 組み込みテスト
- 依存関係管理
- ジェネリクス
- クロックドメインアノテーション
- 末尾カンマ
- クロックとリセットの抽象化
- ドキュメンテーションコメント
always_ffでの複合代入演算子- 独立した名前空間を持つenumバリアント
- ビット連結における
repeat if/case式- 範囲
for/inside/outside msb記法let文<>演算子- 名前付きブロック
- 可視性制御
リアルタイム診断
変数の未定義・未使用・未代入といった問題はエディタでの編集中にリアルタイムに通知されます。次の例では、未使用変数として通知された変数に _ プレフィックスを付加することで未使用であることを明示し、警告を抑制しています。
自動フォーマット
エディタと連携した自動フォーマット機能のほか、コマンドラインでのフォーマットやCIでのフォーマットチェックも可能です。
組み込みテスト
SystemVerilogまたはcocotbで書かれたテストコードをVerylに埋め込み、veryl test コマンドで実行することができます。
#[test(test1)]
embed (inline) sv{{{
module test1;
initial begin
assert (0) else $error("error");
end
endmodule
}}}
依存関係管理
Verylには依存関係の管理機能が組み込まれており、プロジェクト設定に以下のようにライブラリのリポジトリパスとバージョンを追加するだけで、簡単にライブラリを組み込むことができます。
[dependencies]
veryl_sample = {git = "https://github.com/veryl-lang/veryl_sample", version = "0.1.0"}
ジェネリクス
ジェネリクスによるコード生成は従来のパラメータオーバーライドよりさらに再利用性の高いコードを記述することができます。以下の例のような関数のパラメータだけでなく、インスタンスのモジュール名や構造体定義の型名もパラメータ化することができます。
| SystemVerilog | Veryl |
|---|---|
|
|
クロックドメインアノテーション
モジュール内に複数のクロックがある場合、明示的なクロックドメインアノテーションとクロックドメイン境界への unsafe (cdc) ブロックが必要です。Veryl コンパイラは意図しないクロックドメインクロッシングをエラーとして検出し、明示的な unsafe (cdc) ブロックによりレビューが容易になります。
| SystemVerilog | Veryl |
|---|---|
|
|
末尾カンマ
末尾カンマは、リストの最後の要素の後ろにカンマが置かれる構文です。これにより、要素の追加や削除が容易になり、バージョン管理システムにおける不必要な差異を減らすことができます。
| SystemVerilog | Veryl |
|---|---|
|
|
クロックとリセットの抽象化
クロックの極性やリセットの極性と同期性を構文上指定する必要はなく、ビルド時の設定で指定することができます。これにより同じVerylのコードからASIC向けの負極性・非同期リセットとFPGA向けの正極性・同期リセットのそれぞれのコードを生成することができます。
さらに、明示的な clock と reset 型により、レジスタへのクロック・リセット接続が正しく行われているかどうかを確認することができます。モジュール内にクロックとリセットが1つだけの場合、レジスタへの接続を省略することもできます。
| SystemVerilog | Veryl |
|---|---|
|
|
ドキュメンテーションコメント
ドキュメンテーションコメントとしてモジュールの説明を書いておくとドキュメントを自動生成することができます。単なるテキストだけでなく、以下のフォーマットを使用することができます。
| SystemVerilog | Veryl |
|---|---|
|
|
always_ff での複合代入演算子
ノンブロッキング専用の代入演算子はなく、always_ff 内ではノンブロッキング代入が、 always_comb 内ではブロッキング代入が推論されます。そのため always_ff 内でも always_comb 内と同様に様々な複合代入演算子を使用することができます。
| SystemVerilog | Veryl |
|---|---|
|
|
独立した名前空間を持つenumバリアント
enumのバリアントはenum毎に独立した名前空間を持っており意図しない名前の衝突を防ぐことができます。
| SystemVerilog | Veryl |
|---|---|
|
|
ビット連結における repeat
ビット連結における繰り返し記述として明示的な repeat 記法を採用し、 複雑な {} の組み合わせより可読性が向上しています。
| SystemVerilog | Veryl |
|---|---|
|
|
if / case 式
三項演算子の代わりに if 式と case 式を採用することで、比較するアイテム数が多い場合の可読性が向上します。
| SystemVerilog | Veryl |
|---|---|
|
|
範囲 for / inside / outside
閉区間 ..= と半開区間 .. を表す記法を導入し、 for 、inside で範囲を統一的に記述できるようにしました。また、inside の逆を意味する outside も導入しました。
| SystemVerilog | Veryl |
|---|---|
|
|
msb 記法
最上位ビットを示す msb 記法により、パラメータから最上位ビットを計算する必要がなくなり、より意図を明確にすることができます。
| SystemVerilog | Veryl |
|---|---|
|
|
let 文
変数宣言と同時に値を束縛する専用の let 文が用意されており、SystemVerilogではサポートされていなかった様々な場所で使用することができます。
| SystemVerilog | Veryl |
|---|---|
|
|
<> 演算子
<> 演算子は2つのインターフェースを接続します。SystemVerilogではインターフェースを接続するためにぞれぞれのメンバーを代入する必要がありましたが、簡単に接続することができるようになります。
| SystemVerilog | Veryl |
|---|---|
|
|
名前付きブロック
変数のスコープを限定するための名前付きブロックを定義することができます。
| SystemVerilog | Veryl |
|---|---|
|
|
可視性制御
pub キーワードの付かないモジュールはプロジェクト外から参照できず、ドキュメントの自動生成にも含まれません。これによりプロジェクト外に公開したいものと内部実装とを区別することができます。
| SystemVerilog | Veryl |
|---|---|
|
|
はじめに
Veryl を使ってみましょう。この章では Veryl のインストール、サンプルプロジェクトの作成とビルドまでを行います。
インストール
Veryl は公式のツールチェーンインストーラ verylup を使ってインストールできます。ツールチェーンのアップデートなど便利な機能があるので verylup の使用を推奨します。
注: インターネットアクセスのない環境にインストールしたい場合は オフラインインストール が利用できます。
要件
Veryl は git コマンドを内部で使用します。 git が起動できることを確認しておいてください。
verylup のインストール
バイナリのダウンロード
リリースページからダウンロードして、パスの通ったところに展開してください。
Cargo
cargo コマンドからインストールすることもできます。
cargo install verylup
verylup のセットアップ
verylup をインストールした後、以下のコマンドを1回実行してください。最新のツールチェーンをダウンロードし、veryl と veryl-ls コマンドをverylupと同じ場所に作成します。
verylup setup
これで veryl コマンドが使えるようになりました。
エディタ設定
公式には Visual Studio Code と Vim / Neovim がサポートされています。
Visual Studio Code
Visual Studio Code 向けに Veryl 拡張が提供されています。拡張はファイルタイプの検出とシンタックスハイライト、言語サーバの組み込みを提供します。拡張パネルから “Veryl” で検索するか、以下の URL からインストールしてください。
Veryl extension for Visual Studio Code
Vim / Neovim
Vim / Neovim 向けに Veryl プラグインが提供されています。プラグインはファイルタイプの検出とシンタックスハイライトを提供します。プラグインのインストールと言語サーバの組み込みは以下の URL を参照してください。
そのほかのエディタ
Veryl は言語サーバを提供しているので、言語サーバをサポートしているエディタ(例えば Emacs)であれば利用できます。
シェル補完
veryl と verylup のシェル補完スクリプトは verylup completion によって提供されます。例えば以下のコマンドはzsh向けの補完スクリプトを生成します。
verylup completion zsh veryl > _veryl
verylup completion zsh verylup > _verylup
サポートされているシェルは以下の通りです。
- Bash
- Elvish
- Fish
- PowerShell
- Zsh
生成されたスクリプトの使い方は各シェルのドキュメントを参照してください。
Hello, World!
プロジェクトを作る
まず始めに、新しい Veryl プロジェクトを作りましょう。
veryl new hello
コマンドを実行すると、以下のディレクトリとファイルが作成されます。もし git コマンドが利用できれば、ディレクトリは Git リポジトリとして初期化され、デフォルトの .gitignore ファイルも追加されます。
$ veryl new hello
[INFO ] Created "hello" project
$ cd hello
$ tree
.
├── src
└── Veryl.toml
1 directory, 1 file
Veryl.toml はプロジェクトの設定ファイルです。
[project]
name = "hello"
version = "0.1.0"
[build]
source = "src"
target = {type = "directory", path = "target"}
全設定の説明はこちら。
コードを書く
ソースコードはプロジェクトディレクトリ内のどこに書いても構いません。これは Veryl プロジェクトが独立したプロジェクトである場合もあれば、他のSystemVerilog プロジェクトに組み込まれている場合もあるからです。Veryl のソースコードの拡張子は .veryl です。
例えば以下のコードを src/hello.veryl に書いてみましょう。
module ModuleA {
initial {
$display("Hello, world!");
}
}
$ tree
.
├── src
│ └── hello.veryl
└── Veryl.toml
1 directory, 2 files
注:この本のいくつかのソースコードには、マウスをホバーすると現れるプレイボタン “▶” があります。ボタンをクリックすると、トランスパイルされた SystemVerilog のコードが現れます。
module ModuleAのコードのボタンを押してみましょう。
ビルドする
veryl build コマンドで SystemVerilog のソースコードを生成できます。
$ veryl build
[INFO ] Processing file ([path to hello]/src/hello.veryl)
[INFO ] Output filelist ([path to hello]/hello.f)
$ tree
.
├── dependencies
├── hello.f
├── src
│ └── hello.veryl
├── target
│ ├── hello.sv
│ └── hello.sv.map
├── Veryl.lock
└── Veryl.toml
3 directories, 6 files
デフォルトでは SystemVerilog のコードは Veryl のコードと同じディレクトリに生成されます。つまり src/hello.sv です。
module hello_ModuleA;
initial begin
$display("Hello, world!");
end
endmodule
//# sourceMappingURL=hello.sv.map
さらに、生成されたコードのファイルリスト hello.f も生成されます。これは SystemVerilog コンパイラで使用できます。Verilator で使用するには以下のようにします。
$ verilator --binary -f hello.f
生成されたコードを片づける
生成されたコードは veryl clean コマンドで削除することができます。
$ veryl clean
[INFO ] Removing file ([path to hello]/src/hello.sv)
[INFO ] Removing file ([path to hello]/src/hello.sv.map)
[INFO ] Removing dir ([path to hello]/dependencies)
[INFO ] Removing file ([path to hello]/hello.f)
コード例
Veryl は SystemVerilog とほとんど同じセマンティクスを持っています。もし SystemVerilog に慣れていれば、いくつかの例をみるだけで Veryl の構文をだいたい把握できるでしょう。
この小さな例では、コメントに SystemVerilog 構文との違いが書かれています。
module ModuleA (
// 識別子が先で `:` の後に型が来ます
// ビット幅は `<>` で表されます
i_data: input logic<10>,
o_data: output logic<10>,
// `begin`/`end` ではなく `{}` を使います
) {
assign o_data = i_data;
}
さらに、この章のコードブロックは編集することもできます。それぞれのコードを編集して実行してみましょう。
Veryl のソースコードは SystemVerilog と同様に、module、interface、package を持ちます。この章ではそれらの例を示します。
モジュール
// モジュール定義
module ModuleA #(
param ParamA: u32 = 10,
const ParamB: u32 = 10, // 末尾カンマが可能です
) (
i_clk : input clock , // `clock` はクロックのための特別な型です
i_rst : input reset , // `reset` はリセットのための特別な型です
i_sel : input logic ,
i_data: input logic<ParamA> [2], // `[]` は SystemVerilog のアンパック配列です
o_data: output logic<ParamA> , // `<>` は SystemVerilog のパック配列です
) {
// ローカルパラメータ宣言
// モジュール内では `param` は使えません
const ParamC: u32 = 10;
// 変数宣言
var r_data0: logic<ParamA>;
var r_data1: logic<ParamA>;
var r_data2: logic<ParamA>;
// 値の束縛
let _w_data2: logic<ParamA> = i_data[0];
// リセット付き always_ff 文
// `always_ff` はクロック(必須)とリセット(オプション)を持ちます
// `if_reset` は `if (i_rst)` を意味し、リセット極性を隠蔽するための構文です
// `if` 文に `()` はいりません
// `always_ff` 内の `=` はノンブロッキング代入です
always_ff (i_clk, i_rst) {
if_reset {
r_data0 = 0;
} else if i_sel {
r_data0 = i_data[0];
} else {
r_data0 = i_data[1];
}
}
// リセットなし always_ff 文
always_ff (i_clk) {
r_data1 = r_data0;
}
// モジュール内にクロックとリセットが1つしかない場合
// クロックとリセットの指定は省略できます
always_ff {
r_data2 = r_data1;
}
assign o_data = r_data1;
}
インスタンス
module ModuleA #(
param ParamA: u32 = 10,
) (
i_clk : input clock ,
i_rst : input reset ,
i_data: input logic<ParamA>,
o_data: output logic<ParamA>,
) {
var r_data1: logic<ParamA>;
var r_data2: logic<ParamA>;
assign r_data1 = i_data + 1;
assign o_data = r_data2 + 2;
// インスタンス宣言
// インスタンス宣言は `inst` キーワードではじまります
// ポート接続は `()` 内で指定します
// 各ポートの接続は `[port_name]:[variable]` のような形式になります
// `[port_name]` は `[port_name]:[port_name]` を意味します
inst u_module_b: ModuleB (
i_clk ,
i_data: r_data1,
o_data: r_data2,
);
// パラメータオーバーライド付きインスタンス宣言
// パラメータの接続記法はポートと同様です
inst u_module_c: ModuleC #( ParamA, ParamB: 10 );
}
module ModuleB #(
param ParamA: u32 = 10,
) (
i_clk : input clock ,
i_data: input logic<ParamA>,
o_data: output logic<ParamA>,
) {
assign o_data = 1;
}
module ModuleC #(
param ParamA: u32 = 10,
param ParamB: u32 = 10,
) () {}
インターフェース
// インターフェース定義
interface InterfaceA #(
param ParamA: u32 = 1,
param ParamB: u32 = 1,
) {
const ParamC: u32 = 1;
var a: logic<ParamA>;
var b: logic<ParamA>;
var c: logic<ParamA>;
// modport 定義
modport master {
a: input ,
b: input ,
c: output,
}
modport slave {
a: input ,
b: input ,
c: output,
}
}
module ModuleA (
i_clk: input clock,
i_rst: input reset,
// modport によるポート宣言
intf_a_mst: modport InterfaceA::master,
intf_a_slv: modport InterfaceA::slave ,
) {
// インターフェースのインスタンス
inst u_intf_a: InterfaceA [10];
}
パッケージ
// パッケージ定義
package PackageA {
const ParamA: u32 = 1;
const ParamB: u32 = 1;
function FuncA (
a: input logic<ParamA>,
) -> logic<ParamA> {
return a + 1;
}
}
module ModuleA {
let a : logic<10> = PackageA::ParamA;
let _b: logic<10> = PackageA::FuncA(a);
}
言語リファレンス
この章では Veryl の言語仕様について説明します。
ソースコードの構造
Veryl のソースコードはいくつかの module、interface、package からなります。
module ModuleA {}
module ModuleB {}
interface InterfaceA {}
package PackageA {}
トランスパイルされたコードにおける module、interface、package の名前には先頭にプロジェクト名が付きます。このサンプルコードでは project_ が付きます。これはプロジェクト間で名前が衝突するのを防ぐためです。
字句構造
この章では Veryl の字句構造について説明します。まず始めに、全体的なことがらからです。
エンコーディング
Veryl のソースコードは UTF-8 エンコーディングでなければなりません。
空白
(空白)、\t、\n は空白として扱われ、Veryl のパーサはこれらを全て無視します。
コメント
行コメントと複数行コメントが使えます。ほとんどのコメントはトランスパイルされたコードにも出力されます。
// 行コメント
/*
複数
行
コメント
*/
ドキュメンテーションコメント
/// ではじまる行コメントはドキュメンテーションコメントとして扱われます。ドキュメンテーションコメントはドキュメントの生成に使われます。
/// ドキュメンテーションコメント
識別子
識別子は ASCII のアルファベットと数値、 _ からなります。先頭が数値であってはなりません。正式な定義は以下の正規表現です。
[a-zA-Z_][a-zA-Z0-9_]*
生識別子
Veryl のいくつかのキーワードは SystemVerilog では識別子として使用できるため、これらの識別子にアクセスするために生識別子を使います。例えば、clock は Veryl のキーワードなので r#clock とします。r#clock は SystemVerilog では clock にトランスパイルされます。
文字列
" で囲んだものが文字列になります。\" や \n のように \ によるエスケープも可能です。
"Hello, World!"
演算子
ほとんどの演算子は SystemVerilog と同じです。いくつか違いがあるので注意してください。
<:小なり演算子です。SystemVerilog の<と同じです。>:大なり演算子です。SystemVerilog の>と同じです。
// 単項算術演算
a = +1;
a = -1;
// 単項論理演算
a = !1;
a = ~1;
// 単項集約演算
a = &1;
a = |1;
a = ^1;
a = ~&1;
a = ~|1;
a = ~^1;
a = ^~1;
// 二項算術演算
a = 1 ** 1;
a = 1 * 1;
a = 1 / 1;
a = 1 % 1;
a = 1 + 1;
a = 1 - 1;
// シフト演算
a = 1 << 1;
a = 1 >> 1;
a = 1 <<< 1;
a = 1 >>> 1;
// 比較演算
a = 1 <: 1;
a = 1 <= 1;
a = 1 >: 1;
a = 1 >= 1;
a = 1 == 1;
a = 1 != 1;
a = 1 === 1;
a = 1 !== 1;
a = 1 ==? 1;
a = 1 !=? 1;
// ビット演算
a = 1 & 1;
a = 1 ^ 1;
a = 1 ~^ 1;
a = 1 ^~ 1;
a = 1 | 1;
// 二項論理演算
a = 1 && 1;
a = 1 || 1;
数値
整数
// 整数
0123456789
01_23_45_67_89
// 2進数
32'b01xzXZ
32'b01_xz_XZ
// 8進数
36'o01234567xzXZ
36'o01_23_45_67_xz_XZ
// 10進数
32'd0123456789
32'd01_23_45_67_89
// 16進数
128'h0123456789abcdefxzABCDEFXZ
128'h01_23_45_67_89_ab_cd_ef_xz_AB_CD_EF_XZ
全ビットのセット
// 全て 0
'0
// 全て 1
'1
// 全て x
'x
'X
// 全て z
'z
'Z
幅なし整数
ビット幅指定は省略することができます。省略された場合、トランスパイルされたコードでは適切なビット幅が付与されます。
module ModuleA {
const a0: u64 = 'b0101;
const a1: u64 = 'o01234567;
const a2: u64 = 'd0123456789;
const a3: u64 = 'h0123456789fffff;
}
指定ビットのセット
“全ビットのセット” にビット幅指定を付与することもできます。
module ModuleA {
const a0: logic<32> = 1'0;
const a1: logic<32> = 2'1;
const a2: logic<32> = 3'x;
const a3: logic<32> = 4'z;
}
浮動小数点数
// 浮動小数点数
0123456789.0123456789
01_23_45_67_89.01_23_45_67_89
// 指数表記
0123456789.0123456789e+0123456789
01_23_45_67_89.01_23_45_67_89E-01_23_45_67_89
配列リテラル
'{} は配列リテラルを表します。リテラル内には式、repeat キーワード、default キーワードを配置することができます。
module ModuleA {
let _a: logic [3] = '{1, 2, 3};
let _b: logic [3] = '{1 repeat 3}; // '{1, 1, 1}
let _c: logic [3] = '{default: 3}; // '{3, 3, 3}
}
データ型
この章ではデータ型について説明します。
組み込み型
幅指定可能な4値データ型
logic は4値(0、1、x、z)のデータ型です。幅は logic のあとの <> で指定できます。<X, Y, Z,,,> のように多次元指定も可能です。
module ModuleA {
let _a: logic = 1;
let _b: logic<10> = 1;
let _c: logic<10, 10> = 1;
}
幅指定可能な2値データ型
bit は2値(0、1)のデータ型です。幅は logic のあとの <> で指定できます。<X, Y, Z,,,> のように多次元指定も可能です。
module ModuleA {
let _a: bit = 1;
let _b: bit<10> = 1;
let _c: bit<10, 10> = 1;
}
型修飾子
logic と bit 型には以下の型修飾子を付けることができます。
signed: MSBは符号ビットとして扱われるtri: トライステート型
module ModuleA {
let _a: signed logic<10> = 1;
let _b: tri logic <10> = 1;
let _c: signed bit <10> = 1;
let _d: tri bit <10> = 1;
}
整数型
整数型にはいくつかの種類があります。
u8:8ビットの符号なし整数u16:16ビットの符号なし整数u32:32ビットの符号なし整数u64:64ビットの符号なし整数i8:8ビットの符号付き整数i16:16ビットの符号付き整数i32:32ビットの符号付き整数i64:64ビットの符号付き整数
module ModuleA {
let _a: u8 = 1;
let _b: u16 = 1;
let _c: u32 = 1;
let _d: u64 = 1;
let _e: i8 = 1;
let _f: i16 = 1;
let _g: i32 = 1;
let _h: i64 = 1;
}
浮動小数点数型
浮動小数点数型にもいくつかの種類があります。
f32:32ビット浮動小数点数f64:64ビット浮動小数点数
いずれも IEEE Std 754 準拠の表現です。
module ModuleA {
let _a: f32 = 1.0;
let _b: f64 = 1.0;
}
文字列型
string は文字列を表す型です。
module ModuleA {
let _a: string = "";
}
Type型
type は型の種類を表す型です。type 型の変数は param か const としてのみ定義可能です。
module ModuleA {
const a: type = logic;
const b: type = logic<10>;
const c: type = u32;
}
ブーリアン型
bool は ブーリアンを表す logic<1> の型エイリアスです。1'b1 と 1'b0 を表す true と false も使用できます。
module ModuleA {
const a: bool = true;
const b: bool = false;
}
ユーザ定義型
構造体
struct は複合データ型です。いくつかのフィールドを持つことができ、. 演算子を通してアクセスできます。
module ModuleA {
struct StructA {
member_a: logic ,
member_b: logic<10>,
member_c: u32 ,
}
var a: StructA;
assign a.member_a = 0;
assign a.member_b = 1;
assign a.member_c = 2;
}
列挙型
enum は列挙型です。名前の付いたバリアントを複数持ち、enum 型の変数にはそのバリアントのうち1つだけをセットできます。バリアント名は [enum name]::[variant name] の形式で指定可能です。それぞれのバリアントは対応する整数値を持ち、= で指定することができます。指定されなかった場合は自動的に割り当てられます。
module A {
enum EnumA: logic<2> {
member_a,
member_b,
member_c = 3,
}
var a: EnumA;
assign a = EnumA::member_a;
}
enum の型が省略されている場合、適切なサイズの型がバリアントから自動的に推定されます。
module A {
enum EnumA {
member_a,
member_b,
member_c = 3,
}
}
列挙型エンコーディング
デフォルトでは各バリアントの値が省略されたときは0から順に割り当てられます。この割り当てのエンコードを指定したい場合は、#[enum_encoding] アトリビュートを指定できます。使用できるエンコードは以下の通りです。
sequentialonehotgray
module A {
#[enum_encoding(sequential)]
enum EnumA {
member_a,
}
#[enum_encoding(onehot)]
enum EnumB {
member_a,
}
#[enum_encoding(gray)]
enum EnumC {
member_a,
}
}
ユニオン
union はパックされたタグなしの直和型で、SystemVerilog では packed union にトランスパイルされます。ユニオンのそれぞれのバリアントの幅は同じでなければなりません。
module A {
union UnionA {
variant_a: logic<8> ,
variant_b: logic<2, 4> ,
variant_c: logic<4, 2> ,
variant_d: logic<2, 2, 2>,
}
var a : UnionA;
assign a.variant_a = 8'haa;
}
型定義
type キーワードを使って、スカラー型や配列型への型エイリアスを定義することができます。
module A {
type word_t = logic <16> ;
type regfile_t = word_t [16];
type octbyte = bit <8> [8] ;
}
配列
任意のデータ型に対して [] と付与することで配列を定義することができます。配列の長さは [] 内の値で指定します。
module ModuleA {
struct StructA {
A: logic,
}
enum EnumA: logic {
A,
}
var a: logic [20];
var b: logic <10> [20];
var c: u32 [20];
var d: StructA [20];
var e: EnumA [20];
assign a[0] = 0;
assign b[0] = 0;
assign c[0] = 0;
assign d[0] = 0;
assign e[0] = 0;
}
[X, Y, Z,,,] のように多次元配列も定義できます。
module ModuleA {
struct StructA {
A: logic,
}
enum EnumA: logic {
A,
}
var a: logic [10, 20, 30];
var b: logic <10> [10, 20, 30];
var c: u32 [10, 20, 30];
var d: StructA [10, 20, 30];
var e: EnumA [10, 20, 30];
assign a[0][0][0] = 0;
assign b[0][0][0] = 0;
assign c[0][0][0] = 0;
assign d[0][0][0] = 0;
assign e[0][0][0] = 0;
}
クロックとリセット
clock はクロック配線を表す特別な型です。クロックの極性を指定するため以下の3種類があります。
clock: ビルド時の設定で指定される極性を持つクロック型clock_posedge: 正極性のクロック型clock_negedge: 負極性のクロック型
reset はリセット配線を表す特別な型です。リセットの極性と同期・非同期を指定するため以下の5種類があります。
reset: ビルド時の設定で指定される極性と同期性を持つリセット型reset_async_high: 正極性の非同期リセット型reset_async_low: 負極性の非同期リセット型reset_sync_high: 正極性の同期リセット型reset_sync_low: 負極性の同期リセット型
特別な要件がなければ、コードの再利用を高めるため clock と reset の使用を推奨します。
module ModuleA (
i_clk : input '_ clock ,
i_clk_p : input '_ clock_posedge ,
i_clk_n : input '_ clock_negedge ,
i_rst : input '_ reset ,
i_rst_a : input '_ reset_async_high,
i_rst_a_n: input '_ reset_async_low ,
i_rst_s : input '_ reset_sync_high ,
i_rst_s_n: input '_ reset_sync_low ,
) {
var a: logic;
var b: logic;
var c: logic;
always_ff (i_clk, i_rst) {
if_reset {
a = 0;
} else {
a = 1;
}
}
always_ff (i_clk_p, i_rst_a) {
if_reset {
b = 0;
} else {
b = 1;
}
}
always_ff (i_clk_n, i_rst_s_n) {
if_reset {
c = 0;
} else {
c = 1;
}
}
}
デフォルトクロックとリセット
クロックが複数あるものの、 always_ff では単一のクロックしか使われない場合があります。このような場合に default 型修飾子を使ってデフォルトのクロックとリセットを明示することができます。
module ModuleA (
i_clk : input clock,
i_clk_en: input logic,
) {
let clk: '_ default clock = i_clk & i_clk_en;
var a: logic;
always_ff {
a = 0;
}
}
式
この章では式について説明します。式は変数や演算子、関数呼び出しなどを組み合わせたもので、評価して値を得ることができます。
演算子の優先順位
式内での演算子の優先順位は SystemVerilog とほとんど同じです。
| 演算子 | 結合性 | 優先順位 |
|---|---|---|
() [] :: . | 左 | 高い |
+ - ! ~ & ~& | ~| ^ ~^ ^~ (単項) | 左 | |
** | 左 | |
* / % | 左 | |
+ - (二項) | 左 | |
<< >> <<< >>> | 左 | |
<: <= >: >= | 左 | |
== != === !== ==? !=? | 左 | |
& (二項) | 左 | |
^ ~^ ^~ (二項) | 左 | |
| (二項) | 左 | |
&& | 左 | |
|| | 左 | |
= += -= *= /= %= &= ^= |= <<= >>= <<<= >>>= | なし | |
{} inside outside if case switch | なし | 低い |
関数呼び出し
関数は function_name(argument) の形式で呼び出すことができます。$clog2 のような SystemVerilog のシステム関数も使えます。
package PackageA {
function FunctionA (
a: input logic,
b: input logic,
) {}
}
module ModuleA {
let _a: logic = PackageA::FunctionA(1, 1);
let _b: logic = $clog2(1);
}
名前付き引数
多くの引数を持つ関数では、名前付き引数による関数呼び出しが便利です。名前付き引数と位置引数を混在させることはできません。
module ModuleA {
function FunctionA (
a: input logic,
b: input logic,
c: input logic,
d: input logic,
) {}
let _a: logic = FunctionA(
a: 1,
b: 1,
c: 1,
d: 1,
);
// 位置引数と名前付き引数の混在はエラー
//let _a: logic = FunctionA(
// 1,
// 2,
// a: 1,
// b: 1,
//);
}
連結
{} はビット連結を表します。{} の中では repeat キーワードを使うことで指定されたオペランドを繰り返すこともできます。
module ModuleA {
let a : logic<10> = 1;
let b : logic<10> = 1;
let _c: logic = {a[9:0], b[4:3]};
let _d: logic = {a[9:0] repeat 10, b repeat 4};
}
if
if を用いた条件式を使えます。if キーワードの後に条件を示す節を置きますが、() で囲む必要はありません。? のあとに条件が真である場合の式を、: のあとに条件が偽である場合の式を書きます。
module ModuleA {
let a: logic<10> = 1;
var b: logic<10>;
assign b = if a == 0 ? 1 : if a >: 1 ? 2 : 3;
}
Case / Switch
もう一つの条件式が case です。case は 値: 式 という形式の条件を複数持ちます。もし case キーワードの後の式と条件の左側の値が一致すれば、その条件の右側の式が返されます。値としては ..= のような範囲も指定できます。さらに x と z はワイルドカードとして扱われ、任意のビットにマッチします。default はそれ以外の条件が全て失敗したときに返される特別な条件です。case 式は常になんらかの値に評価される必要があるため default は必須です。
module ModuleA {
let a: logic<10> = 1;
var b: logic<10>;
assign b = case a {
0 : 1,
1 : 2,
3..=5 : 4,
10'b00_0000_011x: 5, // 6 か 7 にマッチ
default : 6,
};
}
switch は case のもう一つの形式です。switch は 式: 式 という形式を持ち、左側の式の評価結果が1の場合に、右側の式が返されます。
module ModuleA {
let a: logic<10> = 1;
var b: logic<10>;
assign b = switch {
a == 0 : 1,
a == 1 : 2,
a == 2 : 4,
default: 5,
};
}
ビット選択
[] はビット選択演算子です。[] に式を指定すれば1ビットを選択できます。範囲選択する場合は [式:式] とします。
module ModuleA {
let a: logic<10> = 1;
var b: logic<10>;
var c: logic<10>;
assign b = a[3];
assign c = a[4:0];
}
位置と幅による選択
+: と -: 記法は開始位置と幅により選択することができます。[A+:B] は [(A+B-1):A] を、 [A-:B] は [A:(A-B+1)] を意味します。
module ModuleA {
let a: logic<10> = 1;
var b: logic<10>;
var c: logic<10>;
assign b = a[3+:1];
assign c = a[4-:2];
}
ステップ付きインデックスによる選択
step 記法はステップ付きのインデックスにより選択することができます。[A step B] は “ステップ B で分割したときのインデックス A を選択する” を意味し、[(B*A)+:B] と等しくなります。
module ModuleA {
let a: logic<10> = 1;
var b: logic<10>;
assign b = a[2 step 3];
}
範囲
範囲は範囲演算子で指定できます。範囲演算子には以下の2種類があります。
..:半開区間..=:閉区間
範囲は for 文などの場所で使うことができます。
module ModuleA {
initial {
for _i: u32 in 0..10 {}
for _j: u32 in 0..=10 {}
}
}
msb / lsb
msb と lsb は [] によるビット選択で使用できます。msb はオペランドの最上位ビットを意味します。lsb はオペランドの最下位ビットを意味し、0と同じです。
module ModuleA {
let a : logic<10> = 1;
let _b: logic<10> = a[msb - 3:lsb];
let _c: logic<10> = a[msb - 1:lsb + 1];
}
inside / outside
inside は 指定された式が {} で与えられた条件内にあるかどうかを調べます。条件は単一の式または範囲を指定できます。条件を満たすとき inside は 1 を、そうでなければ 0 を返します。outside はその逆です。
module ModuleA {
var a: logic;
var b: logic;
assign a = inside 1 + 2 / 3 {0, 0..10, 1..=10};
assign b = outside 1 * 2 - 1 {0, 0..10, 1..=10};
}
型キャスト
as は型キャスト演算子です。基数付きあるいは基数なしの数値で指定するビット幅やユーザ定義型の型名をオペランドにとることができます。
module ModuleA {
var a: EnumA ;
var b: logic<2>;
let x: logic = 0;
enum EnumA: logic {
A,
B,
}
assign a = x as EnumA;
assign b = x as 2;
}
構造体コンストラクタ
構造体を初期化するために各メンバーにそれぞれ代入する代わりに構造体コンストラクタを使用することができます。特に const は各メンバーに代入することができないためコンストラクタによる初期化が必要です。
..default 指定子は未指定のメンバーのためのデフォルト値を指定することができます。
module ModuleA {
struct Param {
a: bit<10>,
b: bit<10>,
}
const p: Param = Param'{
a: 10,
b: 10,
};
const q: Param = Param'{
a: 1,
..default(0) // すなわち `b: 0`
};
}
文
この章では文について説明します。文は always_ff や always_comb などいくつかの宣言で使用することができます。
代入
代入文は 変数 = 式; の形式です。SystemVerilog と異なり、always_comb でも always_ff でも代入演算子は = です。以下のような代入演算子もあります。
+=:加算代入-=:減算代入*=:乗算代入/=:除算代入%=:剰余代入&=:ビットAND代入|=:ビットOR代入^=:ビットXOR代入<<=:論理左シフト代入>>=:論理右シフト代入<<<=:算術左シフト代入>>>=:算術右シフト代入
module ModuleA (
i_clk: input clock,
) {
let a: logic<10> = 1;
var b: logic<10>;
var c: logic<10>;
var d: logic<10>;
var e: logic<10>;
always_comb {
b = a + 1;
c += a + 1;
}
always_ff (i_clk) {
d = a + 1;
e -= a + 1;
}
}
関数呼び出し
関数呼び出しは文として使うこともできます。この場合、関数の戻り値は無視されます。
module ModuleA {
initial {
$display("Hello, world!");
}
}
if
if は文として使うこともできます。if 式との違いは {} 内に文を書くことです。
module ModuleA {
let a: logic<10> = 1;
var b: logic<10>;
always_comb {
if a == 0 {
b = 1;
} else if a >: 1 {
b = 2;
} else {
b = 3;
}
}
}
Case / Switch
case と switch は文として使うこともできます。各アームの右辺が文になる点を除けば Case / Switch 式 と同じです。
module ModuleA {
let a: logic<10> = 1;
var b: logic<10>;
var c: logic<10>;
always_comb {
case a {
0: b = 1;
1: b = 2;
2: {
b = 3;
b = 3;
b = 3;
}
default: b = 4;
}
}
always_comb {
switch {
a == 0: c = 1;
a == 1: c = 2;
a == 2: {
c = 3;
c = 3;
c = 3;
}
default: c = 4;
}
}
}
cond_type アトリビュート
SystemVerilogにおける unique unique0 priority を指定するために、cond_type アトリビュートを使うことができます。これらのアトリビュートは case あるいは if 文に付けることができます。
unique: アイテムは重複しない。マッチするアイテムがなければエラー。unique0: アイテムは重複しない。マッチするアイテムがなくてもエラーではない。priority: 最初にマッチしたアイテムが使われる。マッチするアイテムがなければエラー。
module ModuleA {
let a: logic<10> = 1;
var b: logic<10>;
always_comb {
#[cond_type(unique)]
case a {
0: b = 1;
1: b = 2;
}
}
}
これらのアトリビュートは合成時により積極的な最適化を可能にしますが、期待される条件を満たさない場合に合成結果が不正になる可能性があります。そのためデフォルトではアトリビュートは無視され、以下の設定がある場合のみ出力されます。
[build]
emit_cond_type = true
for
for 文は繰り返しを表します。in キーワードの前にループ変数を、後に範囲を書きます。
break を使ってループを中断することもできます。
module ModuleA {
var a: logic<10>;
always_comb {
for i: u32 in 0..10 {
a += i;
if i == 5 {
break;
}
}
}
}
in キーワードの後に rev キーワードを指定することで、ループを降順にすることができます。
module ModuleA {
var a: logic<10>;
always_comb {
for i: i32 in rev 0..10 {
a += i;
if i == 5 {
break;
}
}
}
}
return
return 文は関数からの戻りを示します。return キーワードの後の式は関数の戻り値です。
module ModuleA {
function FunctionA () -> u32 {
return 0;
}
}
let
let 文はある名前に値を束縛します。これは always_ff 、 always_comb および関数宣言の中で使うことができます。
let 文はブロック中のどこにでも置くことができます。
module ModuleA (
i_clk: input clock,
) {
var a: logic;
var b: logic;
var c: logic;
always_ff (i_clk) {
let x: logic = 1;
a = x + 1;
}
always_comb {
let y: logic = 1;
b = y + 1;
let z: logic = 1;
c = z + 1;
}
}
宣言
この章では宣言について説明します。
変数
変数宣言は var キーワードで始まり、変数名、:、変数の型と続きます。
未使用の変数は警告が発生します。_ で始まる変数名は未使用変数を意味し、警告を抑制します。
宣言時に名前に値を束縛する場合は var の代わりに let を使います。
module ModuleA {
var _a: logic ;
var _b: logic<10> ;
var _c: logic<10, 10>;
var _d: u32 ;
let _e: logic = 1;
assign _a = 1;
assign _b = 1;
assign _c = 1;
assign _d = 1;
}
パラメータ
パラメータは変数と同時に宣言できます。param キーワードはモジュールヘッダで使用することができ、インスタンス時に上書きできます。const キーワードはモジュール内で使用することができ、上書きできません。
module ModuleA #(
param ParamA: u32 = 1,
) {
const ParamB: u32 = 1;
}
レジスタ
レジスタ変数とは always_ff で代入される変数です。合成フェーズでフリップフロップにマップされます。
always_ff は必須のクロック変数、オプションのリセット変数、{} ブロックをとります。クロックとリセットは () に書きます。指定されたクロックとリセットは clock / reset 型を持ち、そのビット幅は1ビットでなければなりません。
if_reset は always_ff に書ける特別なキーワードで、そのレジスタ変数のリセット条件を示します。if_reset を使う場合は always_ff のリセット変数は必須です。これを使うことで、リセットの極性と同期性を隠ぺいすることができます。実際の極性と同期性は Veryl.toml の [build] セクションで設定できます。
モジュール内にクロックとリセットが1つしかない場合、クロックとリセットの指定は省略できます。
module ModuleA (
i_clk: input clock,
i_rst: input reset,
) {
var a: logic<10>;
var b: logic<10>;
var c: logic<10>;
always_ff (i_clk) {
a = 1;
}
always_ff (i_clk, i_rst) {
if_reset {
b = 0;
} else {
b = 1;
}
}
always_ff {
if_reset {
c = 0;
} else {
c = 1;
}
}
}
組み合わせ回路
always_comb で代入される変数は組み合わせ回路を意味します。
module ModuleA {
let a: logic<10> = 1;
var b: logic<10>;
always_comb {
b = a + 1;
}
}
assign
assign 宣言で変数に式を代入することができます。
module ModuleA {
var a: logic<10>;
assign a = 1;
}
assign 宣言の左辺には連結も使用することができます。
module ModuleA {
var a: logic<10>;
var b: logic<10>;
assign {a, b} = 1;
}
関数
関数は function キーワードで宣言できます。引数は () 内に書き、戻り値の型を -> の後に書きます。
関数が戻り値を持たない場合、-> は省略できます。
module ModuleA {
let a: logic<10> = 1;
var b: logic<10>;
function FunctionA (
a: input logic<10>,
) -> logic<10> {
return a + 1;
}
function FunctionB (
a: input logic<10>,
) {}
assign b = FunctionA(a);
initial {
FunctionB(a);
}
}
インターフェースのmodportは引数の型としても使用できます。与えられたmodportはSystemVerilog生成時にVerilogポートに展開されます。
interface InterfaceA::<W: u32> {
var ready: logic ;
var valid: logic ;
var data : logic<W>;
modport master {
ready: input ,
valid: output,
data : output,
}
modport slave {
..converse(master)
}
}
module ModuleA {
inst a_if: InterfaceA::<8>;
inst b_if: InterfaceA::<8>;
function FunctionA (
a_if: modport InterfaceA::<8>::slave ,
b_if: modport InterfaceA::<8>::master,
) {
a_if <> b_if;
}
always_comb {
FunctionA(a_if, b_if);
}
}
initial / final
initial ブロック内の文はシミュレーション開始時に実行され、final は終了時です。どちらも論理合成では無視され、デバッグやアサーションに使うことができます。
module ModuleA {
initial {
$display("initial");
}
final {
$display("final");
}
}
アトリビュート
アトリビュートは変数宣言などいくつかの宣言に注釈を付けることができます。
sv アトリビュート
sv アトリビュートは SystemVerilog のアトリビュートを表し、(* *) という形式の SystemVerilog アトリビュートに変換されます。
module ModuleA {
#[sv("ram_style=\"block\"")]
let _a: logic<10> = 1;
#[sv("mark_debug=\"true\"")]
let _b: logic<10> = 1;
}
allow アトリビュート
allow アトリビュートは指定されたリントチェックを無効化するために使用できます。
module ModuleA {
#[allow(unused_variable)]
let a: logic<10> = 1;
}
指定可能なリント名は以下の通りです。
- unused_variable
- missing_reset_statement
- missing_port
ifdef/ifndef/elsif/else アトリビュート
ifdef と ifndef アトリビュートは定義された値によってコードブロックを有効にするかどうかを制御するために使用することができます。さらに、ifdef と ifndef のついたコードブロックに続けてオプションとして elsif と else アトリビュートの付いたブロックを書くこともできます。
以下の例はこれらのアトリビュートの使用方法と、各コードブロックが定義された値によって有効になる様子を示しています。
ifdef/elsif/elseの順に宣言されたアトリビュート- もし
DEFINE_Aが定義されていれば、#[ifdef(DEFINE_A)]のついたコードブロック(コードブロックa)が有効になり、#[ifndef(DEFINE_B)]と#[else]のついたコードブロック(コードブロックbとc)は無効になります。 DEFINE_Aが定義されておらず、DEFINE_Bが定義されていれば、#[elfif(DEFINE_B)]のついたコードブロック(コードブロックb)が有効になり、#[ifndef(DEFINE_A)]と#[else]のついたコードブロック(コードブロックaとc)は無効になります。DEFINE_AとDEFINE_Bが定義されていなければ、#[else]のついたコードブロックが有効になり、#[ifndef(DEFINE_A)]と#[elsif(DEFINE_B)]のついたコードブロック(コードブロックaとb)は無効になります。
- もし
ifndef/elseの順に宣言されたアトリビュート- もし
DEFINE_Dが定義されていなければ、#[ifndef(DEFINE_D)]のついたコードブロック(コードブロックd)が有効になり、#[else]のついたコードブロック(コードブロックe)は無効になります。 DEFINE_Dが定義されていれば、#[else]のついたコードブロック(コードブロックe)が有効になり、#[ifndef(DEFINE_D)]のついたコードブロック(コードブロックd)は無効になります。
- もし
module ModuleA {
#[ifdef(DEFINE_A)]
{
// コードブロック a
let _a: logic<10> = 1;
}
#[elsif(DEFINE_B)]
{
// コードブロック b
let _a: logic<10> = 2;
}
#[else]
{
// コードブロック c
let _a: logic<10> = 3;
}
#[ifndef(DEFINE_D)]
{
// コードブロック d
let _b: logic<10> = 4;
}
#[else]
{
// コードブロック e
let _b: logic<10> = 5;
}
}
生成されたコードにおける末尾カンマ周りの複雑な調整を回避するため、カンマ区切りリストの最後のアイテムにifdefをつけることは禁止されています。
expand アトリビュート
expand アトリビュートが設定されているとき、modport のような構造化されたポートはVerilog のポートに展開されます。合成ツールによってはトップモジュールがそのようなポートを含んではならない場合があり、そのような場合にこのアトリビュートを使うことができます。使用可能な引数は以下の通りです。
modport: ポート方向がmodportのポートを展開する
interface InterfaceA::<W: u32> {
var ready: logic ;
var valid: logic ;
var data : logic<W>;
modport master {
ready: input ,
valid: output,
data : output,
}
modport slave {
ready: output,
valid: input ,
data : input ,
}
}
#[expand(modport)]
module ModuleA (
slave_if : modport InterfaceA::<8>::slave [4],
master_if: modport InterfaceA::<8>::master [4],
) {
for i in 0..4 :g {
connect slave_if[i] <> master_if[i];
}
}
module ModuleB {
inst a_if: InterfaceA::<8> [4];
inst b_if: InterfaceA::<8> [4];
inst u: ModuleA (
slave_if : a_if,
master_if: b_if,
);
}
align アトリビュート
align アトリビュートはフォーマッタの垂直方向の整列を制御することができます。number が align の引数として指定されたとき、全ての数値は整列されます。identifier も使用可能です。
module ModuleA {
let a : logic<32> = 1;
let aa : logic<32> = 1;
let aaa: logic<32> = 1;
let _b: logic = {
a[0] repeat 1, a[0] repeat 1,
aa[1] repeat 8, aa[1] repeat 8,
aaa[2] repeat 16, aaa[2] repeat 16,
};
#[align(number, identifier)]
let _c : logic = {
a [0 ] repeat 1 , a [0 ] repeat 1 ,
aa [1 ] repeat 8 , aa [1 ] repeat 8 ,
aaa[2 ] repeat 16, aaa[2 ] repeat 16,
};
}
fmt アトリビュート
fmt アトリビュートはフォーマットの方法を制御することができます。以下の引数がサポートされています。
compact: 改行なしのコンパクトなフォーマット
module ModuleA {
#[fmt(compact)]
{
inst u1: $sv::Module #( A: 1, B: 2 ) ( x: 1, y: _ );
inst u2: $sv::Module #( A: 1, B: 2 ) ( x: 1, y: _ );
inst u3: $sv::Module #( A: 1, B: 2 ) ( x: 1, y: _ );
inst u4: $sv::Module #( A: 1, B: 2 ) ( x: 1, y: _ );
}
}
skip:veryl fmtはモジュール、インターフェース、パッケージをフォーマットしない
生成
宣言や for や if を使って生成することができます。: で示すラベルは生成された複数の宣言を識別するのに必要です。
module ModuleA {
var a: logic<10>;
for i in 0..10 :label {
if i >: 5 :label {
assign a[i] = i + 2;
} else { // else 句のラベルは省略可能
assign a[i] = i + 2;
}
}
}
in キーワードの後に rev キーワードを付けることで、ループを降順にすることができます。
module ModuleA (
i_a: input logic,
o_a: output logic,
i_b: input logic,
o_b: output logic,
) {
var a: logic<4>;
var b: logic<4>;
always_comb {
a[lsb] = i_a;
o_a = a[msb];
}
for i in 0..4 :g_a {
assign a[i + 1] = a[i];
}
always_comb {
b[msb] = i_b;
o_b = b[lsb];
}
for i in rev 0..4 :g_b {
assign b[i - 1] = b[i];
}
}
インスタンス
inst キーワードはモジュールやインターフェースのインスタンス化を表します。インスタンスの名前は inst の後に、インスタンスの型は : の後に書きます。#() でパラメータオーバーライドを、() でポート接続を表します。
module ModuleA #(
param paramA: u32 = 1,
) {
let a: logic<10> = 1;
let b: logic<10> = 1;
inst instB: ModuleB #(
paramA , // 名前によるパラメータ代入
paramB: 10,
) (
a , // 名前によるポート接続
bb: b,
);
}
module ModuleB #(
param paramA: u32 = 1,
param paramB: u32 = 1,
) (
a : input logic<10>,
bb: input logic<10>,
) {}
bind 宣言もサポートされており、SystemVerilogのbind宣言に変換されます。SystemVerilogと異なり、ターゲットスコープとしてインスタンスを指定することはできず、モジュールかインターフェースのみ指定することができます。
interface InterfaceA {
var a: logic;
modport mp {
a: input,
}
}
module ModuleA (
i_clk: input clock,
i_rst: input reset,
) {
inst a_if: InterfaceA;
}
module ModuleB (
i_clk: input clock ,
i_rst: input reset ,
a_if : modport InterfaceA::mp,
) {}
module ModuleC {
bind ModuleA <- u0: ModuleB (
i_clk ,
i_rst ,
a_if ,
);
}
bind ModuleA <- u1: ModuleB (
i_clk: i_clk,
i_rst: i_rst,
a_if : a_if ,
);
名前付きブロック
{} ブロックにラベルを付けることができます。そのような名前付きブロックは独立した名前空間を持ちます。
module ModuleA {
:labelA {
let _a: logic<10> = 1;
}
:labelB {
let _a: logic<10> = 1;
}
}
インポート
import 宣言は他のパッケージからシンボルをインポートします。モジュール、インターフェース、パッケージの要素としてだけでなくトップレベルにも配置することができます。import 宣言の引数には package::* のようなワイルドカードパターンを使用することができます。
// ファイルスコープインポート
import $sv::SvPackage::*;
package PackageA {
const paramA: u32 = 1;
}
module ModuleA {
import PackageA::*;
import PackageA::paramA;
}
インポート宣言によるシンボルのインポートは、そのインポート宣言が置かれた名前空間内の任意の場所から参照できます。
package PackageA {
const WIDTH: u32 = 8;
}
module ModuleA (
i_d: input logic<WIDTH>, // 有効な参照
o_d: output logic<WIDTH>, // 有効な参照
) {
import PackageA::WIDTH;
let d : logic<WIDTH> = i_d; // 有効な参照
assign o_d = d;
}
Connect
あるインターフェースをほかのインターフェースに接続するために各メンバーを代入する代わりに connect 宣言を使用することができます。connect 宣言はインターフェースの全てのメンバーを自動的に接続します。
代入の方向はmodportによって決まります。つまり output メンバーが input メンバーに代入されます。connect の引数がインターフェースインスタンスの場合、方向を決定するためにmodportの指定が必要です。
接続演算子 <> は always_comb 中でも使用することができます。
interface InterfaceA {
var cmd : logic;
var ready: logic;
modport master {
cmd : output,
ready: input ,
}
modport slave {
..converse(master)
}
}
module ModuleA (
mst_if0: modport InterfaceA::master,
slv_if0: modport InterfaceA::slave ,
mst_if1: modport InterfaceA::master,
slv_if1: modport InterfaceA::slave ,
) {
inst bus_if0: InterfaceA;
inst bus_if1: InterfaceA;
connect mst_if0 <> bus_if0.slave;
connect slv_if0 <> bus_if0.master;
always_comb {
mst_if1 <> bus_if1.slave;
}
always_comb {
slv_if1 <> bus_if1.master;
}
}
モジュール
モジュールはソースコードの最上位コンポーネントの1つです。モジュールはオーバーライド可能なパラメータ、接続ポート、内部ロジックを持ちます。
オーバーライド可能なパラメータは #() 内で宣言できます。それぞれのパラメータ宣言は param キーワードで始まり、識別子、:、パラメータの型、デフォルト値で構成されます。
接続ポートは () 内で宣言できます。それぞれのポート宣言は識別子、:、ポートの方向、ポートの型で構成されます。利用可能なポート方向は以下の通りです。
input:入力ポートoutput:出力ポートinout:双方向ポートmodport:インターフェースのmodportinterface: ジェネリックインターフェース
module ModuleA #(
param ParamA: u32 = 0,
param ParamB: u32 = 0,
) (
a: input logic,
b: input logic,
c: input logic,
x: output logic,
) {
always_comb {
if c {
x = a;
} else {
x = b;
}
}
}
ポートのデフォルト値
モジュールのポートはデフォルトを持つことができます。デフォルト値を持つポートはインスタンス時に省略することができ、省略されたポートにはデフォルト値が割り当てられます。デフォルト値としては以下の値を取ることができます。
- 入力ポート: リテラル、パッケージ内の
const - 出力ポート:
_(無名識別子)
module ModuleA (
a: input logic ,
b: input logic = 1,
x: output logic ,
y: output logic = _,
) {
assign x = a;
assign y = b;
}
module ModubeB {
inst instA: ModuleA (
a: 1,
// b は省略
x: _,
// y は省略
);
}
ジェネリックインターフェース
ジェネリックインターフェースは特別なポート方向指定です。interface が指定されたとき、そのポートには任意のインターフェースを接続可能です。interface::ModPort のように modport を付けることもできます。この場合、ModPort を持つインターフェースだけが接続できます。
module ModuleA (
bus_if : interface,
slave_if: interface::slave,
) {}
インターフェース
インターフェースはソースコードの最上位コンポーネントの1つです。インターフェースはオーバーライド可能なパラメータ、インターフェース定義を持ちます。
オーバーライド可能なパラメータについてはモジュールと同じです。
インターフェース定義では modport を宣言することができます。modport はモジュールのポート宣言で、ポートを束ねて接続するために使うことができます。
interface InterfaceA #(
param ParamA: u32 = 0,
param ParamB: u32 = 0,
) {
var a: logic;
var b: logic;
modport master {
a: output,
b: input ,
}
modport slave {
b: input ,
a: output,
}
}
さらに、import キーワードを付けて指定された関数は modport を通して呼び出すことができます。
interface InterfaceA {
var a: logic;
var b: logic;
function a_and_b -> logic<2> {
return {a, b};
}
modport mp {
a : input ,
b : input ,
a_and_b: import,
}
}
module ModuleA (
ab_if: modport InterfaceA::mp,
) {
let _ab: logic<2> = ab_if.a_and_b();
}
modportのデフォルトメンバー
modportの全てのメンバーを指定する代わりに、以下のようにデフォルトメンバーを指定することができます。
..input: インターフェース内の全ての変数をinputとして追加..output: インターフェース内の全ての変数をoutputとして追加..same(modport_name):modport_nameと同じ変数を同じ方向で追加..converse(modport_name):modport_nameと同じ変数を、方向を逆にして追加
デフォルトメンバーの指定は通常の明示的なメンバーと一緒に使うこともできます。
interface InterfaceA {
var a: logic;
var b: logic;
var c: logic;
modport master {
a: output,
b: input ,
c: input ,
}
modport slave {
..converse(master)
}
modport monitor {
..input
}
modport driver {
b: input,
..output
}
}
インターフェースインスタンスとmodportポートの接続
インターフェースインスタンスとmodportポートは、SystemVerilogと同様に、互換性のあるモジュールポートあるいは generic インターフェースに接続することができます。
interface InterfaceA {
var a: logic;
modport mp {
a: output,
}
}
module ModuleA (
foo_if: modport InterfaceA::mp,
bar_if: modport InterfaceA::mp,
) {
always_comb {
foo_if.a = '0;
bar_if.a = '0;
}
}
module ModuleB (
foo_if: modport InterfaceA::mp,
) {
inst bar_if: InterfaceA;
inst u: ModuleA (
foo_if: foo_if,
bar_if: bar_if,
);
}
パッケージ
パッケージはソースコードの最上位コンポーネントの1つです。パッケージはパラメータや関数などいくつかの宣言をまとめることができます。
パッケージ内の要素にアクセスするには、:: 記号を使って PackageA::ParamA のようにします。
package PackageA {
const ParamA: u32 = 0;
}
SystemVerilogとの相互運用
SystemVerilogの要素にアクセスする場合は $sv 名前空間を使えます。例えば、SystemVerilogソースコードの “ModuleA” は $sv::ModuleA です。Veryl はこれらの要素が実際に存在するかどうかは確認しません。
Verylコンパイラは $sv:: を除いたパス名をそのまま出力します。そのため Verilog や VHDL のような他のHDLのシンボルも参照できます。それぞれのシンボルが解決できるかどうかは実装(シミュレータや合成ツール)に依存します。
module ModuleA {
let _a: logic = $sv::PackageA::ParamA;
inst b: $sv::ModuleB;
inst c: $sv::InterfaceC;
}
Veryl のキーワードとして使われている識別子にアクセスするには生識別子を使います。
module ModuleA (
i_clk: input clock,
) {
inst a: $sv::ModuleA (
// clock: i_clk
// ^ `clock` はキーワードなので構文エラー
// 代わりに `r#clock` を使います
r#clock: i_clk,
);
}
可視性
デフォルトではプロジェクトのトップレベルアイテム(モジュール、インターフェース、パッケージ)はプライベートです。プライベートとは他のプロジェクトから参照できないことを意味します。
pub キーワードによって他のプロジェクトから見えるように指定することができます。veryl doc コマンドはパブリックなアイテムの ドキュメント のみを生成します。
pub module ModuleA {}
pub interface InterfaceA {}
pub package PackageA {}
他言語組み込み
embed 宣言
embed 宣言により他言語をコードに埋め込むことができます。embed 宣言の第一引数は埋め込み方法です。以下の方法がサポートされています。
inline: コードをそのまま展開するcocotb: cocotb テストとして扱う
コードブロックは lang{{{ で始まり、}}} で終わります。以下の lang 指示子がサポートされています。
sv: SystemVerilogpy: Python
embed (inline) sv{{{
module ModuleSv;
endmodule
}}}
inline かつ sv 指定された embed 宣言はモジュール宣言、インターフェース宣言及びパッケージ宣言の中に配置することができます。これはSystemVerilogテストベンチとの統合に使用できます。
#[allow(unused_variable)]
interface bus_monitor_if {
var clk : clock ;
var ready : logic ;
var valid : logic ;
var payload: logic<8>;
embed (inline) sv{{{
clocking monitor_cb @(posedge clk);
input ready;
input valid;
input payload;
endclocking
}}}
}
Verylコード内で定義された識別子は embed コードブロック内に \{ と \} を用いて記述することができます。これらの識別子はコンパイル時に解決され、解決された名前がその場所に挿入されます。
module Module47A {}
module Module47B::<V: u32> {}
module Module47C {
inst u_a: Module47A;
embed (inline) sv{{{
bind u_a \{ Module47B::<32> \} u_b32 ();
bind u_a \{ Module47B::<64> \} u_b64 ();
}}}
}
include 宣言
include 宣言により他言語のファイルを含めることができます。include 宣言の第一引数は embed 宣言と同じです。第二引数はソースコードからの相対ファイルパスです。
include(inline, "module.sv");
組み込みテスト
組み込みテストは #[test(test_name)] アトリビュートでマークすることができます。マークされたブロックはテストとして認識され、 veryl test コマンドによって実行されます。
組み込みテストにはいくつかの種類があります。
- SystemVerilogテスト
- cocotb テスト
veryl test で使用される RTLシミュレータについては シミュレータ を参照してください。--wave オプションで波形を生成することもできます。
SystemVerilogテスト
SystemVerilog テストは inline 指定子で記述することができます。ブロックのトップレベルモジュールはテスト名と同じでなければなりません。
$info、$warning、$error、$fatal システム関数によるメッセージは Veryl コンパイラにより実行ログとして表示されます。$error と $fatal の呼び出しはテストの失敗として扱われます。
以下の例では SystemVerilog のソースコードを embed 宣言で埋め込み、テストとしてマークしています。
#[test(test1)]
embed (inline) sv{{{
module test1;
initial begin
assert (0) else $error("error");
end
endmodule
}}}
cocotb テスト
cocotb テストは cocotb 指定子で記述することができます。テスト対象のモジュール名は #[test] アトリビュートの第二引数で指定します。
#[test(test1, ModuleA)]
embed (cocotb) py{{{
# cocotb code
}}}
ジェネリクス
ジェネリクスはパラメータオーバーライドでは実現できないアイテムのパラメータ化を可能にします。以下のアイテムがジェネリクスをサポートしています。
- 関数
- モジュール
- インターフェース
- パッケージ
- 構造体
- ユニオン
それぞれのジェネリック定義はジェネリックパラメータ(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>;
}
デフォルトパラメータ
ジェネリックパラメータはその後に = を加えることでデフォルト値を指定することができます。呼び出し側でパラメータ指定が省略された場合にデフォルト値が使われます。
module ModuleA {
function FuncA::<T: u32 = 10> (
a: input logic<T>,
) -> logic<T> {
return a + 1;
}
let _a: logic<10> = FuncA::<>(1);
let _b: logic<20> = FuncA::<20>(1);
}
デフォルトパラメータはジェネリックパラメータリストの最後に置く必要があります。そうでなければ、どのパラメータが省略されたかが曖昧になるためです。
module ModuleA {
function FuncA::<T: u32, U: u32 = 1> (
a: input logic<T>,
) -> logic<T> {
return a + U;
}
// エラー
//function FuncA::<T: u32 = 1, U: u32> (
// a: input logic<T>,
//) -> logic<T> {
// return a + U;
//}
let _a: logic<10> = FuncA::<10>(1);
let _b: logic<20> = FuncA::<20, 2>(1);
}
プロトタイプ
プロトタイプは特別なジェネリック境界で、ジェネリックパラメータに渡せるプロトタイプを示します。現在はモジュールプロトタイプ、インターフェースプロトタイプ、パッケージプロトタイプがサポートされています。
モジュールプロトタイプ
以下の例では、ProtoA がパラメータ A とポート i_dat o_dat を持つモジュールプロトタイプです。T: ProtoA のように制約することで、ジェネリックパラメータ T がそれらのパラメータとポートを持つ必要があることが示されます。
プロトタイプを使うには for による実装が必要です。ModuleC と ModuleD は for ProtoA 指定により、 ProtoA の条件を満たすことが示されています。これにより、それらのモジュールは ModuleB の ジェネリックパラメータ T として使用できるようになります。
module ModuleA {
inst u0: ModuleB::<ModuleC>;
inst u1: ModuleB::<ModuleD>;
}
proto module ProtoA #(
param A: u32 = 1,
) (
i_dat: input logic,
o_dat: output logic,
);
module ModuleB::<T: ProtoA> {
inst u: T (
i_dat: 0,
o_dat: _,
);
}
module ModuleC for ProtoA #(
param A: u32 = 1,
) (
i_dat: input logic,
o_dat: output logic,
) {
assign o_dat = i_dat;
}
module ModuleD for ProtoA #(
param A: u32 = 1,
) (
i_dat: input logic,
o_dat: output logic,
) {
assign o_dat = ~i_dat;
}
インターフェースプロトタイプ
以下の例では、ProtoA が定数 A と変数 raedy/valid/data、関数 ack、modport masterを持つインターフェースプロトタイプです。BUS_IF は ProtoA で制約されているので、それらのメンバーを持つことが保証されており、参照することができます。
proto interface ProtoA {
const WIDTH: u32;
var ready: logic ;
var valid: logic ;
var data : logic<WIDTH>;
function ack() -> logic ;
modport master {
ready: input ,
valid: output,
data : output,
ack : import,
}
}
interface InterfaceA::<W: u32> for ProtoA {
const WIDTH: u32 = W;
var ready: logic ;
var valid: logic ;
var data : logic<WIDTH>;
function ack () -> logic {
return ready && valid;
}
modport master {
ready: input ,
valid: output,
data : output,
ack : import,
}
}
module ModuleA::<BUS_IF: ProtoA> (
bus_if: modport BUS_IF::master,
) {
connect bus_if <> 0;
}
module ModuleB {
inst bus_if: InterfaceA::<8>;
inst u: ModuleA::<InterfaceA::<8>> (
bus_if: bus_if,
);
}
パッケージプロトタイプ
以下の例では、ProtoA が型 data_a と型 data_b を持つパッケージプロトタイプです。PKG は ProtoA で制約されているので、data_a と data_b を持つことが保証されており、それらを参照することができます。
proto package ProtoA {
type data_a;
type data_b;
}
package PackageA::<A: u32, B: u32> for ProtoA {
type data_a = logic<A>;
type data_b = logic<B>;
}
module ModuleA::<PKG: ProtoA> {
let _a: PKG::data_a = 0;
}
プロトタイプの要素
以下の要素はモジュール、インターフェース、パッケージのプロトタイプ内で宣言することができます。
テーブルにどのプロトタイプがどの要素を持てるかをまとめます。
| プロトタイプ | パラメータ | ポート | 定数 | 変数 | 型定義 | 構造体/列挙型/ユニオン | 関数 | エイリアス | modport |
|---|---|---|---|---|---|---|---|---|---|
| モジュール | v | v | |||||||
| インターフェース | v | v | v | v | v | v | |||
| パッケージ | v | v | v | v | v |
パラメータ
パラメータプロトタイプは識別子とデータ型を指定します。デフォルト値の指定は省略できます。
proto module ModuleA #(
param A: u32 = 0,
param B: u32,
);
ポート
ポートプロトタイプは識別子と方向、データ型を指定します。
proto module ModuleA (
i_d: input logic,
o_d: output logic,
);
定数
定数プロトタイプは識別子とデータ型を指定します。ジェネリックなパラメータのプレースホルダとして使用できます。
proto package ProtoPkg {
const WIDTH: u32;
}
package PkgA::<W: u32> for ProtoPkg {
const WIDTH: u32 = W;
}
変数
変数プロトタイプは識別子とデータ型を指定します。これらは var 及び let 宣言で使用することができます。
proto interface ProtoA {
var a: logic;
var b: logic;
}
interface InterfaceA for ProtoA {
var a: logic;
let b: lgoic = 0;
}
型定義
Typedefプロトタイプは型エイリアスの識別子を指定します。ジェネリックなパラメータのプレースホルダとして使用できます。
proto package ProtoPkg {
type data_t;
}
package PkgA::<W: u32> for ProtoPkg {
type data_t = logic<W>;
}
さらに、typedefプロトタイプは右辺に実際の型を指定することができます。これにより他のパッケージで定義された型をそのプロトタイプパッケージに導入し、他のコンポーネントから参照することができます。
package FooPkg {
struct Foo {
foo: logic,
}
}
proto package BarProtoPkg {
type Foo = FooPkg::Foo;
}
package BarPkg for BarProtoPkg {
type Foo = FooPkg::Foo;
}
module ModuleA::<PKG: BarProtoPkg> {
var _foo : PKG::Foo;
assign _foo.foo = 0;
}
module ModuleB {
inst u: ModuleA::<BarPkg>;
}
構造体/列挙型/ユニオン
構造体、列挙型、ユニオンプロトタイプは型の識別子と各メンバーの識別子、データ型を指定します。
proto package ProtoPkg {
struct Foo {
a: logic,
b: logic,
}
enum Bar {
C,
D,
}
union Baz {
e: logic,
f: logic,
}
}
関数
関数プロトタイプは識別子と戻り値のデータ型、引数の方向とデータ型を指定します。
proto package ProtoPkg {
function foo (a: input logic, b: input logic) -> logic;
}
モジュール/インターフェース/パッケージ エイリアス
モジュール、インターフェース、パッケージのエイリアス プロトタイプは識別子とモジュール、インターフェース、パッケージのプロトタイプを指定します。そのエイリアスの実際の型は与えられたプロトタイプに制約されます。
proto module ProtoRamWrapper;
proto package ProtoPkg {
alias module ram: ProtoRamWrapper;
}
package Pkg::<RAM: ProtoRamWrapper> for ProtoPkg {
alias module ram = RAM;
}
module RamWrapper for ProtoRamWrapper {}
module top {
inst u_ram: Pkg::<RamWrapper>::ram;
}
modport
modport プロトタイプはmodport の識別子と各メンバーの識別子と方向を指定します。
proto interface ProtoA {
var a: logic;
var b: logic;
modport mp {
a: input ,
b: output,
}
}
クロックドメインアノテーション
モジュール内に複数のクロックがある場合、'a のような明示的なクロックドメインアノテーションが必要です。アノテーションはそれぞれの信号がどのクロックドメインに所属するかを示します。
module ModuleA (
// クロックドメイン 'a に所属
i_clk_a: input 'a clock,
i_dat_a: input 'a logic,
o_dat_a: output 'a logic,
// クロックドメイン 'b に所属
i_clk_b: input 'b clock,
i_dat_b: input 'b logic,
o_dat_b: output 'b logic,
) {
// 同じクロックドメイン内の代入は安全
assign o_dat_a = i_dat_a;
assign o_dat_b = i_dat_b;
}
モジュール内にクロックが1つしかない場合、アノテーションは省略できます。
module ModuleA (
i_clk: input clock,
i_dat: input logic,
o_dat: output logic,
) {
assign o_dat = i_dat;
}
'_ は暗黙のクロックドメインを表す特別なクロックドメインです。これは複数のクロックが同じ暗黙のクロックドメインに所属することを示すために使用できます。
module ModuleA (
// 全ての信号は暗黙のクロックドメインに所属
i_clk : input '_ clock,
i_clk_x2: input '_ clock,
i_dat : input logic,
o_dat : output logic,
) {
assign o_dat = i_dat;
}
インターフェースインスタンスもクロックドメインアノテーションを指定可能です。
module ModuleA {
inst intf: 'a InterfaceA;
}
interface InterfaceA {}
Unsafe CDC
Veryl コンパイラはクロックドメインクロッシングをエラーとして検出します。そのためクロックドメインクロッシングを行う場所には明示的な unsafe (cdc) ブロックが必要です。ブロック内ではクロックドメインクロッシングのチェックが抑制されるため、設計者はそれが安全かどうか注意深く確認する必要があります。
module ModuleA (
i_clk_a: input 'a clock,
i_dat_a: input 'a logic,
i_clk_b: input 'b clock,
o_dat_b: output 'b logic,
) {
// エラー "Clock domain crossing is detected"
//assign o_dat_b = i_dat_a;
unsafe (cdc) {
assign o_dat_b = i_dat_a;
}
}
クロックドメイン境界には通常シンクロナイザセルが挿入されます。この場合も unsafe (cdc) ブロックが必要です。
module ModuleA (
i_clk_a: input 'a clock,
i_dat_a: input 'a logic,
i_clk_b: input 'b clock,
o_dat_b: output 'b logic,
) {
unsafe (cdc) {
inst u_sync: $sv::SynchronizerCell (
i_clk: i_clk_b,
i_dat: i_dat_a,
o_dat: o_dat_b,
);
}
}
標準ライブラリ
Verylはいくつかの便利な汎用モジュールを標準ライブラリとして提供しています。標準ライブラリは $std 名前空間にあり、依存関係を追加することなく使用できます。
標準ライブラリの公開APIは Veryl 1.0 がリリースされるまでは変更される可能性があります。
module ModuleA {
// $std::fifo は標準ライブラリの FIFO モジュール
inst u: $std::fifo (
i_clk : _,
i_rst : _,
i_clear : _,
o_empty : _,
o_almost_full: _,
o_full : _,
o_word_count : _,
i_push : _,
i_data : _,
i_pop : _,
o_data : _,
);
}
標準ライブラリの完全なリストとドキュメントは https://std.veryl-lang.org にあります。
エイリアス
ジェネリック引数を持つモジュール、インターフェース、パッケージの名前は非常に長くなる場合があります。alias はそのような要素に短い名前をつけることができます。
package PkgA::<X: u32, Y: u32, Z: u32> {}
alias package PkgA123 = PkgA::<1, 2, 3>;
開発環境
この章ではプロジェクト設定や開発ツールなど開発環境について説明します。
プロジェクト設定
[project]— プロジェクト定義name— プロジェクトの名前version— プロジェクトのバージョンauthors— プロジェクトの作者description— プロジェクトの説明license— プロジェクトのライセンスrepository— プロジェクトのリポジトリの URL
[build]— ビルド設定[format]— フォーマット設定[lint]— リント設定[test]— テスト設定[publish]— 公開設定[dependencies]— ライブラリの依存関係
[project] セクション
Veryl.toml の最初のセクションは [project] です。name と version は必須です。
name フィールド
プロジェクト名は生成されるコードのプレフィックスに使われます。そのためプロジェクト名はアルファベットか _ で始まり、英数字と_ しか使ってはいけません。
version フィールド
プロジェクトのバージョンは セマンティックバージョニングに従います。バージョンは以下の3つの数字からなります。
- メジャー – 互換性のない変更時に上げる
- マイナー – 互換性のある機能追加時に上げる
- バッチ – 互換性のあるバグ修正時に上げる
[project]
version = "0.1.0"
authors フィールド
オプションの authors フィールドにはこのプロジェクトの作者である人や組織を配列にリストアップします。配列内の各文字列のフォーマットは自由です。名前のみ、Eメールアドレスのみ、名前と括弧で囲んだEメールアドレスといった形式がよく使われます。
[project]
authors = ["Fnu Lnu", "anonymous@example.com", "Fnu Lnu <anonymous@example.com>"]
description フィールド
description はプロジェクトの短い説明です。マークダウンではなくプレーンテキスト形式で書きます。
license フィールド
license フィールドはこのプロジェクトがどのライセンスで公開されているかを指定します。指定する文字列はSPDX 2.3 license expressionに従ってください。
[project]
license = "MIT OR Apache-2.0"
repository フィールド
repository フィールドはプロジェクトのソースリポジトリへのURLです。
[project]
repository = "https://github.com/veryl-lang/veryl"
[build] セクション
[build] セクションはコード生成の設定です。詳細はこちら。
[format] セクション
[format] セクションはコードフォーマッターの設定です。詳細はこちら。
[lint] セクション
[lint] セクションはリンタの設定です。詳細はこちら。
[test] セクション
[test] セクションはRTLシミュレータによるテストの設定です。詳細はこちら。
[publish] セクション
[publish] セクションはプロジェクト公開の設定です。詳細はこちら。
[dependencies] セクション
[dependencies] セクションはライブラリの依存関係です。詳細はこちら。
Build
[build] セクションはコード生成の設定です。
clock_type フィールド
clock_type フィールドはフリップフロップを駆動するクロックエッジを指定します。
posedge– 立ち上がりエッジnegedge– 立ち下がりエッジ
reset_type フィールド
reset_type フィールドはリセットの極性と同期性を指定します。
async_low– 非同期・負極性async_high– 非同期・正極性sync_low– 同期・負極性sync_high– 同期・正極性
filelist_type フィールド
filelist_type フィールドはファイルリストのフォーマットを指定します。
absolute– プレーンテキスト形式の絶対パスのリストrelative– プレーンテキスト形式の相対パスのリストflgen– flgen 形式のファイルリスト
sources フィールド
デフォルトではVerylコンパイラはプロジェクトルートから見える全ての *.veryl ファイルを処理します。特定のディレクトリだけを処理するために sources フィールドを使用することができます。
[build]
sources = ["rtl/foo_module", "rtl/bar_module"]
上記の例では、Verylコンパイラは rtl/foo_module と rtl/bar_module の*.veryl ファイルを処理します。
target フィールド
target フィールドはコードの生成先を指定します。
source– ソースコードと同じディレクトリdirectory– 特定のディレクトリbundle– 特定のファイル
directory あるいは bundle を指定する場合は、ターゲットパスを path キーで指定します。
[build]
target = {type = "directory", path = "[dst dir]"}
implicit_parameter_types フィールド
implicit_parameter_types フィールドは生成コードの parameter 宣言で省略する型をリストアップします。いくつかのEDAツールでは特定の型(例えば string)を parameter 宣言で使うことができないためです。例えば string を指定する場合は以下のようにします。
[build]
implicit_parameter_types = ["string"]
omit_project_prefix フィールド
omit_project_prefix が true のとき、モジュール・インターフェース・パッケージ名のプロジェクトプレフィックスは省略されます。この値はデフォルトで false です。
[build]
omit_project_prefix = true
strip_comments フィールド
strip_comments が true のとき、コメント出力は省略されます。この値はデフォルトで false です。
[build]
strip_comments = true
*_prefix と *_suffix フィールド
*_prefix と *_suffix はコード生成時の追加のプレフィックスとサフィックスを指定します。指定可能な設定は以下の通りです。
clock_posedge_prefix:clock_type = posedgeのときのclock型のプレフィックスclock_posedge_suffix:clock_type = posedgeのときのclock型のサフィックスclock_negedge_prefix:clock_type = negedgeのときのclock型のプレフィックスclock_negedge_suffix:clock_type = negedgeのときのclock型のサフィックスreset_high_prefix:reset_type = *_highのときのreset型のプレフィックスreset_high_suffix:reset_type = *_highのときのreset型のサフィックスreset_low_prefix:reset_type = *_lowのときのreset型のプレフィックスreset_low_suffix:reset_type = *_lowのときのreset型のサフィックス
sourcemap_target フィールド
sourcemap_target フィールドはソースマップの生成先を指定します。指定可能な設定は以下の通りです。
target– ターゲットコードと同じディレクトリdirectory– 特定のディレクトリnone– ソースマップなし
directory を指定する場合は、ターゲットパスを path キーで指定します。
[build]
sourcemap_target = {type = "directory", path = "[dst dir]"}
expand_inside_operation フィールド
expand_inside_operation が true のとき、inside 演算子を使った演算は==? 演算子を使った論理に展開されます。これはいくつかのEDAツールがinside 演算子をサポートしていないためです。この値はデフォルトで false です。
[build]
expand_inside_operation = true
hashed_mangled_name フィールド
hashed_mangled_name が true のとき、出力されるコンポーネント名のうちジェネリック引数を示す部分がハッシュ化されます。この設定はジェネリック引数が多いときにマングリングされた名前が長くなりすぎるのを防ぎます。この値はデフォルトで false です。
[build]
hashed_mangled_name = true
例:
- ハッシュ化されていない名前:
prj___PkgA__0__1__2__3 - ハッシュ化された名前:
prj___PkgA__3894375d1deadabb
flatten_array_interface フィールド
flatten_array_interface が true のとき、多次元の配列インスタンスやmodportは1次元に展開されます。この設定は多次元配列をサポートしていないEDAツールをサポートするためのものです。この値はデフォルトで false です。
[build]
flatten_array_interface = true
例:
Veryl コード
module ModuleA (
a_if: modport InterfaceA::mp [2, 3],
) {
for i in 0..2 :g {
for j in 0..3 :g {
assign a_if[i][j].a = 0;
}
}
}
flatten_array_interface = true で生成された SystemVerilog コード
module veryl_testcase_ModuleA (
veryl_testcase_InterfaceA.mp a_if [0:(2)*(3)-1]
);
for (genvar i = 0; i < 2; i++) begin :g
for (genvar j = 0; j < 3; j++) begin :g
always_comb a_if[(i)*(3)+(j)].a = 0;
end
end
endmodule
exclude_std フィールド
exclude_std が true のとき、標準ライブラリはインクルードされません。
[build]
exclude_std = true
emit_cond_type フィールド
emit_cond_type が true のとき、unique unique0 priority といった指定が出力されます。
[build]
emit_cond_type = true
instance_depth_limit フィールド
instance_depth_limit はインスタンス階層の最大深さです。デフォルト値は 128 です。
[build]
instance_depth_limit = 256
instance_total_limi フィールド
instance_total_limit は1つのモジュール内のサブインスタンスの最大数です。デフォルト値は 1048576 です。
[build]
instance_total_limit = 256
incremental フィールド
incremental が true のとき、Verylコンパイラは更新されたファイルに関連したファイルのみを再生成します。デフォルト値は false です。
[build]
incremental = true
error_count_limit フィールド
表示するエラーメッセージの最大数を指定します。全てのメッセージを表示するにはフィールドを設定しないか、0を指定します。
[build]
error_count_limit = 10
Format
[format] セクションはフォーマッタの設定です。
[format]
indent_width = 4
設定
| 設定 | 設定値 | 説明 |
|---|---|---|
| indent_width | 整数 | インデントのスペース幅 |
Lint
[lint] セクションはリンターの設定です。
[lint.naming]
case_enum = "snake"
設定
[lint.naming] セクション
このセクションは命名規則の設定です。
| 設定 | 設定値 | 説明 |
|---|---|---|
| case_enum | ケースタイプ1 | enum のケーススタイル |
| case_function | ケースタイプ1 | function のケーススタイル |
| case_function_inout | ケースタイプ1 | inout 引数のケーススタイル |
| case_function_input | ケースタイプ1 | input 引数のケーススタイル |
| case_function_output | ケースタイプ1 | output 引数のケーススタイル |
| case_instance | ケースタイプ1 | インスタンスのケーススタイル |
| case_interface | ケースタイプ1 | interface のケーススタイル |
| case_modport | ケースタイプ1 | modport のケーススタイル |
| case_module | ケースタイプ1 | module のケーススタイル |
| case_package | ケースタイプ1 | package のケーススタイル |
| case_parameter | ケースタイプ1 | parameter のケーススタイル |
| case_port_inout | ケースタイプ1 | inout ポートのケーススタイル |
| case_port_input | ケースタイプ1 | input ポートのケーススタイル |
| case_port_modport | ケースタイプ1 | modport ポートのケーススタイル |
| case_port_output | ケースタイプ1 | output ポートのケーススタイル |
| case_reg | ケースタイプ1 | レジスタ変数2のケーススタイル |
| case_struct | ケースタイプ1 | struct のケーススタイル |
| case_union | ケースタイプ1 | union のケーススタイル |
| case_var | ケースタイプ1 | 変数のケーススタイル |
| case_wire | ケースタイプ1 | ワイヤ変数3のケーススタイル |
| prefix_enum | 文字列 | enum のプレフィックス |
| prefix_function | 文字列 | function のプレフィックス |
| prefix_function_inout | 文字列 | inout 引数のプレフィックス |
| prefix_function_input | 文字列 | input 引数のプレフィックス |
| prefix_function_output | 文字列 | output 引数のプレフィックス |
| prefix_instance | 文字列 | インスタンスのプレフィックス |
| prefix_interface | 文字列 | interface のプレフィックス |
| prefix_modport | 文字列 | modport のプレフィックス |
| prefix_module | 文字列 | module のプレフィックス |
| prefix_package | 文字列 | package のプレフィックス |
| prefix_parameter | 文字列 | parameter のプレフィックス |
| prefix_port_inout | 文字列 | inout ポートのプレフィックス |
| prefix_port_input | 文字列 | input ポートのプレフィックス |
| prefix_port_modport | 文字列 | modport ポートのプレフィックス |
| prefix_port_output | 文字列 | output ポートのプレフィックス |
| prefix_reg | 文字列 | レジスタ変数2のプレフィックス |
| prefix_struct | 文字列 | struct のプレフィックス |
| prefix_union | 文字列 | union のプレフィックス |
| prefix_var | 文字列 | 変数のプレフィックス |
| prefix_wire | 文字列 | ワイヤ変数3のプレフィックス |
| suffix_enum | 文字列 | enum のサフィックス |
| suffix_function | 文字列 | function のサフィックス |
| suffix_function_inout | 文字列 | inout 引数のサフィックス |
| suffix_function_input | 文字列 | input 引数のサフィックス |
| suffix_function_output | 文字列 | output 引数のサフィックス |
| suffix_instance | 文字列 | インスタンスのサフィックス |
| suffix_interface | 文字列 | interface のサフィックス |
| suffix_modport | 文字列 | modport のサフィックス |
| suffix_module | 文字列 | module のサフィックス |
| suffix_package | 文字列 | package のサフィックス |
| suffix_parameter | 文字列 | parameter のサフィックス |
| suffix_port_inout | 文字列 | inout ポートのサフィックス |
| suffix_port_input | 文字列 | input ポートのサフィックス |
| suffix_port_modport | 文字列 | modport ポートのサフィックス |
| suffix_port_output | 文字列 | output ポートのサフィックス |
| suffix_reg | 文字列 | レジスタ変数2のサフィックス |
| suffix_struct | 文字列 | struct のサフィックス |
| suffix_union | 文字列 | union のサフィックス |
| suffix_var | 文字列 | 変数のサフィックス |
| suffix_wire | 文字列 | ワイヤ変数3のサフィックス |
| re_forbidden_enum | 正規表現4 | enum の禁止正規表現 |
| re_forbidden_function | 正規表現4 | function の禁止正規表現 |
| re_forbidden_function_inout | 正規表現4 | inout 引数の禁止正規表現 |
| re_forbidden_function_input | 正規表現4 | input 引数の禁止正規表現 |
| re_forbidden_function_output | 正規表現4 | output 引数の禁止正規表現 |
| re_forbidden_instance | 正規表現4 | インスタンスの禁止正規表現 |
| re_forbidden_interface | 正規表現4 | interface の禁止正規表現 |
| re_forbidden_modport | 正規表現4 | modport の禁止正規表現 |
| re_forbidden_module | 正規表現4 | module の禁止正規表現 |
| re_forbidden_package | 正規表現4 | package の禁止正規表現 |
| re_forbidden_parameter | 正規表現4 | parameter の禁止正規表現 |
| re_forbidden_port_inout | 正規表現4 | inout ポートの禁止正規表現 |
| re_forbidden_port_input | 正規表現4 | input ポートの禁止正規表現 |
| re_forbidden_port_modport | 正規表現4 | modport ポートの禁止正規表現 |
| re_forbidden_port_output | 正規表現4 | output ポートの禁止正規表現 |
| re_forbidden_reg | 正規表現4 | レジスタ変数2の禁止正規表現 |
| re_forbidden_struct | 正規表現4 | struct の禁止正規表現 |
| re_forbidden_union | 正規表現4 | union の禁止正規表現 |
| re_forbidden_var | 正規表現4 | 変数の禁止正規表現 |
| re_forbidden_wire | 正規表現4 | ワイヤ変数3の禁止正規表現 |
| re_required_enum | 正規表現4 | enum の必須正規表現 |
| re_required_function | 正規表現4 | function の必須正規表現 |
| re_required_function_inout | 正規表現4 | inout 引数の必須正規表現 |
| re_required_function_input | 正規表現4 | input 引数の必須正規表現 |
| re_required_function_output | 正規表現4 | output 引数の必須正規表現 |
| re_required_instance | 正規表現4 | インスタンスの必須正規表現 |
| re_required_interface | 正規表現4 | interface の必須正規表現 |
| re_required_modport | 正規表現4 | modport の必須正規表現 |
| re_required_module | 正規表現4 | module の必須正規表現 |
| re_required_package | 正規表現4 | package の必須正規表現 |
| re_required_parameter | 正規表現4 | parameter の必須正規表現 |
| re_required_port_inout | 正規表現4 | inout ポートの必須正規表現 |
| re_required_port_input | 正規表現4 | input ポートの必須正規表現 |
| re_required_port_modport | 正規表現4 | modport ポートの必須正規表現 |
| re_required_port_output | 正規表現4 | output ポートの必須正規表現 |
| re_required_reg | 正規表現4 | レジスタ変数2の必須正規表現 |
| re_required_struct | 正規表現4 | struct の必須正規表現 |
| re_required_union | 正規表現4 | union の必須正規表現 |
| re_required_var | 正規表現4 | 変数の必須正規表現 |
| re_required_wire | 正規表現4 | ワイヤ変数3の必須正規表現 |
"snake"– snake_case"screaming_snake"– SCREAMING_SNAKE_CASE"lower_camel"– lowerCamelCase"upper_camel"– UpperCamelCase
-
設定可能な値は以下です。 ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10 ↩11 ↩12 ↩13 ↩14 ↩15 ↩16 ↩17 ↩18 ↩19 ↩20
-
レジスタ変数とは
always_ffで代入される変数です。合成フェーズでフリップフロップにマップされます。 ↩ ↩2 ↩3 ↩4 ↩5 -
ワイヤ変数とは
always_combで代入される変数です。合成フェーズでワイヤにマップされます。 ↩ ↩2 ↩3 ↩4 ↩5 -
".*"のような正規表現です。使用可能な構文はこちら. ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10 ↩11 ↩12 ↩13 ↩14 ↩15 ↩16 ↩17 ↩18 ↩19 ↩20 ↩21 ↩22 ↩23 ↩24 ↩25 ↩26 ↩27 ↩28 ↩29 ↩30 ↩31 ↩32 ↩33 ↩34 ↩35 ↩36 ↩37 ↩38 ↩39 ↩40
Test
[test] セクションは以下のように組み込みユニットテストの設定を指定します。
[test]
simulator = "vcs"
設定
[test] セクション
simulator フィールド
simulator フィールドはデフォルトのシミュレータを指定します。以下のタイプを指定できます。
"verilator""vcs""vivado"
include_files フィールド
include_files フィールドはシミュレーションに使う追加のファイルを指定します。
[test]
include_files = ["test/mem.hex"]
waveform_target フィールド
waveform_target フィールドは波形の生成先を指定します。
target– ターゲットコードと同じディレクトリdirectory– 特定のディレクトリ
directory を指定する場合は、ターゲットパスを path キーで指定します。
[test]
waveform_target = {type = "directory", path = "[dst dir]"}
waveform_format フィールド
waveform_format フィールドはダンプされる波形のフォーマットを指定します。指定できる値は以下の通りです。
vcd– デフォルト値であり、多くのベンダーでサポートされていますが機能は限定的です。fst– 整数の代わりにenum値を表示するなどいくつかの機能をサポートしています。gtkwaveとsurferで扱うことができます。
[test.verilator] セクション
このセクションはVerilatorによるテストの設定です。
| 設定 | 設定値 | 説明 |
|---|---|---|
| compile_args | [文字列] | verilator コマンドへの追加の引数 |
| simulate_args | [文字列] | シミュレーションバイナリへの追加の引数 |
[test.vcs] セクション
このセクションはVCSによるテストの設定です。
| 設定 | 設定値 | 説明 |
|---|---|---|
| compile_args | [文字列] | vcs コマンドへの追加の引数 |
| simulate_args | [文字列] | シミュレーションバイナリへの追加の引数 |
[test.vivado] セクション
このセクションはVivadoによるテストの設定です。
| 設定 | 設定値 | 説明 |
|---|---|---|
| compile_args | [文字列] | xvlog コマンドへの追加の引数 |
| elaborate_args | [文字列] | xelab コマンドへの追加の引数 |
| simulate_args | [文字列] | xsim コマンドへの追加の引数 |
Publish
[publish] セクションは以下のようにプロジェクト公開の設定を指定します。
[publish]
bump_commit = true
bump_commit_message = "Bump"
設定
| 設定 | 設定値 | デフォルト | 説明 |
|---|---|---|---|
| bump_commit | ブーリアン | false | バージョンアップ後の自動コミット |
| publish_commit | ブーリアン | false | 公開後の自動コミット |
| bump_commit_mesasge | 文字列 | “chore: Bump version” | バージョンアップ後のコミットメッセージ |
| publish_commit_mesasge | 文字列 | “chore: Publish” | 公開後のコミットメッセージ |
依存関係
他の Veryl プロジェクトへの依存関係をプロジェクトに追加したい場合、Veryl.toml に [dependencies] セクションを追加します。エントリの左辺は依存関係のプロジェクト名、右辺はソースパスとバージョンです。github はGitHub上のリポジトリを参照する糖衣構文です。代わりに git を用いてURL全体を指定することもできます。
[dependencies]
veryl_sample = {github = "veryl-lang/veryl_sample", version = "0.1.0"}
# これは上記と同じ
veryl_sample = {git = "https://github.com/veryl-lang/veryl_sample", version = "0.1.0"}
デフォルトでは依存関係の名前空間はそのプロジェクト名と同じです。もし左辺の名前を変更した場合は、project フィールドでプロジェクト名を指定する必要があります。
[dependencies]
veryl_sample_alt = {github = "veryl-lang/veryl_sample", project = "veryl_sample", version = "0.2.0"}
リポジトリの内部プロジェクトは以下のように指定できます。
[dependencies]
inner_prj1 = {github = "veryl-lang/veryl_sample", version = "0.1.0"}
inner_prj2 = {github = "veryl-lang/veryl_sample", version = "0.1.0"}
inner_prj3 = {github = "veryl-lang/veryl_sample", version = "0.1.0"}
依存関係の使用
Veryl.toml に依存関係を追加したあとは、その依存関係の module、interface、packageを使うことができます。以下は veryl_sample の依存関係に含まれる delay モジュールを使った例です。
module ModuleA (
i_clk: input clock,
i_rst: input reset,
i_d : input logic,
o_d : output logic,
) {
inst u_delay: veryl_sample::delay (
i_clk,
i_rst,
i_d ,
o_d ,
);
}
注:上記のコードのプレイボタンの結果は依存関係解決を行わないので正確ではありません。実際のモジュール名は
veryl_sample_delayになります。
バージョン要求
[dependencies] セクションの version フィールドはバージョン要求を示します。例えば、version = "0.1.0" は 0.1.0 と互換性のある最新バージョンを意味します。互換性はセマンティックバージョニングで判定されます。バージョンは以下の3つの部分からなります。
メジャーバージョンはAPI非互換な変更マイナーバージョンは互換性のある機能追加パッチバージョンは互換性のあるバグ修正
もし メジャー バージョンが 0 なら、マイナー が非互換変更と解釈されます。
バージョン 0.1.0、0.1.1、0.2.0があった場合、0.1.1 が選択されます。これは以下のように決定されます。
0.1.0は0.1.0と互換性がある0.1.1は0.1.0と互換性がある0.2.0は0.1.0と互換性がない0.1.1は互換性のある最新バージョン
version フィールドは =0.1.0 のような指定も可能です。詳細は Rust のバージョン要求についてのドキュメントを参照してください。Specifying Dependencies.
相対パス依存関係
手元の環境で開発しているとき、ローカルファイルパスへの依存関係が使えると便利なことがあります。相対パス依存関係は以下のように指定することができます。
[dependencies]
veryl_sample = {path = "../../veryl_sample"}
プロジェクトに相対パス依存関係がある場合、そのプロジェクトは veryl publish で公開することはできません。
ローカルパスによる上書き
場合によってはローカルで変更されたバージョンの依存関係を使う必要があることもあります。そのような場合、以下のようにローカルパスによって依存関係を上書きすることができます。
[dependencies]
veryl_sample = {github = "veryl-lang/veryl_sample", version = "0.1.0", path = "../veryl_sample"}
これは ../veryl_sample が存在する場合はそれを使い、そうでない場合は Git から取得する、という意味です。
プロジェクトを公開する
プロジェクトを公開するには veryl publish コマンドを使います。公開とはバージョン番号とgitのリビジョンを紐づけることです。
$ veryl publish
[INFO ] Publishing release (0.2.1 @ 297bc6b24c5ceca9e648c3ea5e01011c67d7efe7)
[INFO ] Writing metadata ([path to project]/Veryl.pub)
veryl publish は以下のように公開されたバージョンの情報を含んだ Veryl.pub というファイルを生成します。
[[releases]]
version = "0.2.1"
revision = "297bc6b24c5ceca9e648c3ea5e01011c67d7efe7"
Veryl.pub と生成した後、gitのadd、commit、pushを行えば公開手続きは完了です。gitブランチはデフォルトブランチでなければなりません。これは Veryl が Veryl.pub をデフォルトブランチから探すためです。
$ git add Veryl.pub
$ git commit -m "Publish"
$ git push
Veryl.toml の [publish] セクションに publish_commit を設定して自動コミットを有効にすれば、gitのaddとcommitが自動で実行されます。
$ veryl publish
[INFO ] Publishing release (0.2.1 @ 297bc6b24c5ceca9e648c3ea5e01011c67d7efe7)
[INFO ] Writing metadata ([path to project]/Veryl.pub)
[INFO ] Committing metadata ([path to project]/Veryl.pub)
バージョンを上げる
--bump オプションを使うと公開と同時にバージョンを上げることもできます。公開と同様に、Veryl.toml の[publish] セクションに bump_commit を設定すれば自動でcommitされます。
$ veryl publish --bump patch
[INFO ] Bumping version (0.2.1 -> 0.2.2)
[INFO ] Updating version field ([path to project]/Veryl.toml)
[INFO ] Committing metadata ([path to project]/Veryl.toml)
[INFO ] Publishing release (0.2.2 @ 159dee3b3f93d3a999d8bac4c6d26d51476b178a)
[INFO ] Writing metadata ([path to project]/Veryl.pub)
[INFO ] Committing metadata ([path to project]/Veryl.pub)
設定
全設定の説明はこちら。
ディレクトリ構成
Veryl は任意のディレクトリ構成をサポートしています。これは独立したプロジェクトと他のプロジェクトに組み込まれたプロジェクトでは最適なディレクトリ構成が異なるためです。
この節ではいくつかのディレクトリ構成パターンを示します。
単一のソースディレクトリ
このパターンでは全てのソースコードは src ディレクトリに配置されます。src 以下のサブディレクトリの構成は自由です。
$ tree
.
|-- src
| |-- module_a.veryl
| `-- module_b
| |-- module_b.veryl
| `-- module_c.veryl
`-- Veryl.toml
2 directories, 4 files
Veryl は全ての *.veryl ファイルを収集し、デフォルトではソースと同じディレクトリにコードを生成します。この挙動は以下の設定で明示することもできます。
[build]
target = "source"
veryl build を実行するとディレクトリ構成は以下のようになります。
$ tree
.
|-- dependencies
|-- prj.f
|-- src
| |-- module_a.sv
| |-- module_a.veryl
| `-- module_b
| |-- module_b.sv
| |-- module_b.veryl
| |-- module_c.sv
| `-- module_c.veryl
`-- Veryl.toml
3 directories, 8 files
単一のソースとターゲットディレクトリ
生成されたコードを1つのディレクトリに入れたい場合、Veryl.toml の [build] セクションで target を以下のように設定します。
[build]
target = {type = "directory", path = "target"}
ディレクトリ構成は以下のようになります。
$ tree
.
|-- dependencies
|-- prj.f
|-- src
| |-- module_a.veryl
| `-- module_b
| |-- module_b.veryl
| `-- module_c.veryl
|-- target
| |-- module_a.sv
| |-- module_b.sv
| `-- module_c.sv
`-- Veryl.toml
4 directories, 8 files
マルチソースディレクトリ
既存の SystemVerilog プロジェクトに Veryl のプロジェクトを組み込む場合、以下のような構成にすることもできます。
$ tree
.
|-- dependencies
|-- module_a
| |-- module_a.sv
| `-- module_a.veryl
|-- module_b
| |-- module_b.sv
| |-- module_b.veryl
| |-- module_c.sv
| `-- module_c.veryl
|-- prj.f
|-- sv_module_x
| `-- sv_module_x.sv
|-- sv_module_y
| `-- sv_module_y.sv
`-- Veryl.toml
5 directories, 10 files
生成された prj.f は生成されたソースコードを全てリストアップしているので、既存の SystemVerilog ファイルリストと一緒に使うことができます。
.gitignore について
Verylは以下の .gitignore をデフォルト値として提供します。.build ディレクトリはVerylコンパイラがビルド情報を記録するために使用します。
.build/
それ以外のパターンはプロジェクトに合わせて追加できます。.gitignore の候補としては以下が考えられます。
dependencies/target/*.sv*.f
フォーマッタ
veryl fmt コマンドでソースコードをフォーマットできます。あるいは言語サーバの textDocument/formatting 要求によるフォーマットにも対応しています。
全設定の説明はこちら。
リンタ
veryl check あるいは veryl build でリントチェックができます。あるいは言語サーバはリアルタイムでのチェックを行います。
全設定の説明はこちら。
シミュレータ
RTLシミュレータによるテストは veryl test で実行することができます。サポートされているシミュレータは以下の通りです。
Verilatorはデフォルトのシミュレータです。Veryl.tomlやコマンドラインオプションでシミュレータが指定されていない場合に使用されます。
全設定の説明はこちら。
cocotb
cocotb テストを実行するには cocotb がインストールされた python3 の環境が必要です。サポートされている cocotb のバージョンは 1.9.0 のみです。
例えば以下のコマンドでインストールすることができます。
$ pip3 install cocotb==1.9.0
シミュレータバックエンドとしては Verilator のみサポートされています。
言語サーバ
veryl-ls は言語サーバのバイナリです。使用するにはエディタの設定やプラグインが必要です。
設定可能な項目は以下の通りです。これは各エディタの設定から指定できます。
| 設定 | 設定値 | デフォルト | 説明 |
|---|---|---|---|
| useOperatorCompletion | ブーリアン | false | 演算子(例 ‘>:’, ‘>>’)の補完を有効にする |
互換性
いくつかのツールはサポートしていない SystemVerilog 構文があります。これをサポートするために、 Veryl.toml の設定でコード生成をカスタマイズすることができます。
Vivado
文字列パラメータ
Vivadoは string 型の parameter をサポートしていません。
parameter string a = "A";
その場合は implicit_parameter_types を設定してください。
[build]
implicit_parameter_types = ["string"]
設定すると生成コードは以下のようになります。
parameter a = "A";
Quartus
inside 演算子
Quartus は inside 演算子をサポートしていません。その場合は expand_inside_operation を設定してください。
[build]
expand_inside_operation = true
設定すると、 inside 演算子を使った演算は ==? 演算子を使った論理に展開されます。
ドキュメンテーション
プロジェクトのドキュメントは veryl doc コマンドで生成することができます。全てのパブリックなモジュールとインターフェース、パッケージがリストアップされます。(参照 可視性)
詳細な説明を書きたい場合はドキュメンテーションコメントを追加することもできます。ドキュメンテーションコメントではマークダウン記法を使えます。
以下のフォーマットもサポートされています。
それぞれの構文は wavedrom と mermaid コードブロック内で使用できます。
詳細な構文は以下を参照してください。
/// ModuleAの詳細説明
///
/// * リスト要素0
/// * リスト要素1
///
/// ```wavedrom
/// {signal: [
/// {name: 'clk', wave: 'p.....|...'},
/// {name: 'dat', wave: 'x.345x|=.x', data: ['head', 'body', 'tail', 'data']},
/// {name: 'req', wave: '0.1..0|1.0'},
/// {},
/// {name: 'ack', wave: '1.....|01.'}
///
/// ]}
/// ```
pub module ModuleA #(
/// データ幅
param ParamA: u32 = 1,
local ParamB: u32 = 1,
) (
i_clk : input clock , /// クロック
i_rst : input reset , /// リセット
i_data: input logic<ParamA>, /// データ入力
o_data: output logic<ParamA>, /// データ出力
) {
assign o_data = 0;
}
設定可能な項目は以下の通りです。これは Veryl.toml の [doc] セクションで指定できます。
[doc]
path = "document"
| 設定 | 設定値 | デフォルト | 説明 |
|---|---|---|---|
| path | 文字列 | “doc” | 出力ディレクトリへのパス |
GitHub Action
ビルド済みのVerylバイナリをダウンロードするための公式GitHub actionが提供されています。
https://github.com/marketplace/actions/setup-veryl
GitHub actionスクリプトの例は以下の通りです。
- フォーマットとビルドチェック
name: Check
on: [push, pull_request]
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: veryl-lang/setup-veryl@v1
- run: veryl fmt --check
- run: veryl check
- GitHub Pagesからドキュメントを公開する
name: Deploy
on: [push]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: veryl-lang/setup-veryl@v1
- run: veryl doc
- uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: doc
- Verilator によるテスト
このために GitHub action veryl-lang/setup-verilator を公開しています。
name: Test
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- uses: veryl-lang/setup-veryl@v1
- uses: veryl-lang/setup-verilator@v1
- run: veryl test --sim verilator
ソースマップ
ソースマップはSystemVerilogからVerylへ位置情報を追跡するために使用されるファイルです。このファイルによって、SystemVerilogのファイルパス・行・列をVeryl上の位置に変換することができます。
デフォルトではVerylは生成されたSystemVerilogと同じディレクトリに拡張子 .sv.map のソースマップを生成します。ソースマップの生成は Veryl.toml の sourcemap_target フィールドで制御することができます。
ソースマップの形式は Source Map Revision 3 に従います。生成されたコードとマップのリンク方法はJavaScriptのものとほとんど同じですが、相対パスのみが使われます。
//# sourceMappingURL=<relative path>
従って、上記のコメントがSystemVerilogファイルの末尾にあればソースマップが利用可能です。
sourcemap-resolver
sourcemap-resolver は Veryl コンパイラに同梱されており、任意のテキストファイルに以下のような注釈を付けることができます。
ERROR: [VRFC 10-4982] syntax error near 'endmodule' [/path/test.sv:23]
^-- /path/test.veryl:18:18
最初の行が元のテキストで、2行目が sourcemap-resolver により追加された行です。使用例は以下の通りです。
$ sourcemap-resolver test.log # annotate the existing log
$ [command] | sourcemap-resolver # on-the-fly annotation by pipe
verylup
verylup はVerylの公式ツールチェーンインストーラです。ツールチェーンの更新や切り替えを簡単に行うことができます。
ツールチェーンの更新
以下のコマンドはVerylツールチェーンとverylupを最新版に更新します。
verylup update
特定のツールチェーンをインストール
もし特定のバージョンのVerylを使用したい場合は、verylup install を使うことができます。
verylup install 0.12.0
インストール後、veryl コマンドで + によるバージョン指定が可能になります。
veryl +0.12.0 build
ディレクトリ毎のツールチェーンオーバーライド
もし特定にディレクトリで特定のバージョンのVerylを使用したい場合は、verylup override を使うことができます。
verylup override set 0.12.0
verylup override はVerylプロジェクト内の任意のディレクトリで実行できます。このコマンドを実行すると、そのプロジェクトのデフォルトのツールチェーンは 0.12.0 になります。
オフラインインストール
インターネットアクセスのない環境にインストールしたい場合は、オフラインインストールが利用できます。オフラインインストールの手順は以下の通りです。
- 最新のツールチェーンパッケージをVeryl リリースページからダウンロードする
- 以下のように
veryl setupを--pkg指定付きで実行する
verylup setup --offline --pkg veryl-x86_64-linux.zip
ツールチェーンの更新やインストールもセットアップと同様に --pkg 指定が必要です。
verylup update --pkg veryl-x86_64-linux.zip
verylup install 0.12.0 --pkg veryl-x86_64-linux.zip
プロキシ
Verylupはプロキシ設定として以下の環境変数を参照します。
HTTPS_PROXYhttps_proxyALL_PROXYall_proxy
プロキシのプロトコルとしては http と socks5 がサポートされています。
プロキシ設定
環境変数の代わりにverylupだけのプロキシ設定を指定することができます。
verylup config set proxy socks5://127.0.0.1:1086
ナイトリーチャンネル
最新の機能を簡単に試すために、ナイトリーチャンネルが利用できます。ナイトリーチャンネルはマスターブランチから毎日ビルドされます。
verylup install nightly
デフォルトではナイトリーチャンネルはインストールしても有効になりません。以下の方法で有効にすることができます。
// +nightly を使う
veryl +nightly build
// デフォルトをナイトリーにする
verylup default nightly
// 特定のプロジェクトをナイトリーで上書きする
verylup override set nightly
Veryl開発者向け
Veryl の開発者向けに、特別なツールチェーン local が用意されています。verylup install local をローカルのVerylリポジトリ上で実行すると、ビルドしたツールチェーンを local ツールチェーンとしてインストールします。local ツールチェーンが存在するときはデフォルトのツールチェーンになります。
// ローカルのVerylリポジトリでビルドしたツールチェーンをインストール
verylup install local
// ビルドしたツールチェーンを使う
veryl build
// 最新のツールチェーンを使う
veryl +latest build
新バージョンへの移行
Verylの新しいバージョンが破壊的な変更を伴うことがあります。veryl migrate は既存のプロジェクトを新バージョンに自動的に移行します。--check オプションによりどのような変更が適用されるか事前に確認することもできます。
$ veryl migrate --check
$ veryl migrate
veryl migrate は単一のメジャーバージョン(1.0まではマイナーバージョン)しか移行しません。複数のバージョンを移行するには以下のようにしてください。
$ veryl +0.15.0 migrate # from v0.14.0 to v0.15.0
$ veryl +0.16.0 migrate # from v0.15.0 to v0.16.0
Docker イメージ
公式のDockerイメージはDocker Hubを通して提供されています。
https://hub.docker.com/r/veryllang/veryl
イメージはカスタムイメージのベースや、GitLab CI/CDのために使うことができます。以下に使用例をいくつか示します。
docker コマンド
イメージを veryllang/veryl からプルできます。
$ docker pull veryllang/veryl
Dockerfile
Dockerイメージのベースとして使用する場合は、以下の FROM ディレクティブを使用できます。
FROM veryllang/veryl:latest
GitLab CI/CD
GitLab CI/CD のための .gitlab-ci.yml の例は以下になります。
image: "veryllang/veryl"
build:
stage: build
script:
- veryl build
fmt:
stage: build
script:
- veryl fmt --check
補遺
構文
Veryl のパーサはパーサジェネレータ parolを使っています。以下の parol の構文定義が正式な構文です。
%start Veryl
%title "Veryl grammar"
%comment "Empty grammar generated by `parol`"
%user_type VerylToken = crate::veryl_token::VerylToken
%user_type Token = crate::veryl_token::Token
%on HashLBracketTerm %push Attr
%on ColonColonLAngleTerm %push Generic
%on EscapedRBraceTerm %pop
%on EmbedTerm %enter EmbedHeader
%scanner EmbedHeader {
%on TripleLBraceTerm %enter EmbedBody
}
%scanner EmbedBody {
%auto_newline_off
%auto_ws_off
%on LBraceTerm %push EmbedBodyInner
%on EscapedLBraceTerm %push INITIAL
%on TripleRBraceTerm %enter INITIAL
}
%scanner EmbedBodyInner {
%auto_newline_off
%auto_ws_off
%on LBraceTerm %push EmbedBodyInner
%on EscapedLBraceTerm %push INITIAL
%on RBraceTerm %pop
}
%scanner Generic {
%on ColonColonLAngleTerm %push Generic
%on RAngleTerm %pop
}
%scanner Attr {
%on RBracketTerm %pop
}
%%
// ----------------------------------------------------------------------------
// Terminal
// ----------------------------------------------------------------------------
// Longest match should be first
CommentsTerm : <INITIAL, Generic, EmbedHeader, Attr>"(?:(?:(?://.*(?:\r\n|\r|\n)?)|(?:(?ms)/\*/?([^/]|[^*]/)*\*/))\s*)+" : Token;
StringLiteralTerm : <INITIAL, Generic, Attr>"\u{0022}(?:\\[\u{0022}\\/bfnrt]|u[0-9a-fA-F]{4}|[^\u{0022}\\\u0000-\u001F])*\u{0022}": Token;
ExponentTerm : <INITIAL, Generic >/[0-9]+(?:_[0-9]+)*\.[0-9]+(?:_[0-9]+)*[eE][+-]?[0-9]+(?:_[0-9]+)*/ : Token;
FixedPointTerm : <INITIAL, Generic >/[0-9]+(?:_[0-9]+)*\.[0-9]+(?:_[0-9]+)*/ : Token;
BasedTerm : <INITIAL, Generic >/(?:[0-9]+(?:_[0-9]+)*)?'s?[bodh][0-9a-fA-FxzXZ]+(?:_[0-9a-fA-FxzXZ]+)*/ : Token;
AllBitTerm : <INITIAL, Generic >/(?:[0-9]+(?:_[0-9]+)*)?'[01xzXZ]/ : Token;
BaseLessTerm : <INITIAL, Generic >/[0-9]+(?:_[0-9]+)*/ : Token;
MinusColonTerm : <INITIAL >'-:' : Token;
MinusGTTerm : <INITIAL >'->' : Token;
LTMinusTerm : <INITIAL >'<-' : Token;
PlusColonTerm : <INITIAL >'+:' : Token;
AssignmentOperatorTerm: <INITIAL >"\+=|-=|\*=|/=|%=|&=|\|=|\^=|<<=|>>=|<<<=|>>>=" : Token;
DiamondOperatorTerm : <INITIAL >'<>' : Token;
Operator12Term : <INITIAL >"\*\*" : Token;
Operator11Term : <INITIAL >"/|%" : Token;
Operator10Term : <INITIAL >"\+|-" : Token;
Operator09Term : <INITIAL >"<<<|>>>|<<|>>" : Token;
Operator08Term : <INITIAL >"<=|>=|<:|>:" : Token;
Operator07Term : <INITIAL >"===|==\?|!==|!=\?|==|!=" : Token;
Operator03Term : <INITIAL >"&&" : Token;
Operator02Term : <INITIAL >"\|\|" : Token;
Operator06Term : <INITIAL >"&" : Token;
Operator05Term : <INITIAL >"\^~|\^|~\^" : Token;
Operator04Term : <INITIAL >"\|" : Token;
UnaryOperatorTerm : <INITIAL >"~&|~\||!|~" : Token;
ColonColonLAngleTerm : <INITIAL, Generic >'::<' : Token;
ColonColonTerm : <INITIAL, Generic >'::' : Token;
ColonTerm : <INITIAL, Generic >':' : Token;
CommaTerm : <INITIAL, Generic, Attr>',' : Token;
DotDotEquTerm : <INITIAL, Generic >'..=' : Token;
DotDotTerm : <INITIAL, Generic >'..' : Token;
DotTerm : <INITIAL, Generic >'.' : Token;
EquTerm : <INITIAL, Generic >'=' : Token;
HashLBracketTerm : <INITIAL >'#[' : Token;
HashTerm : <INITIAL, Generic >'#' : Token;
LAngleTerm : <INITIAL, Generic >'<' : Token;
QuestionTerm : <INITIAL >'?' : Token;
QuoteLBraceTerm : <INITIAL, Generic >"'\{" : Token;
QuoteTerm : <INITIAL >"'" : Token;
EscapedLBraceTerm : < EmbedBody, EmbedBodyInner >'\{' : Token;
TripleLBraceTerm : < EmbedHeader >'{{{' : Token;
LBraceTerm : <INITIAL, Generic, EmbedBody, EmbedBodyInner, Attr>'{' : Token;
LBracketTerm : <INITIAL, Generic, Attr>'[' : Token;
LParenTerm : <INITIAL, Generic, EmbedHeader, Attr>'(' : Token;
RAngleTerm : <INITIAL, Generic >'>' : Token;
EscapedRBraceTerm : <INITIAL >'\}' : Token;
TripleRBraceTerm : < EmbedBody >'}}}' : Token;
RBraceTerm : <INITIAL, Generic, EmbedBodyInner, Attr>'}' : Token;
RBracketTerm : <INITIAL, Generic, Attr>']' : Token;
RParenTerm : <INITIAL, Generic, EmbedHeader, Attr>')' : Token;
SemicolonTerm : <INITIAL, Generic >';' : Token;
StarTerm : <INITIAL, Generic >'*' : Token;
// Keywords are reflected to syntax highlight definitions through highlightgen tool.
// Please refer support/highlightgen/README.md if you want to add a keyword.
AliasTerm : <INITIAL, Generic >'alias' : Token; // Keyword: Statement
AlwaysCombTerm : <INITIAL, Generic >'always_comb' : Token; // Keyword: Statement
AlwaysFfTerm : <INITIAL, Generic >'always_ff' : Token; // Keyword: Statement
AssignTerm : <INITIAL, Generic >'assign' : Token; // Keyword: Statement
AsTerm : <INITIAL, Generic >'as' : Token; // Keyword: Statement
BindTerm : <INITIAL, Generic >'bind' : Token; // Keyword: Statement
BitTerm : <INITIAL, Generic >'bit' : Token; // Keyword: Type
BoolTerm : <INITIAL, Generic >'bool' : Token; // Keyword: Type
CaseTerm : <INITIAL, Generic >'case' : Token; // Keyword: Conditional
ClockTerm : <INITIAL, Generic >'clock' : Token; // Keyword: Type
ClockPosedgeTerm : <INITIAL, Generic >'clock_posedge' : Token; // Keyword: Type
ClockNegedgeTerm : <INITIAL, Generic >'clock_negedge' : Token; // Keyword: Type
ConnectTerm : <INITIAL, Generic >'connect' : Token; // Keyword: Statement
ConstTerm : <INITIAL, Generic >'const' : Token; // Keyword: Statement
ConverseTerm : <INITIAL, Generic >'converse' : Token; // Keyword: Direction
DefaultTerm : <INITIAL, Generic >'default' : Token; // Keyword: Conditional
ElseTerm : <INITIAL, Generic >'else' : Token; // Keyword: Conditional
EmbedTerm : <INITIAL >'embed' : Token; // Keyword: Structure
EnumTerm : <INITIAL, Generic >'enum' : Token; // Keyword: Structure
F32Term : <INITIAL, Generic >'f32' : Token; // Keyword: Type
F64Term : <INITIAL, Generic >'f64' : Token; // Keyword: Type
FalseTerm : <INITIAL, Generic >'false' : Token; // Keyword: Literal
FinalTerm : <INITIAL, Generic >'final' : Token; // Keyword: Statement
ForTerm : <INITIAL, Generic >'for' : Token; // Keyword: Repeat
FunctionTerm : <INITIAL, Generic >'function' : Token; // Keyword: Structure
I8Term : <INITIAL, Generic >'i8' : Token; // Keyword: Type
I16Term : <INITIAL, Generic >'i16' : Token; // Keyword: Type
I32Term : <INITIAL, Generic >'i32' : Token; // Keyword: Type
I64Term : <INITIAL, Generic >'i64' : Token; // Keyword: Type
IfResetTerm : <INITIAL, Generic >'if_reset' : Token; // Keyword: Conditional
IfTerm : <INITIAL, Generic >'if' : Token; // Keyword: Conditional
ImportTerm : <INITIAL, Generic >'import' : Token; // Keyword: Statement
IncludeTerm : <INITIAL, Generic >'include' : Token; // Keyword: Structure
InitialTerm : <INITIAL, Generic >'initial' : Token; // Keyword: Statement
InoutTerm : <INITIAL, Generic >'inout' : Token; // Keyword: Direction
InputTerm : <INITIAL, Generic >'input' : Token; // Keyword: Direction
InsideTerm : <INITIAL, Generic >'inside' : Token; // Keyword: Conditional
InstTerm : <INITIAL, Generic >'inst' : Token; // Keyword: Statement
InterfaceTerm : <INITIAL, Generic >'interface' : Token; // Keyword: Structure
InTerm : <INITIAL, Generic >'in' : Token; // Keyword: Repeat
LetTerm : <INITIAL, Generic >'let' : Token; // Keyword: Statement
LogicTerm : <INITIAL, Generic >'logic' : Token; // Keyword: Type
LsbTerm : <INITIAL, Generic >'lsb' : Token; // Keyword: Literal
ModportTerm : <INITIAL, Generic >'modport' : Token; // Keyword: Structure
ModuleTerm : <INITIAL, Generic >'module' : Token; // Keyword: Structure
MsbTerm : <INITIAL, Generic >'msb' : Token; // Keyword: Literal
OutputTerm : <INITIAL, Generic >'output' : Token; // Keyword: Direction
OutsideTerm : <INITIAL, Generic >'outside' : Token; // Keyword: Conditional
PackageTerm : <INITIAL, Generic >'package' : Token; // Keyword: Structure
ParamTerm : <INITIAL, Generic >'param' : Token; // Keyword: Statement
ProtoTerm : <INITIAL, Generic >'proto' : Token; // Keyword: Structure
PubTerm : <INITIAL, Generic >'pub' : Token; // Keyword: Structure
RepeatTerm : <INITIAL, Generic >'repeat' : Token; // Keyword: Repeat
ResetTerm : <INITIAL, Generic >'reset' : Token; // Keyword: Type
ResetAsyncHighTerm : <INITIAL, Generic >'reset_async_high' : Token; // Keyword: Type
ResetAsyncLowTerm : <INITIAL, Generic >'reset_async_low' : Token; // Keyword: Type
ResetSyncHighTerm : <INITIAL, Generic >'reset_sync_high' : Token; // Keyword: Type
ResetSyncLowTerm : <INITIAL, Generic >'reset_sync_low' : Token; // Keyword: Type
ReturnTerm : <INITIAL, Generic >'return' : Token; // Keyword: Statement
RevTerm : <INITIAL, Generic >'rev' : Token; // Keyword: Repeat
BreakTerm : <INITIAL, Generic >'break' : Token; // Keyword: Statement
SameTerm : <INITIAL, Generic >'same' : Token; // Keyword: Direction
SignedTerm : <INITIAL, Generic >'signed' : Token; // Keyword: Type
StepTerm : <INITIAL, Generic >'step' : Token; // Keyword: Repeat
StringTerm : <INITIAL, Generic >'string' : Token; // Keyword: Type
StructTerm : <INITIAL, Generic >'struct' : Token; // Keyword: Structure
SwitchTerm : <INITIAL, Generic >'switch' : Token; // Keyword: Conditional
TriTerm : <INITIAL, Generic >'tri' : Token; // Keyword: Type
TrueTerm : <INITIAL, Generic >'true' : Token; // Keyword: Literal
TypeTerm : <INITIAL, Generic >'type' : Token; // Keyword: Statement
U8Term : <INITIAL, Generic >'u8' : Token; // Keyword: Type
U16Term : <INITIAL, Generic >'u16' : Token; // Keyword: Type
U32Term : <INITIAL, Generic >'u32' : Token; // Keyword: Type
U64Term : <INITIAL, Generic >'u64' : Token; // Keyword: Type
UnionTerm : <INITIAL, Generic >'union' : Token; // Keyword: Structure
UnsafeTerm : <INITIAL, Generic >'unsafe' : Token; // Keyword: Structure
VarTerm : <INITIAL, Generic >'var' : Token; // Keyword: Statement
DollarIdentifierTerm : <INITIAL, Generic >/\$[a-zA-Z_][0-9a-zA-Z_$]*/ : Token;
IdentifierTerm : <INITIAL, Generic, EmbedHeader, Attr>/(?:r#)?[a-zA-Z_][0-9a-zA-Z_$]*/ : Token;
AnyTerm : < EmbedBody, EmbedBodyInner >/(?:[^{}\\]|\\[^{])+/ : Token;
// ----------------------------------------------------------------------------
// Token
// ----------------------------------------------------------------------------
Comments: [ CommentsTerm ];
StartToken: Comments;
StringLiteralToken: StringLiteralTerm: Token Comments;
ExponentToken : ExponentTerm : Token Comments;
FixedPointToken: FixedPointTerm: Token Comments;
BasedToken : BasedTerm : Token Comments;
BaseLessToken : BaseLessTerm : Token Comments;
AllBitToken : AllBitTerm : Token Comments;
AssignmentOperatorToken: AssignmentOperatorTerm: Token Comments;
DiamondOperatorToken : DiamondOperatorTerm : Token Comments;
Operator02Token : Operator02Term : Token Comments;
Operator03Token : Operator03Term : Token Comments;
Operator04Token : Operator04Term : Token Comments;
Operator05Token : Operator05Term : Token Comments;
Operator06Token : Operator06Term : Token Comments;
Operator07Token : Operator07Term : Token Comments;
Operator08Token : Operator08Term : Token Comments;
Operator09Token : Operator09Term : Token Comments;
Operator10Token : Operator10Term : Token Comments;
Operator11Token : Operator11Term : Token Comments;
Operator12Token : Operator12Term : Token Comments;
UnaryOperatorToken : UnaryOperatorTerm : Token Comments;
ColonToken : ColonTerm : Token Comments;
ColonColonLAngleToken: ColonColonLAngleTerm: Token Comments;
ColonColonToken : ColonColonTerm : Token Comments;
CommaToken : CommaTerm : Token Comments;
DotDotToken : DotDotTerm : Token Comments;
DotDotEquToken : DotDotEquTerm : Token Comments;
DotToken : DotTerm : Token Comments;
EquToken : EquTerm : Token Comments;
HashLBracketToken : HashLBracketTerm : Token Comments;
HashToken : HashTerm : Token Comments;
QuestionToken : QuestionTerm : Token Comments;
QuoteLBraceToken : QuoteLBraceTerm : Token Comments;
QuoteToken : QuoteTerm : Token Comments;
LAngleToken : LAngleTerm : Token Comments;
EmbedLBraceToken : LBraceTerm : Token ;
EscapedLBraceToken : EscapedLBraceTerm : Token ;
TripleLBraceToken : TripleLBraceTerm : Token ;
LBraceToken : LBraceTerm : Token Comments;
LBracketToken : LBracketTerm : Token Comments;
LParenToken : LParenTerm : Token Comments;
LTMinusToken : LTMinusTerm : Token Comments;
MinusColonToken : MinusColonTerm : Token Comments;
MinusGTToken : MinusGTTerm : Token Comments;
PlusColonToken : PlusColonTerm : Token Comments;
RAngleToken : RAngleTerm : Token Comments;
EmbedRBraceToken : RBraceTerm : Token ;
EscapedRBraceToken : EscapedRBraceTerm : Token ;
TripleRBraceToken : TripleRBraceTerm : Token Comments;
RBraceToken : RBraceTerm : Token Comments;
RBracketToken : RBracketTerm : Token Comments;
RParenToken : RParenTerm : Token Comments;
SemicolonToken : SemicolonTerm : Token Comments;
StarToken : StarTerm : Token Comments;
AliasToken : AliasTerm : Token Comments;
AlwaysCombToken : AlwaysCombTerm : Token Comments;
AlwaysFfToken : AlwaysFfTerm : Token Comments;
AsToken : AsTerm : Token Comments;
AssignToken : AssignTerm : Token Comments;
BindToken : BindTerm : Token Comments;
BitToken : BitTerm : Token Comments;
BoolToken : BoolTerm : Token Comments;
CaseToken : CaseTerm : Token Comments;
ClockToken : ClockTerm : Token Comments;
ClockPosedgeToken : ClockPosedgeTerm : Token Comments;
ClockNegedgeToken : ClockNegedgeTerm : Token Comments;
ConnectToken : ConnectTerm : Token Comments;
ConstToken : ConstTerm : Token Comments;
ConverseToken : ConverseTerm : Token Comments;
DefaultToken : DefaultTerm : Token Comments;
ElseToken : ElseTerm : Token Comments;
EmbedToken : EmbedTerm : Token Comments;
EnumToken : EnumTerm : Token Comments;
F32Token : F32Term : Token Comments;
F64Token : F64Term : Token Comments;
FalseToken : FalseTerm : Token Comments;
FinalToken : FinalTerm : Token Comments;
ForToken : ForTerm : Token Comments;
FunctionToken : FunctionTerm : Token Comments;
I8Token : I8Term : Token Comments;
I16Token : I16Term : Token Comments;
I32Token : I32Term : Token Comments;
I64Token : I64Term : Token Comments;
IfResetToken : IfResetTerm : Token Comments;
IfToken : IfTerm : Token Comments;
ImportToken : ImportTerm : Token Comments;
IncludeToken : IncludeTerm : Token Comments;
InitialToken : InitialTerm : Token Comments;
InoutToken : InoutTerm : Token Comments;
InputToken : InputTerm : Token Comments;
InsideToken : InsideTerm : Token Comments;
InstToken : InstTerm : Token Comments;
InterfaceToken : InterfaceTerm : Token Comments;
InToken : InTerm : Token Comments;
LetToken : LetTerm : Token Comments;
LogicToken : LogicTerm : Token Comments;
LsbToken : LsbTerm : Token Comments;
ModportToken : ModportTerm : Token Comments;
ModuleToken : ModuleTerm : Token Comments;
MsbToken : MsbTerm : Token Comments;
OutputToken : OutputTerm : Token Comments;
OutsideToken : OutsideTerm : Token Comments;
PackageToken : PackageTerm : Token Comments;
ParamToken : ParamTerm : Token Comments;
ProtoToken : ProtoTerm : Token Comments;
PubToken : PubTerm : Token Comments;
RepeatToken : RepeatTerm : Token Comments;
ResetToken : ResetTerm : Token Comments;
ResetAsyncHighToken: ResetAsyncHighTerm: Token Comments;
ResetAsyncLowToken : ResetAsyncLowTerm : Token Comments;
ResetSyncHighToken : ResetSyncHighTerm : Token Comments;
ResetSyncLowToken : ResetSyncLowTerm : Token Comments;
ReturnToken : ReturnTerm : Token Comments;
RevToken : RevTerm : Token Comments;
BreakToken : BreakTerm : Token Comments;
SameToken : SameTerm : Token Comments;
SignedToken : SignedTerm : Token Comments;
StepToken : StepTerm : Token Comments;
StringToken : StringTerm : Token Comments;
StructToken : StructTerm : Token Comments;
SwitchToken : SwitchTerm : Token Comments;
TriToken : TriTerm : Token Comments;
TrueToken : TrueTerm : Token Comments;
TypeToken : TypeTerm : Token Comments;
U8Token : U8Term : Token Comments;
U16Token : U16Term : Token Comments;
U32Token : U32Term : Token Comments;
U64Token : U64Term : Token Comments;
UnionToken : UnionTerm : Token Comments;
UnsafeToken : UnsafeTerm : Token Comments;
VarToken : VarTerm : Token Comments;
DollarIdentifierToken: DollarIdentifierTerm: Token Comments;
IdentifierToken : IdentifierTerm : Token Comments;
AnyToken: AnyTerm: Token;
// ----------------------------------------------------------------------------
// VerylToken
// ----------------------------------------------------------------------------
// Start
Start: StartToken: VerylToken;
// StringLiteral
StringLiteral: StringLiteralToken: VerylToken;
// Number
Exponent : ExponentToken : VerylToken;
FixedPoint: FixedPointToken: VerylToken;
Based : BasedToken : VerylToken;
BaseLess : BaseLessToken : VerylToken;
AllBit : AllBitToken : VerylToken;
// Operator
AssignmentOperator: AssignmentOperatorToken: VerylToken;
DiamondOperator : DiamondOperatorToken : VerylToken;
Operator02 : Operator02Token : VerylToken;
Operator03 : Operator03Token : VerylToken;
Operator04 : Operator04Token : VerylToken;
Operator05 : Operator05Token : VerylToken;
Operator06 : Operator06Token : VerylToken;
Operator07 : Operator07Token : VerylToken;
Operator08 : Operator08Token : VerylToken;
Operator09 : Operator09Token : VerylToken;
Operator10 : Operator10Token : VerylToken;
Operator11 : Operator11Token : VerylToken;
Operator12 : Operator12Token : VerylToken;
UnaryOperator : UnaryOperatorToken : VerylToken;
// Symbol
Colon : ColonToken : VerylToken;
ColonColonLAngle: ColonColonLAngleToken: VerylToken;
ColonColon : ColonColonToken : VerylToken;
Comma : CommaToken : VerylToken;
DotDot : DotDotToken : VerylToken;
DotDotEqu : DotDotEquToken : VerylToken;
Dot : DotToken : VerylToken;
Equ : EquToken : VerylToken;
HashLBracket : HashLBracketToken : VerylToken;
Hash : HashToken : VerylToken;
Question : QuestionToken : VerylToken;
QuoteLBrace : QuoteLBraceToken : VerylToken;
Quote : QuoteToken : VerylToken;
LAngle : LAngleToken : VerylToken;
EmbedLBrace : EmbedLBraceToken : VerylToken;
EscapedLBrace : EscapedLBraceToken : VerylToken;
TripleLBrace : TripleLBraceToken : VerylToken;
LBrace : LBraceToken : VerylToken;
LBracket : LBracketToken : VerylToken;
LParen : LParenToken : VerylToken;
LTMinus : LTMinusToken : VerylToken;
MinusColon : MinusColonToken : VerylToken;
MinusGT : MinusGTToken : VerylToken;
PlusColon : PlusColonToken : VerylToken;
RAngle : RAngleToken : VerylToken;
EmbedRBrace : EmbedRBraceToken : VerylToken;
EscapedRBrace : EscapedRBraceToken : VerylToken;
TripleRBrace : TripleRBraceToken : VerylToken;
RBrace : RBraceToken : VerylToken;
RBracket : RBracketToken : VerylToken;
RParen : RParenToken : VerylToken;
Semicolon : SemicolonToken : VerylToken;
Star : StarToken : VerylToken;
// Keyword
Alias : AliasToken : VerylToken;
AlwaysComb : AlwaysCombToken : VerylToken;
AlwaysFf : AlwaysFfToken : VerylToken;
As : AsToken : VerylToken;
Assign : AssignToken : VerylToken;
Bind : BindToken : VerylToken;
Bit : BitToken : VerylToken;
Bool : BoolToken : VerylToken;
Break : BreakToken : VerylToken;
Case : CaseToken : VerylToken;
Clock : ClockToken : VerylToken;
ClockPosedge : ClockPosedgeToken : VerylToken;
ClockNegedge : ClockNegedgeToken : VerylToken;
Connect : ConnectToken : VerylToken;
Const : ConstToken : VerylToken;
Converse : ConverseToken : VerylToken;
Defaul : DefaultToken : VerylToken; // avoid to conflict with Rust's Default trait
Else : ElseToken : VerylToken;
Embed : EmbedToken : VerylToken;
Enum : EnumToken : VerylToken;
F32 : F32Token : VerylToken;
F64 : F64Token : VerylToken;
False : FalseToken : VerylToken;
Final : FinalToken : VerylToken;
For : ForToken : VerylToken;
Function : FunctionToken : VerylToken;
I8 : I8Token : VerylToken;
I16 : I16Token : VerylToken;
I32 : I32Token : VerylToken;
I64 : I64Token : VerylToken;
If : IfToken : VerylToken;
IfReset : IfResetToken : VerylToken;
Import : ImportToken : VerylToken;
In : InToken : VerylToken;
Include : IncludeToken : VerylToken;
Initial : InitialToken : VerylToken;
Inout : InoutToken : VerylToken;
Input : InputToken : VerylToken;
Inside : InsideToken : VerylToken;
Inst : InstToken : VerylToken;
Interface : InterfaceToken : VerylToken;
Let : LetToken : VerylToken;
Logic : LogicToken : VerylToken;
Lsb : LsbToken : VerylToken;
Modport : ModportToken : VerylToken;
Module : ModuleToken : VerylToken;
Msb : MsbToken : VerylToken;
Output : OutputToken : VerylToken;
Outside : OutsideToken : VerylToken;
Package : PackageToken : VerylToken;
Param : ParamToken : VerylToken;
Proto : ProtoToken : VerylToken;
Pub : PubToken : VerylToken;
Repeat : RepeatToken : VerylToken;
Reset : ResetToken : VerylToken;
ResetAsyncHigh: ResetAsyncHighToken: VerylToken;
ResetAsyncLow : ResetAsyncLowToken : VerylToken;
ResetSyncHigh : ResetSyncHighToken : VerylToken;
ResetSyncLow : ResetSyncLowToken : VerylToken;
Return : ReturnToken : VerylToken;
Rev : RevToken : VerylToken;
Same : SameToken : VerylToken;
Signed : SignedToken : VerylToken;
Step : StepToken : VerylToken;
Strin : StringToken : VerylToken; // avoid to conflict with Rust's String struct
Struct : StructToken : VerylToken;
Switch : SwitchToken : VerylToken;
Tri : TriToken : VerylToken;
True : TrueToken : VerylToken;
Type : TypeToken : VerylToken;
U8 : U8Token : VerylToken;
U16 : U16Token : VerylToken;
U32 : U32Token : VerylToken;
U64 : U64Token : VerylToken;
Union : UnionToken : VerylToken;
Unsafe : UnsafeToken : VerylToken;
Var : VarToken : VerylToken;
// Identifier
DollarIdentifier: DollarIdentifierToken: VerylToken;
Identifier : IdentifierToken : VerylToken;
Any: AnyToken: VerylToken;
// ----------------------------------------------------------------------------
// Number
// ----------------------------------------------------------------------------
Number: IntegralNumber
| RealNumber
;
IntegralNumber: Based
| BaseLess
| AllBit
;
RealNumber: FixedPoint
| Exponent
;
// ----------------------------------------------------------------------------
// Complex Identifier
// ----------------------------------------------------------------------------
HierarchicalIdentifier: Identifier { Select } { Dot Identifier { Select } };
ScopedIdentifier : ( DollarIdentifier | Identifier [ WithGenericArgument ] ) { ColonColon Identifier [ WithGenericArgument ] };
ExpressionIdentifier : ScopedIdentifier [ Width ] { Select } { Dot Identifier { Select } };
// ----------------------------------------------------------------------------
// Expression
// ----------------------------------------------------------------------------
Expression : IfExpression;
IfExpression: { If Expression Question Expression Colon } Expression01;
Expression01: Expression02 { Operator02 Expression02 };
Expression02: Expression03 { Operator03 Expression03 };
Expression03: Expression04 { Operator04 Expression04 };
Expression04: Expression05 { Operator05 Expression05 };
Expression05: Expression06 { Operator06 Expression06 };
Expression06: Expression07 { Operator07 Expression07 };
Expression07: Expression08 { Operator08 Expression08 };
Expression08: Expression09 { Operator09 Expression09 };
Expression09: Expression10 { Operator10 Expression10 };
Expression10: Expression11 { ( Operator11 | Star ) Expression11 };
Expression11: Expression12 { Operator12 Expression12 };
Expression12: Expression13 [ As CastingType ];
Expression13: { ( UnaryOperator | Operator10 | Operator06 | Operator04 | Operator05 ) } Factor;
Factor: Number
| BooleanLiteral
| IdentifierFactor
| LParen Expression RParen
| LBrace ConcatenationList RBrace
| QuoteLBrace ArrayLiteralList RBrace
| CaseExpression
| SwitchExpression
| StringLiteral
| ( Msb | Lsb )
| InsideExpression
| OutsideExpression
| TypeExpression
| FactorTypeFactor
;
BooleanLiteral: True | False;
IdentifierFactor: ExpressionIdentifier [ FunctionCall | StructConstructor ];
FactorTypeFactor: { TypeModifier } FactorType;
FunctionCall: LParen [ ArgumentList ] RParen;
ArgumentList: ArgumentItem { Comma ArgumentItem } [ Comma ];
ArgumentItem: ArgumentExpression [ Colon Expression ];
ArgumentExpression: Expression;
StructConstructor: QuoteLBrace StructConstructorList [ DotDot Defaul LParen Expression RParen ] RBrace;
StructConstructorList: StructConstructorItem { Comma StructConstructorItem } [ Comma ];
StructConstructorItem: Identifier Colon Expression;
ConcatenationList: ConcatenationItem { Comma ConcatenationItem } [ Comma ];
ConcatenationItem: Expression [ Repeat Expression ];
ArrayLiteralList: ArrayLiteralItem { Comma ArrayLiteralItem } [ Comma ];
ArrayLiteralItem: ( Expression [ Repeat Expression ] | Defaul Colon Expression );
CaseExpression: Case Expression LBrace CaseCondition Colon Expression Comma { CaseCondition Colon Expression Comma } Defaul Colon Expression [ Comma ] RBrace;
SwitchExpression: Switch LBrace SwitchCondition Colon Expression Comma { SwitchCondition Colon Expression Comma } Defaul Colon Expression [ Comma ] RBrace;
TypeExpression: Type LParen Expression RParen;
InsideExpression: Inside Expression LBrace RangeList RBrace;
OutsideExpression: Outside Expression LBrace RangeList RBrace;
RangeList: RangeItem { Comma RangeItem } [ Comma ];
RangeItem: Range;
// ----------------------------------------------------------------------------
// Select / Width / Array / Range
// ----------------------------------------------------------------------------
Select: LBracket Expression [ SelectOperator Expression ] RBracket;
SelectOperator: Colon
| PlusColon
| MinusColon
| Step
;
Width: LAngle Expression { Comma Expression } RAngle;
Array: LBracket Expression { Comma Expression } RBracket;
Range: Expression [ RangeOperator Expression ];
RangeOperator: DotDot
| DotDotEqu
;
// ----------------------------------------------------------------------------
// ScalarType / ArrayType / CastingType
// ----------------------------------------------------------------------------
FixedType: U8 | U16 | U32 | U64 | I8 | I16| I32 | I64 | F32 | F64 | Bool | Strin;
VariableType: Clock
| ClockPosedge
| ClockNegedge
| Reset
| ResetAsyncHigh
| ResetAsyncLow
| ResetSyncHigh
| ResetSyncLow
| Logic
| Bit;
UserDefinedType: ScopedIdentifier;
TypeModifier: Tri | Signed | Defaul;
FactorType: ( VariableType [ Width ] | FixedType );
ScalarType: { TypeModifier } ( UserDefinedType [ Width ] | FactorType );
ArrayType: ScalarType [ Array ];
CastingType: U8
| U16
| U32
| U64
| I8
| I16
| I32
| I64
| F32
| F64
| Bool
| Clock
| ClockPosedge
| ClockNegedge
| Reset
| ResetAsyncHigh
| ResetAsyncLow
| ResetSyncHigh
| ResetSyncLow
| UserDefinedType
| Based
| BaseLess
;
// ----------------------------------------------------------------------------
// ClockDomain
// ----------------------------------------------------------------------------
ClockDomain: Quote Identifier;
// ----------------------------------------------------------------------------
// Statement
// ----------------------------------------------------------------------------
StatementBlock: LBrace { StatementBlockGroup } RBrace;
StatementBlockGroup: { Attribute } ( LBrace { StatementBlockGroup } RBrace | StatementBlockItem );
StatementBlockItem: VarDeclaration | LetStatement | ConstDeclaration | Statement;
Statement: IdentifierStatement
| IfStatement
| IfResetStatement
| ReturnStatement
| BreakStatement
| ForStatement
| CaseStatement
| SwitchStatement
;
LetStatement: Let Identifier Colon [ ClockDomain ] ArrayType Equ Expression Semicolon;
IdentifierStatement: ExpressionIdentifier ( FunctionCall | Assignment ) Semicolon;
Assignment: ( Equ | AssignmentOperator | DiamondOperator ) Expression;
IfStatement: If Expression StatementBlock { Else If Expression StatementBlock } [ Else StatementBlock ];
IfResetStatement: IfReset StatementBlock { Else If Expression StatementBlock } [ Else StatementBlock ];
ReturnStatement: Return Expression Semicolon;
BreakStatement: Break Semicolon;
ForStatement: For Identifier Colon ScalarType In [ Rev ] Range [ Step AssignmentOperator Expression ] StatementBlock;
CaseStatement: Case Expression LBrace { CaseItem } RBrace;
CaseItem: ( CaseCondition | Defaul ) Colon ( Statement | StatementBlock );
CaseCondition: RangeItem { Comma RangeItem } ;
SwitchStatement: Switch LBrace { SwitchItem } RBrace;
SwitchItem: ( SwitchCondition | Defaul ) Colon ( Statement | StatementBlock );
SwitchCondition: Expression { Comma Expression } ;
// ----------------------------------------------------------------------------
// Attribute
// ----------------------------------------------------------------------------
Attribute: HashLBracket Identifier [ LParen AttributeList RParen ] RBracket ;
AttributeList: AttributeItem { Comma AttributeItem } [ Comma ];
AttributeItem: Identifier
| StringLiteral
;
// ----------------------------------------------------------------------------
// Declaration
// ----------------------------------------------------------------------------
LetDeclaration: Let Identifier Colon [ ClockDomain ] ArrayType Equ Expression Semicolon;
VarDeclaration: Var Identifier Colon [ ClockDomain ] ArrayType Semicolon;
ConstDeclaration: Const Identifier Colon ( ArrayType | Type ) Equ Expression Semicolon;
TypeDefDeclaration: Type Identifier Equ ArrayType Semicolon;
AlwaysFfDeclaration: AlwaysFf [ AlwaysFfEventList ] StatementBlock;
AlwaysFfEventList: LParen AlwaysFfClock [ Comma AlwaysFfReset ] RParen;
AlwaysFfClock: HierarchicalIdentifier;
AlwaysFfReset: HierarchicalIdentifier;
AlwaysCombDeclaration: AlwaysComb StatementBlock;
AssignDeclaration: Assign AssignDestination Equ Expression Semicolon;
AssignDestination: HierarchicalIdentifier
| LBrace AssignConcatenationList RBrace;
AssignConcatenationList: AssignConcatenationItem { Comma AssignConcatenationItem } [ Comma ];
AssignConcatenationItem: HierarchicalIdentifier;
ConnectDeclaration: Connect HierarchicalIdentifier DiamondOperator Expression Semicolon;
ModportDeclaration: Modport Identifier LBrace [ ModportList ] [ DotDot ModportDefault ] RBrace;
ModportList: ModportGroup { Comma ModportGroup } [ Comma ];
ModportGroup: { Attribute } ( LBrace ModportList RBrace | ModportItem );
ModportItem: Identifier Colon Direction;
ModportDefault: Input
| Output
| Same LParen Identifier RParen
| Converse LParen Identifier RParen;
EnumDeclaration: Enum Identifier [ Colon ScalarType ] LBrace EnumList RBrace;
EnumList: EnumGroup { Comma EnumGroup } [ Comma ];
EnumGroup: { Attribute } ( LBrace EnumList RBrace | EnumItem );
EnumItem: Identifier [ Equ Expression ];
StructUnion: Struct | Union;
StructUnionDeclaration: StructUnion Identifier [ WithGenericParameter ] LBrace StructUnionList RBrace;
StructUnionList: StructUnionGroup { Comma StructUnionGroup } [ Comma ];
StructUnionGroup: { Attribute } ( LBrace StructUnionList RBrace | StructUnionItem );
StructUnionItem: Identifier Colon ScalarType;
InitialDeclaration: Initial StatementBlock;
FinalDeclaration: Final StatementBlock;
// ----------------------------------------------------------------------------
// InstDeclaration/BindDeclaration
// ----------------------------------------------------------------------------
InstDeclaration: Inst ComponentInstantiation Semicolon;
BindDeclaration: Bind ScopedIdentifier LTMinus ComponentInstantiation Semicolon;
ComponentInstantiation: Identifier Colon [ ClockDomain ] ScopedIdentifier [ Array ] [ InstParameter ] [ InstPort ];
InstParameter: Hash LParen [ InstParameterList ] RParen;
InstParameterList: InstParameterGroup { Comma InstParameterGroup } [ Comma ];
InstParameterGroup: { Attribute } ( LBrace InstParameterList RBrace | InstParameterItem );
InstParameterItem: Identifier [ Colon Expression ];
InstPort: LParen [ InstPortList ] RParen;
InstPortList: InstPortGroup { Comma InstPortGroup } [ Comma ];
InstPortGroup: { Attribute } ( LBrace InstPortList RBrace | InstPortItem );
InstPortItem: Identifier [ Colon Expression ];
// ----------------------------------------------------------------------------
// WithParameter
// ----------------------------------------------------------------------------
WithParameter: Hash LParen [ WithParameterList ] RParen;
WithParameterList: WithParameterGroup { Comma WithParameterGroup } [ Comma ];
WithParameterGroup: { Attribute } ( LBrace WithParameterList RBrace | WithParameterItem );
WithParameterItem: ( Param | Const ) Identifier Colon ( ArrayType | Type ) [ Equ Expression ];
// ----------------------------------------------------------------------------
// WithGenericParameter
// ----------------------------------------------------------------------------
GenericBound: Type
| Inst ScopedIdentifier
| GenericProtoBound;
WithGenericParameter: ColonColonLAngle WithGenericParameterList RAngle;
WithGenericParameterList: WithGenericParameterItem { Comma WithGenericParameterItem } [ Comma ];
WithGenericParameterItem: Identifier Colon GenericBound [ Equ WithGenericArgumentItem ];
GenericProtoBound: ScopedIdentifier | FixedType;
// ----------------------------------------------------------------------------
// WithGenericArgument
// ----------------------------------------------------------------------------
WithGenericArgument: ColonColonLAngle [ WithGenericArgumentList ] RAngle;
WithGenericArgumentList: WithGenericArgumentItem { Comma WithGenericArgumentItem } [ Comma ];
WithGenericArgumentItem: ExpressionIdentifier
| FixedType
| Number
| BooleanLiteral
;
// ----------------------------------------------------------------------------
// PortDeclaration
// ----------------------------------------------------------------------------
PortDeclaration: LParen [ PortDeclarationList ] RParen;
PortDeclarationList: PortDeclarationGroup { Comma PortDeclarationGroup } [ Comma ];
PortDeclarationGroup: { Attribute } ( LBrace PortDeclarationList RBrace | PortDeclarationItem );
PortDeclarationItem: Identifier Colon ( PortTypeConcrete | PortTypeAbstract );
PortTypeConcrete: Direction [ ClockDomain ] ArrayType [ Equ PortDefaultValue ];
PortDefaultValue: Expression;
PortTypeAbstract: [ ClockDomain ] Interface [ ColonColon Identifier ] [ Array ];
Direction: Input
| Output
| Inout
| Modport
| Import
;
// ----------------------------------------------------------------------------
// Function
// ----------------------------------------------------------------------------
FunctionDeclaration: Function Identifier [ WithGenericParameter ] [ PortDeclaration ] [ MinusGT ScalarType ] StatementBlock;
// ----------------------------------------------------------------------------
// Import
// ----------------------------------------------------------------------------
ImportDeclaration: Import ScopedIdentifier [ ColonColon Star ] Semicolon;
// ----------------------------------------------------------------------------
// Unsafe
// ----------------------------------------------------------------------------
UnsafeBlock: Unsafe LParen Identifier RParen LBrace { GenerateGroup } RBrace;
// ----------------------------------------------------------------------------
// Module/Interface
// ----------------------------------------------------------------------------
ModuleDeclaration: Module Identifier [ WithGenericParameter ] [ For ScopedIdentifier ] [ WithParameter ] [ PortDeclaration ] LBrace { ModuleGroup } RBrace;
ModuleGroup: { Attribute } ( LBrace { ModuleGroup } RBrace | ModuleItem );
ModuleItem: GenerateItem;
InterfaceDeclaration: Interface Identifier [ WithGenericParameter ] [ For ScopedIdentifier ] [ WithParameter ] LBrace { InterfaceGroup } RBrace;
InterfaceGroup: { Attribute } ( LBrace { InterfaceGroup } RBrace | InterfaceItem );
InterfaceItem: GenerateItem | ModportDeclaration;
GenerateIfDeclaration: If Expression GenerateNamedBlock { Else If Expression GenerateOptionalNamedBlock } [ Else GenerateOptionalNamedBlock ];
GenerateForDeclaration: For Identifier In [ Rev ] Range [ Step AssignmentOperator Expression ] GenerateNamedBlock;
GenerateBlockDeclaration: GenerateNamedBlock;
GenerateNamedBlock: Colon Identifier LBrace { GenerateGroup } RBrace;
GenerateOptionalNamedBlock: [ Colon Identifier ] LBrace { GenerateGroup } RBrace;
GenerateGroup: { Attribute } ( LBrace { GenerateGroup } RBrace | GenerateItem );
GenerateItem: LetDeclaration
| VarDeclaration
| InstDeclaration
| BindDeclaration
| ConstDeclaration
| AlwaysFfDeclaration
| AlwaysCombDeclaration
| AssignDeclaration
| ConnectDeclaration
| FunctionDeclaration
| GenerateIfDeclaration
| GenerateForDeclaration
| GenerateBlockDeclaration
| TypeDefDeclaration
| EnumDeclaration
| StructUnionDeclaration
| ImportDeclaration
| AliasDeclaration
| InitialDeclaration
| FinalDeclaration
| UnsafeBlock
| EmbedDeclaration
;
// ----------------------------------------------------------------------------
// Package
// ----------------------------------------------------------------------------
PackageDeclaration: Package Identifier [ WithGenericParameter ] [ For ScopedIdentifier ] LBrace { PackageGroup } RBrace;
PackageGroup: { Attribute } ( LBrace { PackageGroup } RBrace | PackageItem );
PackageItem: ConstDeclaration
| TypeDefDeclaration
| EnumDeclaration
| StructUnionDeclaration
| FunctionDeclaration
| ImportDeclaration
| AliasDeclaration
| EmbedDeclaration
;
// ----------------------------------------------------------------------------
// Alias
// ----------------------------------------------------------------------------
AliasDeclaration: Alias ( Module | Interface | Package ) Identifier Equ ScopedIdentifier Semicolon;
// ----------------------------------------------------------------------------
// Proto
// ----------------------------------------------------------------------------
ProtoDeclaration: Proto ( ProtoModuleDeclaration | ProtoInterfaceDeclaration | ProtoPackageDeclaration );
ProtoModuleDeclaration: Module Identifier [ WithParameter ] [ PortDeclaration ] Semicolon;
ProtoInterfaceDeclaration: Interface Identifier [ WithParameter ] LBrace { ProtoInterfaceItem } RBrace;
ProtoInterfaceItem: VarDeclaration
| ProtoConstDeclaration
| ProtoFunctionDeclaration
| ProtoTypeDefDeclaration
| ProtoAliasDeclaration
| ModportDeclaration
| ImportDeclaration
;
ProtoPackageDeclaration: Package Identifier LBrace { ProtoPacakgeItem } RBrace;
ProtoPacakgeItem: ProtoConstDeclaration
| ProtoTypeDefDeclaration
| EnumDeclaration
| StructUnionDeclaration
| ProtoFunctionDeclaration
| ProtoAliasDeclaration
| ImportDeclaration
;
ProtoConstDeclaration: Const Identifier Colon ( ArrayType | Type ) Semicolon;
ProtoTypeDefDeclaration: Type Identifier [ Equ ArrayType ] Semicolon;
ProtoFunctionDeclaration: Function Identifier [ WithGenericParameter ] [ PortDeclaration ] [ MinusGT ScalarType ] Semicolon;
ProtoAliasDeclaration: Alias ( Module | Interface | Package ) Identifier Colon ScopedIdentifier Semicolon;
// ----------------------------------------------------------------------------
// Embed
// ----------------------------------------------------------------------------
EmbedDeclaration: Embed LParen Identifier RParen Identifier EmbedContent;
EmbedContent: TripleLBrace { EmbedItem } TripleRBrace;
EmbedScopedIdentifier: EscapedLBrace ScopedIdentifier EscapedRBrace;
EmbedItem: EmbedLBrace { EmbedItem } EmbedRBrace
| EmbedScopedIdentifier
| Any;
// ----------------------------------------------------------------------------
// Include
// ----------------------------------------------------------------------------
IncludeDeclaration: Include LParen Identifier Comma StringLiteral RParen Semicolon;
// ----------------------------------------------------------------------------
// Description
// ----------------------------------------------------------------------------
DescriptionGroup: { Attribute } ( LBrace { DescriptionGroup } RBrace | DescriptionItem );
DescriptionItem: [ Pub ] PublicDescriptionItem
| ImportDeclaration
| BindDeclaration
| EmbedDeclaration
| IncludeDeclaration
;
PublicDescriptionItem: ModuleDeclaration
| InterfaceDeclaration
| PackageDeclaration
| AliasDeclaration
| ProtoDeclaration
;
// ----------------------------------------------------------------------------
// SourceCode
// ----------------------------------------------------------------------------
Veryl: Start { DescriptionGroup };
セマンティックエラー
duplicated_identifier
invalid_allow
invalid_direction
invalid_identifier
invalid_lsb
invalid_msb
invalid_number_character
invalid_statement
invalid_system_function
invalid_type_declaration
このエラーは struct、enum、unionのデータ型がインターフェース宣言内で定義されたことを示します。