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
- 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 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 |
---|---|
|
|
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.
SystemVerilog | Veryl |
---|---|
|
|
Documentation comment
Writing module descriptions as documentation comments allows for automatic documentation generation. You can use not only plain text but also MarkDown format or waveform descriptions using WaveDrom.
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
You can install Veryl by downloading binary.
If you have Rust development environment, you can use cargo
instead of it.
Requirement
Veryl uses git
command internally. Please confirm git
can be launched.
Choose a way of installation
Download binary
Download from release page, and extract to the directory in PATH.
Cargo
You can install with cargo.
cargo install veryl veryl-ls
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.
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,
local 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
) {
// local parameter declaration
// `param` is not allowed in module
local ParamC: u32 = 10;
// variable declaration
var r_data0: logic<ParamA>;
var r_data1: 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;
}
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,
) {
local 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 {
local ParamA: u32 = 1;
local 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_]*
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
32'o01234567xzXZ
32'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 {
local a0: u64 = 'b0101;
local a1: u64 = 'o01234567;
local a2: u64 = 'd0123456789;
local a3: u64 = 'h0123456789fffff;
}
Set sized bits
The bit width specification can be added to “set all bits”.
module ModuleA {
local a0: u64 = 1'0;
local a1: u64 = 2'1;
local a2: u64 = 3'x;
local 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 local
only.
module ModuleA {
local a: type = logic;
local b: type = logic<10>;
local 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;
}
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 | |
{} | 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
Another conditional expression is case
.
case
containts some arms like expression: expression
.
If the expression after case
keyword matches the left expression of an arm,
the right expression of the arm will be returned.
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>;
let c: logic<10> = 1;
assign b = case a {
0 : 1,
1 : 2,
c - 1 : 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];
}
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
case
can be used as statement.
The right-hand of arm is statement.
module ModuleA {
let a: logic<10> = 1;
var b: logic<10>;
always_comb {
case a {
0: b = 1;
1: b = 2;
2: {
b = 3;
b = 3;
b = 3;
}
default: b = 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.
local
keyword can be used in module, it can’t be overridden.
module ModuleA #(
param ParamA: u32 = 1,
) {
local 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
.
module ModuleA (
i_clk: input clock,
i_rst: input reset,
) {
var a: logic<10>;
var b: logic<10>;
always_ff (i_clk) {
a = 1;
}
always_ff (i_clk, i_rst) {
if_reset {
b = 0;
} else {
b = 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;
}
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 {
local paramA: u32 = 1;
}
export
declaration exports symbols from the package to other.
export *
represents to export all symbols.
package PackageA {
local 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 {
local 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;
}
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 is
The code block are started by lang{{{
and ended by }}}
.
The following lang
specifiers are supported:
sv
: SystemVerilog
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.
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
}}}
About RTL simulator used by veryl test
, see Simulator.
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 ::<>
.
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> (
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>;
}
module ModuleB::<T> {
inst u: T;
}
module ModuleC {}
module ModuleD {}
Generic Package
module ModuleA {
local A: u32 = PackageA::<1>::X;
local B: u32 = PackageA::<2>::X;
}
package PackageA::<T> {
local X: u32 = T;
}
Generic Struct
module ModuleA {
type TypeA = i32;
struct StructA::<T> {
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;
}
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.clock_type
— The type of clock.reset_type
— The type of reset.filelist_type
— The type of filelist.target
— The way of output.implicit_parameter_types
— Whether implicit parameter type is enabled.omit_project_prefix
— Whether omit project prefix.strip_comments
— Whether strip comments.
[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 charaters 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.
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 [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.
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 moudle
, 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_samlle_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 reprensentation 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
[publish]
bump_commit = true
bump_commit_message = "Bump"
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 |
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 behaviour 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 below.
These can be specified in [format]
section of Veryl.toml
.
[format]
indent_width = 4
Configuration | Value | Description |
---|---|---|
indent_width | integer | indent width by space |
Linter
Lint check is executed at veryl check
or veryl build
.
Alternatively, language server checks lint in real time.
The available configurations are below.
These can be specified in [lint]
section of Veryl.toml
.
[lint.naming]
case_enum = "snake"
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_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_wire | case type1 | case style of wire type variable3 |
prefix_enum | string | prefix of enum |
prefix_function | string | prefix of function |
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_wire | string | prefix of wire type variable3 |
re_forbidden_enum | regex4 | regex forbidden of enum |
re_forbidden_function | regex4 | regex forbidden of function |
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_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_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_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.
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 commandline option, it will be used.
The available configurations are below.
These can be specified in [test]
section of Veryl.toml
.
[test]
simulator = "vcs"
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 |
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";
Documentation
Documant 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.
Waveform description based on WaveDrom is supported too.
In a wavedrom
code block, the syntax of WaveDrom can be written.
Please refer Tutorial 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,
local 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
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]+)*)?'[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;
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;
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;
LocalTerm : <INITIAL, Generic >/(?-u:\b)local(?-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;
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;
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;
VarTerm : <INITIAL, Generic >/(?-u:\b)var(?-u:\b)/ : Token;
DollarIdentifierTerm : <INITIAL, Generic >/\$[a-zA-Z_][0-9a-zA-Z_$]*/ : Token;
IdentifierTerm : <INITIAL, Generic >/[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;
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;
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;
LocalToken : LocalTerm : 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;
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;
TriToken : TriTerm : Token Comments;
TypeToken : TypeTerm : Token Comments;
U32Token : U32Term : Token Comments;
U64Token : U64Term : Token Comments;
UnionToken : UnionTerm : 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
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;
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;
Local : LocalToken : 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;
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;
Tri : TriToken : VerylToken;
Type : TypeToken : VerylToken;
U32 : U32Token : VerylToken;
U64 : U64Token : VerylToken;
Union : UnionToken : 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 { 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 ScopedIdentifier };
Expression12: { ( UnaryOperator | Operator09 | Operator05 | Operator03 | Operator04 ) } Factor;
Factor: Number
| ExpressionIdentifier [ FunctionCall ]
| LParen Expression RParen
| LBrace ConcatenationList RBrace
| QuoteLBrace ArrayLiteralList RBrace
| IfExpression
| CaseExpression
| StringLiteral
| ( Msb | Lsb )
| InsideExpression
| OutsideExpression
;
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 Expression { Comma Expression } Colon Expression Comma { Expression { Comma Expression } Colon Expression Comma } Defaul Colon Expression [ Comma ] RBrace;
TypeExpression: ScalarType
| 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
// ----------------------------------------------------------------------------
FixedType: U32 | U64 | I32 | I64 | F32 | F64 | Strin;
VariableType: ( Clock
| ClockPosedge
| ClockNegedge
| Reset
| ResetAsyncHigh
| ResetAsyncLow
| ResetSyncHigh
| ResetSyncLow
| Logic
| Bit
| ScopedIdentifier
) [ Width ];
TypeModifier: Tri | Signed;
ScalarType: { TypeModifier } ( VariableType | FixedType );
ArrayType: ScalarType [ Array ];
// ----------------------------------------------------------------------------
// Statement
// ----------------------------------------------------------------------------
Statement: LetStatement
| IdentifierStatement
| IfStatement
| IfResetStatement
| ReturnStatement
| BreakStatement
| ForStatement
| CaseStatement
;
LetStatement: Let Identifier Colon ArrayType Equ Expression Semicolon;
IdentifierStatement: ExpressionIdentifier ( FunctionCall | Assignment ) Semicolon;
Assignment: ( Equ | AssignmentOperator ) Expression;
IfStatement: If Expression LBrace { Statement } RBrace { Else If Expression LBrace { Statement } RBrace } [ Else LBrace { Statement } RBrace ];
IfResetStatement: IfReset LBrace { Statement } RBrace { Else If Expression LBrace { Statement } RBrace } [ Else LBrace { Statement } RBrace ];
ReturnStatement: Return Expression Semicolon;
BreakStatement: Break Semicolon;
ForStatement: For Identifier Colon ScalarType In Range [ Step AssignmentOperator Expression ] LBrace { Statement } RBrace;
CaseStatement: Case Expression LBrace { CaseItem } RBrace;
CaseItem: ( Expression { Comma Expression } | Defaul ) Colon ( Statement | LBrace { Statement } RBrace );
// ----------------------------------------------------------------------------
// Attribute
// ----------------------------------------------------------------------------
Attribute: Hash LBracket Identifier [ LParen AttributeList RParen ] RBracket;
AttributeList: AttributeItem { Comma AttributeItem } [ Comma ];
AttributeItem: Identifier
| StringLiteral
;
// ----------------------------------------------------------------------------
// Declaration
// ----------------------------------------------------------------------------
LetDeclaration: Let Identifier Colon ArrayType Equ Expression Semicolon;
VarDeclaration: Var Identifier Colon ArrayType Semicolon;
LocalDeclaration: Local Identifier Colon ( ArrayType Equ Expression | Type Equ TypeExpression ) Semicolon;
TypeDefDeclaration: Type Identifier Equ ArrayType Semicolon;
AlwaysFfDeclaration: AlwaysFf LParen AlwaysFfClock [ Comma AlwaysFfReset ] RParen LBrace { Statement } RBrace;
AlwaysFfClock: HierarchicalIdentifier;
AlwaysFfReset: HierarchicalIdentifier;
AlwaysCombDeclaration: AlwaysComb LBrace { Statement } RBrace;
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 LBrace { Statement } RBrace;
FinalDeclaration: Final LBrace { Statement } RBrace;
// ----------------------------------------------------------------------------
// 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 | Local ) Identifier Colon ( ArrayType Equ Expression | Type Equ TypeExpression );
// ----------------------------------------------------------------------------
// WithGenericParameter
// ----------------------------------------------------------------------------
WithGenericParameter: ColonColonLAngle WithGenericParameterList RAngle;
WithGenericParameterList: WithGenericParameterItem { Comma WithGenericParameterItem } [ Comma ];
WithGenericParameterItem: Identifier;
// ----------------------------------------------------------------------------
// 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 ( Direction ArrayType | Interface [ Array ] );
Direction: Input
| Output
| Inout
| Ref
| Modport
;
// ----------------------------------------------------------------------------
// Function
// ----------------------------------------------------------------------------
FunctionDeclaration: Function Identifier [ WithGenericParameter ] [ PortDeclaration ] [ MinusGT ScalarType ] LBrace { FunctionItem } RBrace;
FunctionItem: VarDeclaration
| Statement
;
// ----------------------------------------------------------------------------
// Import / Export
// ----------------------------------------------------------------------------
ImportDeclaration: Import ScopedIdentifier [ ColonColon Star ] Semicolon;
ExportDeclaration: Export ( Star | ScopedIdentifier [ ColonColon Star ] ) Semicolon;
// ----------------------------------------------------------------------------
// Module
// ----------------------------------------------------------------------------
ModuleDeclaration: [ Pub ] Module Identifier [ WithGenericParameter ] [ WithParameter ] [ PortDeclaration ] LBrace { ModuleGroup } RBrace;
ModuleIfDeclaration: If Expression ModuleNamedBlock { Else If Expression ModuleOptionalNamedBlock } [ Else ModuleOptionalNamedBlock ];
ModuleForDeclaration: For Identifier In Range [ Step AssignmentOperator Expression ] ModuleNamedBlock;
ModuleNamedBlock: Colon Identifier LBrace { ModuleGroup } RBrace;
ModuleOptionalNamedBlock: [ Colon Identifier ] LBrace { ModuleGroup } RBrace;
ModuleGroup: { Attribute } ( LBrace { ModuleGroup } RBrace | ModuleItem );
ModuleItem: LetDeclaration
| VarDeclaration
| InstDeclaration
| TypeDefDeclaration
| LocalDeclaration
| AlwaysFfDeclaration
| AlwaysCombDeclaration
| AssignDeclaration
| FunctionDeclaration
| ModuleIfDeclaration
| ModuleForDeclaration
| EnumDeclaration
| StructUnionDeclaration
| ModuleNamedBlock
| ImportDeclaration
| InitialDeclaration
| FinalDeclaration
;
// ----------------------------------------------------------------------------
// Interface
// ----------------------------------------------------------------------------
InterfaceDeclaration: [ Pub ] Interface Identifier [ WithGenericParameter ] [ WithParameter ] LBrace { InterfaceGroup } RBrace;
InterfaceIfDeclaration: If Expression InterfaceNamedBlock { Else If Expression InterfaceOptionalNamedBlock } [ Else InterfaceOptionalNamedBlock ];
InterfaceForDeclaration: For Identifier In Range [ Step AssignmentOperator Expression ] InterfaceNamedBlock;
InterfaceNamedBlock: Colon Identifier LBrace { InterfaceGroup } RBrace;
InterfaceOptionalNamedBlock: [ Colon Identifier ] LBrace { InterfaceGroup } RBrace;
InterfaceGroup: { Attribute } ( LBrace { InterfaceGroup } RBrace | InterfaceItem );
InterfaceItem: LetDeclaration
| VarDeclaration
| LocalDeclaration
| ModportDeclaration
| InterfaceIfDeclaration
| InterfaceForDeclaration
| TypeDefDeclaration
| EnumDeclaration
| StructUnionDeclaration
| InterfaceNamedBlock
| FunctionDeclaration
| ImportDeclaration
| InitialDeclaration
| FinalDeclaration
;
// ----------------------------------------------------------------------------
// Package
// ----------------------------------------------------------------------------
PackageDeclaration: [ Pub ] Package Identifier [ WithGenericParameter ] LBrace { PackageGroup } RBrace;
PackageGroup: { Attribute } ( LBrace { PackageGroup } RBrace | PackageItem );
PackageItem: VarDeclaration
| LocalDeclaration
| TypeDefDeclaration
| EnumDeclaration
| StructUnionDeclaration
| FunctionDeclaration
| ImportDeclaration
| ExportDeclaration
| InitialDeclaration
| FinalDeclaration
;
// ----------------------------------------------------------------------------
// Embed
// ----------------------------------------------------------------------------
EmbedDeclaration: Embed LParen Identifier RParen Identifier EmbedContent;
EmbedContent: EmbedContentToken: VerylToken;
EmbedContentToken: LBraceTerm %push(Embed) LBraceTerm LBraceTerm { EmbedItem } RBraceTerm RBraceTerm RBraceTerm %pop();
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
| ImportDeclaration
| EmbedDeclaration
| IncludeDeclaration
;
// ----------------------------------------------------------------------------
// SourceCode
// ----------------------------------------------------------------------------
Veryl: Start { DescriptionGroup };