Announcing Veryl 0.20.3
2026-08-03
The Veryl team has published a new release of Veryl, 0.20.3. Veryl is a new hardware description language as an alternate to SystemVerilog.
If you have a previous version of Veryl installed via verylup, you can get the latest version with:
$ verylup update
If you don't have it already, you can get verylup from release page.
Important Notice
Base-less literal in concatenation #3049
A base-less literal like 123 used as an operand of a concatenation is now
reported as invalid_unsized_literal.
assign y = {a, 123}; // error
assign y = {a, 8'd123};
Such a literal was accepted before, but it was emitted verbatim as an unsized
literal, which is forbidden in a concatenation by the SystemVerilog LRM and
rejected by some tools.
Existing code which relies on it needs to give the literal an explicit width.
A base-less replication count like {a repeat 2} keeps working as before.
New Language Features
mixin declaration for interfaces #2996
An interface can now incorporate the members of other interfaces through a
mixin declaration.
All members — variables, functions, and modports — of the mixed-in
interface are expanded as if they were declared directly in the interface.
For example, the channels of a bus protocol can be defined as separate interfaces and reused across multiple bus interfaces.
interface Command::<ADDR_WIDTH: u32, DATA_WIDTH: u32> {
var cmd_valid: logic ;
var cmd_addr : logic<ADDR_WIDTH>;
var cmd_data : logic<DATA_WIDTH>;
modport mp_cmd {
cmd_valid: output,
cmd_addr : output,
cmd_data : output,
}
}
interface Response::<DATA_WIDTH: u32> {
var rsp_valid: logic ;
var rsp_data : logic<DATA_WIDTH>;
modport mp_rsp {
rsp_valid: input,
rsp_data : input,
}
}
interface MemoryBus::<ADDR_WIDTH: u32, DATA_WIDTH: u32> {
mixin Command::<ADDR_WIDTH, DATA_WIDTH>;
mixin Response::<DATA_WIDTH>;
modport master {
..same(mp_cmd, mp_rsp)
}
modport slave {
..converse(mp_cmd, mp_rsp)
}
}
As shown above, a generic interface can be mixed in by giving its generic arguments.
Project property #2968 #3119
A project property is a compile time constant given through Veryl.toml instead
of source code.
Properties are defined in the [properties] section, and their values are
integers or booleans.
[properties]
DATA_WIDTH = 32
ENABLE_DEBUG = false
They are referenced through the $prop namespace, and can be used wherever a
constant expression can be used.
module ModuleA {
var a: logic<$prop::DATA_WIDTH>;
if $prop::ENABLE_DEBUG :g_debug {
// debug logic
}
}
Brace list in import #3053
Multiple symbols can be imported from a single package at once by listing them in braces, in the same style as Rust.
module ModuleA {
import PackageA::{paramA, paramB};
}
New Tool Features
User defined verification components #2985
Verification components written in Rust — a bus functional model, a
protocol checker, or a golden model — can now be driven by the native
simulator under the $comp namespace.
A component is ordinary Rust, so it can pull in any crate instead of relying on
SystemVerilog boilerplate or hand-written DPI-C glue.
#[test(test_req_ack)]
module test_req_ack {
inst clk: $tb::clock_gen;
inst rst: $tb::reset_gen ( clk );
var req: logic;
var ack: logic;
inst dut: Peripheral ( clk, rst, req, ack );
inst chk: $comp::req_ack_checker ( clk, req, ack );
initial {
rst.assert();
req = 1;
clk.next(16);
$finish();
}
}
It is covered in detail by a dedicated article:
Verification components in Rust.
veryl-lang/vip, a set of AXI verification
components, is built this way.
Hierarchical reference in native tests #2974
Signals inside the DUT can be read from an initial block of a test module
through a hierarchical path.
The path starts at an instance of the test module and goes through nested
instances by ., so internal signals no longer have to be routed to the top
level just to be observed.
#[test(test_hier)]
module test_hier {
inst clk: $tb::clock_gen;
inst rst: $tb::reset_gen ( clk );
var din: logic<4>;
inst dut: Top ( clk, rst, din );
initial {
rst.assert();
din = 4'b0001;
clk.next();
$assert(dut.u_sub.internal_reg == 4'h2, "unexpected value");
$display("internal_reg = %h", dut.u_sub.internal_reg);
$finish();
}
}
$tb::random testbench component #3078
$tb::random is a random-number generator for native tests.
The type of the generated value is given as a generic argument.
#[test(test_random)]
module test_random {
var r: $tb::random::<u32>;
var x: u32;
initial {
r.seed(42); // set the seed
x = r.get(); // uniform over the full u32 range
x = r.get_range(10, 20); // 10 <= x <= 20
$finish();
}
}
The seed used by a run is printed, and giving it back through --seed or
[test].seed reproduces the same sequence.
Four-state native test #2984
Native tests can be run in four-state (X/Z) mode.
By default a value which is not assigned is read as 0; under a four-state run,
it is read as x instead, which surfaces missing initialization and incomplete
resets.
$ veryl test --4state
It can also be enabled through Veryl.toml:
[test]
four_state = true
The examples directory #2978
The examples directory at the project root is now reserved as a place for usage
examples and testbenches.
$ tree
.
|-- examples
| `-- example_top.veryl
|-- src
| `-- module_a.veryl
`-- Veryl.toml
Files under examples are analyzed and checked like ordinary sources, and
#[test] modules in them are executed by veryl test.
They are excluded from code generation and the generated document, and ignored
entirely when the project is consumed as a dependency.
So examples can be kept in the repository without leaking into the deliverables
of the projects which depend on it.
External subcommand #2935
The veryl command can be extended by tools distributed separately from Veryl,
in the same way as cargo.
If the given subcommand is not a built-in one, veryl searches PATH for an
executable named veryl-<subcommand> and executes it.
$ veryl import foo.sv
The command above executes veryl-import foo.sv if veryl-import is found on
PATH, so such a tool can be used as if it was a built-in subcommand.
veryl --list shows all available commands including the external ones.
JSON report for veryl synth and veryl test #3074
--format json makes veryl synth and veryl test write a machine-readable
report to stdout instead of the human-readable summary, which is useful to
consume the results from CI or other tools.
$ veryl synth --format json
{
"format_version": 1,
"top": "Counter",
"library": "sky130",
"status": "ok",
"cells": 19,
"ffs": 8,
"area": { "total": 302.5, "combinational": 122.5, "sequential": 180.0, "memory": 0.0 },
"timing": { "delay_ns": 0.38, "depth": 4, "from": "cnt[3]", "to": "cnt[6]" },
"power": { "total_mw": 0.0239, "leakage_mw": 0.0000271, "dynamic_mw": 0.0239, "clock_freq_mhz": 100.0, "activity": 0.1 }
}
For veryl test, the report lists the pass/fail status, message, and runtime of
each test.
Registry registration on publish #3015 #3013
The client-side integration with the official package
registry has landed.
A project which declares its repository can be registered by veryl register,
and veryl publish can register it too through register in the [publish]
section of Veryl.toml.
[project]
name = "my_ip"
version = "0.1.0"
repository = "https://github.com/you/my_ip"
categories = ["interconnect", "verification"]
[publish]
register = true
The new categories field of the [project] section lists the categories which
the project belongs to, and the registry uses them to classify the project.
New Standard Library
ECC encoder / decoder #3087
$std::ecc_encoder and $std::ecc_decoder provide Hamming-code based ECC with
single error correction and double error detection.
Other Changes
Check out everything that changed in Release v0.20.3.