The Veryl Hardware Description Language
Veryl is a hardware description language based on SystemVerilog, providing the following advantages:
Optimized Syntax
Veryl adopts syntax optimized for logic design while being based on a familiar basic syntax for SystemVerilog experts. This optimization includes guarantees for synthesizability, ensuring consistency between simulation results, and providing numerous syntax simplifications for common idioms. This approach enables ease of learning, improves the reliability and efficiency of the design process, and facilitates ease of code writing.
Interoperability
Designed with interoperability with SystemVerilog in mind, Veryl allows smooth integration and partial replacement with existing SystemVerilog components and projects. Furthermore, SystemVerilog source code transpiled from Veryl retains high readability, enabling seamless integration and debugging.
Productivity
Veryl comes with a rich set of development support tools, including package managers, build tools, real-time checkers compatible with major editors such as VSCode, Vim, Emacs, automatic completion, and automatic formatting. These tools accelerate the development process and significantly enhance productivity.
With these features, Veryl provides powerful support for designers to efficiently and productively conduct high-quality hardware design.
Features
In this chapter, we introduce the features of Veryl along with clear examples.
- Real-time diagnostics
- Auto formatting
- Integrated test
- Dependency management
- Generics
- Clock Domain Annotation
- Trailing comma
- Abstraction of clock and reset
- Documentation comment
- Compound assignment operator in
always_ff
- Individual namespace of enum variant
repeat
of concatenationif
/case
expression- Range-based
for
/inside
/outside
msb
notationlet
statement- Named block
- Visibility control
Real-time diagnostics
Issues such as undefined, unused, or unassigned variables are notified in real-time while editing in the editor.
In the following example, adding the _
prefix to variables flagged as unused explicitly indicates their unused status, suppressing warnings.
If the video does not play1
Auto formatting
In addition to the automatic formatting feature integrated with the editor, formatting through the command line and formatting checks in CI are also possible.
If the video does not play1
Integrated test
Test code written by SystemVerilog or cocotb can be embeded in Veryl code,
it can be executed through veryl test
command.
#[test(test1)]
embed (inline) sv{{{
module test1;
initial begin
assert (0) else $error("error");
end
endmodule
}}}
Dependency management
Veryl includes a built-in dependency management feature, allowing for easy incorporation of libraries by simply adding the repository path and version of the library on project settings like below.
[dependencies]
"https://github.com/veryl-lang/sample" = "0.1.0"
Generics
Code generation through generics achieves more reusable code than traditional parameter override. Prarmeters in function like the follwoign example, but also module names of instantiation, type names of struct definition, and so on can be parameterized.
SystemVerilog | Veryl |
---|---|
|
|
Clock Domain Annotation
If there are some clocks in a module, explicit clock domain annotation and unsafe (cdc)
block at the clock domain boundaries are required.
By the annotation, Veryl compiler detects unexpected clock domain crossing as error, and explicit unsafe (cdc)
block eases to review clock domain crossing.
SystemVerilog | Veryl |
---|---|
|
|
Trailing comma
Trailing comma is a syntax where a comma is placed after the last element in a list. It facilitates the addition and removal of elements and reduces unnecessary differences in version control systems.
SystemVerilog | Veryl |
---|---|
|
|
Abstraction of clock and reset
There is no need to specify the polarity and synchronicity of the clock and reset in the syntax; these can be specified during build-time configuration. This allows generating code for both ASICs with negative asynchronous reset and FPGAs with positive synchronous reset from the same Veryl code.
Additionally, explicit clock
and reset
type enables to check whether clock and reset are correctly connected to registers.
If there is a single clock and reset in the module, the connection can be omitted.
SystemVerilog | Veryl |
---|---|
|
|
Documentation comment
Writing module descriptions as documentation comments allows for automatic documentation generation. You can use not only plain text but also the following formats:
SystemVerilog | Veryl |
---|---|
|
|
Compound assignment operator in always_ff
There is no dedicated non-blocking assignment operator;
within always_ff
, non-blocking assignments are inferred, while within always_comb
, blocking assignments are inferred.
Therefore, various compound assignment operators can be used within always_ff
just like within always_comb
.
SystemVerilog | Veryl |
---|---|
|
|
Individual namespace of enum variant
Variants of an enum are defined within separate namespaces for each enum, thus preventing unintended name collisions.
SystemVerilog | Veryl |
---|---|
|
|
repeat
of concatenation
By adopting the explicit repeat
syntax as a repetition description in bit concatenation,
readability improves over complex combinations of {}
.
SystemVerilog | Veryl |
---|---|
|
|
if
/ case
expression
By adopting if
and case
expressions instead of the ternary operator,
readability improves, especially when comparing a large number of items.
SystemVerilog | Veryl |
---|---|
|
|
Range-based for
/ inside
/ outside
With notation representing closed intervals ..=
and half-open intervals ..
,
it is possible to uniformly describe ranges using for
, inside
, and outside
(which denotes the inverse of inside
).
SystemVerilog | Veryl |
---|---|
|
|
msb
notation
The msb
notation, indicating the most significant bit, eliminates the need to calculate the most significant bit from parameters, making intentions clearer.
SystemVerilog | Veryl |
---|---|
|
|
let
statement
There is a dedicated let
statement available for binding values simultaneously with variable declaration,
which can be used in various contexts that were not supported in SystemVerilog.
SystemVerilog | Veryl |
---|---|
|
|
Named block
You can define named blocks to limit the scope of variables.
SystemVerilog | Veryl |
---|---|
|
|
Visibility control
Modules without the pub
keyword cannot be referenced from outside the project
and are not included in automatic documentation generation.
This allows distinguishing between what should be exposed externally from the project and internal implementations.
SystemVerilog | Veryl |
---|---|
|
|
Some browsers by default pause the playback of GIF animations. Please check your browser settings.
Getting Started
Let’s start to use Veryl. In this section, we will install Veryl, create an example project, and build it.
Installation
Veryl can be intalled through the official toolchain installer verylup
.
We recommend to use verylup
because it provides some usefule features like toolchain update.
Note: If you want install on an enviromnent without internet access, you can use offline installation.
Requirement
Veryl uses git
command internally. Please confirm git
can be launched.
Install verylup
Download binary
Download from release page, and extract to the directory in PATH
.
Cargo
You can install with cargo.
cargo install verylup
Setup verylup
After installing verylup, the following command is required once at first.
It downloads the latest toolchain and creates veryl
and veryl-ls
command at the same location as verylup.
verylup setup
Now veryl
command can be used!
Editor integration
Visual Studio Code and Vim / Neovim are supported officially.
Visual Studio Code
For Visual Studio Code, Veryl extension is provided. The extension provides file type detection, syntex highlight and language server integration. You can install it by searching “Veryl” in extension panel or the following URL.
Veryl extension for Visual Studio Code
Vim / Neovim
For Vim / Neovim, Veryl plugin is provided. The plugin provides file type detection, syntex highlight. There are some instructions for plugin installation and language server integration in the following URL.
Other Editors
Veryl provides language server. So other editors supporting language server (ex. Emacs) can use it.
Shell Completion
Shell completion script for veryl
and verylup
is provided through verylup completion
.
For example, the following command generates completion script for zsh.
verylup completion zsh veryl > _veryl
verylup completion zsh verylup > _verylup
Supported shells are below:
- Bash
- Elvish
- Fish
- PowerShell
- Zsh
Please refer the documentation of each shell for usage of generated scripts.
Hello, World!
Create Project
At first, a new Veryl project can be created by:
veryl new hello
After the command, the following directory and file will be created.
$ veryl new hello
[INFO ] Created "hello" project
$ cd hello
$ tree
.
`-- Veryl.toml
0 directories, 1 file
Veryl.toml
is the project configuration.
[project]
name = "hello"
version = "0.1.0"
The description of all configuration is here.
Write Code
You can add source codes at an arbitrary position in the project directory.
This is because Veryl project can be independent or integrated to other SystemVerilog project.
The extension of Veryl’s source codes is .veryl
.
For example, put the following code to src/hello.veryl
.
module ModuleA {
initial {
$display("Hello, world!");
}
}
$ tree
.
|-- src
| `-- hello.veryl
`-- Veryl.toml
1 directory, 2 files
Note: Some source codes in the book have play button “▶” which will be appeared when mouse cursor is hovered at the code. If you click the button, the transpiled SystemVerilog code will appear. Please try to click the button of
module ModuleA
code.
Build Code
You can generate a SystemVerilog code by veryl build
.
$ 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.sv
| `-- hello.veryl
`-- Veryl.toml
2 directories, 4 files
By default, SystemVerilog code will be generated at the same directory as Veryl code.
The generated code is src/hello.sv
.
module hello_ModuleA;
initial begin
$display("Hello, world!");
end
endmodule
Additionally, hello.f
which is the filelist of generated codes will be generated.
You can use it for SystemVerilog compiler.
The following example is to use Verilator.
$ verilator --cc -f hello.f
Code Examples
Veryl has the almost same semantics as SystemVerilog. If you are used to SystemVerilog, you will guess Veryl semantics with a small example source code.
This is a small example. In the following example, comments show the difference with SystemVerilog syntax.
module ModuleA (
// name is first, and type is followed after `:`
// bit width is represented by `<>`
i_data: input logic<10>,
o_data: output logic<10>,
// use `{}` instead of `begin`/`end`
) {
assign o_data = i_data;
}
Additionally, the codeblocks in this chapter can be edit. Let’s try to edit and play each code.
A source code of Veryl has some module
, interface
and package
like SystemVerilog.
In this chapter, we’ll show the some example source codes of them.
Module
// module definition
module ModuleA #(
param ParamA: u32 = 10,
const ParamB: u32 = 10, // trailing comma is allowed
) (
i_clk : input clock , // `clock` is a special type for clock
i_rst : input reset , // `reset` is a special type for reset
i_sel : input logic ,
i_data: input logic<ParamA> [2], // `[]` means unpacked array in SystemVerilog
o_data: output logic<ParamA> , // `<>` means packed array in SystemVerilog
) {
// const parameter declaration
// `param` is not allowed in module
const ParamC: u32 = 10;
// variable declaration
var r_data0: logic<ParamA>;
var r_data1: logic<ParamA>;
var r_data2: logic<ParamA>;
// value binding
let _w_data2: logic<ParamA> = i_data;
// always_ff statement with reset
// `always_ff` can take a mandatory clock and a optional reset
// `if_reset` means `if (i_rst)`. This conceals reset porality
// `()` of `if` is not required
// `=` in `always_ff` is non-blocking assignment
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 statement without reset
always_ff (i_clk) {
r_data1 = r_data0;
}
// clock and reset can be omitted
// if there is a single clock and reset in the module
always_ff {
r_data2 = r_data1;
}
assign o_data = r_data1;
}
Instantiation
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;
// instance declaration
// `inst` keyword starts instance declaration
// port connnection can be specified by `()`
// each port connection is `[port_name]:[variable]`
// `[port_name]` means `[port_name]:[port_name]`
inst u_module_b: ModuleB (
i_clk ,
i_data: r_data1,
o_data: r_data2,
);
// instance declaration with parameter override
// notation of parameter connection is the same as port
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
// interface definition
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 definition
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,
// port declaration by modport
intf_a_mst: modport InterfaceA::master,
intf_a_slv: modport InterfaceA::slave ,
) {
// interface instantiation
inst u_intf_a: InterfaceA [10];
}
Package
// package definition
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);
}
Language Reference
In this chapter, we’ll discuss the lauguage definition of Veryl.
Source Code Structure
Veryl’s source code is composed by some module
, interface
and package
.
module ModuleA {}
module ModuleB {}
interface InterfaceA {}
package PackageA {}
The name of module
, interface
and package
in the transpiled code will added project name as prefix.
In the sample code, project_
will be added.
It is to avoid name conflict between projects.
Lexical Structure
This chapter shows the lexical structure of Veryl. At the first, we’ll discuss about the general parts in it.
Encoding
The encoding of Veryl source code should be UTF-8.
White Space
(white space), \t
and \n
are treated as white space.
All of them are skipped by Veryl’s parser.
Comment
Single line comment and multi line comment can be used. Almost all comment will be outputted at the transpiled code.
// single line comment
/*
multi
line
comment
*/
Documentation comment
Signle line comment starts with ///
is treated as documentation comment.
Documentation comment is used for document generation.
/// documentation comment
Identifier
Identifier is composed with ASCII alphabet and number and _
.
Leading number is not allowed.
The following regular expression shows the definition.
[a-zA-Z_][a-zA-Z0-9_]*
Raw Identifier
Some keywords of Veryl can be used as identifier in SystemVerilog.
To access these identifiers, raw identifier can be used.
For example, clock
which is a keyword of Veryl can be used as identifier like r#clock
.
The r#clock
will be transpiled to clock
in SystemVerilog.
String
String is surrounded by "
.
Escape by \
can be used like \"
, \n
and so on.
"Hello, World!"
Operator
Almost all operators are the same as SystemVerilog. Please be careful the some differences.
<:
less than operator which is the same as<
in SystemVerilog.>:
greater than operator which is the same as>
in SystemVerilog.
// unary arithmetic
a = +1;
a = -1;
// unary logical
a = !1;
a = ~1;
// unary reduce
a = &1;
a = |1;
a = ^1;
a = ~&1;
a = ~|1;
a = ~^1;
a = ^~1;
// binary arithmetic
a = 1 ** 1;
a = 1 * 1;
a = 1 / 1;
a = 1 % 1;
a = 1 + 1;
a = 1 - 1;
// binary shift
a = 1 << 1;
a = 1 >> 1;
a = 1 <<< 1;
a = 1 >>> 1;
// binary compare
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;
// binary bitwise
a = 1 & 1;
a = 1 ^ 1;
a = 1 ~^ 1;
a = 1 ^~ 1;
a = 1 | 1;
// binary logical
a = 1 && 1;
a = 1 || 1;
Number
Integer
// integer
0123456789
01_23_45_67_89
// binary
32'b01xzXZ
32'b01_xz_XZ
// octal
36'o01234567xzXZ
36'o01_23_45_67_xz_XZ
// decimal
32'd0123456789
32'd01_23_45_67_89
// hex
128'h0123456789abcdefxzABCDEFXZ
128'h01_23_45_67_89_ab_cd_ef_xz_AB_CD_EF_XZ
Set all bits
// all 0
'0
// all 1
'1
// all x
'x
'X
// all z
'z
'Z
Widthless integer
The bit width specification of integer can be omitted. If it is omitted, the appropriate width will be filled in the translated code.
module ModuleA {
const a0: u64 = 'b0101;
const a1: u64 = 'o01234567;
const a2: u64 = 'd0123456789;
const a3: u64 = 'h0123456789fffff;
}
Set sized bits
The bit width specification can be added to “set all bits”.
module ModuleA {
const a0: u64 = 1'0;
const a1: u64 = 2'1;
const a2: u64 = 3'x;
const a3: u64 = 4'z;
}
Floating point
// floating point
0123456789.0123456789
01_23_45_67_89.01_23_45_67_89
// floating with exponent
0123456789.0123456789e+0123456789
01_23_45_67_89.01_23_45_67_89E-01_23_45_67_89
Array Literal
'{}
represents array literal.
In the literal, expression, repeat
keyword and default
keyword can be placed.
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}
}
Data Type
In this chapter, we’ll discuss about data type.
Builtin Type
4-state data type which has variable width
logic
is 4-state (0
, 1
, x
, z
) data type.
The variable width can be specified by <>
after logic
.
Multi-dimentional can be specified by <X, Y, Z,,,>
.
module ModuleA {
let _a: logic = 1;
let _b: logic<10> = 1;
let _c: logic<10, 10> = 1;
}
2-state data type which has variable width
bit
is 2-state (0
, 1
) data type.
The variable width can be specified by <>
after bit
.
Multi-dimentional can be specified by <X, Y, Z,,,>
.
module ModuleA {
let _a: bit = 1;
let _b: bit<10> = 1;
let _c: bit<10, 10> = 1;
}
Integer type
There are some integer types:
u32
: 32bit unsigned integeru64
: 64bit unsigned integeri32
: 32bit signed integeri64
: 64bit signed integer
module ModuleA {
let _a: u32 = 1;
let _b: u64 = 1;
let _c: i32 = 1;
let _d: i64 = 1;
}
Floating point type
There are some floating point types:
f32
: 32bit floating pointf64
: 64bit floating point
Both of them are represented as described by IEEE Std 754.
module ModuleA {
let _a: f32 = 1.0;
let _b: f64 = 1.0;
}
String type
string
is string type.
module ModuleA {
let _a: string = "";
}
Type type
type
is a type which represents type kind.
Variable of type
can be defined as param
or const
only.
module ModuleA {
const a: type = logic;
const b: type = logic<10>;
const c: type = u32;
}
User Defined Type
Struct
struct
is composite data type.
It can contain some fields, and these fields can be access through .
operator.
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
is enumerable type.
It has some named variant, and the value of enum
can be set to the one of them.
The variant name can be specified by [enum name]::[variant name]
.
Each variant has the corresponding integral value.
The value can be specified by =
.
Otherwise, it is assigned automatically.
module A {
enum EnumA: logic<2> {
member_a,
member_b,
member_c = 3,
}
var a: EnumA;
assign a = EnumA::member_a;
}
If the type of enum
is omitted, it will be infered from the variants automatically.
module A {
enum EnumA {
member_a,
member_b,
member_c = 3,
}
}
Enum Encoding
By default, the value of each variant is assigned sequentially if it is omitted.
If you want to specify value encoding, #[enum_encoding]
attribute can be used.
The available encodings are here:
sequential
onehot
gray
module A {
#[enum_encoding(sequential)]
enum EnumA {
member_a,
}
#[enum_encoding(onehot)]
enum EnumB {
member_a,
}
#[enum_encoding(gray)]
enum EnumC {
member_a,
}
}
Union
A Veryl union
is a packed, untagged sum type and is transpiled to SystemVerilog’s packed union
.
Each union variant should have the same packed width as each other union variant.
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;
}
Typedef
The type
keyword can be used to define a type alias to scalar or array types.
module A {
type word_t = logic <16> ;
type regfile_t = word_t [16];
type octbyte = bit <8> [8] ;
}
Array
Array can be defined by appending []
to any data type.
The length of array can be specified by the value in []
.
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;
}
Multi-dimentional array can be defined by [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 / Reset
clock
is a special types to represent clock wiring.
There are 3 variants to specify clock polarity.
clock
: clock type of which polarity is specified by the build optionclock_posedge
: clock type of which polarity is positiveclock_negedge
: clock type of which polarity is negative
reset
is a special types to represent reset wiring.
There are 5 variants to specify reset polarity and synchronicity.
reset
: reset type of which polarity and synchronicity are specified by the build optionreset_async_high
: async/high active reset typereset_async_low
: async/low active reset typereset_sync_high
: sync/active high reset typereset_sync_low
: sync/active low reset type
If there is no special requirement, clock
and reset
are recommended for code reusability.
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;
}
}
}
Expression
In this chapter, we’ll discuss about expression. Expression is combination of variable, operator, function call, and so on. It can be evaluated to a value.
Operator Precedence
In expression, operator precedence is almost the same as SystemVerilog.
Operator | Associativity | Precedence |
---|---|---|
() [] :: . | Left | Highest |
+ - ! ~ & ~& | ~| ^ ~^ ^~ (unary) | Left | |
** | Left | |
* / % | Left | |
+ - (binary) | Left | |
<< >> <<< >>> | Left | |
<: <= >: >= | Left | |
== != === !== ==? !=? | Left | |
& (binary) | Left | |
^ ~^ ^~ (binary) | Left | |
| (binary) | Left | |
&& | Left | |
|| | Left | |
= += -= *= /= %= &= ^= |= <<= >>= <<<= >>>= | None | |
{} inside outside if case switch | None | Lowest |
Function Call
Function can be call by function_name(argument)
.
System function of SystemVerilog like $clog2
can be used too.
module ModuleA {
let _a: logic = PackageA::FunctionA(1, 1);
let _b: logic = $clog2(1, 1);
}
package PackageA {
function FunctionA (
a: input logic,
b: input logic,
) {}
}
Concatenation
{}
represents bit concatenation.
In {}
, repeat
keyword can be used to repeat specified operand.
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
Conditional expression using if
can be used.
The section which represents condition is placed after if
keyword,
and ()
is not required surrounding it.
else
is mandatory because if expression always have to be evaluated to value.
module ModuleA {
let a: logic<10> = 1;
var b: logic<10>;
assign b = if a == 0 {
1
} else if a >: 1 {
2
} else {
3
};
}
Case / Switch
Another conditional expression is case
.
case
containts some arms like value: expression
.
If the expression after case
keyword matches the left value of an arm,
the right expression of the arm will be returned.
As the value, range like ..=
can be used too.
default
is a special arm which will be returned when all other arms are failed.
default
is mandatory because if expression always have to be evaluated to value.
module ModuleA {
let a: logic<10> = 1;
var b: logic<10>;
assign b = case a {
0 : 1,
1 : 2,
3..=5 : 4,
default: 5,
};
}
switch
is another form of case
.
switch
containts some arms like expression: expression
, and if the left expression is evaluated to 1, the right expression of the arm will be returned.
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,
};
}
Bit Select
[]
is bit select operator.
If an expression is specified to []
, single bit is selected.
Bit range selection can be specified by [expression:expression]
.
module ModuleA {
let a: logic<10> = 1;
var b: logic<10>;
var c: logic<10>;
assign b = a[3];
assign c = a[4:0];
}
Select by position and width
+:
and -:
notation can select by start position and width.
[A+:B]
means [(A+B-1):A]
, and [A-:B]
means [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];
}
Select by index with step
step
notation can select by index with step.
[A step B]
means “select index A
in step B
”, so it equals [(B*A)+:B]
.
module ModuleA {
let a: logic<10> = 1;
var b: logic<10>;
assign b = a[2 step 3];
}
Range
Range can be specified through range operator. There are two range operator:
..
: half-open interval..=
: closed interval
Range can be used at some description like for
statement.
module ModuleA {
initial {
for _i: u32 in 0..10 {}
for _j: u32 in 0..=10 {}
}
}
Msb / Lsb
msb
and lsb
can be used in bit selection by []
.
msb
means most significant bit of the operand.
lsb
means least significant bit of the operand, it is the same as 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
check the specified expression is inside conditions which are specified in {}
.
Condition can be single expression or range.
If the expression matches any condition, inside
will return 1
, otherwise 0
.
outside
is vice versa.
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};
}
Statement
In this chapter, we’ll discuss about statement.
Statement can be used in some declaration like always_ff
, always_comb
.
Assignment
Assignment statement is variable = expression;
.
Unlike SystemVerilog, assignment operator is =
in both always_comb
and always_ff
.
There are other assignment operators:
+=
: addition assignment-=
: subtraction assignment*=
: multiplication assignment/=
: division assignment%=
: remainder assignment&=
: bitwise AND assignment|=
: bitwise OR assignment^=
: bitwise XOR assignment<<=
: logical left shift assignment>>=
: logical right shift assignment<<<=
: arithmetic left shift assignment>>>=
: arithmetic right shift assignment
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;
}
}
Function Call
Function call can be used as statement. In this case, the return value of function will be ignored.
module ModuleA {
initial {
$display("Hello, world!");
}
}
If
if
can be used as statement.
The difference from if
expression is that statements are placed in {}
.
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
and switch
can be used as statement.
The meaning of them are the same as Case / Switch expression except that the right-hand of arm is statement.
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;
}
}
}
For
for
statement represent repetition.
Loop variable is placed before in
keyword,
and range is placed after it.
break
can be used to break the loop.
module ModuleA {
var a: logic<10>;
always_comb {
for i: u32 in 0..10 {
a += i;
if i == 5 {
break;
}
}
}
}
Return
return
statement represents return from function.
The expression after return
keyword is the return value of the function.
module ModuleA {
function FunctionA () -> u32 {
return 0;
}
}
Let
let
statement represents a name bound to a value.
It can be used in always_ff
, always_comb
and function declaration.
let
statement can be placed anywhere in block.
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;
}
}
Declaration
In this chapter, we’ll discuss about declaration.
Variable
Variable declaration is started by var
keyword.
After var
, variable name, :
, and the type of the variable are followed.
If there are unused variables, warning will be occured.
Variable name starting with _
means unused variable, and suppresses the warning.
If you want to bind a value to a name at the declaration, let
can be used instead of var
.
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;
}
Parameter
Parameter can be declarated as the same as variable.
param
keyword can be used at module header, it can be overridden at instantiation.
const
keyword can be used in module, it can’t be overridden.
module ModuleA #(
param ParamA: u32 = 1,
) {
const ParamB: u32 = 1;
}
Register
If a variable is assigned in always_ff
declaration, it becomes register variable.
Register variable will be mapped to flip-flop in synthesis phase.
always_ff
has mandatory clock variable, optional reset variable, and {}
block.
Clock and reset are placed in ()
.
The specified clock and reset should have clock
/ reset
type and the witdh of them should be 1bit.
if_reset
is a special keyword which can be used in always_ff
.
It means reset condition of the register variable.
If if_reset
is used, always_ff
must have reset variable.
if_reset
can be conceal reset porality and synchronisity.
The actual porality and synchronisity can be configured through [build]
section of Veryl.toml
.
If there is a single clock and reset in the module, clock and reset specification can be omitted.
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;
}
}
}
Combinational
If a variable is assigned in always_comb
declaration, it means combinational circuit.
module ModuleA {
let a: logic<10> = 1;
var b: logic<10>;
always_comb {
b = a + 1;
}
}
Assign
assign
declaration can assign expression to variable.
module ModuleA {
var a: logic<10>;
assign a = 1;
}
Function
Function can be declared by function
keyword.
Arguments are placed in ()
and return type is placed after ->
.
If function doesn’t have a return value, ->
can be omitted.
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);
}
}
Initial / Final
Statements in initial
are executed at the beginning of simulation,
final
is the end.
Both will be ignored logical synthesis, and can be used as debug or assertion.
module ModuleA {
initial {
$display("initial");
}
final {
$display("final");
}
}
Attribute
Attribute can annotate some declarations like variable declaration.
sv
Attribute
sv
attribute represents SystemVerilog attribute.
It will be transpiled to SystemVerilog attribute (* *)
.
module ModuleA {
#[sv("ram_style=\"block\"")]
let _a: logic<10> = 1;
#[sv("mark_debug=\"true\"")]
let _b: logic<10> = 1;
}
allow
Attribute
allow
attribute is used to disable specified lint check.
module ModuleA {
#[allow(unused_variable)]
let a: logic<10> = 1;
}
Available lint names are below:
unused_variable
missing_reset_statement
missing_port
ifdef
/ifndef
Attribute
ifdef
and ifndef
attribute is used to control whether the annotated code block is enabled by defined value.
If DEFINE_A
is defined, the code block with #[ifdef(DEFINE_A)]
is enabled, and the code block with #[ifndef(DEFINE_A)]
is disabled.
module ModuleA {
#[ifdef(DEFINE_A)]
{
let _a: logic<10> = 1;
}
#[ifndef(DEFINE_A)]
{
let _b: logic<10> = 1;
}
}
Generate
Declaration can be generated by for
and if
.
Label which is shown by :
is required to idenfity the generated declarations.
module ModuleA {
var a: logic<10>;
for i in 0..10 :label {
if i >: 5 :label {
assign a[i] = i + 2;
} else { // label of else clause can be omit
assign a[i] = i + 2;
}
}
}
Instantiation
inst
keyword represents instantiation of modula and interface.
The name of instance is placed after inst
keyword,
and the type of instance is placed after :
.
Parameter override is #()
, and port connection is ()
.
module ModuleA #(
param paramA: u32 = 1,
) {
let a: logic<10> = 1;
let b: logic<10> = 1;
inst instB: ModuleB #(
paramA , // Parameter assignment by name
paramB: 10,
) (
a , // Port connection by name
bb: b,
);
}
module ModuleB #(
param paramA: u32 = 1,
param paramB: u32 = 1,
) (
a : input logic<10>,
bb: input logic<10>,
) {}
Named Block
Label can be added to {}
block.
The named block has an individual namespace.
module ModuleA {
:labelA {
let _a: logic<10> = 1;
}
:labelB {
let _a: logic<10> = 1;
}
}
Import / Export
import
declaration imports symbols from other packages.
It can be placed at the top level or as a module/interface/package item.
Wildcard pattern like package::*
can be used as an argument of import
declaration.
// file scope import
import $sv::SvPackage::*;
module ModuleA {
import PackageA::*;
import PackageA::paramA;
}
package PackageA {
const paramA: u32 = 1;
}
export
declaration exports symbols from the package to other.
export *
represents to export all symbols.
package PackageA {
const paramA: u32 = 1;
}
package PackageB {
import PackageA::*;
export paramA;
}
package PackageC {
import PackageA::*;
export *;
}
Module
Module is one of top level components in source code. Module has overridable parameters, connection ports, and internal logic.
Overridable parameters can be declared in #()
.
Each parameter declaration is started by param
keyword.
After the keyword, an identifier, :
, the type of the parameter, and a default value are placed.
Connection ports can be declared in ()
.
Each port declaration is constructed by an identifier, :
, port direction, and the type of the port.
The available port directions are:
input
: input portoutput
: output portinout
: bi-directional portmodport
: modport of interface
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;
}
}
}
Interface
Interface is one of top level components in source code. Interface has overridable parameters, and interface definitions.
Overridable parameters are the same as them of module.
In interface definitions, modport
can be declared.
modport
can be used as bundled port connection at the port declaration of module.
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,
}
}
Package
Package is one of top level components in source code. Package can organize some declarations like parameter and function.
To access an item in a package, ::
symbol can be used like PackageA::ParamA
.
package PackageA {
const ParamA: u32 = 0;
}
SystemVerilog Interoperation
If you want to access to items of SystemVerilog, $sv
namespace can be used.
For example, “ModuleA” in SystemVerilog source code can be accessed by $sv::ModuleA
.
Veryl don’t check the existence of the items.
module ModuleA {
let _a: logic = $sv::PackageA::ParamA;
inst b: $sv::ModuleB;
inst c: $sv::InterfaceC;
}
To access some identifiers which are used as Veryl’s keywords, raw identifier can be used.
module ModuleA (
i_clk: input clock,
) {
inst a: $sv::ModuleA (
// clock: i_clk
// ^ this is syntax error because `clock` is a keyword
// Instead of it, `r#clock` can be used
r#clock: i_clk,
);
}
Visibility
By default, all top level items of a project (module, interface and package) are private. The “private” means they are not visible from other project.
pub
keyword can be used to specify an item as public to other project.
veryl doc
will generate documents of public items only.
pub module ModuleA {}
pub interface InterfaceA {}
pub package PackageA {}
Foreign Language Integration
embed
declaration
embed
declaration can embed the code of foreign languages.
The first argument of embed
declaration shows the way of embedding.
The following ways are supported:
inline
: expand the code as iscocotb
: treated as cocotb based test
The code block are started by lang{{{
and ended by }}}
.
The following lang
specifiers are supported:
sv
: SystemVerilogpy
: Python
embed (inline) sv{{{
module ModuleSv;
endmodule
}}}
include
declaration
include
declaration can include a file of foreign languages.
The first argument is the same as embed
declaration, and the second is a relative file path from the source code.
include(inline, "module.sv");
Integrated Test
Integrated test can be marked by #[test(test_name)]
attribute.
The marked block will be identified as test, and executed through veryl test
command.
There are two way to describe integrated test:
- SystemVerilog test
- cocotb test
About RTL simulator used by veryl test
, see Simulator.
If --wave
option is specified, waveforms are generated.
SystemVerilog test
SystemVerilog test can be described with inline
specifier.
The top level module of the block must have the same name as the test name.
The messages through $info
, $warning
, $error
and $fatal
system function are handled by Veryl compiler, and shown as exectution log.
The calls of $error
and $fatal
are treated as test failure.
The following example, a SystemVerilog source code embeded by embed
declaration are marked as test.
#[test(test1)]
embed (inline) sv{{{
module test1;
initial begin
assert (0) else $error("error");
end
endmodule
}}}
cocotb test
cocotb test can be described with cocotb
specifier.
The target module name for test should be specified by the second argument of #[test]
attribute.
#[test(test1, ModuleA)]
embed (cocotb) py{{{
# cocotb code
}}}
Generics
Generics can define parameterized items which can’t achieved by parameter override. The following items support generics:
- function
- module
- interface
- package
- struct
- union
Each generic definition has generic parameters (often an uppercase letter is used like T
) which can be placed as identifier or expression in the definition.
Generic parameters are declarated after item’s identifier with ::<>
.
Each generic parameter should have generic bound after colon like T: const
.
Generic bound represents what value can be passed to the generic parameter.
The available generic bounds are below:
const
: means constant value can be passedtype
: means arbitrary type can be passed- named prototype
Named prototype is a special generic bound. See Prototype for details.
At the usage of generics, actual parameters can be given through ::<>
.
As the actual parameters, numeric literal and identifier concatenated by ::
can be used.
Additionally, the actual parameters should be accessible at the position of the generics declaration. For example, module names can be used as actual parameters because it is accessible through the whole project. On the other hand, local parameters can’t be used as actual parameters in many cases. This is caused by that the local parameters is not accessible from the potision of the generics declaration.
Generic Function
module ModuleA {
function FuncA::<T: const> (
a: input logic<T>,
) -> logic<T> {
return a + 1;
}
let _a: logic<10> = FuncA::<10>(1);
let _b: logic<20> = FuncA::<20>(1);
}
Generic Module/Interface
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 {}
Generic Package
module ModuleA {
const A: u32 = PackageA::<1>::X;
const B: u32 = PackageA::<2>::X;
}
package PackageA::<T: const> {
const X: u32 = T;
}
Generic Struct
module ModuleA {
type TypeA = i32;
struct StructA::<T: type> {
A: T,
}
// local defined type can be used
// because `TypeA` is accessible at the definition of `StructA`
var _a: StructA::<TypeA> ;
var _b: StructA::<PackageA::TypeB>;
var _c: StructA::<PackageA::TypeC>;
}
package PackageA {
type TypeB = u32;
type TypeC = u64;
}
Default Parameter
Generic parameter can take a default value through =
after the generic parameter.
If the parameter specifications at call site is omitted, the default value is used.
module ModuleA {
function FuncA::<T: const = 10> (
a: input logic<T>,
) -> logic<T> {
return a + 1;
}
let _a: logic<10> = FuncA::<>(1);
let _b: logic<20> = FuncA::<20>(1);
}
Default parameters should be placed at the last of generic parameter list. If not, it causes ambiguous which parameters are omitted.
module ModuleA {
function FuncA::<T: const, U: const = 1> (
a: input logic<T>,
) -> logic<T> {
return a + U;
}
// Error
//function FuncA::<T: const = 1, U: const> (
// a: input logic<T>,
//) -> logic<T> {
// return a + U;
//}
let _a: logic<10> = FuncA::<10>(1);
let _b: logic<20> = FuncA::<20, 2>(1);
}
Prototype
Prototype is a special generic bound. It represents prototype which can be passed to the generic parameter. Currently module prototype is supported only.
In the following example, ProtoA
is a module prototype which has parameter A
and port i_dat
and o_dat
.
By binding like T: ProtoA
, it is represented that the generic parameter T
should have the parameters and ports.
To use prototype, for
implementation is required. ModuleC
and ModuleD
have for ProroA
specifier which means the module satisfies the condision of ProroA
.
So the modules can be used as the generic parameter T
of ModuleB
.
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;
}
Clock Domain Annotation
If there are some clocks in a module, explicit clock domain annotation like `a
is required.
The annotation shows which clock domain each signals belong.
module ModuleA (
// belong clock domain `a
i_clk_a: input `a clock,
i_dat_a: input `a logic,
o_dat_a: output `a logic,
// belong clock domain `b
i_clk_b: input `b clock,
i_dat_b: input `b logic,
o_dat_b: output `b logic,
) {
// assignment in the same clock domain is safe
assign o_dat_a = i_dat_a;
assign o_dat_b = i_dat_b;
}
If there is single clock only in a module, the annotation can be omitted.
module ModuleA (
i_clk: input clock,
i_dat: input logic,
o_dat: output logic,
) {
assign o_dat = i_dat;
}
`_
is a special clock domain which means implicit clock domain.
This can be used to specify that some clocks belong the same implicit clock domain.
module ModuleA (
// all signals belong implicit clock domain
i_clk : input `_ clock,
i_clk_x2: input `_ clock,
i_dat : input logic,
o_dat : output logic,
) {
assign o_dat = i_dat;
}
Unsafe CDC
Veryl compiler detects clock domain crossing as error.
So explicit unsafe (cdc)
block is required for clock domain crossing.
In the block, clock domain crossing error is suppressed, so designer should check whether it is safe carefully.
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,
) {
// Error "Clock domain crossing is detected"
//assign o_dat_b = i_dat_a;
unsafe (cdc) {
assign o_dat_b = i_dat_a;
}
}
Typically, synchronizer cells are inserted to the boundaries between clock domains.
unsafe (cdc)
block is required for this usage too.
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,
);
}
}
Standard Library
Veryl provides some useful and general modules as standard library.
Standard library is under $std
namespace, and it can be used without adding dependency.
The public API of standard library may be changed until Veryl 1.0 release.
module ModuleA {
// $std::fifo is FIFO module in standard library
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 : _,
);
}
The full list and document of standard library is https://std.veryl-lang.org.
Development Environment
In this chapter, we’ll discuss about development environment including project configuration and development tools.
Project Configuration
[project]
— Defines a project.name
— The name of the project.version
— The version of the project.authors
— The authors of the project.description
— A description of the project.license
— The project license.repository
— URL of the project source repository.
[build]
— Build settings.[format]
— Format settings.[lint]
— Lint settings.[test]
— Test settings.[publish]
— Publish settings.[dependencies]
— Library dependencies.
The [project]
section
The first section of Veryl.toml
is [project]
.
The mandatory fields are name
and version
.
The name
field
The project name is used as prefix in the generated codes.
So the name must start with alphabet or _
, and use only alphanumeric characters or _
.
The version
field
The project version should follow Semantic Versioning. The version is constructed by the following three numbers.
- Major – increment at incompatible changes
- Minor – increment at adding features with backward compatibility
- Patch – increment at bug fixes with backward compatibility
[project]
version = "0.1.0"
The authors
field
The optional authors
field lists in an array the people or organizations that are considered the “authors” of the project.
The format of each string in the list is free. Name only, e-mail address only, and name with e-mail address included within angled brackets are commonly used.
[project]
authors = ["Fnu Lnu", "anonymous@example.com", "Fnu Lnu <anonymous@example.com>"]
The description
field
The description
is a short blurb about the project. This should be plane text (not Markdown).
The license
field
The license
field contains the name of license that the project is released under.
The string should be follow SPDX 2.3 license expression.
[project]
license = "MIT OR Apache-2.0"
The repository
field
The repository
field should be a URL to the source repository for the project.
[project]
repository = "https://github.com/veryl-lang/veryl"
The [build]
section
The [build]
section contains the configurations of code generation.
Available configurations is here.
The [format]
section
The [format]
section contains the configurations of code formatter.
Available configurations is here.
The [lint]
section
The [lint]
section contains the configurations of linter.
Available configurations is here.
The [test]
section
The [test]
section contains the configurations of test by RTL simulator.
Available configurations is here.
The [publish]
section
The [publish]
section contains the configurations of publishing.
Available configurations is here.
The [dependencies]
section
The [dependencies]
section contains library dependencies.
Available configurations is here.
Build
[build]
section specifies the configuration for code generation.
The clock_type
field
The clock_type
field specifies which clock edge is used to drive flip-flop.
The available types are below:
posedge
– positive edgenegedge
– negetive edge
The reset_type
field
The reset_type
field specifies reset polarity and synchronisity.
The available types are below:
async_low
– asynchronous and active lowasync_high
– asynchronous and active highsync_low
– synchronous and active lowsync_high
– synchronous and active high
The filelist_type
field
The filelist_type
field specifies filelist format.
The available types are below:
absolute
– plane text filelist including absolute file pathsrelative
– plane text filelist including relative file pathsflgen
– flgen filelist
The target
field
The target
field specifies where the generated codes will be placed at.
The available types are below:
source
– as the same directory as the source codedirectory
– specified directorybundle
– specified file
If you want to use directory
or bundle
, you should specify the target path by path
key.
[build]
target = {type = "directory", path = "[dst dir]"}
The implicit_parameter_types
field
The implicit_parameter_types
field lists the types which will be elided in parameter
declaration of the generated codes.
This is because some EDA tools don’t support parameter
declaration with specific types (ex.string
).
If you want to elide string
, you can specify like below:
[build]
implicit_parameter_types = ["string"]
The omit_project_prefix
field
If omit_project_prefix
is set to true
, the project prefix of module/interface/package name will be omitted.
This is false
by default.
[build]
omit_project_prefix = true
The strip_comments
field
If strip_comments
is set to true
, all comments will be stripped.
This is false
by default.
[build]
strip_comments = true
The *_prefix
and *_suffix
field
*_prefix
and *_suffix
represent additional prefix and suffix for the generated code.
The available configurations are below:
clock_posedge_prefix
: Prefix forclock
type atclock_type = posedge
clock_posedge_suffix
: Suffix forclock
type atclock_type = posedge
clock_negedge_prefix
: Prefix forclock
type atclock_type = negedge
clock_negedge_suffix
: Suffix forclock
type atclock_type = negedge
reset_high_prefix
: Prefix forreset
type atreset_type = *_high
reset_high_suffix
: Suffix forreset
type atreset_type = *_high
reset_low_prefix
: Prefix forreset
type atreset_type = *_low
reset_low_suffix
: Suffix forreset
type atreset_type = *_low
The sourcemap_target
field
The sourcemap_target
field specifies where the generated source maps will be placed at.
The available types are below:
target
– as the same directory as the target codedirectory
– specified directorynone
– no source map
If you want to use directory
, you should specify the target path by path
key.
[build]
sourcemap_target = {type = "directory", path = "[dst dir]"}
The expand_inside_operation
field
If expand_inside_operation
is set to true
, operations using inside
operator will be expended to logic using ==?
operator.
This is because some EDA tools don’t support inside
operator.
This is false
by default.
[build]
expand_inside_operation = true
The exclude_std
field
If exclude_std
is set to true
, standard library will not be included.
[build]
exclude_std = true
Format
[format]
section specifies the configuration for formatter like below:
[format]
indent_width = 4
Available configurations
Configuration | Value | Description |
---|---|---|
indent_width | integer | indent width by space |
Lint
[lint]
section specifies the configuration for linter like below:
[lint.naming]
case_enum = "snake"
Available configurations
The [lint.naming]
section
This section contains configurations of naming conventions.
Configuration | Value | Description |
---|---|---|
case_enum | case type1 | case style of enum |
case_function | case type1 | case style of function |
case_function_inout | case type1 | case style of inout argument |
case_function_input | case type1 | case style of input argument |
case_function_output | case type1 | case style of output argument |
case_function_ref | case type1 | case style of ref argument |
case_instance | case type1 | case style of instance |
case_interface | case type1 | case style of interface |
case_modport | case type1 | case style of modport |
case_module | case type1 | case style of module |
case_package | case type1 | case style of package |
case_parameter | case type1 | case style of parameter |
case_port_inout | case type1 | case style of inout port |
case_port_input | case type1 | case style of input port |
case_port_modport | case type1 | case style of modport port |
case_port_output | case type1 | case style of output port |
case_reg | case type1 | case style of register type variable2 |
case_struct | case type1 | case style of struct |
case_union | case type1 | case style of union |
case_var | case type1 | case style of variable |
case_wire | case type1 | case style of wire type variable3 |
prefix_enum | string | prefix of enum |
prefix_function | string | prefix of function |
prefix_function_inout | string | prefix of inout argument |
prefix_function_input | string | prefix of input argument |
prefix_function_output | string | prefix of output argument |
prefix_function_ref | string | prefix of ref argument |
prefix_instance | string | prefix of instance |
prefix_interface | string | prefix of interface |
prefix_modport | string | prefix of modport |
prefix_module | string | prefix of module |
prefix_package | string | prefix of package |
prefix_parameter | string | prefix of parameter |
prefix_port_inout | string | prefix of inout port |
prefix_port_input | string | prefix of input port |
prefix_port_modport | string | prefix of modport port |
prefix_port_output | string | prefix of output port |
prefix_reg | string | prefix of register type variable2 |
prefix_struct | string | prefix of struct |
prefix_union | string | prefix of union |
prefix_var | string | prefix of variable |
prefix_wire | string | prefix of wire type variable3 |
suffix_enum | string | suffix of enum |
suffix_function | string | suffix of function |
suffix_function_inout | string | suffix of inout argument |
suffix_function_input | string | suffix of input argument |
suffix_function_output | string | suffix of output argument |
suffix_function_ref | string | suffix of ref argument |
suffix_instance | string | suffix of instance |
suffix_interface | string | suffix of interface |
suffix_modport | string | suffix of modport |
suffix_module | string | suffix of module |
suffix_package | string | suffix of package |
suffix_parameter | string | suffix of parameter |
suffix_port_inout | string | suffix of inout port |
suffix_port_input | string | suffix of input port |
suffix_port_modport | string | suffix of modport port |
suffix_port_output | string | suffix of output port |
suffix_reg | string | suffix of register type variable2 |
suffix_struct | string | suffix of struct |
suffix_union | string | suffix of union |
suffix_var | string | suffix of variable |
suffix_wire | string | suffix of wire type variable3 |
re_forbidden_enum | regex4 | regex forbidden of enum |
re_forbidden_function | regex4 | regex forbidden of function |
re_forbidden_function_inout | regex4 | regex forbidden of inout argument |
re_forbidden_function_input | regex4 | regex forbidden of input argument |
re_forbidden_function_output | regex4 | regex forbidden of output argument |
re_forbidden_function_ref | regex4 | regex forbidden of ref argument |
re_forbidden_instance | regex4 | regex forbidden of instance |
re_forbidden_interface | regex4 | regex forbidden of interface |
re_forbidden_modport | regex4 | regex forbidden of modport |
re_forbidden_module | regex4 | regex forbidden of module |
re_forbidden_package | regex4 | regex forbidden of package |
re_forbidden_parameter | regex4 | regex forbidden of parameter |
re_forbidden_port_inout | regex4 | regex forbidden of inout port |
re_forbidden_port_input | regex4 | regex forbidden of input port |
re_forbidden_port_modport | regex4 | regex forbidden of modport port |
re_forbidden_port_output | regex4 | regex forbidden of output port |
re_forbidden_reg | regex4 | regex forbidden of register type variable2 |
re_forbidden_struct | regex4 | regex forbidden of struct |
re_forbidden_union | regex4 | regex forbidden of union |
re_forbidden_var | regex4 | regex forbidden of variable |
re_forbidden_wire | regex4 | regex forbidden of wire type variable3 |
re_required_enum | regex4 | regex required of enum |
re_required_function | regex4 | regex required of function |
re_required_function_inout | regex4 | regex required of inout argument |
re_required_function_input | regex4 | regex required of input argument |
re_required_function_output | regex4 | regex required of output argument |
re_required_function_ref | regex4 | regex required of ref argument |
re_required_instance | regex4 | regex required of instance |
re_required_interface | regex4 | regex required of interface |
re_required_modport | regex4 | regex required of modport |
re_required_module | regex4 | regex required of module |
re_required_package | regex4 | regex required of package |
re_required_parameter | regex4 | regex required of parameter |
re_required_port_inout | regex4 | regex required of inout port |
re_required_port_input | regex4 | regex required of input port |
re_required_port_modport | regex4 | regex required of modport port |
re_required_port_output | regex4 | regex required of output port |
re_required_reg | regex4 | regex required of register type variable2 |
re_required_struct | regex4 | regex required of struct |
re_required_union | regex4 | regex required of union |
re_required_var | regex4 | regex required of variable |
re_required_wire | regex4 | regex required of wire type variable3 |
The available values are
"snake"
– snake_case"screaming_snake"
– SCREAMING_SNAKE_CASE"lower_camel"
– lowerCamelCase"upper_camel"
– UpperCamelCase
Regular expression string like ".*"
. The available syntax is here.
Register type means that the variable is assigned in always_ff
. It will be mapped to flip-flop in synthesis phase.
Wire type means that the variable is assigned in always_comb
. It will be mapped to wire in synthesis phase.
Test
[test]
section specifies the configuration for integrated unit test like below:
[test]
simulator = "vcs"
Available configurations
The [test]
section
This section contains configurations of test.
Configuration | Value | Description |
---|---|---|
simulator | simulator name1 | default simulator |
The available values are
"verilator"
"vcs"
"vivado"
The [test.verilator]
section
This section contains configurations of test by Verilator.
Configuration | Value | Description |
---|---|---|
compile_args | [string] | additional arguments to verilator command |
simulate_args | [string] | additional arguments to simulation binary |
The [test.vcs]
section
This section contains configurations of test by VCS.
Configuration | Value | Description |
---|---|---|
compile_args | [string] | additional arguments to vcs command |
simulate_args | [string] | additional arguments to simulation binary |
The [test.vivado]
section
This section contains configurations of test by Vivado.
Configuration | Value | Description |
---|---|---|
compile_args | [string] | additional arguments to xvlog command |
elaborate_args | [string] | additional arguments to xelab command |
simulate_args | [string] | additional arguments to xsim command |
The waveform_target
field
The waveform_target
field specifies where the generated waveforms will be placed at.
The available types are below:
target
– as the same directory as the target codedirectory
– specified directory
If you want to use directory
, you should specify the target path by path
key.
[build]
waveform_target = {type = "directory", path = "[dst dir]"}
Publish
[publish]
section specifies the configuration for publishing a project like below:
[publish]
bump_commit = true
bump_commit_message = "Bump"
Available configurations
Configuration | Value | Default | Description |
---|---|---|---|
bump_commit | boolean | false | automatic commit after bump |
publish_commit | boolean | false | automatic commit after publish |
bump_commit_mesasge | string | “chore: Bump version” | commit message after bump |
publish_commit_mesasge | string | “chore: Publish” | commit message after publish |
Dependencies
If you want to add other Veryl projects to dependencies of your project, you can add them to [dependencies]
section in Veryl.toml
.
The left hand side of entry is path to the dependency, and the right hand side is version.
[dependencies]
"https://github.com/veryl-lang/sample" = "0.1.0"
By default, the namespace of the dependency is the same as the project name of the dependency.
If you want to specify namespace, you can use name
field.
[dependencies]
"https://github.com/veryl-lang/sample" = {version = "0.1.0", name = "veryl_sample_alt"}
If you want to use many versions of the same dependency path, you can specify each name.
[dependencies]
"https://github.com/veryl-lang/sample" = [
{version = "0.1.0", name = "veryl_sample1"},
{version = "0.2.0", name = "veryl_sample2"},
]
Usage of dependency
After adding dependencies to Veryl.toml
, you can use module
, interface
and package
in the dependencies.
The following example uses delay
module in the veryl_sample
dependency.
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 ,
);
}
Note: The result of play button in the above code is not exact because it doesn’t use dependency resolution. Actually the module name becomes
veryl_sample_delay
Version Requirement
The version
field of [dependencies]
section shows version requirement.
For example, version = "0.1.0"
means the latest version which has compatibility with 0.1.0
.
The compatibility is judged by Semantic Versioning.
A version is constructed from the following three parts.
MAJOR
version when you make incompatible API changesMINOR
version when you add functionality in a backwards compatible mannerPATCH
version when you make backwards compatible bug fixes
If MAJOR
version is 0
, MINOR
is interpreted as incompatible changes.
If there are 0.1.0
and 0.1.1
and 0.2.0
, 0.1.1
will be selected.
This is because
0.1.0
is compatible with0.1.0
.0.1.1
is compatible with0.1.0
.0.2.0
is not compatible with0.1.0
.0.1.1
is the latest in the compatible versions.
The version
field allows other version requirement representation like =0.1.0
.
Please see version requirement of Rust for detailed information: Specifying Dependencies.
Publish Project
To publish your project, veryl publish
can be used.
Publising means to associate a version with a git revision.
$ veryl publish
[INFO ] Publishing release (0.2.1 @ 297bc6b24c5ceca9e648c3ea5e01011c67d7efe7)
[INFO ] Writing metadata ([path to project]/Veryl.pub)
veryl publish
generates Veryl.pub
which contains published version information like below.
[[releases]]
version = "0.2.1"
revision = "297bc6b24c5ceca9e648c3ea5e01011c67d7efe7"
After generating Veryl.pub
, publishing sequence is completed by git add, commit and push.
The git branch to be committed must be the default branch because Veryl search Veryl.pub
in the default branch.
$ git add Veryl.pub
$ git commit -m "Publish"
$ git push
If you enable automatic commit by publish_commit
in [publish]
section of Veryl.toml
, git add and commit will be executed after publish.
$ 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)
Version Bump
You can bump version with publish at the same time by --bump
option.
As the same as publish, bump_commit
in [publish]
section of Veryl.toml
can specify automatic commit after bump version.
$ 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)
Configuration
The available configurations are here.
Directory Layout
Veryl supports arbitrary directory layout. This is because the optimal directory layout for an independent project and an integrated project within other projects is different.
In this section, we suggest some directory layout patterns.
Single source directory
This pattern contains all sources in src
directory.
In src
, you can configure arbitrary sub directories.
$ tree
.
|-- src
| |-- module_a.veryl
| `-- module_b
| |-- module_b.veryl
| `-- module_c.veryl
`-- Veryl.toml
2 directories, 4 files
Veryl gathers all *.veryl
files and generates codes at the same directory as the source by default.
You can show the behavior explicitly by the following configuration.
[build]
target = "source"
After veryl build
, the directory structure will become below:
$ 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
Single source and target directory
If you want to place the generated codes into a directory, you can use target
configure in [build]
section of Veryl.toml
.
[build]
target = {type = "directory", path = "target"}
The directory layout of this configure will become below:
$ 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
Multi source directory
If you want to add a veryl project to the existing SystemVerilog project, you can choose the following structure.
$ 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
The generated prj.f
lists all generated files. So you can use it along with the existing SystemVerilog filelists.
About .gitignore
Veryl doesn’t provide the default .gitignore
.
This is because which files should be ignored is different by each projects.
The candidates of .gitignore
is below:
dependencies/
target/
*.sv
*.f
Formatter
Source code can be formatted by veryl fmt
command.
Alternatively, language server support formatting through textDocument/formatting
request.
The available configurations are here.
Linter
Lint check is executed at veryl check
or veryl build
.
Alternatively, language server checks lint in real time.
The available configurations are here.
Simulator
Test by RTL simulator is executed through veryl test
.
Supported simulators are below:
Verilator is the default simulator.
If no simulator is specified through Veryl.toml
and command-line option, it will be used.
The available configurations are here.
cocotb
cocotb
tests require python3
environment in which cocotb
is installed.
The supported version of cocotb
is 1.9.0 only.
For example, it can be installed by the following command.
$ pip3 install cocotb==1.9.0
As simulator backend, Verilator is only supported.
Language Server
veryl-ls
is a language server binary.
If you want to use it, editor configuration or plugin to use it is required.
The available configurations are below. These can be specified by each editor’s config.
Configuration | Value | Default | Description |
---|---|---|---|
useOperatorCompletion | boolean | false | use operator (e.g. ‘>:’, ‘>>’) completion |
Compatibility
Some tools supporting SystemVerilog don’t support some features.
Code generation can be customized by configuration of Veryl.toml
to support these tools.
Vivado
String parameter
Vivado don’t support parameter
which is typed as string
.
parameter string a = "A";
So you can use implicit_parameter_types
like below:
[build]
implicit_parameter_types = ["string"]
By the configuration, the generated code becomes like below:
parameter a = "A";
Quartus
inside
operator
Quartus don’t support inside
operator.
So you can use expand_inside_operation
like below:
[build]
expand_inside_operation = true
By the configuration, operations using inside
operator will be expanded to logic using ==?
operator.
Documentation
Document of project can be generated by veryl doc
command.
All public modules, interfaces and packages will be listed in it. (See Visibility )
If you want to add a detailed description, you can add documentation comment. In the documentation comment, Markdown syntax can be used.
The following formats are supported too.
Each syntax can be used in wavedrom
and mermaid
code block.
Please refer the following for the detailed syntax.
/// The detailed description of ModuleA
///
/// * list item0
/// * list item1
///
/// ```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 #(
/// Data width
param ParamA: u32 = 1,
const ParamB: u32 = 1,
) (
i_clk : input clock , /// Clock
i_rst : input reset , /// Reset
i_data: input logic<ParamA>, /// Data input
o_data: output logic<ParamA>, /// Data output
) {
assign o_data = 0;
}
The available configurations are below.
These can be specified in [doc]
section of Veryl.toml
.
[doc]
path = "document"
Configuration | Value | Default | Description |
---|---|---|---|
path | string | “doc” | path to output directory |
GitHub Action
The official GitHub action to download a prebuilt binary of Veryl is provided.
https://github.com/marketplace/actions/setup-veryl
The examples of GitHub action script are below:
- Format and build check
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
- Publish document through 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
- Test by Verilator
For this purpose, we provide 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
Source Map
Source map is a file to be used for tracking location from SystemVerilog to Veryl. By this file, a file path, line and column of SystemVerilog can be translated into the position in Veryl.
By default, Veryl generates source map at the same directory as generated SystemVerilog with .sv.map
extension.
Source map generation can be configured through sourcemap_target
field in Veryl.toml
.
The format of source map follows Source Map Revision 3. The convention of linking generated code to source map is almost the same as JavaScript, but relative path is used only:
//# sourceMappingURL=<relative path>
So, if there is the above comment at the end of a SystemVerilog file, it shows source map can be used.
sourcemap-resolver
sourcemap-resolver
which is shipped together Veryl compiler can be used to annotate arbitrary text file like below:
ERROR: [VRFC 10-4982] syntax error near 'endmodule' [/path/test.sv:23]
^-- /path/test.veryl:18:18
The first line is the original text, and the second line is added by sourcemap-resolver
.
The usage examples are below:
$ sourcemap-resolver test.log # annotate the existing log
$ [command] | sourcemap-resolver # on-the-fly annotation by pipe
verylup
verylup is the official toolchain installer of Veryl. It eases to update and switch toolchains.
Update toolchain
The following command updates Veryl toolchain and verylup to the latest version.
verylup update
Install a specific toolchain
If you want to use a specific version of Veryl, verylup install
can be used.
verylup install 0.12.0
After installing it, +
version specifier can be used in veryl
command like below:
veryl +0.12.0 build
Toolchain override for directories
If you want to use a specific version of Veryl for specific directories, verylup override
can be used.
verylup override set 0.12.0
verylup override
can be executed in arbitrary directories in a Veryl project.
After this command, the default toolchain becomes 0.12.0
in the project.
Offline installation
If you want to verylup on an environment without internet access, offline installation can be used. The procedure of offline installation is below:
- Download the latest toolchain package from Veryl release page.
- Execute
veryl setup
with--pkg
specification like the following command.
verylup setup --offline --pkg veryl-x86_64-linux.zip
If you want to update/install toolchain, --pkg
specification is required as the same as setup.
verylup update --pkg veryl-x86_64-linux.zip
verylup install 0.12.0 --pkg veryl-x86_64-linux.zip
For Veryl Developer
For Veryl developer, a special toolchain target local
is prepared.
If verylup install local
is executed in your local Veryl repository, the built toolchain is installed as local
toolchain.
local
becomes the default toolchain if it exists.
// Build and install the toolchain from local Veryl repository
verylup install local
// Use the built toolchain
veryl build
// Use the latest toolchain
veryl +latest build
Appendix
Formal Syntax
Veryl’s parser is based on parser generator parol. The following syntex definition of parol is formal syntax.
%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
%scanner Embed {
%auto_newline_off
%auto_ws_off
}
%scanner Generic {
}
%%
// ----------------------------------------------------------------------------
// Terminal
// ----------------------------------------------------------------------------
// Longest match should be first
CommentsTerm : <INITIAL, Generic >"(?:(?:(?://.*(?:\r\n|\r|\n|$))|(?:(?ms)/\u{2a}.*?\u{2a}/))\s*)+" : Token;
StringLiteralTerm : <INITIAL, Generic >"\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;
PlusColonTerm : <INITIAL >'+:' : Token;
AssignmentOperatorTerm: <INITIAL >"\+=|-=|\*=|/=|%=|&=|\|=|\^=|<<=|>>=|<<<=|>>>=" : Token;
Operator11Term : <INITIAL >"\*\*" : Token;
Operator10Term : <INITIAL >"/|%" : Token;
Operator09Term : <INITIAL >"\+|-" : Token;
Operator08Term : <INITIAL >"<<<|>>>|<<|>>" : Token;
Operator07Term : <INITIAL >"<=|>=|<:|>:" : Token;
Operator06Term : <INITIAL >"===|==\?|!==|!=\?|==|!=" : Token;
Operator02Term : <INITIAL >"&&" : Token;
Operator01Term : <INITIAL >"\|\|" : Token;
Operator05Term : <INITIAL >"&" : Token;
Operator04Term : <INITIAL >"\^~|\^|~\^" : Token;
Operator03Term : <INITIAL >"\|" : Token;
UnaryOperatorTerm : <INITIAL >"~&|~\||!|~" : Token;
BackQuoteTerm : <INITIAL, Generic >"`" : Token;
ColonColonLAngleTerm : <INITIAL, Generic >'::<' : Token;
ColonColonTerm : <INITIAL, Generic >'::' : Token;
ColonTerm : <INITIAL, Generic >':' : Token;
CommaTerm : <INITIAL, Generic >',' : Token;
DotDotEquTerm : <INITIAL, Generic >'..=' : Token;
DotDotTerm : <INITIAL, Generic >'..' : Token;
DotTerm : <INITIAL, Generic >'.' : Token;
EquTerm : <INITIAL, Generic >'=' : Token;
HashTerm : <INITIAL, Generic >'#' : Token;
LAngleTerm : <INITIAL, Generic >'<' : Token;
QuoteLBraceTerm : <INITIAL, Generic >"'\{" : Token;
LBraceTerm : <INITIAL, Generic, Embed>'{' : Token;
LBracketTerm : <INITIAL, Generic >'[' : Token;
LParenTerm : <INITIAL, Generic >'(' : Token;
RAngleTerm : <INITIAL, Generic >'>' : Token;
RBraceTerm : <INITIAL, Generic, Embed>'}' : Token;
RBracketTerm : <INITIAL, Generic >']' : Token;
RParenTerm : <INITIAL, Generic >')' : Token;
SemicolonTerm : <INITIAL, Generic >';' : Token;
StarTerm : <INITIAL, Generic >'*' : Token;
AlwaysCombTerm : <INITIAL, Generic >/(?-u:\b)always_comb(?-u:\b)/ : Token;
AlwaysFfTerm : <INITIAL, Generic >/(?-u:\b)always_ff(?-u:\b)/ : Token;
AssignTerm : <INITIAL, Generic >/(?-u:\b)assign(?-u:\b)/ : Token;
AsTerm : <INITIAL, Generic >/(?-u:\b)as(?-u:\b)/ : Token;
BitTerm : <INITIAL, Generic >/(?-u:\b)bit(?-u:\b)/ : Token;
CaseTerm : <INITIAL, Generic >/(?-u:\b)case(?-u:\b)/ : Token;
ClockTerm : <INITIAL, Generic >/(?-u:\b)clock(?-u:\b)/ : Token;
ClockPosedgeTerm : <INITIAL, Generic >/(?-u:\b)clock_posedge(?-u:\b)/ : Token;
ClockNegedgeTerm : <INITIAL, Generic >/(?-u:\b)clock_negedge(?-u:\b)/ : Token;
ConstTerm : <INITIAL, Generic >/(?-u:\b)const(?-u:\b)/ : Token;
DefaultTerm : <INITIAL, Generic >/(?-u:\b)default(?-u:\b)/ : Token;
ElseTerm : <INITIAL, Generic >/(?-u:\b)else(?-u:\b)/ : Token;
EmbedTerm : <INITIAL, Generic >/(?-u:\b)embed(?-u:\b)/ : Token;
EnumTerm : <INITIAL, Generic >/(?-u:\b)enum(?-u:\b)/ : Token;
ExportTerm : <INITIAL, Generic >/(?-u:\b)export(?-u:\b)/ : Token;
F32Term : <INITIAL, Generic >/(?-u:\b)f32(?-u:\b)/ : Token;
F64Term : <INITIAL, Generic >/(?-u:\b)f64(?-u:\b)/ : Token;
FinalTerm : <INITIAL, Generic >/(?-u:\b)final(?-u:\b)/ : Token;
ForTerm : <INITIAL, Generic >/(?-u:\b)for(?-u:\b)/ : Token;
FunctionTerm : <INITIAL, Generic >/(?-u:\b)function(?-u:\b)/ : Token;
I32Term : <INITIAL, Generic >/(?-u:\b)i32(?-u:\b)/ : Token;
I64Term : <INITIAL, Generic >/(?-u:\b)i64(?-u:\b)/ : Token;
IfResetTerm : <INITIAL, Generic >/(?-u:\b)if_reset(?-u:\b)/ : Token;
IfTerm : <INITIAL, Generic >/(?-u:\b)if(?-u:\b)/ : Token;
ImportTerm : <INITIAL, Generic >/(?-u:\b)import(?-u:\b)/ : Token;
IncludeTerm : <INITIAL, Generic >/(?-u:\b)include(?-u:\b)/ : Token;
InitialTerm : <INITIAL, Generic >/(?-u:\b)initial(?-u:\b)/ : Token;
InoutTerm : <INITIAL, Generic >/(?-u:\b)inout(?-u:\b)/ : Token;
InputTerm : <INITIAL, Generic >/(?-u:\b)input(?-u:\b)/ : Token;
InsideTerm : <INITIAL, Generic >/(?-u:\b)inside(?-u:\b)/ : Token;
InstTerm : <INITIAL, Generic >/(?-u:\b)inst(?-u:\b)/ : Token;
InterfaceTerm : <INITIAL, Generic >/(?-u:\b)interface(?-u:\b)/ : Token;
InTerm : <INITIAL, Generic >/(?-u:\b)in(?-u:\b)/ : Token;
LetTerm : <INITIAL, Generic >/(?-u:\b)let(?-u:\b)/ : Token;
LogicTerm : <INITIAL, Generic >/(?-u:\b)logic(?-u:\b)/ : Token;
LsbTerm : <INITIAL, Generic >/(?-u:\b)lsb(?-u:\b)/ : Token;
ModportTerm : <INITIAL, Generic >/(?-u:\b)modport(?-u:\b)/ : Token;
ModuleTerm : <INITIAL, Generic >/(?-u:\b)module(?-u:\b)/ : Token;
MsbTerm : <INITIAL, Generic >/(?-u:\b)msb(?-u:\b)/ : Token;
OutputTerm : <INITIAL, Generic >/(?-u:\b)output(?-u:\b)/ : Token;
OutsideTerm : <INITIAL, Generic >/(?-u:\b)outside(?-u:\b)/ : Token;
PackageTerm : <INITIAL, Generic >/(?-u:\b)package(?-u:\b)/ : Token;
ParamTerm : <INITIAL, Generic >/(?-u:\b)param(?-u:\b)/ : Token;
ProtoTerm : <INITIAL, Generic >/(?-u:\b)proto(?-u:\b)/ : Token;
PubTerm : <INITIAL, Generic >/(?-u:\b)pub(?-u:\b)/ : Token;
RefTerm : <INITIAL, Generic >/(?-u:\b)ref(?-u:\b)/ : Token;
RepeatTerm : <INITIAL, Generic >/(?-u:\b)repeat(?-u:\b)/ : Token;
ResetTerm : <INITIAL, Generic >/(?-u:\b)reset(?-u:\b)/ : Token;
ResetAsyncHighTerm : <INITIAL, Generic >/(?-u:\b)reset_async_high(?-u:\b)/ : Token;
ResetAsyncLowTerm : <INITIAL, Generic >/(?-u:\b)reset_async_low(?-u:\b)/ : Token;
ResetSyncHighTerm : <INITIAL, Generic >/(?-u:\b)reset_sync_high(?-u:\b)/ : Token;
ResetSyncLowTerm : <INITIAL, Generic >/(?-u:\b)reset_sync_low(?-u:\b)/ : Token;
ReturnTerm : <INITIAL, Generic >/(?-u:\b)return(?-u:\b)/ : Token;
BreakTerm : <INITIAL, Generic >/(?-u:\b)break(?-u:\b)/ : Token;
SignedTerm : <INITIAL, Generic >/(?-u:\b)signed(?-u:\b)/ : Token;
StepTerm : <INITIAL, Generic >/(?-u:\b)step(?-u:\b)/ : Token;
StringTerm : <INITIAL, Generic >/(?-u:\b)string(?-u:\b)/ : Token;
StructTerm : <INITIAL, Generic >/(?-u:\b)struct(?-u:\b)/ : Token;
SwitchTerm : <INITIAL, Generic >/(?-u:\b)switch(?-u:\b)/ : Token;
TriTerm : <INITIAL, Generic >/(?-u:\b)tri(?-u:\b)/ : Token;
TypeTerm : <INITIAL, Generic >/(?-u:\b)type(?-u:\b)/ : Token;
U32Term : <INITIAL, Generic >/(?-u:\b)u32(?-u:\b)/ : Token;
U64Term : <INITIAL, Generic >/(?-u:\b)u64(?-u:\b)/ : Token;
UnionTerm : <INITIAL, Generic >/(?-u:\b)union(?-u:\b)/ : Token;
UnsafeTerm : <INITIAL, Generic >/(?-u:\b)unsafe(?-u:\b)/ : Token;
VarTerm : <INITIAL, Generic >/(?-u:\b)var(?-u:\b)/ : Token;
DollarIdentifierTerm : <INITIAL, Generic >/\$[a-zA-Z_][0-9a-zA-Z_$]*/ : Token;
IdentifierTerm : <INITIAL, Generic >/(?:r#)?[a-zA-Z_][0-9a-zA-Z_$]*/ : Token;
AnyTerm : < Embed>/[^{}]*/ : 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;
Operator01Token : Operator01Term : 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;
UnaryOperatorToken : UnaryOperatorTerm : Token Comments;
BackQuoteToken : BackQuoteTerm : 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;
HashToken : HashTerm : Token Comments;
QuoteLBraceToken : QuoteLBraceTerm : Token Comments;
LAngleToken : LAngleTerm : Token Comments;
LBraceToken : LBraceTerm : Token Comments;
LBracketToken : LBracketTerm : Token Comments;
LParenToken : LParenTerm : Token Comments;
MinusColonToken : MinusColonTerm : Token Comments;
MinusGTToken : MinusGTTerm : Token Comments;
PlusColonToken : PlusColonTerm : Token Comments;
RAngleToken : RAngleTerm : Token Comments;
RBraceToken : RBraceTerm : Token Comments;
RBracketToken : RBracketTerm : Token Comments;
RParenToken : RParenTerm : Token Comments;
SemicolonToken : SemicolonTerm : Token Comments;
StarToken : StarTerm : Token Comments;
AlwaysCombToken : AlwaysCombTerm : Token Comments;
AlwaysFfToken : AlwaysFfTerm : Token Comments;
AsToken : AsTerm : Token Comments;
AssignToken : AssignTerm : Token Comments;
BitToken : BitTerm : Token Comments;
CaseToken : CaseTerm : Token Comments;
ClockToken : ClockTerm : Token Comments;
ClockPosedgeToken : ClockPosedgeTerm : Token Comments;
ClockNegedgeToken : ClockNegedgeTerm : Token Comments;
ConstToken : ConstTerm : Token Comments;
DefaultToken : DefaultTerm : Token Comments;
ElseToken : ElseTerm : Token Comments;
EmbedToken : EmbedTerm : Token Comments;
EnumToken : EnumTerm : Token Comments;
ExportToken : ExportTerm : Token Comments;
F32Token : F32Term : Token Comments;
F64Token : F64Term : Token Comments;
FinalToken : FinalTerm : Token Comments;
ForToken : ForTerm : Token Comments;
FunctionToken : FunctionTerm : 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;
RefToken : RefTerm : 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;
BreakToken : BreakTerm : 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;
TypeToken : TypeTerm : 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;
// ----------------------------------------------------------------------------
// 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;
Operator01 : Operator01Token : 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;
UnaryOperator : UnaryOperatorToken : VerylToken;
// Symbol
BackQuote : BackQuoteToken : VerylToken;
Colon : ColonToken : VerylToken;
ColonColonLAngle: ColonColonLAngleToken: VerylToken;
ColonColon : ColonColonToken : VerylToken;
Comma : CommaToken : VerylToken;
DotDot : DotDotToken : VerylToken;
DotDotEqu : DotDotEquToken : VerylToken;
Dot : DotToken : VerylToken;
Equ : EquToken : VerylToken;
Hash : HashToken : VerylToken;
QuoteLBrace : QuoteLBraceToken : VerylToken;
LAngle : LAngleToken : VerylToken;
LBrace : LBraceToken : VerylToken;
LBracket : LBracketToken : VerylToken;
LParen : LParenToken : VerylToken;
MinusColon : MinusColonToken : VerylToken;
MinusGT : MinusGTToken : VerylToken;
PlusColon : PlusColonToken : VerylToken;
RAngle : RAngleToken : VerylToken;
RBrace : RBraceToken : VerylToken;
RBracket : RBracketToken : VerylToken;
RParen : RParenToken : VerylToken;
Semicolon : SemicolonToken : VerylToken;
Star : StarToken : VerylToken;
// Keyword
AlwaysComb : AlwaysCombToken : VerylToken;
AlwaysFf : AlwaysFfToken : VerylToken;
As : AsToken : VerylToken;
Assign : AssignToken : VerylToken;
Bit : BitToken : VerylToken;
Break : BreakToken : VerylToken;
Case : CaseToken : VerylToken;
Clock : ClockToken : VerylToken;
ClockPosedge : ClockPosedgeToken : VerylToken;
ClockNegedge : ClockNegedgeToken : VerylToken;
Const : ConstToken : VerylToken;
Defaul : DefaultToken : VerylToken; // avoid to conflict with Rust's Default trait
Else : ElseToken : VerylToken;
Embed : EmbedToken : VerylToken;
Enum : EnumToken : VerylToken;
Export : ExportToken : VerylToken;
F32 : F32Token : VerylToken;
F64 : F64Token : VerylToken;
Final : FinalToken : VerylToken;
For : ForToken : VerylToken;
Function : FunctionToken : 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;
Ref : RefToken : VerylToken;
Repeat : RepeatToken : VerylToken;
Reset : ResetToken : VerylToken;
ResetAsyncHigh: ResetAsyncHighToken: VerylToken;
ResetAsyncLow : ResetAsyncLowToken : VerylToken;
ResetSyncHigh : ResetSyncHighToken : VerylToken;
ResetSyncLow : ResetSyncLowToken : VerylToken;
Return : ReturnToken : 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;
Type : TypeToken : VerylToken;
U32 : U32Token : VerylToken;
U64 : U64Token : VerylToken;
Union : UnionToken : VerylToken;
Unsafe : UnsafeToken : VerylToken;
Var : VarToken : VerylToken;
// Identifier
DollarIdentifier: DollarIdentifierToken: VerylToken;
Identifier : IdentifierToken : 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 : Expression01 { Operator01 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 | Star ) Expression10 };
Expression10: Expression11 { Operator11 Expression11 };
Expression11: Expression12 [ As CastingType ];
Expression12: { ( UnaryOperator | Operator09 | Operator05 | Operator03 | Operator04 ) } Factor;
Factor: Number
| ExpressionIdentifier [ FunctionCall ]
| LParen Expression RParen
| LBrace ConcatenationList RBrace
| QuoteLBrace ArrayLiteralList RBrace
| IfExpression
| CaseExpression
| SwitchExpression
| StringLiteral
| ( Msb | Lsb )
| InsideExpression
| OutsideExpression
| TypeExpression
| FactorType
;
FunctionCall: LParen [ ArgumentList ] RParen;
ArgumentList: ArgumentItem { Comma ArgumentItem } [ Comma ];
ArgumentItem: Expression;
ConcatenationList: ConcatenationItem { Comma ConcatenationItem } [ Comma ];
ConcatenationItem: Expression [ Repeat Expression ];
ArrayLiteralList: ArrayLiteralItem { Comma ArrayLiteralItem } [ Comma ];
ArrayLiteralItem: ( Expression [ Repeat Expression ] | Defaul Colon Expression );
IfExpression: If Expression LBrace Expression RBrace { Else If Expression LBrace Expression RBrace } Else LBrace Expression RBrace;
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: U32 | U64 | I32 | I64 | F32 | F64 | Strin;
VariableType: Clock
| ClockPosedge
| ClockNegedge
| Reset
| ResetAsyncHigh
| ResetAsyncLow
| ResetSyncHigh
| ResetSyncLow
| Logic
| Bit;
UserDefinedType: ScopedIdentifier;
TypeModifier: Tri | Signed;
FactorType: ( VariableType [ Width ] | FixedType );
ScalarType: { TypeModifier } ( UserDefinedType [ Width ] | FactorType );
ArrayType: ScalarType [ Array ];
CastingType: U32
| U64
| I32
| I64
| F32
| F64
| Clock
| ClockPosedge
| ClockNegedge
| Reset
| ResetAsyncHigh
| ResetAsyncLow
| ResetSyncHigh
| ResetSyncLow
| UserDefinedType
;
// ----------------------------------------------------------------------------
// ClockDomain
// ----------------------------------------------------------------------------
ClockDomain: BackQuote Identifier;
// ----------------------------------------------------------------------------
// Statement
// ----------------------------------------------------------------------------
StatementBlock: LBrace { StatementBlockItem } RBrace;
StatementBlockItem: VarDeclaration | LetStatement | 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 ) 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 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: Hash LBracket 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 [ AlwayfFfEventList ] StatementBlock;
AlwayfFfEventList: LParen AlwaysFfClock [ Comma AlwaysFfReset ] RParen;
AlwaysFfClock: HierarchicalIdentifier;
AlwaysFfReset: HierarchicalIdentifier;
AlwaysCombDeclaration: AlwaysComb StatementBlock;
AssignDeclaration: Assign HierarchicalIdentifier Equ Expression Semicolon;
ModportDeclaration: Modport Identifier LBrace ModportList RBrace;
ModportList: ModportGroup { Comma ModportGroup } [ Comma ];
ModportGroup: { Attribute } ( LBrace ModportList RBrace | ModportItem );
ModportItem: Identifier Colon Direction;
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
// ----------------------------------------------------------------------------
InstDeclaration: Inst Identifier Colon ScopedIdentifier [ Array ] [ InstParameter ] [ LParen [ InstPortList ] RParen ] Semicolon;
InstParameter: Hash LParen [ InstParameterList ] RParen;
InstParameterList: InstParameterGroup { Comma InstParameterGroup } [ Comma ];
InstParameterGroup: { Attribute } ( LBrace InstParameterList RBrace | InstParameterItem );
InstParameterItem: Identifier [ Colon Expression ];
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: Const
| Type
| ScopedIdentifier;
WithGenericParameter: ColonColonLAngle WithGenericParameterList RAngle;
WithGenericParameterList: WithGenericParameterItem { Comma WithGenericParameterItem } [ Comma ];
WithGenericParameterItem: Identifier Colon GenericBound [ Equ WithGenericArgumentItem ];
// ----------------------------------------------------------------------------
// WithGenericArgument
// ----------------------------------------------------------------------------
WithGenericArgument: ColonColonLAngle %push(Generic) [ WithGenericArgumentList ] RAngle %pop();
WithGenericArgumentList: WithGenericArgumentItem { Comma WithGenericArgumentItem } [ Comma ];
WithGenericArgumentItem: ScopedIdentifier
| Number
;
// ----------------------------------------------------------------------------
// 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;
PortTypeAbstract: [ ClockDomain ] Interface [ Array ];
Direction: Input
| Output
| Inout
| Ref
| Modport
| Import
;
// ----------------------------------------------------------------------------
// Function
// ----------------------------------------------------------------------------
FunctionDeclaration: Function Identifier [ WithGenericParameter ] [ PortDeclaration ] [ MinusGT ScalarType ] StatementBlock;
// ----------------------------------------------------------------------------
// Import / Export
// ----------------------------------------------------------------------------
ImportDeclaration: Import ScopedIdentifier [ ColonColon Star ] Semicolon;
ExportDeclaration: Export ( Star | ScopedIdentifier [ ColonColon Star ] ) Semicolon;
// ----------------------------------------------------------------------------
// Unsafe
// ----------------------------------------------------------------------------
UnsafeBlock: Unsafe LParen Identifier RParen LBrace { GenerateGroup } RBrace;
// ----------------------------------------------------------------------------
// Module/Interface
// ----------------------------------------------------------------------------
ModuleDeclaration: [ Pub ] Module Identifier [ WithGenericParameter ] [ For ScopedIdentifier ] [ WithParameter ] [ PortDeclaration ] LBrace { ModuleGroup } RBrace;
ModuleGroup: { Attribute } ( LBrace { ModuleGroup } RBrace | ModuleItem );
ModuleItem: GenerateItem;
InterfaceDeclaration: [ Pub ] Interface Identifier [ WithGenericParameter ] [ 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 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
| ConstDeclaration
| AlwaysFfDeclaration
| AlwaysCombDeclaration
| AssignDeclaration
| FunctionDeclaration
| GenerateIfDeclaration
| GenerateForDeclaration
| GenerateBlockDeclaration
| TypeDefDeclaration
| EnumDeclaration
| StructUnionDeclaration
| ImportDeclaration
| InitialDeclaration
| FinalDeclaration
| UnsafeBlock
;
// ----------------------------------------------------------------------------
// Package
// ----------------------------------------------------------------------------
PackageDeclaration: [ Pub ] Package Identifier [ WithGenericParameter ] LBrace { PackageGroup } RBrace;
PackageGroup: { Attribute } ( LBrace { PackageGroup } RBrace | PackageItem );
PackageItem: VarDeclaration
| ConstDeclaration
| TypeDefDeclaration
| EnumDeclaration
| StructUnionDeclaration
| FunctionDeclaration
| ImportDeclaration
| ExportDeclaration
;
// ----------------------------------------------------------------------------
// Proto
// ----------------------------------------------------------------------------
ProtoModuleDeclaration: [ Pub ] Proto Module Identifier [ WithParameter ] [ PortDeclaration ] Semicolon;
// ----------------------------------------------------------------------------
// Embed
// ----------------------------------------------------------------------------
EmbedDeclaration: Embed LParen Identifier RParen Identifier EmbedContent;
EmbedContent: EmbedContentToken: VerylToken;
EmbedContentToken: LBraceTerm %push(Embed) LBraceTerm LBraceTerm { EmbedItem } RBraceTerm RBraceTerm RBraceTerm %pop() Comments;
EmbedItem: LBraceTerm { EmbedItem } RBraceTerm
| AnyTerm;
// ----------------------------------------------------------------------------
// Include
// ----------------------------------------------------------------------------
IncludeDeclaration: Include LParen Identifier Comma StringLiteral RParen Semicolon;
// ----------------------------------------------------------------------------
// Description
// ----------------------------------------------------------------------------
DescriptionGroup: { Attribute } ( LBrace { DescriptionGroup } RBrace | DescriptionItem );
DescriptionItem: ModuleDeclaration
| InterfaceDeclaration
| PackageDeclaration
| ProtoModuleDeclaration
| ImportDeclaration
| EmbedDeclaration
| IncludeDeclaration
;
// ----------------------------------------------------------------------------
// SourceCode
// ----------------------------------------------------------------------------
Veryl: Start { DescriptionGroup };