Chisel is a recently released HDL similar to HardCaml based on Scala. To constrast and compare here are a few examples from the Chisel website converted to HardCaml.
In [1]:
open HardCaml
open Signal.Comb
open Signal.Seq
open Signal.Guarded
class GCD extends Module {
val io = new Bundle {
val a = UInt(INPUT, 16)
val b = UInt(INPUT, 16)
val e = Bool(INPUT)
val z = UInt(OUTPUT, 16)
val v = Bool(OUTPUT)
}
val x = Reg(UInt())
val y = Reg(UInt())
when (x > y) { x := x - y }
unless (x > y) { y := y - x }
when (io.e) { x := io.a; y := io.b }
io.z := x
io.v := y === UInt(0)
}
In [2]:
let gcd e a b =
let bits = width a in
let x, y = g_reg r_sync empty bits, g_reg r_sync empty bits in
let () = compile [
g_if (x#q >: y#q)
[ x $== x#q -: y#q ]
[ y $== y#q -: x#q ];
g_when (e) [ x $== a; y $== b; ];
] in
let z, v = x#q, y#q ==:. 0 in
z, v
Out[2]:
class MaxN(n: Int, w: Int /* parameterized input */) extends Module {
private def Max2(x: UInt, y: UInt) = Mux(x > y, x, y)
val io = new Bundle {
val in = Vec.fill(n){ UInt(INPUT, w) }
val out = UInt(OUTPUT, w)
}
io.out := io.in.reduceLeft(Max2)
}
In [3]:
let maxn = reduce (fun x y -> mux2 (x >: y) x y)
Out[3]:
class Mul extends Module {
val io = new Bundle {
val x = UInt(INPUT, 4)
val y = UInt(INPUT, 4)
val z = UInt(OUTPUT, 8)
}
val muls = new ArrayBuffer[UInt]()
for (i <- 0 until 16)
for (j <- 0 until 16)
muls += UInt(i * j, width = 8)
val tbl = Vec(muls)
io.z := tbl((io.x << UInt(4)) | io.y)
}
In [4]:
let rom_of_binop f a b =
let wa, wb = width a, width b in
let na, nb = 1 lsl wa, 1 lsl wb in
let r = Array.init na (fun ia -> Array.init nb (fun ib -> f (consti wa ia) (consti wb ib))) in
r |> Array.map Array.to_list |> Array.to_list |> List.concat |> mux (a @: b)
let mulu_rom = rom_of_binop ( *: )
Out[4]:
Out[4]:
class Adder(val n:Int) extends Module {
val io = new Bundle {
val A = UInt(INPUT, n)
val B = UInt(INPUT, n)
val Cin = UInt(INPUT, 1)
val Sum = UInt(OUTPUT, n)
val Cout = UInt(OUTPUT, 1)
}
//create a vector of FullAdders
val FAs = Vec.fill(n){ Module(new FullAdder()).io }
val carry = Vec.fill(n+1){ UInt(width = 1) }
val sum = Vec.fill(n){ Bool() }
//first carry is the top level carry in
carry(0) := io.Cin
//wire up the ports of the full adders
for (i <- 0 until n) {
FAs(i).a := io.A(i)
FAs(i).b := io.B(i)
FAs(i).cin := carry(i)
carry(i+1) := FAs(i).cout
sum(i) := FAs(i).sum.toBool()
}
io.Sum := sum.toBits().toUInt()
io.Cout := carry(n)
}
In [5]:
(* single bit full adder *)
let fa c_in x y =
let sum = (x ^: y) ^: c_in in
let c_out = (x &: y) |: (x &: c_in) |: (y &: c_in) in
sum, c_out
(* ripple carry adder *)
let adder c_in x y =
let fa (result, c_in) x y =
let sum, c_out = fa c_in x y in
(sum::result), c_out
in
let result, carry = List.fold_left2 fa ([], c_in)
(List.rev (bits x)) (List.rev (bits y))
in
carry @: (result |> concat)
Out[5]:
Out[5]: