Skip to content
/ hdl Public

A proof-of-concept, Rust-inspired, declarative hardware description language optimized for RTL coding

License

Notifications You must be signed in to change notification settings

Jacajack/hdl

Folders and files

NameName
Last commit message
Last commit date
Nov 23, 2023
Jan 2, 2024
Mar 29, 2023
May 25, 2023
Nov 5, 2023
Nov 19, 2024
Nov 19, 2024
Jan 4, 2024
Jan 4, 2024
Oct 30, 2023
Apr 11, 2023
Jan 11, 2024
Nov 23, 2023
Apr 14, 2023
Nov 19, 2024
May 6, 2024
Jan 5, 2024
Apr 11, 2023

Repository files navigation

HIRL Hardware Description Language

Main CI codecov

HIRL (working name: Hardware Intermediate Representation Language) is a proof-of-concept, declarative hardware description language optimized for RTL coding, aiming to provide modern Rust-like syntax and more restrictive semantics protecting the user from typical errors.

Notable features:

  • Syntax inspired by Rust and C++
  • Sensitivity semantics in the type system provide basic CDC validation
  • Restrictive signal width and signedness semantics
  • Bi-directional type deduction - not all types need to be explicitly specified in assignments
  • No implicit conversions - potentially harmful implicit conversions are not allowed
  • Generic constructs compiled to equivalent generic System Verilog code
  • Builtin elab phase ensuring proper use of signals (i.e. no double drivers, no dangling inputs etc.)
  • Interoperability with System Verilog

Examples

This section presents some basic code examples. More code samples can be found in the tests directory.

Combinational full adder

// Interface definition
module full_adder {
	// All inputs and outputs are asynchronous
	input async a;
	input async b;
	input async cin;
	output async cout;
	output async q;
}

// Module logic
impl full_adder {
	cout = (a & b) | (cin & (a ^ b));
	q = a ^ b ^ cin;
}

Simple counter

module simple_counter{
	// Clock input
	input clock clk;

	// Asynchronous reset signal (active low)
	input async wire nreset;

	// Combinational enable signal (clock domain is clk)
	input comb(clk) wire enable;

	// Synchronous 16-bit output bus
	output unsigned sync(clk) bus<16> data;
}

impl simple_counter {
	// data is 16 bits wide, 1u1 is 1 bit wide.
	// Addition result is 17-bit and therefore needs 
	// to be explicitly truncated with trunc() builtin function
	bus<16> counter_next = trunc(data + 1u1);

	// Register storing counter's value
	reg counter{
		clk,    // Auto-connected to `clk`
		nreset, // Auto-connected to `nreset`
		en: enable, // Enable the register with `enable` signal
		next: counter_next, // Next value for the register
		data, // Output is auto-connected to `data`
	};
}

Building

Use Cargo for building. The compiler has builtin command line help. For practical example of use please also see this Makefile.

Coverage graphs