Supports only a simple subset of SystemVerilog.
- Variables: Only
logic
is available. Noreg
orwire
. - Combinational circuits: Only
always_comb
is available. Noassign
. - Sequential circuits: Only
always_ff
is available. Noalways
.
Table of Contents
$ cargo add --git "https://github.com/kanade-k-1228/ruverta.git"
or
[dependencies]
ruverta = { git = "https://github.com/kanade-k-1228/ruverta.git" }
Rust | SystemVerilog |
---|---|
use ruverta::{Module, Sens, Stmt};
fn test_module() {
let m = Module::new("test_module")
.param("BIT", Some("8"))
.input("clk", 1)
.input("rstn", 1)
.input("in0", 8)
.input("in1", 8)
.output("out", 8)
.always_comb(Stmt::assign("out", "in0 + in1"))
.always_ff(
Sens::new().posedge("clk"),
Stmt::begin().add(Stmt::assign("a", "b")).end(),
);
println!("{}", m.verilog().join("\n"));
} |
module test_module #(
parameter BIT = 8
) (
input logic clk,
input logic rstn,
input logic [ 7:0] in0,
input logic [ 7:0] in1,
output logic [ 7:0] out
);
always_comb
out = in0 + in1;
always_ff @(posedge clk)
begin
a <= b;
end
endmodule; |
.input(name, width)
.output(name, width)
.inout(name, width)
.param(name, default_value)
.lparam(name, value)
.logic(name, bit, len)
.instant(inst: Instant)
.always_comb(stmt: Stmt)
Stmt
is a class representing a statement.
.always_ff(Sens, Stmt)
Sens
is a class representing a sensitivity list.
.posedge(wire_name)
.negedge(wire_name)
.bothedge(wire_name)
Generate Verilog with .verilog()
. Since it returns Vec<String>
, use .join("\n")
to concatenate.
The API design is quite rough, so feel free to request anything~
Extend the builder methods of Module to easily construct various circuits.
When implementing sequential circuits, it is recommended to use sync_ff
/ async_ff
api instead of always_ff
.
DFF has several usage patterns depending on the clock and reset settings.
- clock edge: posedge / negedge / bothedge
- reset edge: positive / negative
- reset timing: sync / async
Currently, only the following patterns are supported.
clock edge | reset logic | reset timing | |
---|---|---|---|
sync_ff |
posedge | negative | sync |
async_ff |
posedge | negative | async |
Module::new(name)
.input("clk", 1)
.input("rstn", 1)
.input("in0", 8)
.input("in1", 8)
.output("out", 8)
.sync_ff(
"clk",
"rstn",
Stmt::begin().assign("out", "0").end(),
Stmt::begin().assign("out", "in0 + in1").end(),
);
When implementing combinational circuits, it is recommended to use comb
instead of always_comb
.
Since it always requires a default, there are no omissions in case distinctions.
Module::new(name)
.input("clk", 1)
.input("rstn", 1)
.input("hoge", 1)
.comb(
Comb::new()
.input("in0")
.input("in1")
.output("out0")
.output("out1")
.case("in0==0", "out0=0", "out1=0")
.default("0", "1"),
);
Construct a state machine with a single state variable.
Module::new(name)
.input("clk", 1)
.input("rstn", 1)
.input("hoge", 1)
.sync_fsm(
FSM::new("init", "clk", "rstn")
.state("init")
.jump("hoge == 1", "fuga")
.r#else("init")
.state("fuga")
.jump("hoge == 0", "init")
.r#else("fuga"),
);
Module::new(name)
.input("clk", 1)
.input("rstn", 1)
.axi_lite_slave(
"clk",
"rstn",
AXILiteSlave::new("cbus", 32)
.read_write("csr_rw0", 8, 1)
.read_write("csr_rw1", 8, 1)
.read_only("csr_ro", 8, 1)
.trigger("csr_tw"),
);
Tests are located under tests.
$ cargo test
will output sv files under tests/verilog/
.
Running make will launch gtkwave.
ruverta/tests/verilog$ make ???
??? is the name of the test case.