Calyx is a compiler infrastructure for languages that target hardware accelerators. Calyx’s control language simplifies encoding of high-level semantics. The Calyx compiler automatically optimizes and lowers programs into synthesizable hardware designs. Calyx has been integrated with the LLVM CIRCT infrastructure and is available as a dialect within it.
If you’re interested in building on Calyx, please join our Zulip chat or start a discussion and let’s chat!
Components are the basic building block of Calyx programs. A component has three sections: cells, wires, and control. An empty component does nothing.
component main() -> () {
cells { }
wires { }
control { }
}
The cells section instantiates sub-components like adders and registers. These sub-components can be used in this component to define behaviour.
component main() -> () {
cells {
// A 32-bit register
c = std_reg(32);
}
wires { }
control { }
}
The wires section specifies connections to cells. They are continuously active by default and work like non-blocking assignments in RTL.
Guarded assignments have a boolean expression that controls when the assignment should be active.
component main() -> () {
cells {
// A 1-bit register
b = std_reg(1);
// A 32-bit register
c = std_reg(32);
}
wires {
// write a 1-bit constant to b
b.in = 1'd1;
b.write_en = 1'd1;
// write 1 when b.out == 1
c.in = b.out ? 32'd1;
// write 2 when b.out == 0
c.in = !b.out ? 32'd2;
}
control { }
}
A group is a collection
of assignments that are only active when the group is run from
the control program. The write_c[done]
port is a special
port defined on groups that signify when the group has finished.
component main() -> () {
cells {
// A 32-bit register
c = std_reg(32);
}
wires {
group write_c {
c.in = 32'd1;
c.write_en = 1'd1;
// group is done when reg is done
write_c[done] = c.done;
}
}
control { }
}
The control language specifies the order to run
groups. The language has the normal imperative
control flow operators: seq
, if
, and while
.
It also has par
to express parallel composition.
component main() -> () {
cells {
a = std_reg(32);
b = std_reg(32);
}
wires {
group write_a { ... }
group read_a { ... }
group write_b { ... }
}
control {
seq {
write_a;
par {
read_a;
write_b;
}
}
}
}