Chisel

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

GCD

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]:
val gcd : t -> t -> t -> t * t = <fun>

MaxN

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]:
val maxn : t list -> t = <fun>

Mul

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]:
val rom_of_binop : (t -> t -> t) -> t -> t -> t = <fun>
Out[4]:
val mulu_rom : t -> t -> t = <fun>

Adder

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]:
val fa : t -> t -> t -> t * t = <fun>
Out[5]:
val adder : t -> t -> t -> t = <fun>