Filament is a hardware description language (HDL) that uses types to ensure that your hardware pipelines are composed correctly. Filament’s type system is very different from every other typed HDL: it uses a Rust-inspired type system to reason about structural hazards in your designs and eliminates them at compile-time. For examples of the kinds of problems Filament can solve, take a look at our tutorial.
Filament's modules are parameterized by events which denote particular clock cycles. Events are used to define the availability intervals of the module's inputs and outputs.
comp Add<'G>(
left: ['G, 'G+1] 32,
right: ['G, 'G+1] 32
) -> (out: ['G, 'G+1] 32) {...}
In addition to instantiation hardware modules (using the new
keyword), Filament uses invocations to
to denote when an instance performs some computation. This slight addition enables Filament's powerful type system to reason
about structural hazards and imbalanced pipeline paths.
comp main<'G>(
x: ['G, 'G+1] 32, y: ['G, 'G+1] 32
) -> () {
A := new Add[32]; // 32-bit adder
a0 := A<'G>(x, x); // 1st use
b0 := A<'G+2>(a0.out, y); // 2nd use
}
Each event is associated with a delay that corresponds to the pipeline's initiation interval (II)—the minimum number of clock cycles before the pipeline can process new inputs. Filament's type system checks the implementation of the component and ensures that the delay is correct. This means that your components support the II they promise!
// Processes new inputs every cycle
comp Add<'G:1>(
left: ['G, 'G+1] 32,
right: ['G, 'G+1] 32
) -> (out: ['G, 'G+1] 32) {...}
Filament's guarantees extend to generative programs that generate hardware based on parameters. for
loops and if
statements can be used to generate hardware and Filament's type system ensures that all valid parameters generate correctly pipelined hardware. This is a really strong property because once your program type checks, you know that all possible instantiations of the program will work!
/* A parameteric shift register */
comp Shift[W, N]<'G:1>(
in: ['G, 'G+1] W
) -> (
// delay the signal by N cycles
out: ['G+N, 'G+N+1] W
) {
// Tracks the wires b/w registers
bundle f[N+1]: for<k> ['G+k, 'G+k+1] W;
f{0} = in;
for i in 0..N {
d := new Delay[W]<'G+i>(f{i});
f{i+1} = d.out;
}
out = f{N};
}