#verilog #builder #reg #fsm #stream #comb #dff

ruverta

Rust to Verilog: Very Simple Verilog Builder

1 unstable release

0.1.0 Dec 3, 2024

#202 in Hardware support

Download history 169/week @ 2024-12-02

169 downloads per month

MIT/Apache

51KB
1.5K SLoC

ruverta

Rust to Verilog: Very Simple Verilog Builder

English | 日本語

Supports only a simple subset of SystemVerilog.

  • Variables: Only logic is available. No reg or wire.
  • Combinational circuits: Only always_comb is available. No assign.
  • Sequential circuits: Only always_ff is available. No always.

Table of Contents

Installation

$ cargo add ruverta

Basic API

RustSystemVerilog
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/Output Ports

  • .input(name, width)
  • .output(name, width)
  • .inout(name, width)

Parameters

  • .param(name, default_value)
  • .lparam(name, value)

Wires

  • .logic(name, bit, len)

Instances

  • .instant(inst: Instant)

Combinational Circuits

  • .always_comb(stmt: Stmt)

Stmt is a class representing a statement.

Sequential Circuits

  • .always_ff(Sens, Stmt)

Sens is a class representing a sensitivity list.

  • .posedge(wire_name)
  • .negedge(wire_name)
  • .bothedge(wire_name)

Verilog Generation

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~

Extended API

Extend the builder methods of Module to easily construct various circuits.

Rust Verilog Test
DFF dff.sv dff.sv dff_tb.sv
Comb comb.rs comb.sv comb_tb.sv
FSM fsm.rs fsm.sv fsm_tb.sv
AXILiteSlave axi_lite_slave.rs axi_lite_slave.sv axi_lite_slave_tb.sv
PicoSlave
Stream stream.rs stream.sv
FIFO fifo.rs fifo.sv

DFF

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(),
    );

Comb

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"),
    );

FSM

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"),
    );

Stream

FIFO

Bus API

Rust Verilog Test
AXILiteSlave axi_lite_slave.rs axi_lite_slave.sv axi_lite_slave_tb.sv
PicoSlave
Module::new(name)
  .input("clk", 1)
  .input("rstn", 1)
  .axi_lite_slave(
    "clk",
    "rstn",
    AXILiteSlave::new(
      "cbus",
      MMap::new(32, 32)
        .read_write("csr_rw", 8, 2)
        .read_only("csr_ro", 8, 1)
        .trigger("csr_tw"),
      ),
  );
  • AXI Lite Slave
  • Pico Slave

Test

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.

No runtime deps

Features