TxHDL: a hardware description language is just a Rust async runtime
TxHDL is an open-source hardware description language embedded directly in Rust as an async runtime library, developed by Dragiša Janković and Filip Filmar (me). Instead of inventing a custom compiler and type checker, TxHDL expresses digital circuits using standard Rust types, structs, and asynchronous functions. From a single Rust source file, the library provides software simulation, Verilog and VHDL code generation, and multi-tool verification. To demonstrate hardware fidelity, the project includes Vreteno, a 32-bit RISC-V CPU core written in TxHDL and running on an Artix-7 FPGA at 100 MHz. Since then, the same library has been used to write a minimal GPU, an AXI bus, a network on chip, an Ethernet MAC and an HDMI output, each with its own document. Each of these designs will get a post of its own here later.
Mainstream HDLs like Verilog and VHDL operate at a low level of abstraction, while high-level synthesis (HLS) tools take structural scheduling control away from designers. We decided to pull a XKCD and build our own language. TxHDL occupies the middle ground. You define the exact cycle-by-cycle circuit structure, but you describe it with the expressive syntax, strong types, and package management of modern Rust.
A summary of the project appears in a six-page technical paper. The complete design history, tutorials and reference manuals span over 1,000 pages of documentation, with complete source code mirrored on GitHub. The entire codebase builds under a hermetic Bazel build system, allowing readers to reproduce every simulation, benchmark, and bitstream.
What we did not write
Most new hardware description languages require building an entire software stack from scratch: a parser, type checker, module system, package manager, and editor tooling. TxHDL avoids that engineering burden by reusing the existing Rust toolchain.
The project began as an effort to design an independent HDL specification. During early design reconciliation, we noticed that our desired abstractions matched the core mechanics of Rust. Rather than implementing a custom compiler, we removed every construct that Rust already provides. What remained was a concise domain-specific library and a set of procedural macros.
In TxHDL, a hardware module (called a unit) is a standard Rust struct.
Internal registers are struct fields, and unit behavior is an async fn
containing an event loop.
On each iteration, the loop awaits a clock edge, reads input state, and assigns
output signals.
A runtime library executes these async functions, providing an event-driven
simulator without external tooling.
The standard Rust compiler acts as the hardware type checker.
Connecting multiple drivers to a single wire causes a borrow-checker move error.
Passing a signal across clock domains without an explicit synchronizer causes a
type error.
Combinational feedback loops appear as cyclic dependencies across loop
iterations.
By mapping hardware rules to Rust semantics, rustc enforces structural
correctness at compile time.
One source, three forms
A single TxHDL source file serves three distinct operational roles.
First, you can execute the design directly as software. The library includes an event-driven executor that models simulation time. Running the compiled Rust binary produces standard FST or VCD waveforms without requiring third-party simulators.
Second, you can lower the design to standard HDL for synthesis.
A procedural macro attribute, #[lower], inspects the unit’s execution loop and
generates equivalent synthesizable Verilog and VHDL.
The macro accepts a well-defined subset of Rust expressions suitable for
hardware generation.
Arbitrary dynamic Rust code cannot be synthesized, which ensures predictable
hardware translation.
Third, you can verify behavioral equivalence across all targets automatically. The build system compiles the generated netlist and runs it under both nvc (for VHDL) and Verilator (for Verilog). The test harness replays the signal trace recorded during the Rust simulation, checking every register and output at every clock tick. A design that passes this cross-check produces identical outputs across all three implementations.
A unit can also state properties about itself with the check!, assume! and
cover! macros.
The simulation tests them on every run.
A formal_test target passes the generated Verilog to SymbiYosys,
which proves them for every input.
A property that does not hold fails the test with a counterexample trace.
TxHDL also supports foreign unit instantiation.
You can embed existing Verilog or VHDL modules directly within a TxHDL
simulation hierarchy.
The runtime evaluates Verilog modules via in-process Verilator calls and VHDL
modules via child nvc processes.
This allows new designs to interface with existing IP blocks without rewriting
them.
Silicon verification on FPGA hardware
Hardware description languages must prove themselves on real silicon. Rather than testing only toy examples, the project evaluated TxHDL by implementing a complete processor.
The primary demonstration design is Vreteno, a three-stage pipelined RV32IMC core, which includes the compressed instruction set. Vreteno supports machine-mode traps, an interrupt controller, a timer, an on-chip bus, block RAM data memory, and an asynchronous serial UART. During verification, the core runs in lockstep against a software RISC-V reference model across fixed test programs and sixty-four randomized instruction streams, with interrupts raised at random. The test harness checks the generated netlist against the cycle traces recorded during the Rust software simulation. A separate post describes the core in more detail.
Figure 1 shows the opening cycles of the demonstration program rendered from simulation traces:
To test physical execution, Vivado synthesized, placed, and routed the Vreteno bitstream targeting an AMD Artix-7 FPGA (xc7a200t) at 100 MHz. The complete core occupies about 2,200 lookup tables (LUTs): 2,151 as logic and 48 as distributed RAM, with data memory mapped to block RAM.
We loaded the resulting bitstream onto an Alinx AX7A200B FPGA board connected
to a host workstation over a serial terminal.
Upon reset, the board transmitted OK over UART.
When the test script sent three input bytes, the core echoed each byte and
updated onboard LEDs according to top-level port rules.
The observed hardware UART bytes matched the simulation lockstep trace
identically, proving that the generated logic functions correctly on physical
FPGA hardware.
Figure 2 illustrates the transmitted byte in simulation:
Figure 3 shows incoming UART data received from the terminal:
Figure 4 details memory bus transactions during a status register poll:
The build system automatically renders each waveform diagram directly from simulation traces. Every code listing, table, and timing chart in the paper and documentation is generated directly from source code, preventing documentation drift.
The FPGA is one target. The same core has also been mapped onto an open 45 nm standard cell library, then floorplanned, placed, routed and timed with OpenROAD, as a preparation for a tapeout. Other designs have been on the board as well. For example, a TxHDL core draws an icosahedron on HDMI.
Hardware description versus high-level synthesis
Evaluating TxHDL requires understanding the distinction between hardware description languages (HDLs) and high-level synthesis (HLS) tools.
An HDL expresses explicit digital structure: which registers exist, how signals interconnect, and how state transitions on each clock edge. The designer specifies the cycle-by-cycle microarchitecture directly. In contrast, an HLS tool accepts algorithmic sequential code (often in C or C++) and automatically synthesizes a pipeline, choosing register placement, scheduling, and resource sharing through heuristics. Both approaches have distinct uses. An HDL gives the engineer direct control over circuit layout and timing, while HLS trades structural control for automated scheduling.
TxHDL is strictly an HDL. A unit maps directly to declared circuit structures: registers correspond to struct fields, and combinational logic corresponds to the statements inside the event loop. TxHDL does not infer pipelines or schedule operations across cycles. Rust provides the host language syntax and type system, while the designer retains full architectural control.
Comparison with related hardware frameworks
Embedding hardware descriptions in general-purpose languages is an established technique. TxHDL distinguishes itself through several concrete properties:
- Native Rust embedding: designs compile with standard
cargoandrustcwithout requiring custom language front-ends or runtime virtual machines. - Direct structural control: the language describes explicit register-transfer logic rather than inferred schedules.
- Physical hardware verification: complete processor designs synthesize and run on FPGA hardware at target frequencies.
- Hermetic multi-target verification: automated builds compare software execution traces directly against VHDL and Verilog netlists.
Several related projects share architectural goals with TxHDL:
Chisel embeds hardware construction primitives in Scala. Executing a Chisel program constructs an intermediate circuit graph in memory, requiring the Java Virtual Machine (JVM) and the Scala runtime. In TxHDL, the compiled Rust binary itself is the simulator, eliminating external runtime dependencies.
RHDL explored Rust-based hardware description with clock domains parameterized by types. RHDL is no longer actively maintained. TxHDL builds upon similar type-level clock representations while adding automated netlist cross-verification against simulator traces and physical FPGA deployment.
XLS operates as a high-level synthesis framework developed by
Google.
XLS parses algorithms written in DSLX (a custom language with Rust-like syntax)
and derives pipelined microarchitectures automatically.
DSLX requires its own compiler and cannot compile with standard rustc.
In contrast, TxHDL is an HDL compiled by standard rustc, producing the
explicit register structure specified by the author.
Bluespec1 uses Guarded Atomic Actions to describe hardware. The Bluespec compiler automatically synthesizes an arbitration and scheduling circuit around user rules. TxHDL operates at a lower structural level: the user directly implements clock edges, state registers, and multiplexers without an interposed scheduler.
Documentation and repository links
The project provides documentation at multiple levels of detail:
- Executive summary: the six-page paper outlines the language architecture, typing model, and experimental results.
- Comprehensive documentation: a combined PDF of over 1,000 pages contains more than twenty documents, from the tutorials to the designs, with individual document bookmarks.
- Individual documents: separate PDF specifications are available on the releases page.
- Source repository: the active codebase, examples, test suite, and Vreteno core are mirrored publicly at github.com/filmil/hdl-txhdl.
Development occurs primarily on the private hdlfactory forge, with continuous synchronization to the public GitHub mirror. The authors welcome technical questions and feedback via the contact information listed in the paper. An automated coding assistant (Claude) assisted in exploring architectural concepts, generating documentation drafts, and assembling test harnesses under human supervision.
Questions and answers
Is the Rust syntax heavier than Verilog?
Verilog provides dedicated syntactic keywords for hardware primitives, which can look more compact for small leaf modules. In exchange for standard Rust syntax, TxHDL provides compile-time ownership checks, strong typing, package management via Cargo, and macro metaprogramming. Engineers familiar with Rust can write hardware without learning a separate language syntax or installing specialized IDE extensions.
Why does the project use Bazel?
As argued in our article on Bazel for hardware, Bazel manages the heterogeneous toolchains required for end-to-end verification. A single build command coordinates Rust compilation, simulation under Verilator and nvc, trace comparisons, formal proofs, documentation generation, FPGA bitstream synthesis under Vivado, and the open ASIC flow with Yosys and OpenROAD.
What is the project license?
The repository is published under the Apache 2.0 license. The license file is committed at the repository root.
Why create a new HDL rather than using an existing one?
Mainstream HDLs operate at a low level of abstraction, while high-level synthesis tools remove architectural control from the designer. We needed an environment where we maintain cycle-accurate control over registers while benefiting from modern language tooling, type safety, and fast software simulation. Embedding the language in Rust allowed us to achieve these goals without building a custom compiler.
Why does the repository use Forgejo actions with a GitHub mirror?
Full hardware verification requires commercial synthesis tools with proprietary licenses, which cannot execute on standard public CI runners. The primary CI runs on self-hosted infrastructure. The repository is automatically mirrored to GitHub to provide public access to source code, documentation, and release archives.
Does TxHDL aim to replace Verilog or solve every HDL limitation?
No. TxHDL was created to solve specific productivity and verification bottlenecks in our own projects. It integrates with existing industry workflows by emitting standard Verilog and VHDL, and by instantiating existing external HDL IP blocks inside TxHDL simulations. It complements rather than replaces the existing EDA ecosystem.
Why write Rust that lowers to Verilog instead of writing Verilog directly?
Writing hardware in Rust provides structural safety checks before synthesis. The Rust compiler prevents multi-driver contention, catches unsynchronized clock-domain crossings, and detects combinational loops at compile time. Furthermore, designs can be tested immediately as native software executables without running slow commercial simulators. Lowering to Verilog is a synthesis step analogous to a compiler compiling C code down to assembly.
-
While TxHDL addresses some modularity challenges shared with Bluespec, its development proceeded independently as a pure register-transfer library. ↩︎