The Veryl Hardware Description Language

Veryl

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

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.

diagnostics

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.

format

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
function automatic logic [20-1:0] FuncA_20 (
    input logic [20-1:0] a
);
    return a + 1;
endfunction

function automatic logic [10-1:0] FuncA_10 (
    input logic [10-1:0] a
);
    return a + 1;
endfunction

logic [10-1:0] a;
logic [20-1:0] b;
always_comb begin
    a = FuncA_10(1);
    b = FuncA_20(1);
end
function FuncA::<T> (
    a: input logic<T>,
) -> logic<T> {
    return a + 1;
}

var a: logic<10>;
var b: logic<10>;
always_comb {
    a = FuncA::<10>(1);
    b = FuncA::<20>(1);
}

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
module ModuleA (
    input  a,
    input  b,
    output o
);
endmodule
module ModuleA (
    a: input logic,
    b: input logic,
    o: input logic,
) {
}

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
module ModuleA (
    input logic i_clk,
    input logic i_rst_n
);

always_ff @ (posedge i_clk or negedge i_rst_n) begin
    if (!i_rst_n) begin
    end else begin
    end
end

endmodule
module ModuleA (
    i_clk: input clock,
    i_rst: input reset,
){
    always_ff (i_clk, i_rst) {
        if_reset {
        } else {
        }
    }
}

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
// Comment
module ModuleA;
endmodule
/// Documentation comment written by Markdown
///
/// * list
/// * list
/// 
/// ```wavedrom
/// { signal: [{ name: "Alfa", wave: "01.zx=ud.23.456789" }] }
/// ```
module ModuleA {
}

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
always_ff @ (posedge i_clk) begin
    if (a) begin
        x <= x + 1;
    end
end
always_ff (i_clk) {
    if a {
        x += 1;
    }
}

Individual namespace of enum variant

Variants of an enum are defined within separate namespaces for each enum, thus preventing unintended name collisions.

SystemVerilog Veryl
typedef enum logic[1:0] {
    MemberA,
    MemberB
} EnumA;

EnumA a;
assign a = MemberA;
enum EnumA: logic<2> {
    MemberA,
    MemberB
}

var a: EnumA;
assign a = EnumA::MemberA;

repeat of concatenation

By adopting the explicit repeat syntax as a repetition description in bit concatenation, readability improves over complex combinations of {}.

SystemVerilog Veryl
logic [31:0] a;
assign a = {{2{X[9:0]}}, {12{Y}}};
var a: logic<32>;
assign a = {X[9:0] repeat 2, Y repeat 12};

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
logic a;
assign a = X == 0 ? Y0 :
           X == 1 ? Y1 :
           X == 2 ? Y2 : 
                    Y3;
var a: logic;
assign a = case X {
    0      : Y0,
    1      : Y1,
    2      : Y2,
    default: Y3,
};

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
for (int i = 0; i < 10; i++) begin
    a[i] =   X[i] inside {[1:10]};
    b[i] = !(X[i] inside {[1:10]});
end
for i: u32 in 0..10 {
    a[i] = inside  X[i] {1..=10};
    b[i] = outside X[i] {1..=10};
}

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
logic a;
logic [WIDTH-1:0] X;
assign a = X[WIDTH-1];
var a: logic;
var X: logic<WIDTH>;
assign a = X[msb];

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
logic tmp;
always_ff @ (posedge i_clk) begin
    tmp = b + 1;
    x <= tmp;
end
always_ff (i_clk) {
    let tmp: logic = b + 1;
    x = tmp;
}

Named block

You can define named blocks to limit the scope of variables.

SystemVerilog Veryl
if (1) begin: BlockA
end
:BlockA {
}

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
module ModuleA;
endmodule

module ModuleB;
endmodule
pub module ModuleA {
}

module ModuleB {
}
1

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.

Vim / Neovim plugin

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 integer
  • u64: 64bit unsigned integer
  • i32: 32bit signed integer
  • i64: 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 point
  • f64: 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 option
  • clock_posedge: clock type of which polarity is positive
  • clock_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 option
  • reset_async_high: async/high active reset type
  • reset_async_low: async/low active reset type
  • reset_sync_high: sync/active high reset type
  • reset_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.

OperatorAssociativityPrecedence
() [] :: .LeftHighest
+ - ! ~ & ~& | ~| ^ ~^ ^~ (unary)Left
**Left
* / %Left
+ - (binary)Left
<< >> <<< >>>Left
<: <= >: >=Left
== != === !== ==? !=?Left
& (binary)Left
^ ~^ ^~ (binary)Left
| (binary)Left
&&Left
||Left
= += -= *= /= %= &= ^= |=
<<= >>= <<<= >>>=
None
{}NoneLowest

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 port
  • output: output port
  • inout: bi-directional port
  • modport: 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

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 edge
  • negedge – 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 low
  • async_high – asynchronous and active high
  • sync_low – synchronous and active low
  • sync_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 paths
  • relative – plane text filelist including relative file paths
  • flgenflgen 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 code
  • directory – specified directory
  • bundle – 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 changes
  • MINOR version when you add functionality in a backwards compatible manner
  • PATCH 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 with 0.1.0.
  • 0.1.1 is compatible with 0.1.0.
  • 0.2.0 is not compatible with 0.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"
