A small HDL compiler in Rust with Verilog generation, simulation, and graph output.
Frag is a compact Hardware Description Language compiler. It parses .frag
source files, performs semantic checks, lowers the checked module into a
typed netlist-style IR, and emits Verilog, simulator output, or graph output.
flowchart LR
Source[".frag"] --> Lexer["Lexer"]
Lexer --> Parser["Parser"]
Parser --> AST["AST"]
AST --> Semantics["Semantic analysis"]
Semantics --> IR["Netlist IR"]
IR --> Verilog["Verilog"]
IR --> Sim["Simulator"]
IR --> Graph["DOT / Mermaid"]
Frag is pre-1.0. The language and CLI may change between alpha releases.
Supported:
- Single-module
.fragsource files input,output,wire,reg, andconstdeclarationsbit,bool, anduNunsigned integer widths up to 128 bits- Combinational assignments
- Sequential
on rising(clk)andon falling(clk)processes - Arithmetic, comparison, logical, bitwise, and shift operators
- Bit indexing and slicing with
value[3]andvalue[7:4] if condition { a } else { b }conditional expressionscase selector { pattern => value, else => value }expressions- Source-span diagnostics
- IR validation after lowering
- Verilog generation
- Truth-table and tick-based simulation
- VCD waveform output
- Graphviz DOT and Mermaid graph output
Semantic checks:
- Duplicate declarations
- Unknown signals
- Invalid assignment targets
- Width mismatches
- Unassigned outputs
- Multiple combinational drivers
- Multiple sequential register drivers
- Invalid clocks
- Constant dependency cycles
- Combinational dependency cycles
Current limits:
- One module per file
- No module instantiation
- No arrays or memories
- No loops or generics
- No signed arithmetic
- No reset syntax
The repository pins Rust in rust-toolchain.toml.
cargo build
cargo install --path .External tools are optional but recommended for generated Verilog validation and waveform inspection.
Ubuntu / Debian:
sudo apt-get update
sudo apt-get install -y iverilog verilator graphviz gtkwaveMSYS2 MinGW64:
pacman -Syu
pacman -S --needed mingw-w64-x86_64-iverilog mingw-w64-x86_64-verilator mingw-w64-x86_64-graphviz mingw-w64-x86_64-gtkwavefrag <file.frag> Generate Verilog
frag tokens <file.frag> Print tokens
frag ast <file.frag> Print AST
frag ir <file.frag> Print netlist IR
frag check <file.frag> Validate frontend, semantics, and IR
frag verilog <file.frag> [-o out] Generate Verilog
frag run <file.frag> [options] Simulate a module
frag graph <file.frag> [options] Emit DOT or Mermaid graph output
Simulation options:
frag check examples/half_adder.frag
frag run examples/half_adder.frag
frag run examples/mux4_if.frag --set sel=2,a=10,b=20,c=30,d=40
frag run examples/counter.frag --ticks 16 --vcd target/counter.vcdGraph options:
frag graph examples/half_adder.frag --format mermaid
frag graph examples/half_adder.frag --format dot -o target/half_adder.dot
dot -Tsvg target/half_adder.dot -o target/half_adder.svgVerilog validation:
frag verilog examples/half_adder.frag -o target/half_adder.v
iverilog -g2012 -tnull target/half_adder.v
verilator --lint-only -Wno-DECLFILENAME target/half_adder.vmodule HalfAdder {
input a: bit;
input b: bit;
output sum: bit;
output carry: bit;
sum = a ^ b;
carry = a & b;
}Generated Verilog:
module HalfAdder(
input a,
input b,
output sum,
output carry
);
assign sum = (a ^ b);
assign carry = (a & b);
endmoduleConditional expression:
module Mux2If {
input sel: bit;
input a: u8;
input b: u8;
output out: u8;
out = if sel { a } else { b };
}Generated Verilog:
assign out = (sel ? a : b);Case expression:
out = case sel {
0 => a,
1 => b,
else => c
};Bit selection:
high = data[7:4];
low = data[3:0];
top = data[7];
masked_low = (data & mask)[3:0];Rust-only checks:
cargo fmt --check
cargo clippy --all-targets -- -D warnings
cargo test
cargo doc --no-deps
cargo build --releaseExternal-tool checks:
export FRAG_REQUIRE_EXTERNAL_TOOLS=1
cargo testCheck all example-generated Verilog:
mkdir -p target/verify/verilog
for file in examples/*.frag; do
name="$(basename "$file" .frag)"
cargo run --release -- verilog "$file" -o "target/verify/verilog/$name.v"
iverilog -g2012 -tnull "target/verify/verilog/$name.v"
verilator --lint-only -Wno-DECLFILENAME "target/verify/verilog/$name.v"
donesrc/
ast.rs AST definitions
diagnostic.rs Diagnostics and spans
graph.rs DOT and Mermaid graph backends
ir.rs Netlist IR
lexer.rs Tokenizer
main.rs CLI
parser.rs Recursive descent parser
semantic.rs Semantic analyzer
simulator.rs Simulator and VCD output
verilog.rs Verilog backend
examples/ Example circuits
tests/ Integration tests
docs/ Architecture, language, roadmap, and release process docs
The repository includes these circuits:
- 1-bit ALU slice
- 1-bit comparator
- 2:1 mux
- 2-to-4 decoder
- 4:1 conditional mux
- 4:1 case mux
- 4-bit incrementer
- 8-bit register
- AND gate
- Constant mask
- Control datapath stress circuit
- Counter
- Full adder
- Half adder
- Majority gate
- Nibble splitter
- XOR gate
Releases are tag-driven. Pushing a version tag such as v0.1.0-alpha.N runs
the release workflow and uploads Linux, macOS, and Windows binaries with
checksum files.
Frag is licensed under the MIT License. See LICENSE.