ConfigurationValueDefaultDescription
bump_commitbooleanfalseautomatic commit after bump
publish_commitbooleanfalseautomatic commit after publish
bump_commit_mesasgestring“chore: Bump version”commit message after bump
publish_commit_mesasgestring“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
ConfigurationValueDescription
indent_widthintegerindent 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.

ConfigurationValueDescription
case_enumcase type1case style of enum
case_functioncase type1case style of function
case_instancecase type1case style of instance
case_interfacecase type1case style of interface
case_modportcase type1case style of modport
case_modulecase type1case style of module
case_packagecase type1case style of package
case_parametercase type1case style of parameter
case_port_inoutcase type1case style of inout port
case_port_inputcase type1case style of input port
case_port_modportcase type1case style of modport port
case_port_outputcase type1case style of output port
case_regcase type1case style of register type variable2
case_structcase type1case style of struct
case_wirecase type1case style of wire type variable3
prefix_enumstringprefix of enum
prefix_functionstringprefix of function
prefix_instancestringprefix of instance
prefix_interfacestringprefix of interface
prefix_modportstringprefix of modport
prefix_modulestringprefix of module
prefix_packagestringprefix of package
prefix_parameterstringprefix of parameter
prefix_port_inoutstringprefix of inout port
prefix_port_inputstringprefix of input port
prefix_port_modportstringprefix of modport port
prefix_port_outputstringprefix of output port
prefix_regstringprefix of register type variable2
prefix_structstringprefix of struct
prefix_wirestringprefix of wire type variable3
re_forbidden_enumregex4regex forbidden of enum
re_forbidden_functionregex4regex forbidden of function
re_forbidden_instanceregex4regex forbidden of instance
re_forbidden_interfaceregex4regex forbidden of interface
re_forbidden_modportregex4regex forbidden of modport
re_forbidden_moduleregex4regex forbidden of module
re_forbidden_packageregex4regex forbidden of package
re_forbidden_parameterregex4regex forbidden of parameter
re_forbidden_port_inoutregex4regex forbidden of inout port
re_forbidden_port_inputregex4regex forbidden of input port
re_forbidden_port_modportregex4regex forbidden of modport port
re_forbidden_port_outputregex4regex forbidden of output port
re_forbidden_regregex4regex forbidden of register type variable2
re_forbidden_structregex4regex forbidden of struct
re_forbidden_wireregex4regex forbidden of wire type variable3
re_required_enumregex4regex required of enum
re_required_functionregex4regex required of function
re_required_instanceregex4regex required of instance
re_required_interfaceregex4regex required of interface
re_required_modportregex4regex required of modport
re_required_moduleregex4regex required of module
re_required_packageregex4regex required of package
re_required_parameterregex4regex required of parameter
re_required_port_inoutregex4regex required of inout port
re_required_port_inputregex4regex required of input port
re_required_port_modportregex4regex required of modport port
re_required_port_outputregex4regex required of output port
re_required_regregex4regex required of register type variable2
re_required_structregex4regex required of struct
re_required_wireregex4regex required of wire type variable3
1

The available values are

  • "snake" – snake_case
  • "screaming_snake" – SCREAMING_SNAKE_CASE
  • "lower_camel" – lowerCamelCase
  • "upper_camel" – UpperCamelCase
4

Regular expression string like ".*". The available syntax is here.

2

Register type means that the variable is assigned in always_ff. It will be mapped to flip-flop in synthesis phase.

3

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.

ConfigurationValueDescription
simulatorsimulator name1default simulator
1

The available values are

  • "verilator"
  • "vcs"
  • "vivado"

The [test.verilator] section

This section contains configurations of test by Verilator.

ConfigurationValueDescription
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.

ConfigurationValueDescription
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.

ConfigurationValueDescription
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.

ConfigurationValueDefaultDescription
useOperatorCompletionbooleanfalseuse 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"
ConfigurationValueDefaultDescription
pathstring“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

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 };

Semantic Error

duplicated_identifier

invalid_allow

invalid_direction

invalid_identifier

invalid_lsb

invalid_msb

invalid_number_character

invalid_statement

invalid_system_function

mismatch_arity

mismatch_attribute_args

mismatch_type

missing_if_reset

missing_port

missing_reset_signal

missing_reset_statement

too_large_enum_variant

too_large_number

too_much_enum_variant

undefined_identifier

unknown_attribute

unknown_member

unknown_msb

unknown_port

unused_variable